diff --git a/.editorconfig b/.editorconfig index 598dd721..167f4671 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,9 @@ -root = true - -[*] -end_of_line = crlf -insert_final_newline = true - -[*.cs] -indent_style = tab -trim_trailing_whitespace = true +root = true + +[*] +end_of_line = crlf +insert_final_newline = true + +[*.cs] +indent_style = tab +trim_trailing_whitespace = true diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..c1f89e94 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "TerrariaServerAPI"] + path = TerrariaServerAPI + url = https://github.com/Deathmax/TerrariaAPI-Server.git diff --git a/CONTRIBUTING b/CONTRIBUTING index 8f36fd52..095ad8ea 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -1,36 +1,36 @@ -### Issue Guidelines -Please follow these simple requirements before posting an issue: - -1. TShock version number -2. Any stack traces that may have happened when the issue occurred -3. How to reproduce the issue - -### Pull Request Dev Guidelines - -These guidelines are for contributors. If you do not follow these guidelines your commits will be reverted. - -Required: -- Follow the code style. We generally use microsofts except for m_ infront of private variables. -- Do not push unfinished features to the master branch, instead create a remote branch and push to that. -- Do not push untested code to the master branch, instead push to the test branch. -- Document all compatibility issues in the COMPATIBILITY file. (IE file formats changing) -- DO NOT MASS COMMIT. Commit changes as you go (without pushing). That way when you push we don't get a thousand changes with a 1-3 line commit message. - -Optional: -- Build Version Increment (http://autobuildversion.codeplex.com/). - ----- - -### Dev Team Guidelines - -These guidelines are to be followed by all developers with commit level access to this repository: - -- Do not, for any reason, submit code to the master branch before it hits the development branch first. If the development branch is far ahead, and a new bug fix is going out, branch master, then merge with master and remove your branch. - - If you are found to do this, you will be the person merging and rebasing your code to fit general-devel. -- Prior to posting any version on the website, you must tick the version in AssemblyInfo.cs. This is the versioning formula: - - Major.Minor.Revision.BuildDate (tick Revision if you're fixing prior to an actual planned release) -- Do not release any development builds on the forums without consulting another developer first. -- __Document code prior to marking it done in JIRA__ -- Move any un-tested code to the "Needs Validation" section on JIRA prior to marking it as done. -- Do not push changes to any branch without a proper issue being assigned in JIRA. If a feature isn't planned for this release, __it shouldn't be in the repo about to be released__. +### Issue Guidelines +Please follow these simple requirements before posting an issue: + +1. TShock version number +2. Any stack traces that may have happened when the issue occurred +3. How to reproduce the issue + +### Pull Request Dev Guidelines + +These guidelines are for contributors. If you do not follow these guidelines your commits will be reverted. + +Required: +- Follow the code style. We generally use microsofts except for m_ infront of private variables. +- Do not push unfinished features to the master branch, instead create a remote branch and push to that. +- Do not push untested code to the master branch, instead push to the test branch. +- Document all compatibility issues in the COMPATIBILITY file. (IE file formats changing) +- DO NOT MASS COMMIT. Commit changes as you go (without pushing). That way when you push we don't get a thousand changes with a 1-3 line commit message. + +Optional: +- Build Version Increment (http://autobuildversion.codeplex.com/). + +---- + +### Dev Team Guidelines + +These guidelines are to be followed by all developers with commit level access to this repository: + +- Do not, for any reason, submit code to the master branch before it hits the development branch first. If the development branch is far ahead, and a new bug fix is going out, branch master, then merge with master and remove your branch. + - If you are found to do this, you will be the person merging and rebasing your code to fit general-devel. +- Prior to posting any version on the website, you must tick the version in AssemblyInfo.cs. This is the versioning formula: + - Major.Minor.Revision.BuildDate (tick Revision if you're fixing prior to an actual planned release) +- Do not release any development builds on the forums without consulting another developer first. +- __Document code prior to marking it done in JIRA__ +- Move any un-tested code to the "Needs Validation" section on JIRA prior to marking it as done. +- Do not push changes to any branch without a proper issue being assigned in JIRA. If a feature isn't planned for this release, __it shouldn't be in the repo about to be released__. - Submit all pull requests to the general-devel branch prior to the master branch, or you will be ignored. \ No newline at end of file diff --git a/TShock.sln b/TShock.sln index da320f87..904e7dcd 100644 --- a/TShock.sln +++ b/TShock.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\Unit EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockRestTestPlugin", "TShockRestTestPlugin\TShockRestTestPlugin.csproj", "{F2FEDAFB-58DE-4611-9168-A86112C346C7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerrariaAPI-Server", "TerrariaServerAPI\TerrariaAPI-Server.csproj", "{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}" +EndProject Global GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = Terraria.vsmdi @@ -52,6 +54,18 @@ Global {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|x86.ActiveCfg = Release|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Any CPU.Build.0 = Debug|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|x86.ActiveCfg = Debug|x86 + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|x86.Build.0 = Debug|x86 + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Any CPU.ActiveCfg = Release|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Any CPU.Build.0 = Release|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|x86.ActiveCfg = Release|x86 + {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs old mode 100644 new mode 100755 index 7ff6516d..72e7ff34 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -24,7 +24,6 @@ using System.IO; using System.Linq; using System.Text; using System.Threading; -using TShockAPI.PluginUpdater; using Terraria; using TShockAPI.DB; @@ -58,14 +57,29 @@ namespace TShockAPI public class Command { - public string Name - { - get { return Names[0]; } - } - - public List Names { get; protected set; } - public bool AllowServer { get; set; } + /// + /// Gets or sets whether to allow non-players to use this command. + /// + public bool AllowServer { get; set; } + /// + /// Gets or sets whether to do logging of this command. + /// public bool DoLog { get; set; } + /// + /// Gets or sets the help text of this command. + /// + public string HelpText { get; set; } + /// + /// Gets the name of the command. + /// + public string Name { get { return Names[0]; } } + /// + /// Gets the names of the command. + /// + public List Names { get; protected set; } + /// + /// Gets the permissions of the command. + /// public List Permissions { get; protected set; } private CommandDelegate commandDelegate; @@ -81,16 +95,16 @@ namespace TShockAPI } } - public Command(List permissionsneeded, CommandDelegate cmd, params string[] names) + public Command(List permissions, CommandDelegate cmd, params string[] names) : this(cmd, names) { - Permissions = permissionsneeded; + Permissions = permissions; } - public Command(string permissionneeded, CommandDelegate cmd, params string[] names) + public Command(string permissions, CommandDelegate cmd, params string[] names) : this(cmd, names) { - Permissions = new List { permissionneeded }; + Permissions = new List { permissions }; } public Command(CommandDelegate cmd, params string[] names) @@ -99,11 +113,13 @@ namespace TShockAPI 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; + CommandDelegate = cmd; DoLog = true; + HelpText = "No help available."; + Names = new List(names); + Permissions = new List(); } public bool Run(string msg, TSPlayer ply, List parms) @@ -152,100 +168,381 @@ namespace TShockAPI public static void InitCommands() { List tshockCommands = new List(100); - Action add2 = (cmd) => + Action add = (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.user, 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.worldspawn, 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.cfgreload, Reload, "reload"); - add(Permissions.cfgpassword, ServerPassword, "serverpassword"); - add(Permissions.worldsave, Save, "save"); - add(Permissions.worldsettle, Settle, "settle"); - add(Permissions.cfgmaxspawns, MaxSpawns, "maxspawns"); - add(Permissions.cfgspawnrate, SpawnRate, "spawnrate"); - add(Permissions.time, Time, "time"); - add(Permissions.slap, 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.authverify, AuthVerify, "auth-verify"); - add(Permissions.broadcast, 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.serverinfo, ServerInfo, "stats"); - add(Permissions.worldinfo, 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"); + add(new Command(AuthToken, "auth") + { + AllowServer = false, + HelpText = "Used to authenticate as superadmin when first setting up TShock." + }); + add(new Command(Permissions.authverify, AuthVerify, "auth-verify") + { + HelpText = "Used to verify that you have correctly set up TShock." + }); + add(new Command(Permissions.user, ManageUsers, "user") + { + DoLog = false, + HelpText = "Manages user accounts." + }); + + #region Account Commands + add(new Command(Permissions.canlogin, AttemptLogin, "login") + { + AllowServer = false, + DoLog = false, + HelpText = "Logs you into an account." + }); + add(new Command(Permissions.canchangepassword, PasswordUser, "password") + { + AllowServer = false, + DoLog = false, + HelpText = "Changes your account's password." + }); + add(new Command(Permissions.canregister, RegisterUser, "register") + { + AllowServer = false, + DoLog = false, + HelpText = "Registers you an account." + }); + #endregion + #region Admin Commands + add(new Command(Permissions.ban, Ban, "ban") + { + HelpText = "Manages player bans." + }); + add(new Command(Permissions.broadcast, Broadcast, "broadcast", "bc", "say") + { + HelpText = "Broadcasts a message to everyone on the server." + }); + add(new Command(Permissions.logs, DisplayLogs, "displaylogs") + { + HelpText = "Toggles whether you receive server logs." + }); + add(new Command(Permissions.managegroup, Group, "group") + { + HelpText = "Manages groups." + }); + add(new Command(Permissions.manageitem, ItemBan, "itemban") + { + HelpText = "Manages item bans." + }); + add(new Command(Permissions.manageregion, Region, "region") + { + HelpText = "Manages regions." + }); + add(new Command(Permissions.kick, Kick, "kick") + { + HelpText = "Removes a player from the server." + }); + add(new Command(Permissions.mute, Mute, "mute", "unmute") + { + HelpText = "Prevents a player from talking." + }); + add(new Command(Permissions.savessc, OverrideSSC, "overridessc", "ossc") + { + HelpText = "Overrides serverside characters for a player, temporarily." + }); + add(new Command(Permissions.savessc, SaveSSC, "savessc") + { + HelpText = "Saves all serverside characters." + }); + add(new Command(Permissions.settempgroup, TempGroup, "tempgroup") + { + HelpText = "Temporarily sets another player's group." + }); + add(new Command(Permissions.userinfo, GrabUserUserInfo, "userinfo", "ui") + { + HelpText = "Shows information about a user." + }); + #endregion + #region Annoy Commands + add(new Command(Permissions.annoy, Annoy, "annoy") + { + HelpText = "Annoys a player for an amount of time." + }); + add(new Command(Permissions.annoy, Confuse, "confuse") + { + HelpText = "Confuses a player for an amount of time." + }); + add(new Command(Permissions.annoy, Rocket, "rocket") + { + HelpText = "Rockets a player upwards. Requires SSC." + }); + add(new Command(Permissions.annoy, FireWork, "firework") + { + HelpText = "Spawns fireworks at a player." + }); + #endregion + #region Configuration Commands + add(new Command(Permissions.maintenance, CheckUpdates, "checkupdates") + { + HelpText = "Checks for TShock updates." + }); + add(new Command(Permissions.maintenance, Off, "off", "exit") + { + HelpText = "Shuts down the server while saving." + }); + add(new Command(Permissions.maintenance, OffNoSave, "off-nosave", "exit-nosave") + { + HelpText = "Shuts down the server without saving." + }); + add(new Command(Permissions.maintenance, Reload, "reload") + { + HelpText = "Reloads the server configuration file." + }); + add(new Command(Permissions.maintenance, Restart, "restart") + { + HelpText = "Restarts the server." + }); + add(new Command(Permissions.cfgpassword, ServerPassword, "serverpassword") + { + HelpText = "Changes the server password." + }); + add(new Command(Permissions.maintenance, GetVersion, "version") + { + HelpText = "Shows the TShock version." + }); + /* Does nothing atm. + * + * add(new Command(Permissions.updateplugins, UpdatePlugins, "updateplugins") + { + });*/ + add(new Command(Permissions.whitelist, Whitelist, "whitelist") + { + HelpText = "Manages the server whitelist." + }); + #endregion + #region Item Commands + add(new Command(Permissions.item, Give, "give", "g") + { + HelpText = "Gives another player an item." + }); + add(new Command(Permissions.item, Item, "item", "i") + { + AllowServer = false, + HelpText = "Gives yourself an item." + }); + #endregion + #region NPC Commands + add(new Command(Permissions.butcher, Butcher, "butcher") + { + HelpText = "Kills hostile NPCs or NPCs of a certain type." + }); + add(new Command(Permissions.invade, Invade, "invade") + { + HelpText = "Starts an NPC invasion." + }); + add(new Command(Permissions.maxspawns, MaxSpawns, "maxspawns") + { + HelpText = "Sets the maximum number of NPCs." + }); + add(new Command(Permissions.spawnboss, SpawnBoss, "spawnboss", "sb") + { + AllowServer = false, + HelpText = "Spawns a number of bosses around you." + }); + add(new Command(Permissions.spawnmob, SpawnMob, "spawnmob", "sm") + { + AllowServer = false, + HelpText = "Spawns a number of mobs around you." + }); + add(new Command(Permissions.spawnrate, SpawnRate, "spawnrate") + { + HelpText = "Sets the spawn rate of NPCs." + }); + add(new Command(Permissions.invade, PumpkinInvasion, "pumpkin") + { + HelpText = "Starts a Pumpkin Moon invasion at the specified wave." + }); + add(new Command(Permissions.invade, SnowInvasion, "snowinvasion") + { + HelpText = "Starts a Snow Moon invasion at the specified wave." + }); + #endregion + #region TP Commands + add(new Command(Permissions.home, Home, "home") + { + AllowServer = false, + HelpText = "Sends you to your spawn point." + }); + add(new Command(Permissions.spawn, Spawn, "spawn") + { + AllowServer = false, + HelpText = "Sends you to the world's spawn point." + }); + add(new Command(Permissions.tp, TP, "tp") + { + AllowServer = false, + HelpText = "Teleports you to another player or a coordinate." + }); + add(new Command(Permissions.tpallow, TPAllow, "tpallow") + { + AllowServer = false, + HelpText = "Toggles whether other people can teleport to you." + }); + add(new Command(Permissions.tphere, TPHere, "tphere") + { + AllowServer = false, + HelpText = "Teleports another player to you." + }); + #endregion + #region World Commands + add(new Command(Permissions.antibuild, ToggleAntiBuild, "antibuild") + { + HelpText = "Toggles build protection." + }); + add(new Command(Permissions.bloodmoon, Bloodmoon, "bloodmoon") + { + HelpText = "Sets a blood moon." + }); + add(new Command(Permissions.snowmoon, SnowMoon, "snowmoon") + { + HelpText = "Sets a snow moon." + }); + add(new Command(Permissions.pumpkinmoon, PumpkinMoon, "pumpkinmoon") + { + HelpText = "Sets a pumpkin moon." + }); + add(new Command(Permissions.grow, Grow, "grow") + { + AllowServer = false, + HelpText = "Grows plants at your location." + }); + add(new Command(Permissions.dropmeteor, DropMeteor, "dropmeteor") + { + HelpText = "Drops a meteor somewhere in the world." + }); + add(new Command(Permissions.eclipse, Eclipse, "eclipse") + { + HelpText = "Sets an eclipse." + }); + add(new Command(Permissions.xmas, ForceXmas, "forcexmas") + { + HelpText = "Toggles christmas mode (present spawning, santa, etc)." + }); + add(new Command(Permissions.fullmoon, Fullmoon, "fullmoon") + { + HelpText = "Sets a full moon." + }); + add(new Command(Permissions.hardmode, Hardmode, "hardmode") + { + HelpText = "Toggles the world's hardmode status." + }); + add(new Command(Permissions.editspawn, ProtectSpawn, "protectspawn") + { + HelpText = "Toggles spawn protection." + }); + add(new Command(Permissions.rain, Rain, "rain") + { + HelpText = "Toggles the rain." + }); + add(new Command(Permissions.worldsave, Save, "save") + { + HelpText = "Saves the world file." + }); + add(new Command(Permissions.worldspawn, SetSpawn, "setspawn") + { + AllowServer = false, + HelpText = "Sets the world's spawn point to your location." + }); + add(new Command(Permissions.worldsettle, Settle, "settle") + { + HelpText = "Forces all liquids to update immediately." + }); + add(new Command(Permissions.time, Time, "time") + { + HelpText = "Sets the world time." + }); + add(new Command(Permissions.worldinfo, WorldInfo, "world") + { + HelpText = "Shows information about the current world." + }); + #endregion + #region Other Commands + add(new Command(Permissions.buff, Buff, "buff") + { + AllowServer = false, + HelpText = "Gives yourself a buff for an amount of time." + }); + add(new Command(Permissions.clear, Clear, "clear") + { + HelpText = "Clears item drops or projectiles." + }); + add(new Command(Permissions.buffplayer, GBuff, "gbuff", "buffplayer") + { + HelpText = "Gives another player a buff for an amount of time." + }); + add(new Command(Permissions.godmode, ToggleGodMode, "godmode") + { + HelpText = "Toggles godmode on a player." + }); + add(new Command(Permissions.heal, Heal, "heal") + { + HelpText = "Heals a player in HP and MP." + }); + add(new Command(Permissions.kill, Kill, "kill") + { + HelpText = "Kills another player." + }); + add(new Command(Permissions.cantalkinthird, ThirdPerson, "me") + { + HelpText = "Sends an action message to everyone." + }); + add(new Command(Permissions.canpartychat, PartyChat, "party", "p") + { + AllowServer = false, + HelpText = "Sends a message to everyone on your team." + }); + add(new Command(Permissions.whisper, Reply, "reply", "r") + { + HelpText = "Replies to a PM sent to you." + }); + add(new Command(Rests.RestPermissions.restmanage, ManageRest, "rest") + { + HelpText = "Manages the REST API." + }); + add(new Command(Permissions.slap, Slap, "slap") + { + HelpText = "Slaps a player, dealing damage." + }); + add(new Command(Permissions.serverinfo, ServerInfo, "stats") + { + HelpText = "Shows the server information." + }); + add(new Command(Permissions.warp, Warp, "warp") + { + HelpText = "Teleports you to a warp point or manages warps." + }); + add(new Command(Permissions.whisper, Whisper, "whisper", "w", "tell") + { + HelpText = "Sends a PM to a player." + }); + #endregion + + add(new Command(Aliases, "aliases") + { + HelpText = "Shows a command's aliases." + }); + add(new Command(Help, "help") + { + HelpText = "Lists commands or gives help on them." + }); + add(new Command(Motd, "motd") + { + HelpText = "Shows the message of the day." + }); + add(new Command(ListConnectedPlayers, "playing", "online", "who") + { + HelpText = "Shows the currently connected players." + }); + add(new Command(Rules, "rules") + { + HelpText = "Shows the server's rules." + }); TShockCommands = new ReadOnlyCollection(tshockCommands); } @@ -283,7 +580,7 @@ namespace TShockAPI 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."); + player.SendErrorMessage("You do not have access to this command."); } else if (!cmd.AllowServer && !player.RealPlayer) { @@ -313,47 +610,36 @@ namespace TShockAPI { char c = str[i]; - if (instr) + if (c == '\\' && ++i < str.Length) { - if (c == '\\') - { - if (i + 1 >= str.Length) - break; - c = GetEscape(str[++i]); - } - else if (c == '"') + if (str[i] != '"' && str[i] != ' ' && str[i] != '\\') + sb.Append('\\'); + sb.Append(str[i]); + } + else if (c == '"') + { + instr = !instr; + if (!instr) + { + ret.Add(sb.ToString()); + sb.Clear(); + } + else if (sb.Length > 0) + { + ret.Add(sb.ToString()); + sb.Clear(); + } + } + else if (IsWhiteSpace(c) && !instr) + { + if (sb.Length > 0) { 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); - } - } + sb.Append(c); } if (sb.Length > 0) ret.Add(sb.ToString()); @@ -381,13 +667,6 @@ namespace TShockAPI return c == ' ' || c == '\t' || c == '\n'; } - //private static void TestCallbackCommand(CommandArgs args) - //{ - // Action a = (s) => { ((CommandArgs)s).Player.SendSuccessMessage("This is your callack"); }; - // args.Player.AddResponse( "yes", a); - // args.Player.SendInfoMessage( "Type /yes to get called back." ); - //} - #region Account commands private static void AttemptLogin(CommandArgs args) @@ -402,18 +681,25 @@ namespace TShockAPI User user = TShock.Users.GetUserByName(args.Player.Name); string encrPass = ""; - - if (args.Parameters.Count == 1) + bool usingUUID = false; + if (args.Parameters.Count == 0 && !TShock.Config.DisableUUIDLogin) { - if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0])) - return; + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, "")) + return; + user = TShock.Users.GetUserByName(args.Player.Name); + usingUUID = true; + } + else if (args.Parameters.Count == 1) + { + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0])) + return; user = TShock.Users.GetUserByName(args.Player.Name); encrPass = TShock.Utils.HashPassword(args.Parameters[0]); } else if (args.Parameters.Count == 2 && TShock.Config.AllowLoginAnyUsername) { - if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1])) - return; + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1])) + return; user = TShock.Users.GetUserByName(args.Parameters[0]); encrPass = TShock.Utils.HashPassword(args.Parameters[1]); @@ -425,7 +711,9 @@ namespace TShockAPI } else { - args.Player.SendErrorMessage(String.Format("Syntax: /login{0} ", TShock.Config.AllowLoginAnyUsername ? " [username]" : " ")); + args.Player.SendErrorMessage("Syntax: /login - Logs in using your UUID and character name"); + args.Player.SendErrorMessage(" /login - Logs in using your password and character name"); + args.Player.SendErrorMessage(" /login - Logs in using your username and password"); args.Player.SendErrorMessage("If you forgot your password, there is no way to recover it."); return; } @@ -435,25 +723,21 @@ namespace TShockAPI { args.Player.SendErrorMessage("A user by that name does not exist."); } - else if (user.Password.ToUpper() == encrPass.ToUpper()) + else if (user.Password.ToUpper() == encrPass.ToUpper() || + (usingUUID && user.UUID == args.Player.UUID && !TShock.Config.DisableUUIDLogin && + !String.IsNullOrWhiteSpace(args.Player.UUID))) { - args.Player.PlayerData = TShock.InventoryDB.GetPlayerData(args.Player, TShock.Users.GetUserID(user.Name)); + args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, TShock.Users.GetUserID(user.Name)); var group = TShock.Utils.GetGroup(user.Group); - if (TShock.Config.ServerSideInventory) + if (TShock.Config.ServerSideCharacter) { if (group.HasPermission(Permissions.bypassinventorychecks)) { args.Player.IgnoreActionsForClearingTrashCan = false; } - else if (!TShock.CheckInventory(args.Player)) - { - args.Player.LoginFailsBySsi = true; - args.Player.SendErrorMessage("Login failed. Please fix the above errors then /login again."); - args.Player.IgnoreActionsForClearingTrashCan = true; - return; - } + args.Player.PlayerData.RestoreCharacter(args.Player); } args.Player.LoginFailsBySsi = false; @@ -464,16 +748,16 @@ namespace TShockAPI args.Player.IgnoreActionsForDisabledArmor = "none"; args.Player.Group = group; - args.Player.tempGroup = null; + args.Player.tempGroup = null; args.Player.UserAccountName = user.Name; args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName); args.Player.IsLoggedIn = true; args.Player.IgnoreActionsForInventory = "none"; - if (!args.Player.IgnoreActionsForClearingTrashCan) + if (!args.Player.IgnoreActionsForClearingTrashCan && TShock.Config.ServerSideCharacter) { - args.Player.PlayerData.CopyInventory(args.Player); - TShock.InventoryDB.InsertPlayerData(args.Player); + args.Player.PlayerData.CopyCharacter(args.Player); + TShock.CharacterDB.InsertPlayerData(args.Player); } args.Player.SendSuccessMessage("Authenticated as " + user.Name + " successfully."); @@ -483,17 +767,25 @@ namespace TShockAPI if (TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP) != Vector2.Zero) { Vector2 pos = TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP); - args.Player.Teleport((int)pos.X, (int)pos.Y + 3); + args.Player.Teleport((int) pos.X*16, (int) pos.Y*16); } args.Player.LoginHarassed = false; } + TShock.Users.SetUserUUID(user, args.Player.UUID); - Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); + Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); } else { - args.Player.SendErrorMessage("Incorrect password."); + if (usingUUID && !TShock.Config.DisableUUIDLogin) + { + args.Player.SendErrorMessage("UUID does not match this character!"); + } + else + { + args.Player.SendErrorMessage("Invalid password!"); + } Log.Warn(args.Player.IP + " failed to authenticate as user: " + user.Name + "."); args.Player.LoginAttempts++; } @@ -515,7 +807,7 @@ namespace TShockAPI string encrPass = TShock.Utils.HashPassword(args.Parameters[0]); if (user.Password.ToUpper() == encrPass.ToUpper()) { - args.Player.SendSuccessMessage("You changed your password to " + args.Parameters[1] + "!"); + args.Player.SendSuccessMessage("You changed your password!"); TShock.Users.SetUserPassword(user, args.Parameters[1]); // SetUserPassword will hash it for you. Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of account " + user.Name + "."); } @@ -561,13 +853,15 @@ namespace TShockAPI } user.Group = TShock.Config.DefaultRegistrationGroupName; // FIXME -- we should get this from the DB. --Why? + user.UUID = args.Player.UUID; if (TShock.Users.GetUserByName(user.Name) == null && user.Name != TSServerPlayer.AccountName) // Cheap way of checking for existance of a user { - args.Player.SendSuccessMessage("Account " + user.Name + " has been registered."); - args.Player.SendSuccessMessage("Your password is " + user.Password); + args.Player.SendSuccessMessage("Account \"{0}\" has been registered.", user.Name); + args.Player.SendSuccessMessage("Your password is {0}.", user.Password); TShock.Users.AddUser(user); - Log.ConsoleInfo(args.Player.Name + " registered an account: " + user.Name + "."); + TShock.CharacterDB.SeedInitialData(TShock.Users.GetUser(user)); + Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name); } else { @@ -608,6 +902,7 @@ namespace TShockAPI args.Player.SendSuccessMessage("Account " + user.Name + " has been added to group " + user.Group + "!"); TShock.Users.AddUser(user); + TShock.CharacterDB.SeedInitialData(TShock.Users.GetUser(user)); Log.ConsoleInfo(args.Player.Name + " added Account " + user.Name + " to group " + user.Group); } else @@ -739,19 +1034,7 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(args.Parameters[0]); if (players.Count > 1) { - var plrMatches = ""; - foreach (TSPlayer plr in players) - { - if (plrMatches.Length != 0) - { - plrMatches += ", " + plr.Name; - } - else - { - plrMatches += plr.Name; - } - } - args.Player.SendErrorMessage("More than one player matched! Matches: " + plrMatches); + TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); return; } try @@ -785,19 +1068,7 @@ namespace TShockAPI } else if (players.Count > 1) { - var plrMatches = ""; - foreach (TSPlayer plr in players) - { - if (plrMatches.Length != 0) - { - plrMatches += ", " + plr.Name; - } - else - { - plrMatches += plr.Name; - } - } - args.Player.SendErrorMessage("More than one player matched! Matches: " + plrMatches); + TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); } else { @@ -813,279 +1084,226 @@ namespace TShockAPI private static void Ban(CommandArgs args) { - if (args.Parameters.Count == 0 || args.Parameters[0].ToLower() == "help") + string subcmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower(); + switch (subcmd) { - args.Player.SendInfoMessage("Syntax: /ban [option] [arguments]"); - args.Player.SendInfoMessage("Options: list, listip, clear, add, addip, del, delip"); - args.Player.SendInfoMessage("Arguments: list, listip, clear [code], add [name], addip [ip], del [name], delip [name]"); - args.Player.SendInfoMessage("In addition, a reason may be provided for all new bans after the arguments."); - return; - } - if (args.Parameters[0].ToLower() == "list") - { - #region List bans - if (TShock.Bans.GetBans().Count == 0) - { - args.Player.SendErrorMessage("There are currently no players banned."); - return; - } - - string banString = ""; - foreach (Ban b in TShock.Bans.GetBans()) - { - - if (b.Name.Trim() == "") - { - continue; - } - - if (banString.Length == 0) - { - banString = b.Name; - } - else - { - int length = banString.Length; - while (length > 60) - { - length = length - 60; - } - if (length + b.Name.Length >= 60) - { - banString += "|, " + b.Name; - } - else - { - banString += ", " + b.Name; - } - } - } - - String[] banStrings = banString.Split('|'); - - if (banStrings.Length == 0) - { - args.Player.SendErrorMessage("There are currently no players with valid names banned."); - return; - } - - if (banStrings[0].Trim() == "") - { - args.Player.SendErrorMessage("There are currently no bans with valid names found."); - return; - } - - args.Player.SendInfoMessage("List of banned players:"); - foreach (string s in banStrings) - { - args.Player.SendInfoMessage(s); - } - return; - #endregion List bans - } - - if (args.Parameters[0].ToLower() == "listip") - { - #region List ip bans - if (TShock.Bans.GetBans().Count == 0) - { - args.Player.SendWarningMessage("There are currently no players banned."); - return; - } - - string banString = ""; - foreach (Ban b in TShock.Bans.GetBans()) - { - - if (b.IP.Trim() == "") - { - continue; - } - - if (banString.Length == 0) - { - banString = b.IP; - } - else - { - int length = banString.Length; - while (length > 60) - { - length = length - 60; - } - if (length + b.Name.Length >= 60) - { - banString += "|, " + b.IP; - } - else - { - banString += ", " + b.IP; - } - } - } - - String[] banStrings = banString.Split('|'); - - if (banStrings.Length == 0) - { - args.Player.SendErrorMessage("There are currently no players with valid IPs banned."); - return; - } - - if (banStrings[0].Trim() == "") - { - args.Player.SendErrorMessage("There are currently no bans with valid IPs found."); - return; - } - - args.Player.SendInfoMessage("List of IP banned players:"); - foreach (string s in banStrings) - { - args.Player.SendInfoMessage(s); - } - return; - #endregion List ip bans - } - - if (args.Parameters.Count >= 2) - { - if (args.Parameters[0].ToLower() == "add") - { + case "add": #region Add ban - string plStr = args.Parameters[1]; - var players = TShock.Utils.FindPlayer(plStr); - if (players.Count == 0) { - args.Player.SendErrorMessage("Invalid player!"); - } - else if (players.Count > 1) - { - var plrMatches = ""; - foreach (TSPlayer plr in players) + if (args.Parameters.Count < 2) { - if (plrMatches.Length != 0) - { - plrMatches += ", " + plr.Name; - } - else - { - plrMatches += plr.Name; - } + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /ban add [reason]"); + return; + } + + List players = TShock.Utils.FindPlayer(args.Parameters[1]); + if (players.Count == 0) + args.Player.SendErrorMessage("Invalid player!"); + else if (players.Count > 1) + TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + else + { + string reason = args.Parameters.Count > 2 + ? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2)) + : "Misbehavior."; + + if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.UserAccountName)) + args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name); } - args.Player.SendErrorMessage("More than one player matched! Matches: " + plrMatches); } - else + #endregion + return; + case "addip": + #region Add IP ban { + if (args.Parameters.Count < 2) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /ban addip [reason]"); + return; + } + + string ip = args.Parameters[1]; string reason = args.Parameters.Count > 2 ? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2)) - : "Misbehavior."; - if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.UserAccountName)) + : "Manually added IP address ban."; + TShock.Bans.AddBan(ip, "", "", reason, false, args.Player.UserAccountName); + args.Player.SendSuccessMessage("Banned IP {0}.", ip); + } + #endregion + return; + case "addtemp": + #region Add temp ban + { + if (args.Parameters.Count < 3) { - args.Player.SendErrorMessage("You can't ban another admin!"); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /ban addtemp