/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using TShockAPI.PluginUpdater;
using Terraria;
using TShockAPI.DB;
using System.Reflection;
namespace TShockAPI
{
public delegate void CommandDelegate(CommandArgs args);
public class CommandArgs : EventArgs
{
public string Message { get; private set; }
public TSPlayer Player { get; private set; }
///
/// Parameters passed to the arguement. Does not include the command name.
/// IE '/kick "jerk face"' will only have 1 argument
///
public List Parameters { get; private set; }
public Player TPlayer
{
get { return Player.TPlayer; }
}
public CommandArgs(string message, TSPlayer ply, List args)
{
Message = message;
Player = ply;
Parameters = args;
}
}
public class Command
{
public string Name
{
get { return Names[0]; }
}
public List Names { get; protected set; }
public bool AllowServer { get; set; }
public bool DoLog { get; set; }
public List Permissions { get; protected set; }
private CommandDelegate commandDelegate;
public CommandDelegate CommandDelegate
{
get { return commandDelegate; }
set
{
if (value == null)
throw new ArgumentNullException();
commandDelegate = value;
}
}
public Command(List permissionsneeded, CommandDelegate cmd, params string[] names)
: this(cmd, names)
{
Permissions = permissionsneeded;
}
public Command(string permissionneeded, CommandDelegate cmd, params string[] names)
: this(cmd, names)
{
Permissions = new List { permissionneeded };
}
public Command(CommandDelegate cmd, params string[] names)
{
if (cmd == null)
throw new ArgumentNullException("cmd");
if (names == null || names.Length < 1)
throw new ArgumentException("names");
Permissions = new List();
Names = new List(names);
CommandDelegate = cmd;
AllowServer = true;
DoLog = true;
}
public bool Run(string msg, TSPlayer ply, List parms)
{
if (!CanRun(ply))
return false;
try
{
CommandDelegate(new CommandArgs(msg, ply, parms));
}
catch (Exception e)
{
ply.SendErrorMessage("Command failed, check logs for more details.");
Log.Error(e.ToString());
}
return true;
}
public bool HasAlias(string name)
{
return Names.Contains(name);
}
public bool CanRun(TSPlayer ply)
{
if (Permissions == null || Permissions.Count < 1)
return true;
foreach (var Permission in Permissions)
{
if (ply.Group.HasPermission(Permission))
return true;
}
return false;
}
}
public static class Commands
{
public static List ChatCommands = new List();
public static ReadOnlyCollection TShockCommands = new ReadOnlyCollection(new List());
private delegate void AddChatCommand(string permission, CommandDelegate command, params string[] names);
public static void InitCommands()
{
List tshockCommands = new List(100);
Action add2 = (cmd) =>
{
tshockCommands.Add(cmd);
ChatCommands.Add(cmd);
};
AddChatCommand add = (p, c, n) => add2(new Command(p, c, n));
add2(new Command(AuthToken, "auth") { AllowServer = false });
add2(new Command(Permissions.canchangepassword, PasswordUser, "password") { AllowServer = false, DoLog = false });
add2(new Command(Permissions.canregister, RegisterUser, "register") { AllowServer = false, DoLog = false });
add2(new Command(Permissions.rootonly, ManageUsers, "user") { DoLog = false });
add2(new Command(Permissions.canlogin, AttemptLogin, "login") { AllowServer = false, DoLog = false });
add2(new Command(Permissions.buff, Buff, "buff") { AllowServer = false });
add2(new Command(Permissions.cfg, SetSpawn, "setspawn") { AllowServer = false });
add2(new Command(Permissions.grow, Grow, "grow") { AllowServer = false });
add2(new Command(Permissions.item, Item, "item", "i") { AllowServer = false });
add2(new Command(Permissions.home, Home, "home") { AllowServer = false });
add2(new Command(Permissions.canpartychat, PartyChat, "p") { AllowServer = false });
add2(new Command(Permissions.spawn, Spawn, "spawn") { AllowServer = false });
add2(new Command(Permissions.tp, TP, "tp") { AllowServer = false });
add2(new Command(Permissions.tphere, TPHere, "tphere") { AllowServer = false });
add2(new Command(Permissions.tpallow, TPAllow, "tpallow") { AllowServer = false });
add(Permissions.kick, Kick, "kick");
add(Permissions.ban, Ban, "ban");
add(Permissions.whitelist, Whitelist, "whitelist");
add(Permissions.maintenance, Off, "off", "exit");
add(Permissions.maintenance, Restart, "restart");
add(Permissions.maintenance, OffNoSave, "off-nosave", "exit-nosave");
add(Permissions.maintenance, CheckUpdates, "checkupdates");
add(Permissions.updateplugins, UpdatePlugins, "updateplugins");
add(Permissions.causeevents, DropMeteor, "dropmeteor");
add(Permissions.causeevents, Star, "star");
add(Permissions.causeevents, Fullmoon, "fullmoon");
add(Permissions.causeevents, Bloodmoon, "bloodmoon");
add(Permissions.causeevents, Invade, "invade");
add(Permissions.spawnboss, Eater, "eater");
add(Permissions.spawnboss, Eye, "eye");
add(Permissions.spawnboss, King, "king");
add(Permissions.spawnboss, Skeletron, "skeletron");
add(Permissions.spawnboss, WoF, "wof", "wallofflesh");
add(Permissions.spawnboss, Twins, "twins");
add(Permissions.spawnboss, Destroyer, "destroyer");
add(Permissions.spawnboss, SkeletronPrime, "skeletronp", "prime");
add(Permissions.spawnboss, Hardcore, "hardcore");
add(Permissions.spawnmob, SpawnMob, "spawnmob", "sm");
add(Permissions.warp, Warp, "warp");
add(Permissions.managegroup, Group, "group");
add(Permissions.managegroup, GroupDeprecated, "addgroup", "delgroup", "modgroup");
add(Permissions.manageitem, ItemBan, "itemban");
add(Permissions.manageitem, ItemBanDeprecated,
"additem", "additemgroup", "banitem", "delitem", "delitemgroup", "listitems", "listbanneditems", "unbanitem");
add(Permissions.manageregion, Region, "region");
add(Permissions.manageregion, DebugRegions, "debugreg");
add(Permissions.cfg, Reload, "reload");
add(Permissions.cfg, ServerPassword, "serverpassword");
add(Permissions.cfg, Save, "save");
add(Permissions.cfg, Settle, "settle");
add(Permissions.cfg, MaxSpawns, "maxspawns");
add(Permissions.cfg, SpawnRate, "spawnrate");
add(Permissions.time, Time, "time");
add(Permissions.pvpfun, Slap, "slap");
add(Permissions.editspawn, ToggleAntiBuild, "antibuild");
add(Permissions.editspawn, ProtectSpawn, "protectspawn");
add(Permissions.maintenance, GetVersion, "version");
add(null, ListConnectedPlayers, "playing", "online", "who");
add(null, Motd, "motd");
add(null, Rules, "rules");
add(null, Help, "help");
add(Permissions.cantalkinthird, ThirdPerson, "me");
add(Permissions.mute, Mute, "mute", "unmute");
add(Permissions.logs, DisplayLogs, "displaylogs");
add(Permissions.userinfo, GrabUserUserInfo, "userinfo", "ui");
add(Permissions.rootonly, AuthVerify, "auth-verify");
add(Permissions.cfg, Broadcast, "broadcast", "bc", "say");
add(Permissions.whisper, Whisper, "whisper", "w", "tell");
add(Permissions.whisper, Reply, "reply", "r");
add(Permissions.annoy, Annoy, "annoy");
add(Permissions.kill, Kill, "kill");
add(Permissions.butcher, Butcher, "butcher");
add(Permissions.item, Give, "give", "g");
add(Permissions.clearitems, ClearItems, "clear", "clearitems");
add(Permissions.heal, Heal, "heal");
add(Permissions.buffplayer, GBuff, "gbuff", "buffplayer");
add(Permissions.hardmode, StartHardMode, "hardmode");
add(Permissions.hardmode, DisableHardMode, "stophardmode", "disablehardmode");
add(Permissions.cfg, ServerInfo, "stats");
add(Permissions.cfg, WorldInfo, "world");
add(Permissions.savessi, SaveSSI, "savessi");
add(Permissions.savessi, OverrideSSI, "overridessi", "ossi");
add(Permissions.xmas, ForceXmas, "forcexmas");
add(Permissions.settempgroup, TempGroup, "tempgroup");
add(null, Aliases, "aliases");
add(Rests.RestPermissions.restmanage, ManageRest, "rest");
//add(null, TestCallbackCommand, "test");
TShockCommands = new ReadOnlyCollection(tshockCommands);
}
public static bool HandleCommand(TSPlayer player, string text)
{
string cmdText = text.Remove(0, 1);
var args = ParseParameters(cmdText);
if (args.Count < 1)
return false;
string cmdName = args[0].ToLower();
args.RemoveAt(0);
if (Hooks.PlayerHooks.OnPlayerCommand(player, cmdName, cmdText, args))
return true;
IEnumerable cmds = ChatCommands.Where(c => c.HasAlias(cmdName));
if (cmds.Count() == 0)
{
if (player.AwaitingResponse.ContainsKey(cmdName))
{
Action call = player.AwaitingResponse[cmdName];
player.AwaitingResponse.Remove(cmdName);
call(new CommandArgs(cmdText, player, args));
return true;
}
player.SendErrorMessage("Invalid command entered. Type /help for a list of valid commands.");
return true;
}
foreach (Command cmd in cmds)
{
if (!cmd.CanRun(player))
{
TShock.Utils.SendLogs(string.Format("{0} tried to execute /{1}.", player.Name, cmdText), Color.PaleVioletRed, player);
player.SendErrorMessage("You do not have access to that command.");
}
else if (!cmd.AllowServer && !player.RealPlayer)
{
player.SendErrorMessage("You must use this command in-game.");
}
else
{
if (cmd.DoLog)
TShock.Utils.SendLogs(string.Format("{0} executed: /{1}.", player.Name, cmdText), Color.PaleVioletRed, player);
cmd.Run(cmdText, player, args);
}
}
return true;
}
///
/// Parses a string of parameters into a list. Handles quotes.
///
///
///
private static List ParseParameters(string str)
{
var ret = new List();
var sb = new StringBuilder();
bool instr = false;
for (int i = 0; i < str.Length; i++)
{
char c = str[i];
if (instr)
{
if (c == '\\')
{
if (i + 1 >= str.Length)
break;
c = GetEscape(str[++i]);
}
else if (c == '"')
{
ret.Add(sb.ToString());
sb.Clear();
instr = false;
continue;
}
sb.Append(c);
}
else
{
if (IsWhiteSpace(c))
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
}
else if (c == '"')
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
instr = true;
}
else
{
sb.Append(c);
}
}
}
if (sb.Length > 0)
ret.Add(sb.ToString());
return ret;
}
private static char GetEscape(char c)
{
switch (c)
{
case '\\':
return '\\';
case '"':
return '"';
case 't':
return '\t';
default:
return c;
}
}
private static bool IsWhiteSpace(char c)
{
return c == ' ' || c == '\t' || c == '\n';
}
//private static void TestCallbackCommand(CommandArgs args)
//{
// Action