diff --git a/.gitmodules b/.gitmodules index c1f89e94..fb54e5a5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "TerrariaServerAPI"] path = TerrariaServerAPI url = https://github.com/Deathmax/TerrariaAPI-Server.git + ignore = dirty diff --git a/Local.testsettings b/Local.testsettings deleted file mode 100644 index 24250d4b..00000000 --- a/Local.testsettings +++ /dev/null @@ -1,10 +0,0 @@ - - - These are default test settings for a local test run. - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index f394cf6c..13d50d62 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# Current Status +This project is in maintenance mode. This means that the core team of developers' time is very limited, and only extremely game breaking bugs will be fixed. Improvements, new features, and minor issues will not be resolved by direct development until this time restriction has passed. Issues created reflecting these requests will not be worked on until this notice is removed. + +Thanks for your continued support of TShock for Terraria. + # TShock [![Build Status](https://travis-ci.org/NyxStudios/TShock.png?branch=general-devel)](https://travis-ci.org/NyxStudios/TShock) TShock is a server modification for Terraria, written in C#, and based upon the [Terraria Server API](https://github.com/Deathmax/TerrariaAPI-Server). It uses JSON for configuration management, and offers several features not present in the Terraria Server normally. diff --git a/TShock.sln b/TShock.sln index 904e7dcd..5044784e 100644 --- a/TShock.sln +++ b/TShock.sln @@ -2,15 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2010 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{755F5B05-0924-47E9-9563-26EB20FE3F67}" - ProjectSection(SolutionItems) = preProject - Local.testsettings = Local.testsettings - Terraria.vsmdi = Terraria.vsmdi - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockAPI", "TShockAPI\TShockAPI.csproj", "{49606449-072B-4CF5-8088-AA49DA586694}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{F3742F51-D7BF-4754-A68A-CD944D2A21FF}" -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}" @@ -38,12 +32,6 @@ Global {49606449-072B-4CF5-8088-AA49DA586694}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {49606449-072B-4CF5-8088-AA49DA586694}.Release|Mixed Platforms.Build.0 = Release|Any CPU {49606449-072B-4CF5-8088-AA49DA586694}.Release|x86.ActiveCfg = Release|Any CPU - {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|x86.ActiveCfg = Debug|Any CPU - {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|x86.ActiveCfg = Release|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs index bc5cec6a..1882d0bb 100644 --- a/TShockAPI/BackupManager.cs +++ b/TShockAPI/BackupManager.cs @@ -1,6 +1,6 @@ /* TShock, a server mod for Terraria -Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team) +Copyright (C) 2011-2015 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 diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 72e7ff34..7837af80 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1,6 +1,6 @@ /* TShock, a server mod for Terraria -Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team) +Copyright (C) 2011-2015 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 @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -26,6 +27,7 @@ using System.Text; using System.Threading; using Terraria; using TShockAPI.DB; +using TerrariaApi.Server; namespace TShockAPI { @@ -69,6 +71,10 @@ namespace TShockAPI /// Gets or sets the help text of this command. /// public string HelpText { get; set; } + /// + /// Gets or sets an extended description of this command. + /// + public string[] HelpDesc { get; set; } /// /// Gets the name of the command. /// @@ -118,6 +124,7 @@ namespace TShockAPI CommandDelegate = cmd; DoLog = true; HelpText = "No help available."; + HelpDesc = null; Names = new List(names); Permissions = new List(); } @@ -230,6 +237,14 @@ namespace TShockAPI { HelpText = "Manages item bans." }); + add(new Command(Permissions.manageprojectile, ProjectileBan, "projban") + { + HelpText = "Manages projectile bans." + }); + add(new Command(Permissions.managetile, TileBan, "tileban") + { + HelpText = "Manages tile bans." + }); add(new Command(Permissions.manageregion, Region, "region") { HelpText = "Manages regions." @@ -332,6 +347,10 @@ namespace TShockAPI { HelpText = "Kills hostile NPCs or NPCs of a certain type." }); + add(new Command(Permissions.renamenpc, RenameNPC, "renamenpc") + { + HelpText = "Renames an NPC." + }); add(new Command(Permissions.invade, Invade, "invade") { HelpText = "Starts an NPC invasion." @@ -354,13 +373,17 @@ namespace TShockAPI { HelpText = "Sets the spawn rate of NPCs." }); - add(new Command(Permissions.invade, PumpkinInvasion, "pumpkin") + add(new Command(Permissions.invade, PumpkinMoon, "pumpkinmoon", "pmoon") { - HelpText = "Starts a Pumpkin Moon invasion at the specified wave." + HelpText = "Starts a Pumpkin Moon at the specified wave." }); - add(new Command(Permissions.invade, SnowInvasion, "snowinvasion") + add(new Command(Permissions.invade, FrostMoon, "frostmoon", "fmoon") { - HelpText = "Starts a Snow Moon invasion at the specified wave." + HelpText = "Starts a Frost Moon at the specified wave." + }); + add(new Command(Permissions.clearangler, ClearAnglerQuests, "clearangler") + { + HelpText = "Resets the list of users who have completed an angler quest that day." }); #endregion #region TP Commands @@ -377,17 +400,27 @@ namespace TShockAPI add(new Command(Permissions.tp, TP, "tp") { AllowServer = false, - HelpText = "Teleports you to another player or a coordinate." + HelpText = "Teleports a player to another player." + }); + add(new Command(Permissions.tpothers, TPHere, "tphere") + { + AllowServer = false, + HelpText = "Teleports a player to yourself." + }); + add(new Command(Permissions.tpnpc, TPNpc, "tpnpc") + { + AllowServer = false, + HelpText = "Teleports you to an npc." + }); + add(new Command(Permissions.tppos, TPPos, "tppos") + { + AllowServer = false, + HelpText = "Teleports you to tile coordinates." }); 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." + HelpText = "Toggles whether other people can teleport you." }); #endregion #region World Commands @@ -399,14 +432,6 @@ namespace TShockAPI { 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, @@ -420,6 +445,10 @@ namespace TShockAPI { HelpText = "Sets an eclipse." }); + add(new Command(Permissions.halloween, ForceHalloween, "forcehalloween") + { + HelpText = "Toggles halloween mode (goodie bags, pumpkins, etc)." + }); add(new Command(Permissions.xmas, ForceXmas, "forcexmas") { HelpText = "Toggles christmas mode (present spawning, santa, etc)." @@ -457,6 +486,10 @@ namespace TShockAPI { HelpText = "Sets the world time." }); + add(new Command(Permissions.wind, Wind, "wind") + { + HelpText = "Changes the wind speed." + }); add(new Command(Permissions.worldinfo, WorldInfo, "world") { HelpText = "Shows information about the current world." @@ -558,10 +591,10 @@ namespace TShockAPI 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)).ToList(); - IEnumerable cmds = ChatCommands.Where(c => c.HasAlias(cmdName)); + if (Hooks.PlayerHooks.OnPlayerCommand(player, cmdName, cmdText, args, ref cmds)) + return true; if (cmds.Count() == 0) { @@ -572,14 +605,14 @@ namespace TShockAPI call(new CommandArgs(cmdText, player, args)); return true; } - player.SendErrorMessage("Invalid command entered. Type /help for a list of valid commands."); + player.SendErrorMessage("Invalid command entered. Type {0}help for a list of valid commands.", TShock.Config.CommandSpecifier); 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); + TShock.Utils.SendLogs(string.Format("{0} tried to execute {1}{2}.", player.Name, TShock.Config.CommandSpecifier, cmdText), Color.PaleVioletRed, player); player.SendErrorMessage("You do not have access to this command."); } else if (!cmd.AllowServer && !player.RealPlayer) @@ -589,7 +622,7 @@ namespace TShockAPI else { if (cmd.DoLog) - TShock.Utils.SendLogs(string.Format("{0} executed: /{1}.", player.Name, cmdText), Color.PaleVioletRed, player); + TShock.Utils.SendLogs(string.Format("{0} executed: {1}{2}.", player.Name, TShock.Config.CommandSpecifier, cmdText), Color.PaleVioletRed, player); cmd.Run(cmdText, player, args); } } @@ -647,21 +680,6 @@ namespace TShockAPI 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'; @@ -731,9 +749,9 @@ namespace TShockAPI var group = TShock.Utils.GetGroup(user.Group); - if (TShock.Config.ServerSideCharacter) + if (Main.ServerSideCharacter) { - if (group.HasPermission(Permissions.bypassinventorychecks)) + if (group.HasPermission(Permissions.bypassssc)) { args.Player.IgnoreActionsForClearingTrashCan = false; } @@ -754,7 +772,7 @@ namespace TShockAPI args.Player.IsLoggedIn = true; args.Player.IgnoreActionsForInventory = "none"; - if (!args.Player.IgnoreActionsForClearingTrashCan && TShock.Config.ServerSideCharacter) + if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter) { args.Player.PlayerData.CopyCharacter(args.Player); TShock.CharacterDB.InsertPlayerData(args.Player); @@ -1097,16 +1115,32 @@ namespace TShockAPI } List players = TShock.Utils.FindPlayer(args.Parameters[1]); + string reason = args.Parameters.Count > 2 ? String.Join(" ", args.Parameters.Skip(2)) : "Misbehavior."; if (players.Count == 0) - args.Player.SendErrorMessage("Invalid player!"); + { + var user = TShock.Users.GetUserByName(args.Parameters[1]); + if (user != null) + { + bool force = !args.Player.RealPlayer; + if (TShock.Groups.GetGroupByName(user.Group).HasPermission(Permissions.immunetoban) && !force) + args.Player.SendErrorMessage("You can't ban {0}!", user.Name); + else + { + var knownIps = JsonConvert.DeserializeObject>(user.KnownIps); + TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.UserAccountName); + if (String.IsNullOrWhiteSpace(args.Player.UserAccountName)) + TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason); + else + TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", args.Player.Name, force ? "force " : "", user.Name, reason); + } + } + else + args.Player.SendErrorMessage("Invalid player or account!"); + } 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); } @@ -1140,24 +1174,44 @@ namespace TShockAPI return; } + int time; + if (!TShock.Utils.TryParseTime(args.Parameters[2], out time)) + { + args.Player.SendErrorMessage("Invalid time string! Proper format: _d_h_m_s, with at least one time specifier."); + args.Player.SendErrorMessage("For example, 1d and 10h-30m+2m are both valid time strings, but 2 is not."); + return; + } + + string reason = args.Parameters.Count > 3 + ? String.Join(" ", args.Parameters.Skip(3)) + : "Misbehavior."; + List players = TShock.Utils.FindPlayer(args.Parameters[1]); if (players.Count == 0) - args.Player.SendErrorMessage("Invalid player!"); + { + var user = TShock.Users.GetUserByName(args.Parameters[1]); + if (user != null) + { + bool force = !args.Player.RealPlayer; + if (TShock.Groups.GetGroupByName(user.Group).HasPermission(Permissions.immunetoban) && !force) + args.Player.SendErrorMessage("You can't ban {0}!", user.Name); + else + { + var knownIps = JsonConvert.DeserializeObject>(user.KnownIps); + TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.UserAccountName, DateTime.UtcNow.AddSeconds(time).ToString("s")); + if (String.IsNullOrWhiteSpace(args.Player.UserAccountName)) + TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason); + else + TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", args.Player.Name, force ? "force " : "", user.Name, reason); + } + } + else + args.Player.SendErrorMessage("Invalid player or account!"); + } else if (players.Count > 1) TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); else { - int time; - if (!TShock.Utils.TryParseTime(args.Parameters[2], out time)) - { - args.Player.SendErrorMessage("Invalid time string! Proper format: 0d0h0m0s, with at least one time specifier."); - return; - } - - string reason = args.Parameters.Count > 3 - ? String.Join(" ", args.Parameters.GetRange(3, args.Parameters.Count - 3)) - : "Misbehavior."; - if (args.Player.RealPlayer && players[0].Group.HasPermission(Permissions.immunetoban)) { args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name); @@ -1168,7 +1222,6 @@ namespace TShockAPI false, args.Player.Name, DateTime.UtcNow.AddSeconds(time).ToString("s"))) { players[0].Disconnect(String.Format("Banned: {0}", reason)); - Log.ConsoleInfo("Banned {0} for : '{1}'", players[0].Name, reason); string verb = args.Player.RealPlayer ? "force " : ""; if (args.Player.RealPlayer) TSPlayer.All.SendSuccessMessage("{0} {1}banned {2} for '{3}'", args.Player.Name, verb, players[0].Name, reason); @@ -1230,7 +1283,7 @@ namespace TShockAPI var lines = new List { - "add [reason] - Bans a player.", + "add [reason] - Bans a player or user account if the player is not online.", "addip [reason] - Bans an IP.", "addtemp