diff --git a/GUIDELINES b/GUIDELINES new file mode 100644 index 00000000..fd99abcf --- /dev/null +++ b/GUIDELINES @@ -0,0 +1,11 @@ +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/). \ No newline at end of file diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs new file mode 100644 index 00000000..31be1b5b --- /dev/null +++ b/TShockAPI/BackupManager.cs @@ -0,0 +1,98 @@ +/* +TShock, a server mod for Terraria +Copyright (C) 2011 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.IO; +using System.Linq; +using System.Text; +using System.Threading; +using Terraria; + +namespace TShockAPI +{ + public class BackupManager + { + public string BackupPath { get; set; } + public int Interval { get; set; } + public int KeepFor { get; set; } + + DateTime lastbackup = DateTime.UtcNow; + public BackupManager(string path) + { + BackupPath = path; + } + + public bool IsBackupTime + { + get + { + return (Interval > 0) && ((DateTime.UtcNow - lastbackup).TotalMinutes >= Interval); + } + } + + public void Backup() + { + lastbackup = DateTime.UtcNow; + ThreadPool.QueueUserWorkItem(DoBackup); + ThreadPool.QueueUserWorkItem(DeleteOld); + } + + void DoBackup(object o) + { + try + { + string worldname = Main.worldPathName; + string name = Path.GetFileName(worldname); + + Main.worldPathName = Path.Combine(BackupPath, string.Format("{0}.{1:dd.MM.yy-HH.mm.ss}.bak", name, DateTime.UtcNow)); + + string worldpath = Path.GetDirectoryName(Main.worldPathName); + if (worldpath != null && !Directory.Exists(worldpath)) + Directory.CreateDirectory(worldpath); + + WorldGen.saveWorld(); + + Console.WriteLine("World backed up"); + Log.Info(string.Format("World backed up ({0})", Main.worldPathName)); + + Main.worldPathName = worldname; + } + catch (Exception ex) + { + Console.WriteLine("Backup failed"); + Log.Error("Backup failed"); + Log.Error(ex.ToString()); + } + } + + void DeleteOld(object o) + { + if (KeepFor <= 0) + return; + foreach (var fi in new DirectoryInfo(BackupPath).GetFiles("*.bak")) + { + if ((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalMinutes > KeepFor) + { + fi.Delete(); + } + } + } + } +} diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index e9853157..56d46df2 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -93,7 +93,7 @@ namespace TShockAPI } public static class Commands { - private static List ChatCommands = new List(); + public static List ChatCommands = new List(); public static void InitCommands() { @@ -102,6 +102,7 @@ namespace TShockAPI ChatCommands.Add(new Command("banip", "ban", BanIP)); ChatCommands.Add(new Command("unban", "unban", UnBan)); ChatCommands.Add(new Command("unbanip", "unban", UnBanIP)); + ChatCommands.Add(new Command("whitelist", "whitelist", Whitelist)); ChatCommands.Add(new Command("off", "maintenance", Off)); ChatCommands.Add(new Command("off-nosave", "maintenance", OffNoSave)); ChatCommands.Add(new Command("checkupdates", "maintenance", CheckUpdates)); @@ -111,6 +112,7 @@ namespace TShockAPI ChatCommands.Add(new Command("invade", "causeevents", Invade)); ChatCommands.Add(new Command("eater", "spawnboss", Eater)); ChatCommands.Add(new Command("eye", "spawnboss", Eye)); + ChatCommands.Add(new Command("king", "spawnboss", King)); ChatCommands.Add(new Command("skeletron", "spawnboss", Skeletron)); ChatCommands.Add(new Command("hardcore", "spawnboss", Hardcore)); ChatCommands.Add(new Command("spawnmob", "spawnmob", SpawnMob)); @@ -119,16 +121,20 @@ namespace TShockAPI ChatCommands.Add(new Command("spawn", "tp", Spawn)); ChatCommands.Add(new Command("tp", "tp", TP)); ChatCommands.Add(new Command("tphere", "tp", TPHere)); + ChatCommands.Add(new Command("warp", "warp", UseWarp)); + ChatCommands.Add(new Command("setwarp", "managewarp", SetWarp)); + ChatCommands.Add(new Command("delwarp", "managewarp", DeleteWarp)); ChatCommands.Add(new Command("reload", "cfg", Reload)); ChatCommands.Add(new Command("debug-config", "cfg", DebugConfiguration)); ChatCommands.Add(new Command("password", "cfg", Password)); ChatCommands.Add(new Command("save", "cfg", Save)); ChatCommands.Add(new Command("maxspawns", "cfg", MaxSpawns)); ChatCommands.Add(new Command("spawnrate", "cfg", SpawnRate)); - ChatCommands.Add(new Command("time", "cfg", Time)); + ChatCommands.Add(new Command("time", "time", Time)); ChatCommands.Add(new Command("slap", "pvpfun", Slap)); ChatCommands.Add(new Command("antibuild", "editspawn", ToggleAntiBuild)); ChatCommands.Add(new Command("protectspawn", "editspawn", ProtectSpawn)); + ChatCommands.Add(new Command("region", "editspawn", Region)); ChatCommands.Add(new Command("help", "", Help)); ChatCommands.Add(new Command("playing", "", Playing)); ChatCommands.Add(new Command("online", "", Playing)); @@ -137,10 +143,11 @@ namespace TShockAPI ChatCommands.Add(new Command("me", "", ThirdPerson)); ChatCommands.Add(new Command("p", "", PartyChat)); ChatCommands.Add(new Command("rules", "", Rules)); + ChatCommands.Add(new Command("displaylogs", "logs", Rules)); if (ConfigurationManager.DistributationAgent != "terraria-online") { ChatCommands.Add(new Command("kill", "kill", Kill)); - ChatCommands.Add(new Command("butcher", "cheat", Butcher)); + ChatCommands.Add(new Command("butcher", "butcher", Butcher)); ChatCommands.Add(new Command("i", "cheat", Item)); ChatCommands.Add(new Command("item", "cheat", Item)); ChatCommands.Add(new Command("give", "cheat", Give)); @@ -175,20 +182,18 @@ namespace TShockAPI if (cmd == null) { - player.SendMessage("That command does not exist, try /help", Color.Red); + return false; + } + + if (!cmd.CanRun(player)) + { + Tools.SendLogs(string.Format("{0} tried to execute {1}", player.Name, cmd.Name), Color.Red); + player.SendMessage("You do not have access to that command.", Color.Red); } else { - if (!cmd.CanRun(player)) - { - Tools.SendLogs(string.Format("{0} tried to execute {1}", player.Name, cmd.Name), Color.Red); - player.SendMessage("You do not have access to that command.", Color.Red); - } - else - { - Tools.SendLogs(string.Format("{0} executed: /{1}", player.Name, cmdText), Color.Red); - cmd.Run(cmdText, player, args); - } + Tools.SendLogs(string.Format("{0} executed: /{1}", player.Name, cmdText), Color.Red); + cmd.Run(cmdText, player, args); } return true; } @@ -291,19 +296,19 @@ namespace TShockAPI } string plStr = args.Parameters[0]; - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) { args.Player.SendMessage("Invalid player!", Color.Red); } - else if (player.Count > 1) + else if (players.Count > 1) { args.Player.SendMessage("More than one player matched!", Color.Red); } else { string reason = args.Parameters.Count > 1 ? String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)) : "Misbehaviour."; - if (!Tools.Kick(player[0], reason)) + if (!Tools.Kick(players[0], reason)) { args.Player.SendMessage("You can't kick another admin!", Color.Red); } @@ -324,19 +329,19 @@ namespace TShockAPI } string plStr = args.Parameters[0]; - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) { args.Player.SendMessage("Invalid player!", Color.Red); } - else if (player.Count > 1) + else if (players.Count > 1) { args.Player.SendMessage("More than one player matched!", Color.Red); } else { string reason = args.Parameters.Count > 1 ? String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)) : "Misbehaviour."; - if (!Tools.Ban(player[0], reason)) + if (!Tools.Ban(players[0], reason)) { args.Player.SendMessage("You can't ban another admin!", Color.Red); } @@ -413,6 +418,23 @@ namespace TShockAPI } } + public static void Whitelist(CommandArgs args) + { + if (args.Parameters.Count == 1) + { + TextWriter tw = new StreamWriter(FileTools.WhitelistPath, true); + tw.WriteLine(args.Parameters[0]); + tw.Close(); + args.Player.SendMessage("Added " + args.Parameters[0] + " to the whitelist."); + } + } + + public static void DisplayLogs(CommandArgs args) + { + args.Player.DisplayLogs = (!args.Player.DisplayLogs); + args.Player.SendMessage("You now " + (args.Player.DisplayLogs ? "receive" : "stopped receiving") + " logs"); + } + #endregion Player Management Commands #region Server Maintenence Commands @@ -490,12 +512,8 @@ namespace TShockAPI private static void Bloodmoon(CommandArgs args) { + TSPlayer.Server.SetBloodMoon(true); Tools.Broadcast(string.Format("{0} turned on blood moon.", args.Player.Name)); - Main.bloodMoon = true; - Main.time = 0; - Main.dayTime = false; - NetMessage.SendData(18, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); } private static void Invade(CommandArgs args) @@ -514,29 +532,101 @@ namespace TShockAPI private static void Eater(CommandArgs args) { - Tools.NewNPC(NPCList.WORLD_EATER, args.Player); - Tools.Broadcast(string.Format("{0} has spawned an eater of worlds!", args.Player.Name)); + if (args.Parameters.Count > 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /eater [amount]", Color.Red); + return; + } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /eater [amount]", Color.Red); + return; + } + NPC eater = Tools.GetNPCById(13); + TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + Tools.Broadcast(string.Format("{0} has spawned eater of worlds {1} times!", args.Player.Name, amount)); } private static void Eye(CommandArgs args) { - Tools.NewNPC(NPCList.EYE, args.Player); - Tools.Broadcast(string.Format("{0} has spawned an eye!", args.Player.Name)); + if (args.Parameters.Count > 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /eye [amount]", Color.Red); + return; + } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /eye [amount]", Color.Red); + return; + } + NPC eye = Tools.GetNPCById(4); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + Tools.Broadcast(string.Format("{0} has spawned eye {1} times!", args.Player.Name, amount)); + } + + private static void King(CommandArgs args) + { + if (args.Parameters.Count > 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /king [amount]", Color.Red); + return; + } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /king [amount]", Color.Red); + return; + } + NPC king = Tools.GetNPCById(50); + TSPlayer.Server.SpawnNPC(king.type, king.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + Tools.Broadcast(string.Format("{0} has spawned king slime {1} times!", args.Player.Name, amount)); } private static void Skeletron(CommandArgs args) { - Tools.NewNPC(NPCList.SKELETRON, args.Player); - Tools.Broadcast(string.Format("{0} has spawned skeletron!", args.Player.Name)); + if (args.Parameters.Count > 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /skeletron [amount]", Color.Red); + return; + } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /skeletron [amount]", Color.Red); + return; + } + NPC skeletron = Tools.GetNPCById(35); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + Tools.Broadcast(string.Format("{0} has spawned skeletron {1} times!", args.Player.Name, amount)); } private static void Hardcore(CommandArgs args) { - foreach (NPCList type in Enum.GetValues(typeof(NPCList))) + if (args.Parameters.Count > 1) { - Tools.NewNPC(type, args.Player); + args.Player.SendMessage("Invalid syntax! Proper syntax: /hardcore [amount]", Color.Red); + return; } - Tools.Broadcast(string.Format("{0} has spawned all bosses!", args.Player.Name)); + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /hardcore [amount]", Color.Red); + return; + } + NPC eater = Tools.GetNPCById(13); + NPC eye = Tools.GetNPCById(4); + NPC king = Tools.GetNPCById(50); + NPC skeletron = Tools.GetNPCById(35); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + TSPlayer.Server.SpawnNPC(king.type, king.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); + Tools.Broadcast(string.Format("{0} has spawned all bosses {1} times!", args.Player.Name, amount)); } private static void SpawnMob(CommandArgs args) @@ -551,27 +641,33 @@ namespace TShockAPI args.Player.SendMessage("Missing mob name/id", Color.Red); return; } - - int type = -1; int amount = 1; - - if (!int.TryParse(args.Parameters[0], out type)) - type = TShock.GetNPCID(args.Parameters[0]); if (args.Parameters.Count == 2 && !int.TryParse(args.Parameters[1], out amount)) { args.Player.SendMessage("Invalid syntax! Proper syntax: /spawnmob [amount]", Color.Red); return; } - if (type >= 1 && type < Main.maxNPCTypes) + var npcs = Tools.GetNPCByIdOrName(args.Parameters[0]); + if (npcs.Count == 0) { - int npcid = -1; - for (int i = 0; i < amount; i++) - npcid = NPC.NewNPC((int)args.Player.X, (int)args.Player.Y, type, 0); - Tools.Broadcast(string.Format("{0} was spawned {1} time(s).", Main.npc[npcid].name, amount)); + args.Player.SendMessage("Invalid mob type!", Color.Red); + } + else if (npcs.Count > 1) + { + args.Player.SendMessage(string.Format("More than one ({0}) mob matched!", npcs.Count), Color.Red); } else - args.Player.SendMessage("Invalid mob type!", Color.Red); + { + var npc = npcs[0]; + if (npc.type >= 1 && npc.type < Main.maxNPCTypes) + { + TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, (int)args.Player.TileX, (int)args.Player.TileY, 50, 20); + Tools.Broadcast(string.Format("{0} was spawned {1} time(s).", npc.name, amount)); + } + else + args.Player.SendMessage("Invalid mob type!", Color.Red); + } } #endregion Cause Events and Spawn Monsters Commands @@ -580,20 +676,38 @@ namespace TShockAPI private static void Home(CommandArgs args) { - TShock.Teleport(args.Player.Index, args.TPlayer.SpawnX * 16 + 8 - args.TPlayer.width / 2, - args.TPlayer.SpawnY * 16 - args.TPlayer.height); + if (!args.Player.RealPlayer) + { + args.Player.SendMessage("You cannot use teleport commands!"); + return; + } + + args.Player.Spawn(); args.Player.SendMessage("Teleported to your spawnpoint."); } private static void Spawn(CommandArgs args) { - TShock.Teleport(args.Player.Index, Main.spawnTileX * 16 + 8 - args.TPlayer.width / 2, - Main.spawnTileY * 16 - args.TPlayer.height); - args.Player.SendMessage("Teleported to the map's spawnpoint."); + if (!args.Player.RealPlayer) + { + args.Player.SendMessage("You cannot use teleport commands!"); + return; + } + + if (args.Player.Teleport(Main.spawnTileX, Main.spawnTileY)) + args.Player.SendMessage("Teleported to the map's spawnpoint."); + else + args.Player.SendMessage("Teleport unavailable - Spawn point set to Bed. To unset, destroy Bed and suicide at least once.", Color.Red); } private static void TP(CommandArgs args) { + if (!args.Player.RealPlayer) + { + args.Player.SendMessage("You cannot use teleport commands!"); + return; + } + if (args.Parameters.Count < 1) { args.Player.SendMessage("Invalid syntax! Proper syntax: /tp ", Color.Red); @@ -601,21 +715,29 @@ namespace TShockAPI } string plStr = String.Join(" ", args.Parameters); - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) args.Player.SendMessage("Invalid player!", Color.Red); - else if (player.Count > 1) + else if (players.Count > 1) args.Player.SendMessage("More than one player matched!", Color.Red); else { - var plr = player[0]; - TShock.Teleport(args.Player.Index, plr.X, plr.Y); - args.Player.SendMessage(string.Format("Teleported to {0}", plr.Name)); + var plr = players[0]; + if (args.Player.Teleport(plr.TileX, plr.TileY + 3)) + args.Player.SendMessage(string.Format("Teleported to {0}", plr.Name)); + else + args.Player.SendMessage("Teleport unavailable - Spawn point set to Bed. To unset, destroy Bed and suicide at least once.", Color.Red); } } private static void TPHere(CommandArgs args) { + if (!args.Player.RealPlayer) + { + args.Player.SendMessage("You cannot use teleport commands!"); + return; + } + if (args.Parameters.Count < 1) { args.Player.SendMessage("Invalid syntax! Proper syntax: /tphere ", Color.Red); @@ -623,24 +745,126 @@ namespace TShockAPI } string plStr = String.Join(" ", args.Parameters); - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) { args.Player.SendMessage("Invalid player!", Color.Red); } - else if (player.Count > 1) + else if (players.Count > 1) { args.Player.SendMessage("More than one player matched!", Color.Red); } else { - var plr = player[0]; - TShock.Teleport(plr.Index, args.Player.X, args.Player.Y); - plr.SendMessage(string.Format("You were teleported to {0}.", plr.Name)); - args.Player.SendMessage(string.Format("You brought {0} here.", plr.Name)); + var plr = players[0]; + if (plr.Teleport(args.Player.TileX, args.Player.TileY + 3)) + { + plr.SendMessage(string.Format("You were teleported to {0}.", plr.Name)); + args.Player.SendMessage(string.Format("You brought {0} here.", plr.Name)); + } + else + args.Player.SendMessage("Teleport unavailable - Target player has spawn point set to Bed.", Color.Red); + } } + private static void SetWarp(CommandArgs args) + { + if (args.Parameters.Count > 0) + { + string warpName = String.Join(" ", args.Parameters); + if (warpName.Equals("list")) + { + args.Player.SendMessage("Name reserved, use a different name", Color.Red); + } + else if (WarpsManager.AddWarp(args.Player.TileX, args.Player.TileY, warpName, Main.worldName)) + { + args.Player.SendMessage("Set warp " + warpName, Color.Yellow); + WarpsManager.WriteSettings(); + } + else + { + args.Player.SendMessage("Warp " + warpName + " already exists", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /setwarp [name]", Color.Red); + } + + private static void DeleteWarp(CommandArgs args) + { + if (args.Parameters.Count > 0) + { + string warpName = String.Join(" ", args.Parameters); + if (WarpsManager.DeleteWarp(warpName)) + args.Player.SendMessage("Deleted warp " + warpName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified warp", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /delwarp [name]", Color.Red); + } + + private static void UseWarp(CommandArgs args) + { + if (args.Parameters.Count > 0) + { + if (args.Parameters[0].Equals("list")) + { + args.Player.SendMessage("Current Warps:", Color.Green); + int page = 1; + if (args.Parameters.Count > 1) + int.TryParse(args.Parameters[1], out page); + var sb = new StringBuilder(); + if (WarpsManager.Warps.Count > (15 * (page - 1))) + { + for (int j = (15 * (page - 1)); j < (15 * page); j++) + { + if (WarpsManager.Warps[j].WorldWarpName == Main.worldName) + { + if (sb.Length != 0) + sb.Append(", "); + sb.Append("/").Append(WarpsManager.Warps[j].WarpName); + if (j == WarpsManager.Warps.Count - 1) + { + args.Player.SendMessage(sb.ToString(), Color.Yellow); + break; + } + if ((j + 1) % 5 == 0) + { + args.Player.SendMessage(sb.ToString(), Color.Yellow); + sb.Clear(); + } + } + } + } + if (WarpsManager.Warps.Count > (15 * page)) + { + args.Player.SendMessage(string.Format("Type /warp list {0} for more warps.", (page + 1)), Color.Yellow); + } + } + else + { + string warpName = String.Join(" ", args.Parameters); + var warp = WarpsManager.FindWarp(warpName); + if (warp != Vector2.Zero) + { + if (args.Player.Teleport((int)warp.X, (int)warp.Y + 3)) + args.Player.SendMessage("Warped to " + warpName, Color.Yellow); + else + args.Player.SendMessage("Warp unavailable - Spawn point set to Bed. To unset, destroy Bed and suicide at least once.", Color.Red); + + } + else + { + args.Player.SendMessage("Specified warp not found", Color.Red); + } + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /warp [name] or warp list", Color.Red); + } + #endregion Teleport Commands #region Server Config Commands @@ -675,7 +899,12 @@ namespace TShockAPI private static void Password(CommandArgs args) { - string passwd = args.Message.Remove(0, 9).Trim(); + if (args.Parameters.Count != 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /password \"\"", Color.Red); + return; + } + string passwd = args.Parameters[0]; Netplay.password = passwd; args.Player.SendMessage(string.Format("Server password changed to: {0}", passwd)); } @@ -717,6 +946,10 @@ namespace TShockAPI Tools.Broadcast(string.Format("{0} changed the spawn rate to: {1}", args.Player.Name, amount)); } + #endregion Server Config Commands + + #region Time/PvpFun Commands + private static void Time(CommandArgs args) { if (args.Parameters.Count != 1) @@ -728,38 +961,23 @@ namespace TShockAPI switch (args.Parameters[0]) { case "day": - Main.time = 0; - Main.dayTime = true; - NetMessage.SendData(18, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); + TSPlayer.Server.SetTime(true, 0.0); Tools.Broadcast(string.Format("{0} set time to day.", args.Player.Name)); break; case "night": - Main.time = 0; - Main.dayTime = false; - NetMessage.SendData(18, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); + TSPlayer.Server.SetTime(false, 0.0); Tools.Broadcast(string.Format("{0} set time to night.", args.Player.Name)); break; case "dusk": - Main.dayTime = false; - Main.time = 0.0; - NetMessage.SendData(18, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); + TSPlayer.Server.SetTime(false, 0.0); Tools.Broadcast(string.Format("{0} set time to dusk.", args.Player.Name)); break; case "noon": - Main.dayTime = true; - Main.time = 27000.0; - NetMessage.SendData(18, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); + TSPlayer.Server.SetTime(true, 27000.0); Tools.Broadcast(string.Format("{0} set time to noon.", args.Player.Name)); break; case "midnight": - Main.dayTime = false; - Main.time = 16200.0; - NetMessage.SendData(18, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); + TSPlayer.Server.SetTime(false, 16200.0); Tools.Broadcast(string.Format("{0} set time to midnight.", args.Player.Name)); break; default: @@ -768,7 +986,44 @@ namespace TShockAPI } } - #endregion Server Config Commands + private static void Slap(CommandArgs args) + { + if (args.Parameters.Count < 1 || args.Parameters.Count > 2) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /slap [dmg]", Color.Red); + return; + } + if (args.Parameters[0].Length == 0) + { + args.Player.SendMessage("Missing player name", Color.Red); + return; + } + + string plStr = args.Parameters[0]; + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) + { + args.Player.SendMessage("Invalid player!", Color.Red); + } + else if (players.Count > 1) + { + args.Player.SendMessage("More than one player matched!", Color.Red); + } + else + { + var plr = players[0]; + int damage = 5; + if (args.Parameters.Count == 2) + { + int.TryParse(args.Parameters[1], out damage); + } + plr.DamagePlayer(damage); + Tools.Broadcast(string.Format("{0} slapped {1} for {2} damage.", + args.Player.Name, plr.Name, damage)); + } + } + + #endregion Time/PvpFun Commands #region World Protection Commands @@ -784,6 +1039,176 @@ namespace TShockAPI Tools.Broadcast(string.Format("Spawn is now {0}.", (ConfigurationManager.SpawnProtect ? "protected" : "open"))); } + private static void Region(CommandArgs args) + { + string cmd = "help"; + if (args.Parameters.Count > 0) + { + cmd = args.Parameters[0].ToLower(); + } + switch (cmd) + { + case "set": + { + if (args.Parameters.Count == 2) + { + if (args.Parameters[1] == "1") + { + args.Player.TempArea.X = args.Player.TileX; + args.Player.TempArea.Y = args.Player.TileY; + args.Player.SendMessage("Set Temp Point 1", Color.Yellow); + } + else if (args.Parameters[1] == "2") + { + if (args.Player.TempArea.X != 0) + { + if (args.Player.TileX > args.Player.TempArea.X && args.Player.TileY > args.Player.TempArea.Y) + { + args.Player.TempArea.Width = args.Player.TileX - args.Player.TempArea.X; + args.Player.TempArea.Height = (args.Player.TileY + 3) - args.Player.TempArea.Y; + args.Player.SendMessage("Set Temp Point 2", Color.Yellow); + } + else + { + args.Player.SendMessage("Point 2 must be below and right of Point 1", Color.Yellow); + args.Player.SendMessage("Use /region clear to start again", Color.Yellow); + } + } + else + { + args.Player.SendMessage("You have not set Point 1 yet", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region set [1/2]", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region set [1/2]", Color.Red); + break; + } + case "define": + { + if (args.Parameters.Count > 1) + { + if (!args.Player.TempArea.IsEmpty) + { + string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); + if (RegionManager.AddRegion(args.Player.TempArea.X, args.Player.TempArea.Y, + args.Player.TempArea.Width, args.Player.TempArea.Height, + regionName, Main.worldName)) + { + args.Player.TempArea = Rectangle.Empty; + args.Player.SendMessage("Set region " + regionName, Color.Yellow); + } + else + { + args.Player.SendMessage("Region " + regionName + " already exists", Color.Red); + } + } + else + args.Player.SendMessage("Points not set up yet", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region define [name]", Color.Red); + break; + } + case "protect": + { + if (args.Parameters.Count == 3) + { + string regionName = args.Parameters[1]; + if (args.Parameters[2].ToLower() == "true") + { + if (RegionManager.SetRegionState(regionName, true)) + args.Player.SendMessage("Protected region " + regionName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else if (args.Parameters[2].ToLower() == "false") + { + if (RegionManager.SetRegionState(regionName, false)) + args.Player.SendMessage("Unprotected region " + regionName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region protected [name] [true/false]", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region protected [name] [true/false]", Color.Red); + break; + } + case "delete": + { + if (args.Parameters.Count > 1) + { + string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); + if (RegionManager.DeleteRegion(regionName)) + args.Player.SendMessage("Deleted region " + regionName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region delete [name]", Color.Red); + break; + } + case "clear": + { + args.Player.TempArea = Rectangle.Empty; + args.Player.SendMessage("Cleared temp area", Color.Yellow); + break; + } + case "allow": + { + if (args.Parameters.Count > 2) + { + string playerName = args.Parameters[1]; + string regionName = ""; + string playerIP = null; + + for (int i = 2; i < args.Parameters.Count; i++) + { + if (regionName == "") + { + regionName = args.Parameters[2]; + } + else + { + regionName = regionName + " " + args.Parameters[i]; + } + } + if ((playerIP = Tools.GetPlayerIP(playerName)) != null) + { + if (RegionManager.AddNewUser(regionName, playerIP)) + { + args.Player.SendMessage("Added user " + playerName + " to " + regionName, Color.Yellow); + RegionManager.WriteSettings(); + } + else + args.Player.SendMessage("Region " + regionName + " not found", Color.Red); + } + else + { + args.Player.SendMessage("Player " + playerName + " not found", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region allow [name] [region]", Color.Red); + break; + } + case "help": + default: + { + args.Player.SendMessage("Avialable region commands:", Color.Green); + args.Player.SendMessage("/region set [1/2] /region define [name] /region protect [name] [true/false]", Color.Yellow); + args.Player.SendMessage("/region delete [name] /region clear (temporary region)", Color.Yellow); + args.Player.SendMessage("/region allow [name] [regionname]", Color.Yellow); + break; + } + } + + } + #endregion World Protection Commands #region General Commands @@ -852,16 +1277,25 @@ namespace TShockAPI private static void ThirdPerson(CommandArgs args) { - string msg = args.Message.Remove(0, 3); - Tools.Broadcast(string.Format("*{0} {1}", args.Player.Name, msg), 205, 133, 63); + if (args.Parameters.Count == 0) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /me ", Color.Red); + return; + } + Tools.Broadcast(string.Format("*{0} {1}", args.Player.Name, String.Join(" ", args.Parameters)), 205, 133, 63); } private static void PartyChat(CommandArgs args) { + if (args.Parameters.Count == 0) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /p ", Color.Red); + return; + } int playerTeam = args.Player.Team; if (playerTeam != 0) { - string msg = string.Format("<{0}> {1}", args.Player.Name, args.Message.Remove(0, 2)); + string msg = string.Format("<{0}> {1}", args.Player.Name, String.Join(" ", args.Parameters)); foreach (TSPlayer player in TShock.Players) { if (player != null && player.Active && player.Team == playerTeam) @@ -883,43 +1317,6 @@ namespace TShockAPI #region Cheat Commands - private static void Slap(CommandArgs args) - { - if (args.Parameters.Count < 1 || args.Parameters.Count > 2) - { - args.Player.SendMessage("Invalid syntax! Proper syntax: /slap [dmg]", Color.Red); - return; - } - if (args.Parameters[0].Length == 0) - { - args.Player.SendMessage("Missing player name", Color.Red); - return; - } - - string plStr = args.Parameters[0]; - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) - { - args.Player.SendMessage("Invalid player!", Color.Red); - } - else if (player.Count > 1) - { - args.Player.SendMessage("More than one player matched!", Color.Red); - } - else - { - var plr = player[0]; - int damage = 5; - if (args.Parameters.Count == 2) - { - int.TryParse(args.Parameters[1], out damage); - } - TShock.PlayerDamage(plr, damage); - Tools.Broadcast(string.Format("{0} slapped {1} for {2} damage.", - args.Player.Name, plr.Name, damage)); - } - } - private static void Kill(CommandArgs args) { if (args.Parameters.Count < 1) @@ -929,33 +1326,42 @@ namespace TShockAPI } string plStr = String.Join(" ", args.Parameters); - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) { args.Player.SendMessage("Invalid player!", Color.Red); } - else if (player.Count > 1) + else if (players.Count > 1) { args.Player.SendMessage("More than one player matched!", Color.Red); } else { - var plr = player[0]; + var plr = players[0]; + plr.DamagePlayer(999999); args.Player.SendMessage(string.Format("You just killed {0}!", plr.Name)); plr.SendMessage(string.Format("{0} just killed you!", args.Player.Name)); - TShock.PlayerDamage(plr, 999999); } } private static void Butcher(CommandArgs args) { + if (args.Parameters.Count > 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /butcher [killFriendly(true/false)]", Color.Red); + return; + } + + bool killFriendly = true; + if (args.Parameters.Count == 1) + bool.TryParse(args.Parameters[0], out killFriendly); + int killcount = 0; for (int i = 0; i < Main.npc.Length; i++) { - if (!Main.npc[i].townNPC && Main.npc[i].active) + if ( Main.npc[i].active && !Main.npc[i].townNPC && (!Main.npc[i].friendly || killFriendly)) { - Main.npc[i].StrikeNPC(99999, 90f, 1); - NetMessage.SendData(28, -1, -1, "", i, 99999, 90f, 1); + TSPlayer.Server.StrikeNPC(i, 99999, 90f, 1); killcount++; } } @@ -975,39 +1381,35 @@ namespace TShockAPI return; } - int type = -1; - if (!int.TryParse(args.Parameters[0], out type)) - type = TShock.GetItemID(String.Join(" ", args.Parameters)); - - if (type < 1 || type >= Main.maxItemTypes) + var items = Tools.GetItemByIdOrName(String.Join(" ", args.Parameters)); + if (items.Count == 0) { args.Player.SendMessage("Invalid item type!", Color.Red); - return; } - - if (!args.Player.RealPlayer) + else if (items.Count > 1) { - args.Player.SendMessage("You cant get items!"); - return; + args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); } - - bool flag = false; - for (int i = 0; i < 40; i++) + else { - if (!args.TPlayer.inventory[i].active) + var item = items[0]; + if (item.type >= 1 && item.type < Main.maxItemTypes) { - int id = Terraria.Item.NewItem(0, 0, 0, 0, type, 1, true); - Main.item[id].position.X = args.Player.X; - Main.item[id].position.Y = args.Player.Y; - Main.item[id].stack = Main.item[id].maxStack; - NetMessage.SendData(21, -1, -1, "", id, 0f, 0f, 0f); - args.Player.SendMessage(string.Format("Got some {0}.", Main.item[id].name)); - flag = true; - break; + if (args.Player.InventorySlotAvailable) + { + args.Player.GiveItem(item.type, item.name, item.width, item.height, item.maxStack); + args.Player.SendMessage(string.Format("Got some {0}.", item.name)); + } + else + { + args.Player.SendMessage("You don't have free slots!", Color.Red); + } + } + else + { + args.Player.SendMessage("Invalid item type!", Color.Red); } } - if (!flag) - args.Player.SendMessage("You don't have free slots!", Color.Red); } private static void Give(CommandArgs args) @@ -1028,101 +1430,102 @@ namespace TShockAPI return; } - int type = -1; - if (!int.TryParse(args.Parameters[0], out type)) - type = TShock.GetItemID(args.Parameters[0]); + var items = Tools.GetItemByIdOrName(args.Parameters[0]); - if (type < 1 || type >= Main.maxItemTypes) + if (items.Count == 0) { args.Player.SendMessage("Invalid item type!", Color.Red); - return; } - - string plStr = args.Parameters[1]; - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + else if (items.Count > 1) { - args.Player.SendMessage("Invalid player!", Color.Red); - } - else if (player.Count > 1) - { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); } else { - var plr = player[0]; - bool flag = false; - for (int i = 0; i < 40; i++) + var item = items[0]; + if (item.type >= 1 && item.type < Main.maxItemTypes) { - if (!plr.TPlayer.inventory[i].active) + string plStr = args.Parameters[1]; + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) { - int id = Terraria.Item.NewItem(0, 0, 0, 0, type, 1, true); - Main.item[id].position.X = plr.X; - Main.item[id].position.Y = plr.Y; - Main.item[id].stack = Main.item[id].maxStack; - NetMessage.SendData(21, -1, -1, "", id, 0f, 0f, 0f); - args.Player.SendMessage(string.Format("Gave {0} some {1}.", plr.Name, Main.item[id].name)); - plr.SendMessage(string.Format("{0} gave you some {1}.", args.Player.Name, Main.item[id].name)); - flag = true; - break; + args.Player.SendMessage("Invalid player!", Color.Red); + } + else if (players.Count > 1) + { + args.Player.SendMessage("More than one player matched!", Color.Red); + } + else + { + var plr = players[0]; + if (plr.InventorySlotAvailable) + { + plr.GiveItem(item.type, item.name, item.width, item.height, item.maxStack); + args.Player.SendMessage(string.Format("Gave {0} some {1}.", plr.Name, item.name)); + plr.SendMessage(string.Format("{0} gave you some {1}.", args.Player.Name, item.name)); + } + else + { + args.Player.SendMessage("Player does not have free slots!", Color.Red); + } } } - if (!flag) - args.Player.SendMessage("Player does not have free slots!", Color.Red); + else + { + args.Player.SendMessage("Invalid item type!", Color.Red); + } } } private static void Heal(CommandArgs args) { + TSPlayer playerToHeal; if (args.Parameters.Count > 0) { string plStr = String.Join(" ", args.Parameters); - var player = Tools.FindPlayer(plStr); - if (player.Count == 0) + var players = Tools.FindPlayer(plStr); + if (players.Count == 0) { args.Player.SendMessage("Invalid player!", Color.Red); + return; } - else if (player.Count > 1) + else if (players.Count > 1) { args.Player.SendMessage("More than one player matched!", Color.Red); + return; } else { - var plr = player[0]; - DropHearts(plr.X, plr.Y, 20); - if (plr == args.Player) - { - args.Player.SendMessage("You just got healed!"); - } - else - { - args.Player.SendMessage(string.Format("You just healed {0}", plr.Name)); - plr.SendMessage(string.Format("{0} just healed you!", args.Player.Name)); - } + playerToHeal = players[0]; } } else if (!args.Player.RealPlayer) { args.Player.SendMessage("You cant heal yourself!"); + return; } else { - DropHearts(args.Player.X, args.Player.Y, 20); + playerToHeal = args.Player; + } + + Item heart = Tools.GetItemById(58); + Item star = Tools.GetItemById(184); + for (int i = 0; i < 20; i++) + playerToHeal.GiveItem(heart.type, heart.name, heart.width, heart.height, heart.maxStack); + for (int i = 0; i < 10; i++) + playerToHeal.GiveItem(star.type, star.name, star.width, star.height, star.maxStack); + if (playerToHeal == args.Player) + { args.Player.SendMessage("You just got healed!"); } - } - - private static void DropHearts(float x, float y, int count) - { - for (int i = 0; i < count; i++) + else { - int itemid = Terraria.Item.NewItem(1, 1, 1, 1, 58); - Main.item[itemid].position.X = x; - Main.item[itemid].position.Y = y; - NetMessage.SendData(21, -1, -1, "", itemid, 0f, 0f, 0f); + args.Player.SendMessage(string.Format("You just healed {0}", playerToHeal.Name)); + playerToHeal.SendMessage(string.Format("{0} just healed you!", args.Player.Name)); } } #endregion Cheat Comamnds } -} \ No newline at end of file +} diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index f0a37a22..eff333b1 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -30,10 +30,11 @@ namespace TShockAPI public bool BanCheaters = true; public bool KickGriefers = true; public bool BanGriefers = true; - public bool BanKillTileAbusers; - public bool KickKillTileAbusers; + public bool BanKillTileAbusers = true; + public bool KickKillTileAbusers = true; public bool BanExplosives = true; public bool KickExplosives = true; + public bool DisableExplosives = true; public bool SpawnProtection = true; public int SpawnProtectionRadius = 5; public string DistributationAgent = "facepunch"; @@ -41,7 +42,22 @@ namespace TShockAPI public bool RangeChecks = true; public bool SpamChecks = false; public bool DisableBuild = false; + public int TileThreshold = 20; + public float[] AdminChatRGB = {255, 0, 0}; public string AdminChatPrefix = "(Admin) "; + + public int PvpThrottle = 0; + + public int BackupInterval = 0; + public int BackupKeepFor = 60; + + public bool RememberLeavePos = false; + + public bool HardcoreOnly = false; + public bool KickOnHardcoreOnlyDeath = false; + public bool BanOnHardcoreOnlyDeath = false; + + public bool AutoSave = true; } } \ No newline at end of file diff --git a/TShockAPI/ConfigurationManager.cs b/TShockAPI/ConfigurationManager.cs index c826d134..fa89dc4b 100644 --- a/TShockAPI/ConfigurationManager.cs +++ b/TShockAPI/ConfigurationManager.cs @@ -44,6 +44,7 @@ namespace TShockAPI public static bool KickTnt = true; public static bool BanBoom = true; public static bool KickBoom = true; + public static bool DisableBoom = true; public static bool SpawnProtect = true; public static bool RangeChecks = true; public static int SpawnProtectRadius = 5; @@ -54,6 +55,28 @@ namespace TShockAPI public static bool DisableBuild = false; public static float[] AdminChatRGB = {255, 0, 0}; public static string AdminChatPrefix = "(Admin) "; + public static bool RememberLeavePos = false; + public static int TileThreshold = 20; + + /// + /// Don't allow pvp changing for x seconds. + /// + public static int PvpThrottle = 0; + + /// + /// Backup every x minutes + /// + public static int BackupInterval = 0; + /// + /// Delete backups that are older than x mintues. + /// + public static int BackupKeepFor = 60; + + public static bool HardcoreOnly = false; + public static bool KickOnHardcoreDeath = false; + public static bool BanOnHardcoreDeath = false; + + public static bool AutoSave = true; public static void ReadJsonConfiguration() { @@ -76,6 +99,7 @@ namespace TShockAPI KickTnt = cfg.KickKillTileAbusers; BanBoom = cfg.BanExplosives; KickBoom = cfg.KickExplosives; + DisableBoom = cfg.DisableExplosives; SpawnProtect = cfg.SpawnProtection; SpawnProtectRadius = cfg.SpawnProtectionRadius; DistributationAgent = cfg.DistributationAgent; @@ -83,10 +107,19 @@ namespace TShockAPI RangeChecks = cfg.RangeChecks; SpamChecks = cfg.SpamChecks; DisableBuild = cfg.DisableBuild; + TileThreshold = cfg.TileThreshold; NPC.maxSpawns = DefaultMaxSpawns; NPC.defaultSpawnRate = DefaultSpawnRate; AdminChatRGB = cfg.AdminChatRGB; AdminChatPrefix = cfg.AdminChatPrefix; + PvpThrottle = cfg.PvpThrottle; + BackupInterval = cfg.BackupInterval; + BackupKeepFor = cfg.BackupKeepFor; + RememberLeavePos = cfg.RememberLeavePos; + HardcoreOnly = cfg.HardcoreOnly; + KickOnHardcoreDeath = cfg.KickOnHardcoreOnlyDeath; + BanOnHardcoreDeath = cfg.BanOnHardcoreOnlyDeath; + AutoSave = cfg.AutoSave; } public static void WriteJsonConfiguration() @@ -103,18 +136,28 @@ namespace TShockAPI cfg.BanCheaters = BanCheater; cfg.KickGriefers = KickGriefer; cfg.BanGriefers = BanGriefer; - cfg.BanKillTileAbusers = BanGriefer; - cfg.KickKillTileAbusers = KickGriefer; + cfg.BanKillTileAbusers = BanTnt; + cfg.KickKillTileAbusers = KickTnt; cfg.BanExplosives = BanBoom; cfg.KickExplosives = KickBoom; + cfg.DisableExplosives = DisableBoom; cfg.SpawnProtection = SpawnProtect; cfg.SpawnProtectionRadius = SpawnProtectRadius; cfg.MaxSlots = MaxSlots; cfg.RangeChecks = RangeChecks; cfg.SpamChecks = SpamChecks; cfg.DisableBuild = DisableBuild; + cfg.TileThreshold = TileThreshold; cfg.AdminChatRGB = AdminChatRGB; cfg.AdminChatPrefix = AdminChatPrefix; + cfg.PvpThrottle = PvpThrottle; + cfg.BackupInterval = BackupInterval; + cfg.BackupKeepFor = BackupKeepFor; + cfg.RememberLeavePos = RememberLeavePos; + cfg.HardcoreOnly = HardcoreOnly; + cfg.BanOnHardcoreOnlyDeath = BanOnHardcoreDeath; + cfg.KickOnHardcoreOnlyDeath = KickOnHardcoreDeath; + cfg.AutoSave = AutoSave; string json = JsonConvert.SerializeObject(cfg, Formatting.Indented); TextWriter tr = new StreamWriter(FileTools.ConfigPath); tr.Write(json); diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index a87f94af..d553af0c 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -29,7 +29,11 @@ namespace TShockAPI public static readonly string WhitelistPath = Path.Combine(TShock.SavePath, "whitelist.txt"); public static readonly string GroupsPath = Path.Combine(TShock.SavePath, "groups.txt"); public static readonly string UsersPath = Path.Combine(TShock.SavePath, "users.txt"); + public static readonly string ItemBansPath = Path.Combine(TShock.SavePath, "itembans.txt"); + public static readonly string RememberedPosPath = Path.Combine(TShock.SavePath, "oldpos.xml"); public static readonly string ConfigPath = Path.Combine(TShock.SavePath, "config.json"); + public static readonly string RegionsPath = Path.Combine(TShock.SavePath, "regions.xml"); + public static readonly string WarpsPath = Path.Combine(TShock.SavePath, "warps.xml"); public static void CreateFile(string file) { @@ -60,6 +64,25 @@ namespace TShockAPI CreateIfNot(WhitelistPath); CreateIfNot(GroupsPath, Resources.groups); CreateIfNot(UsersPath, Resources.users); + CreateIfNot(ItemBansPath, Resources.itembans); + + //Copies if using old paths (Remove in future releases, after everyone is running this version +) + if (File.Exists("regions.xml") && !File.Exists(RegionsPath)) + { + File.Move("regions.xml", RegionsPath); + } + else + { + CreateIfNot(RegionsPath); + } + if (File.Exists("warps.xml") && !File.Exists(WarpsPath)) + { + File.Move("warps.xml", WarpsPath); + } + else + { + CreateIfNot(WarpsPath); + } try { @@ -100,7 +123,23 @@ namespace TShockAPI TextReader tr = new StreamReader(WhitelistPath); string whitelist = tr.ReadToEnd(); ip = Tools.GetRealIP(ip); - return whitelist.Contains(ip); + bool contains = whitelist.Contains(ip); + if (!contains) + { + var char2 = Environment.NewLine.ToCharArray(); + var array = whitelist.Split(Environment.NewLine.ToCharArray()); + foreach (var line in whitelist.Split(Environment.NewLine.ToCharArray())) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + contains = Tools.GetIPv4Address(line).Equals(ip); + if (contains) + return true; + } + return false; + } + else + return true; } } } \ No newline at end of file diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 9f43c8d1..ba7feda1 100755 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1,426 +1,481 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 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.Diagnostics; -using System.IO; -using System.Text; -using Microsoft.Xna.Framework; -using StreamBinary; -using Terraria; -using TerrariaAPI; - -namespace TShockAPI -{ - public delegate bool GetDataHandlerDelegate(GetDataHandlerArgs args); - public class GetDataHandlerArgs : EventArgs - { - public TSPlayer Player { get; private set; } - public MemoryStream Data { get; private set; } - - public Player TPlayer - { - get { return Player.TPlayer; } - } - - public GetDataHandlerArgs(TSPlayer player, MemoryStream data) - { - Player = player; - Data = data; - } - } - public static class GetDataHandlers - { - private static Dictionary GetDataHandlerDelegates; - private static bool[] BlacklistTiles; - - public static void InitGetDataHandler() - { - #region Blacklisted tiles - - BlacklistTiles = new bool[Main.maxTileSets]; - BlacklistTiles[0] = true; - BlacklistTiles[1] = true; - BlacklistTiles[2] = true; - BlacklistTiles[6] = true; - BlacklistTiles[7] = true; - BlacklistTiles[8] = true; - BlacklistTiles[9] = true; - BlacklistTiles[22] = true; - BlacklistTiles[23] = true; - BlacklistTiles[25] = true; - BlacklistTiles[30] = true; - BlacklistTiles[37] = true; - BlacklistTiles[38] = true; - BlacklistTiles[39] = true; - BlacklistTiles[40] = true; - BlacklistTiles[41] = true; - BlacklistTiles[43] = true; - BlacklistTiles[44] = true; - BlacklistTiles[45] = true; - BlacklistTiles[46] = true; - BlacklistTiles[47] = true; - BlacklistTiles[53] = true; - BlacklistTiles[54] = true; - BlacklistTiles[56] = true; - BlacklistTiles[57] = true; - BlacklistTiles[58] = true; - BlacklistTiles[59] = true; - BlacklistTiles[60] = true; - BlacklistTiles[63] = true; - BlacklistTiles[64] = true; - BlacklistTiles[65] = true; - BlacklistTiles[66] = true; - BlacklistTiles[67] = true; - BlacklistTiles[68] = true; - BlacklistTiles[70] = true; - BlacklistTiles[75] = true; - BlacklistTiles[76] = true; - - #endregion Blacklisted tiles - - GetDataHandlerDelegates = new Dictionary - { - {PacketTypes.PlayerInfo, HandlePlayerInfo}, - {PacketTypes.TileSendSection, HandleSendSection}, - {PacketTypes.PlayerUpdate, HandlePlayerUpdate}, - {PacketTypes.Tile, HandleTile}, - {PacketTypes.TileSendSquare, HandleSendTileSquare}, - {PacketTypes.NPCUpdate, HandleNpcUpdate}, - {PacketTypes.PlayerDamage, HandlePlayerDamage}, - {PacketTypes.ProjectileNew, HandleProjectileNew}, - {PacketTypes.TogglePVP, HandleTogglePvp}, - {PacketTypes.TileKill, HandleTileKill}, - {PacketTypes.PlayerKillMe, HandlePlayerKillMe}, - {PacketTypes.LiquidSet, HandleLiquidSet}, - }; - } - - public static bool HandlerGetData(PacketTypes type, TSPlayer player, MemoryStream data) - { - GetDataHandlerDelegate handler; - if (GetDataHandlerDelegates.TryGetValue(type, out handler)) - { - try - { - return handler(new GetDataHandlerArgs(player, data)); - } - catch (Exception ex) - { - Log.Error(ex.ToString()); - } - } - return false; - } - - private static bool HandlePlayerInfo(GetDataHandlerArgs args) - { - byte playerid = args.Data.ReadInt8(); - byte hair = args.Data.ReadInt8(); - Color hairColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - Color skinColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - Color eyeColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - Color shirtColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - Color underShirtColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - Color pantsColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - Color shoeColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8()); - string name = Encoding.ASCII.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1))); - - if (hair >= Main.maxHair) - { - Tools.ForceKick(args.Player, "Hair crash exploit."); - return true; - } - - if (name.Length > 32) - { - Tools.ForceKick(args.Player, "Name exceeded 32 characters."); - return true; - } - if (name.Trim().Length == 0) - { - Tools.ForceKick(args.Player, "Empty Name."); - return true; - } - var ban = TShock.Bans.GetBanByName(name); - if (ban != null) - { - Tools.ForceKick(args.Player, string.Format("You are banned: {0}", ban.Reason)); - return true; - } - if (args.Player.ReceivedInfo) - { - return Tools.HandleGriefer(args.Player, "Sent client info more than once"); - } - - args.Player.ReceivedInfo = true; - return false; - } - - private static bool HandleSendTileSquare(GetDataHandlerArgs args) - { - short size = args.Data.ReadInt16(); - int x = args.Data.ReadInt32(); - int y = args.Data.ReadInt32(); - int plyX = Math.Abs(args.Player.TileX); - int plyY = Math.Abs(args.Player.TileY); - int tileX = Math.Abs(x); - int tileY = Math.Abs(y); - if (size > 5 || (ConfigurationManager.RangeChecks && (Math.Abs(plyX - tileX) > 32 || Math.Abs(plyY - tileY) > 32))) - { - Log.Debug(string.Format("SendTileSquare(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Size:{6})", - plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), size)); - return Tools.HandleGriefer(args.Player, "Send Tile Square Abuse"); - } - return false; - } - - private static bool HandleTile(GetDataHandlerArgs args) - { - byte type = args.Data.ReadInt8(); - int x = args.Data.ReadInt32(); - int y = args.Data.ReadInt32(); - byte tiletype = args.Data.ReadInt8(); - if (type == 1 || type == 3) - { - int plyX = Math.Abs(args.Player.TileX); - int plyY = Math.Abs(args.Player.TileY); - int tileX = Math.Abs(x); - int tileY = Math.Abs(y); - - if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32))) - { - Log.Debug(string.Format("TilePlaced(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Type:{6})", - plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), tiletype)); - return Tools.HandleGriefer(args.Player, "Placing impossible to place blocks."); - } - } - if (ConfigurationManager.DisableBuild) - { - if (!args.Player.Group.HasPermission("editspawn")) - { - args.Player.SendMessage("World protected from changes.", Color.Red); - TShock.SendTileSquare(args.Player, x, y); - return true; - } - } - if (ConfigurationManager.SpawnProtect) - { - if (!args.Player.Group.HasPermission("editspawn")) - { - var flag = TShock.CheckSpawn(x, y); - if (flag) - { - args.Player.SendMessage("Spawn protected from changes.", Color.Red); - TShock.SendTileSquare(args.Player, x, y); - return true; - } - } - } - if (type == 0 && BlacklistTiles[Main.tile[x, y].type] && args.Player.Active) - { - args.Player.TileThreshold++; - var coords = new Vector2(x, y); - if (!args.Player.TilesDestroyed.ContainsKey(coords)) - args.Player.TilesDestroyed.Add(coords, Main.tile[x, y]); - } - - return false; - } - - private static bool HandleTogglePvp(GetDataHandlerArgs args) - { - int id = args.Data.ReadByte(); - bool pvp = args.Data.ReadBoolean(); - - args.TPlayer.hostile = pvp; - if (id != args.Player.Index) - args.TPlayer.hostile = true; - if (ConfigurationManager.PermaPvp) - args.TPlayer.hostile = true; - NetMessage.SendData(30, -1, -1, "", args.Player.Index); - return true; - } - - private static bool HandleSendSection(GetDataHandlerArgs args) - { - return Tools.HandleGriefer(args.Player, "SendSection abuse."); - } - - private static bool HandleNpcUpdate(GetDataHandlerArgs args) - { - return Tools.HandleGriefer(args.Player, "Spawn NPC abuse"); - } - - private static bool HandlePlayerUpdate(GetDataHandlerArgs args) - { - byte plr = args.Data.ReadInt8(); - byte control = args.Data.ReadInt8(); - byte item = args.Data.ReadInt8(); - float posx = args.Data.ReadSingle(); - float posy = args.Data.ReadSingle(); - float velx = args.Data.ReadSingle(); - float vely = args.Data.ReadSingle(); - - if (Main.verboseNetplay) - Debug.WriteLine("Update: {{{0},{1}}} {{{2}, {3}}}", (int)posx, (int)posy, (int)velx, (int)vely); - - if (plr != args.Player.Index) - { - return Tools.HandleGriefer(args.Player, "Update Player abuse"); - } - return false; - } - - private static bool HandleProjectileNew(GetDataHandlerArgs args) - { - short ident = args.Data.ReadInt16(); - float posx = args.Data.ReadSingle(); - float posy = args.Data.ReadSingle(); - float velx = args.Data.ReadSingle(); - float vely = args.Data.ReadSingle(); - float knockback = args.Data.ReadSingle(); - short dmg = args.Data.ReadInt16(); - byte owner = args.Data.ReadInt8(); - byte type = args.Data.ReadInt8(); - - if (type == 29 || type == 28 || type == 37) - { - Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type)); - return Tools.HandleExplosivesUser(args.Player, "Throwing an explosive device."); - } - return false; - } - - private static bool HandlePlayerKillMe(GetDataHandlerArgs args) - { - byte id = args.Data.ReadInt8(); - byte hitdirection = args.Data.ReadInt8(); - short dmg = args.Data.ReadInt16(); - bool pvp = args.Data.ReadBoolean(); - - if (id != args.Player.Index) - { - return Tools.HandleGriefer(args.Player, "Trying to execute KillMe on someone else."); - } - return false; - } - - private static bool HandlePlayerDamage(GetDataHandlerArgs args) - { - byte playerid = args.Data.ReadInt8(); - byte direction = args.Data.ReadInt8(); - Int16 damage = args.Data.ReadInt16(); - byte pvp = args.Data.ReadInt8(); - - return !TShock.Players[playerid].TPlayer.hostile; - } - - private static bool HandleLiquidSet(GetDataHandlerArgs args) - { - int x = args.Data.ReadInt32(); - int y = args.Data.ReadInt32(); - byte liquid = args.Data.ReadInt8(); - bool lava = args.Data.ReadBoolean(); - - //The liquid was picked up. - if (liquid == 0) - return false; - - int plyX = Math.Abs(args.Player.TileX); - int plyY = Math.Abs(args.Player.TileY); - int tileX = Math.Abs(x); - int tileY = Math.Abs(y); - - bool bucket = false; - for (int i = 0; i < 44; i++) - { - if (args.TPlayer.inventory[i].type >= 205 && args.TPlayer.inventory[i].type <= 207) - { - bucket = true; - break; - } - } - - if (lava && !args.Player.Group.HasPermission("canlava")) - { - args.Player.SendMessage("You do not have permission to use lava", Color.Red); - Tools.SendLogs(string.Format("{0} tried using lava", args.Player.Name), Color.Red); - // TODO need to revert player changes so they are insync with server - return true; - } - if (!lava && !args.Player.Group.HasPermission("canwater")) - { - args.Player.SendMessage("You do not have permission to use water", Color.Red); - Tools.SendLogs(string.Format("{0} tried using water", args.Player.Name), Color.Red); - // TODO need to revert player changes so they are insync with server - return true; - } - - if (!bucket) - { - Log.Debug(string.Format("{0}(PlyXY:{1}_{2}, TileXY:{3}_{4}, Result:{5}_{6}, Amount:{7})", - lava ? "Lava" : "Water", plyX, plyY, tileX, tileY, - Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), liquid)); - return Tools.HandleGriefer(args.Player, "Manipulating liquid without bucket."); ; - } - if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32))) - { - Log.Debug(string.Format("Liquid(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Amount:{6})", - plyX, plyY, - tileX, tileY, - Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), - liquid - )); - return Tools.HandleGriefer(args.Player, "Placing impossible to place liquid."); ; - } - - if (ConfigurationManager.SpawnProtect) - { - if (!args.Player.Group.HasPermission("editspawn")) - { - var flag = TShock.CheckSpawn(x, y); - if (flag) - { - args.Player.SendMessage("The spawn is protected!", Color.Red); - // TODO need to revert player changes so they are insync with server - return true; - } - } - } - return false; - } - - private static bool HandleTileKill(GetDataHandlerArgs args) - { - int tilex = args.Data.ReadInt32(); - int tiley = args.Data.ReadInt32(); - if (tilex < 0 || tilex >= Main.maxTilesX || tiley < 0 || tiley >= Main.maxTilesY) - return false; - - if (Main.tile[tilex, tiley].type != 0x15) //Chest - { - Log.Debug(string.Format("TileKill(TileXY:{0}_{1}, Type:{2})", - tilex, tiley, Main.tile[tilex, tiley].type)); - Tools.ForceKick(args.Player, string.Format("Tile Kill abuse ({0})", Main.tile[tilex, tiley].type)); - return true; - } - return false; - } - } -} +/* +TShock, a server mod for Terraria +Copyright (C) 2011 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.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.Xna.Framework; +using Terraria; +using TerrariaAPI; +using XNAHelpers; + +namespace TShockAPI +{ + public delegate bool GetDataHandlerDelegate(GetDataHandlerArgs args); + public class GetDataHandlerArgs : EventArgs + { + public TSPlayer Player { get; private set; } + public MemoryStream Data { get; private set; } + + public Player TPlayer + { + get { return Player.TPlayer; } + } + + public GetDataHandlerArgs(TSPlayer player, MemoryStream data) + { + Player = player; + Data = data; + } + } + public static class GetDataHandlers + { + private static Dictionary GetDataHandlerDelegates; + private static bool[] BlacklistTiles; + + public static void InitGetDataHandler() + { + #region Blacklisted tiles + + BlacklistTiles = new bool[Main.maxTileSets]; + BlacklistTiles[0] = true; + BlacklistTiles[1] = true; + BlacklistTiles[2] = true; + BlacklistTiles[6] = true; + BlacklistTiles[7] = true; + BlacklistTiles[8] = true; + BlacklistTiles[9] = true; + BlacklistTiles[22] = true; + BlacklistTiles[23] = true; + BlacklistTiles[25] = true; + BlacklistTiles[30] = true; + BlacklistTiles[37] = true; + BlacklistTiles[38] = true; + BlacklistTiles[39] = true; + BlacklistTiles[40] = true; + BlacklistTiles[41] = true; + BlacklistTiles[43] = true; + BlacklistTiles[44] = true; + BlacklistTiles[45] = true; + BlacklistTiles[46] = true; + BlacklistTiles[47] = true; + BlacklistTiles[53] = true; + BlacklistTiles[54] = true; + BlacklistTiles[56] = true; + BlacklistTiles[57] = true; + BlacklistTiles[58] = true; + BlacklistTiles[59] = true; + BlacklistTiles[60] = true; + BlacklistTiles[63] = true; + BlacklistTiles[64] = true; + BlacklistTiles[65] = true; + BlacklistTiles[66] = true; + BlacklistTiles[67] = true; + BlacklistTiles[68] = true; + BlacklistTiles[70] = true; + BlacklistTiles[75] = true; + BlacklistTiles[76] = true; + + #endregion Blacklisted tiles + + GetDataHandlerDelegates = new Dictionary + { + {PacketTypes.PlayerInfo, HandlePlayerInfo}, + {PacketTypes.TileSendSection, HandleSendSection}, + {PacketTypes.PlayerUpdate, HandlePlayerUpdate}, + {PacketTypes.Tile, HandleTile}, + {PacketTypes.TileSendSquare, HandleSendTileSquare}, + {PacketTypes.NPCUpdate, HandleNpcUpdate}, + {PacketTypes.PlayerDamage, HandlePlayerDamage}, + {PacketTypes.ProjectileNew, HandleProjectileNew}, + {PacketTypes.TogglePVP, HandleTogglePvp}, + {PacketTypes.TileKill, HandleTileKill}, + {PacketTypes.PlayerKillMe, HandlePlayerKillMe}, + {PacketTypes.LiquidSet, HandleLiquidSet}, + {PacketTypes.PlayerSpawn, HandleSpawn}, + }; + } + + public static bool HandlerGetData(PacketTypes type, TSPlayer player, MemoryStream data) + { + GetDataHandlerDelegate handler; + if (GetDataHandlerDelegates.TryGetValue(type, out handler)) + { + try + { + return handler(new GetDataHandlerArgs(player, data)); + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + } + return false; + } + + private static bool HandlePlayerInfo(GetDataHandlerArgs args) + { + byte playerid = args.Data.ReadInt8(); + byte hair = args.Data.ReadInt8(); + //Various colours here + + args.Data.Position += 21; + bool hardcore = args.Data.ReadBoolean(); + string name = Encoding.ASCII.GetString(args.Data.ReadBytes((int)(args.Data.Length - args.Data.Position - 1))); + + if (hair >= Main.maxHair) + { + Tools.ForceKick(args.Player, "Hair crash exploit."); + return true; + } + if (name.Length > 32) + { + Tools.ForceKick(args.Player, "Name exceeded 32 characters."); + return true; + } + if (name.Trim().Length == 0) + { + Tools.ForceKick(args.Player, "Empty Name."); + return true; + } + var ban = TShock.Bans.GetBanByName(name); + if (ban != null) + { + Tools.ForceKick(args.Player, string.Format("You are banned: {0}", ban.Reason)); + return true; + } + if (args.Player.ReceivedInfo) + { + return Tools.HandleGriefer(args.Player, "Sent client info more than once"); + } + if (ConfigurationManager.HardcoreOnly) + if (!hardcore) + { + Tools.ForceKick(args.Player, "Server is set to hardcore characters only!"); + return true; + } + + args.Player.ReceivedInfo = true; + return false; + } + + private static bool HandleSendTileSquare(GetDataHandlerArgs args) + { + short size = args.Data.ReadInt16(); + int x = args.Data.ReadInt32(); + int y = args.Data.ReadInt32(); + int plyX = Math.Abs(args.Player.TileX); + int plyY = Math.Abs(args.Player.TileY); + int tileX = Math.Abs(x); + int tileY = Math.Abs(y); + if (size > 5 || (ConfigurationManager.RangeChecks && (Math.Abs(plyX - tileX) > 32 || Math.Abs(plyY - tileY) > 32))) + { + Log.Debug(string.Format("SendTileSquare(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Size:{6})", + plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), size)); + return Tools.HandleGriefer(args.Player, "Send Tile Square Abuse"); + } + return false; + } + + private static bool HandleTile(GetDataHandlerArgs args) + { + byte type = args.Data.ReadInt8(); + int x = args.Data.ReadInt32(); + int y = args.Data.ReadInt32(); + byte tiletype = args.Data.ReadInt8(); + if (type == 1 || type == 3) + { + int plyX = Math.Abs(args.Player.TileX); + int plyY = Math.Abs(args.Player.TileY); + int tileX = Math.Abs(x); + int tileY = Math.Abs(y); + + if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32))) + { + if (!(type == 1 && ((tiletype == 0 && args.Player.TPlayer.selectedItem == 114) || (tiletype == 53 && args.Player.TPlayer.selectedItem == 266)))) + { + Log.Debug(string.Format("TilePlaced(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Type:{6})", + plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), tiletype)); + return Tools.HandleGriefer(args.Player, "Placing impossible to place blocks."); + } + } + if (tiletype == 48 && !args.Player.Group.HasPermission("canspike")) + { + args.Player.SendMessage("You do not have permission to place spikes.", Color.Red); + Tools.SendLogs(string.Format("{0} tried to place spikes", args.Player.Name), Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + } + if (!args.Player.Group.HasPermission("editspawn") && RegionManager.InProtectedArea(x, y, Tools.GetPlayerIP(args.Player.Name))) + { + args.Player.SendMessage("Region protected from changes.", Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + if (ConfigurationManager.DisableBuild) + { + if (!args.Player.Group.HasPermission("editspawn")) + { + args.Player.SendMessage("World protected from changes.", Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + } + if (ConfigurationManager.SpawnProtect) + { + if (!args.Player.Group.HasPermission("editspawn")) + { + var flag = TShock.CheckSpawn(x, y); + if (flag) + { + args.Player.SendMessage("Spawn protected from changes.", Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + } + } + if (type == 0 && BlacklistTiles[Main.tile[x, y].type] && args.Player.Active) + { + args.Player.TileThreshold++; + var coords = new Vector2(x, y); + if (!args.Player.TilesDestroyed.ContainsKey(coords)) + args.Player.TilesDestroyed.Add(coords, Main.tile[x, y]); + } + if (args.Player.LastExplosive != null) + if ((DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds < 1000) + { + args.Player.SendMessage("Please wait another " + (1000 - (DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds).ToString() + " milliseconds before placing/destroying tiles", Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + + return false; + } + + private static bool HandleTogglePvp(GetDataHandlerArgs args) + { + int id = args.Data.ReadByte(); + bool pvp = args.Data.ReadBoolean(); + + long seconds = (long)(DateTime.UtcNow - args.Player.LastPvpChange).TotalSeconds; + if (ConfigurationManager.PvpThrottle > 0 && seconds < ConfigurationManager.PvpThrottle) + { + args.Player.SendMessage(string.Format("You cannot change pvp status for {0} seconds", ConfigurationManager.PvpThrottle - seconds), 255, 0, 0); + args.Player.SetPvP(id != args.Player.Index || ConfigurationManager.PermaPvp ? true : args.TPlayer.hostile); + } + else + { + args.Player.SetPvP(id != args.Player.Index || ConfigurationManager.PermaPvp ? true : pvp); + } + return true; + } + + private static bool HandleSendSection(GetDataHandlerArgs args) + { + return Tools.HandleGriefer(args.Player, "SendSection abuse."); + } + + private static bool HandleNpcUpdate(GetDataHandlerArgs args) + { + return Tools.HandleGriefer(args.Player, "Spawn NPC abuse"); + } + + private static bool HandlePlayerUpdate(GetDataHandlerArgs args) + { + byte plr = args.Data.ReadInt8(); + byte control = args.Data.ReadInt8(); + byte item = args.Data.ReadInt8(); + float posx = args.Data.ReadSingle(); + float posy = args.Data.ReadSingle(); + float velx = args.Data.ReadSingle(); + float vely = args.Data.ReadSingle(); + + if (Main.verboseNetplay) + Debug.WriteLine("Update: {{{0},{1}}} {{{2}, {3}}}", (int)posx, (int)posy, (int)velx, (int)vely); + + if (plr != args.Player.Index) + { + return Tools.HandleGriefer(args.Player, "Update Player abuse"); + } + + return false; + } + + private static bool HandleProjectileNew(GetDataHandlerArgs args) + { + short ident = args.Data.ReadInt16(); + float posx = args.Data.ReadSingle(); + float posy = args.Data.ReadSingle(); + float velx = args.Data.ReadSingle(); + float vely = args.Data.ReadSingle(); + float knockback = args.Data.ReadSingle(); + short dmg = args.Data.ReadInt16(); + byte owner = args.Data.ReadInt8(); + byte type = args.Data.ReadInt8(); + + if (type == 29 || type == 28 || type == 37) + { + Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type)); + if (ConfigurationManager.DisableBoom && (!args.Player.Group.HasPermission("useexplosives") || !args.Player.Group.HasPermission("ignoregriefdetection"))) + { + Main.projectile[ident].type = 0; + args.Player.SendData(PacketTypes.ProjectileNew, "", ident); + args.Player.SendMessage("Explosives are disabled!", Color.Red); + args.Player.LastExplosive = DateTime.UtcNow; + //return true; + } + else + return Tools.HandleExplosivesUser(args.Player, "Throwing an explosive device."); + } + return false; + } + + private static bool HandlePlayerKillMe(GetDataHandlerArgs args) + { + byte id = args.Data.ReadInt8(); + if (id != args.Player.Index) + { + return Tools.HandleGriefer(args.Player, "Trying to execute KillMe on someone else."); + } + return false; + } + + private static bool HandlePlayerDamage(GetDataHandlerArgs args) + { + byte playerid = args.Data.ReadInt8(); + return !TShock.Players[playerid].TPlayer.hostile; + } + + private static bool HandleLiquidSet(GetDataHandlerArgs args) + { + int x = args.Data.ReadInt32(); + int y = args.Data.ReadInt32(); + byte liquid = args.Data.ReadInt8(); + bool lava = args.Data.ReadBoolean(); + + //The liquid was picked up. + if (liquid == 0) + return false; + + int plyX = Math.Abs(args.Player.TileX); + int plyY = Math.Abs(args.Player.TileY); + int tileX = Math.Abs(x); + int tileY = Math.Abs(y); + + bool bucket = false; + for (int i = 0; i < 44; i++) + { + if (args.TPlayer.inventory[i].type >= 205 && args.TPlayer.inventory[i].type <= 207) + { + bucket = true; + break; + } + } + + if (lava && !args.Player.Group.HasPermission("canlava")) + { + args.Player.SendMessage("You do not have permission to use lava", Color.Red); + Tools.SendLogs(string.Format("{0} tried using lava", args.Player.Name), Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + if (!lava && !args.Player.Group.HasPermission("canwater")) + { + args.Player.SendMessage("You do not have permission to use water", Color.Red); + Tools.SendLogs(string.Format("{0} tried using water", args.Player.Name), Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + + if (!bucket) + { + Log.Debug(string.Format("{0}(PlyXY:{1}_{2}, TileXY:{3}_{4}, Result:{5}_{6}, Amount:{7})", + lava ? "Lava" : "Water", plyX, plyY, tileX, tileY, + Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), liquid)); + return Tools.HandleGriefer(args.Player, "Manipulating liquid without bucket."); ; + } + if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32))) + { + Log.Debug(string.Format("Liquid(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Amount:{6})", + plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), liquid)); + return Tools.HandleGriefer(args.Player, "Placing impossible to place liquid."); ; + } + + if (ConfigurationManager.SpawnProtect) + { + if (!args.Player.Group.HasPermission("editspawn")) + { + var flag = TShock.CheckSpawn(x, y); + if (flag) + { + args.Player.SendMessage("The spawn is protected!", Color.Red); + args.Player.SendTileSquare(x, y); + return true; + } + } + } + return false; + } + + private static bool HandleTileKill(GetDataHandlerArgs args) + { + int tilex = args.Data.ReadInt32(); + int tiley = args.Data.ReadInt32(); + if (tilex < 0 || tilex >= Main.maxTilesX || tiley < 0 || tiley >= Main.maxTilesY) + return false; + + if (Main.tile[tilex, tiley].type != 0x15) //Chest + { + Log.Debug(string.Format("TileKill(TileXY:{0}_{1}, Type:{2})", + tilex, tiley, Main.tile[tilex, tiley].type)); + Tools.ForceKick(args.Player, string.Format("Tile Kill abuse ({0})", Main.tile[tilex, tiley].type)); + return true; + } + return false; + } + + private static bool HandleSpawn(GetDataHandlerArgs args) + { + byte player = args.Data.ReadInt8(); + int spawnx = args.Data.ReadInt32(); + int spawny = args.Data.ReadInt32(); + + if (args.Player.InitSpawn) + { + if (ConfigurationManager.HardcoreOnly && (ConfigurationManager.KickOnHardcoreDeath || ConfigurationManager.BanOnHardcoreDeath)) + if (args.TPlayer.selectedItem != 50) + { + if (ConfigurationManager.BanOnHardcoreDeath) + { + if (!Tools.Ban(args.Player, "Death results in a ban")) + Tools.ForceKick(args.Player, "Death results in a ban, but can't ban you"); + } + else + Tools.ForceKick(args.Player, "Death results in a kick"); + return true; + } + } + else + args.Player.InitSpawn = true; + + return false; + } + } +} diff --git a/TShockAPI/ItemManager.cs b/TShockAPI/ItemManager.cs new file mode 100644 index 00000000..e1c2b97c --- /dev/null +++ b/TShockAPI/ItemManager.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using Terraria; + +namespace TShockAPI +{ + class ItemManager + { + public static List BannedItems = new List(); + + public static void LoadBans() + { + try + { + if (!File.Exists(FileTools.ItemBansPath)) + return; + + BannedItems.Clear(); + + foreach (var line in File.ReadAllLines(FileTools.ItemBansPath)) + { + int ID = -1; + if (Int32.TryParse(line, out ID)) + { + if (ID < Main.maxItemTypes && ID > 0) + { + var item = Tools.GetItemById(ID); + BannedItems.Add(new ItemBan(ID, item.name)); + Log.Info("Item: " + item.name + " is banned"); + } + else + { + Log.Warn("Invalid ID " + ID); + } + } + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + } + + public static bool ItemIsBanned(string ID) + { + foreach (ItemBan item in BannedItems) + { + if (ID == item.Name) + return true; + } + return false; + } + } + + public class ItemBan + { + public int ID { get; set; } + + public string Name { get; set; } + + public ItemBan(int id, string name) + { + ID = id; + Name = name; + } + + public ItemBan() + { + ID = -1; + Name = string.Empty; + } + } +} diff --git a/TShockAPI/Log.cs b/TShockAPI/Log.cs index a674f16b..cb89e1e2 100644 --- a/TShockAPI/Log.cs +++ b/TShockAPI/Log.cs @@ -53,24 +53,6 @@ namespace TShockAPI _logWriter = new StreamWriter(filename, !clear); } - /// - /// Internal method which writes a message directly to the log file. - /// - private static void Write(String message, LogLevel level) - { - if (!MayWriteType(level)) - { - return; - } - - string caller = "TShock"; - - _logWriter.WriteLine(string.Format("{0} - {1}: {2}: {3}", - DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), - caller, level.ToString().ToUpper(), message)); - _logWriter.Flush(); - } - /// /// Checks whether the log level contains the specified flag. /// @@ -116,6 +98,16 @@ namespace TShockAPI Write(message, LogLevel.Info); } + /// + /// Writes an informative string to the log file. Also outputs to the console. + /// + /// The message to be written. + public static void ConsoleInfo(String message) + { + Console.WriteLine(message); + Write(message, LogLevel.Info); + } + /// /// Writes a debug string to the log file. /// @@ -124,5 +116,31 @@ namespace TShockAPI { Write(message, LogLevel.Debug); } + + /// + /// Internal method which writes a message directly to the log file. + /// + private static void Write(String message, LogLevel level) + { + if (!MayWriteType(level)) + { + return; + } + + string caller = "TShock"; + + StackFrame frame = new StackTrace().GetFrame(2); + if (frame != null) + { + var meth = frame.GetMethod(); + if (meth != null) + caller = meth.DeclaringType.Name; + } + + _logWriter.WriteLine(string.Format("{0} - {1}: {2}: {3}", + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), + caller, level.ToString().ToUpper(), message)); + _logWriter.Flush(); + } } } \ No newline at end of file diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs index a220c10d..9bbabf72 100644 --- a/TShockAPI/Properties/AssemblyInfo.cs +++ b/TShockAPI/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("2.3.0.0627")] +[assembly: AssemblyFileVersion("2.3.0.0627")] \ No newline at end of file diff --git a/TShockAPI/RegionManager.cs b/TShockAPI/RegionManager.cs new file mode 100644 index 00000000..1a7ccf5e --- /dev/null +++ b/TShockAPI/RegionManager.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using Microsoft.Xna.Framework; +using Terraria; + +namespace TShockAPI +{ + public class RegionManager + { + public static List Regions = new List(); + + public static bool AddRegion(int tx, int ty, int width, int height, string regionname, string worldname) + { + foreach (Region nametest in Regions) + { + if (regionname.ToLower() == nametest.RegionName.ToLower()) + { + return false; + } + } + Regions.Add(new Region(new Rectangle(tx, ty, width, height), regionname, true, worldname)); + WriteSettings(); + return true; + } + + public static bool AddNewUser(string regionName, string IP) + { + foreach (Region nametest in Regions) + { + if (regionName.ToLower() == nametest.RegionName.ToLower()) + { + nametest.RegionAllowedIPs.Add(IP.ToLower()); + return true; + } + } + return false; + } + + public static bool DeleteRegion(string name) + { + foreach (Region nametest in Regions) + { + if (name.ToLower() == nametest.RegionName.ToLower() && nametest.WorldRegionName == Main.worldName) + { + Regions.Remove(nametest); + WriteSettings(); + return true; + } + } + return false; + } + + public static bool SetRegionState(string name, bool state) + { + foreach (Region nametest in Regions) + { + if (name.ToLower() == nametest.RegionName.ToLower()) + { + nametest.DisableBuild = state; + WriteSettings(); + return true; + } + } + return false; + } + + public static bool InProtectedArea(int X, int Y, string IP) + { + foreach(Region region in Regions) + { + if (X >= region.RegionArea.Left && X <= region.RegionArea.Right && Y >= region.RegionArea.Top && Y <= region.RegionArea.Bottom && region.DisableBuild && Main.worldName == region.WorldRegionName && (!AllowedUser(region.RegionName, IP.ToLower()) || region.RegionAllowedIPs.Count == 0)) + { + Console.WriteLine(region.RegionName); + return true; + } + } + return false; + } + + public static int GetRegionIndex(string regionName) + { + for(int i = 0; i< Regions.Count;i++) + { + if(Regions[i].RegionName == regionName) + return i; + } + return -1; + } + + public static bool AllowedUser(string regionName, string playerIP) + { + int ID = -1; + if ((ID = GetRegionIndex(regionName)) != -1) + { + for (int i = 0; i < Regions[ID].RegionAllowedIPs.Count; i++) + { + if (Regions[ID].RegionAllowedIPs[i].ToLower() == playerIP.ToLower()) + { + return true; + } + } + } + return false; + } + + public static void WriteSettings() + { + try + { + XmlWriterSettings xmlWriterSettings = new XmlWriterSettings(); + xmlWriterSettings.Indent = true; + xmlWriterSettings.NewLineChars = Environment.NewLine; + + using (XmlWriter settingsw = XmlWriter.Create(FileTools.RegionsPath, xmlWriterSettings)) + { + settingsw.WriteStartDocument(); + settingsw.WriteStartElement("Regions"); + + foreach (Region region in Regions) + { + settingsw.WriteStartElement("ProtectedRegion"); + settingsw.WriteElementString("RegionName", region.RegionName); + settingsw.WriteElementString("Point1X", region.RegionArea.X.ToString()); + settingsw.WriteElementString("Point1Y", region.RegionArea.Y.ToString()); + settingsw.WriteElementString("Point2X", region.RegionArea.Width.ToString()); + settingsw.WriteElementString("Point2Y", region.RegionArea.Height.ToString()); + settingsw.WriteElementString("Protected", region.DisableBuild.ToString()); + settingsw.WriteElementString("WorldName", region.WorldRegionName); + + settingsw.WriteElementString("AllowedUserCount", region.RegionAllowedIPs.Count.ToString()); + for (int i = 0; i < region.RegionAllowedIPs.Count; i++) + { + settingsw.WriteElementString("IP", region.RegionAllowedIPs[i]); + } + + settingsw.WriteEndElement(); + } + + settingsw.WriteEndElement(); + settingsw.WriteEndDocument(); + } + Log.Info("Wrote Regions"); + } + catch + { + Log.Warn("Could not write Regions"); + } + } + + public static void ReadAllSettings() + { + try + { + XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); + xmlReaderSettings.IgnoreWhitespace = true; + + using (XmlReader settingr = XmlReader.Create(FileTools.RegionsPath, xmlReaderSettings)) + { + while (settingr.Read()) + { + if (settingr.IsStartElement()) + { + switch (settingr.Name) + { + case "Regions": + { + break; + } + case "ProtectedRegion": + { + if (settingr.Read()) + { + string name = null; + int x = 0; + int y = 0; + int width = 0; + int height = 0; + bool state = true; + string worldname = null; + int playercount = 0; + + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + name = settingr.Value; + else + Log.Warn("Region name is empty"); + + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + Int32.TryParse(settingr.Value, out x); + else + Log.Warn("x for region " + name + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + Int32.TryParse(settingr.Value, out y); + else + Log.Warn("y for region " + name + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + Int32.TryParse(settingr.Value, out width); + else + Log.Warn("Width for region " + name + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + Int32.TryParse(settingr.Value, out height); + else + Log.Warn("Height for region " + name + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + bool.TryParse(settingr.Value, out state); + else + Log.Warn("State for region " + name + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + worldname = settingr.Value; + else + Log.Warn("Worldname for region " + name + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + Int32.TryParse(settingr.Value, out playercount); + else + Log.Warn("Playercount for region " + name + " is empty"); + + AddRegion(x, y, width, height, name, worldname); + + if (playercount > 0) + { + for (int i = 0; i < playercount; i++) + { + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + { + int ID = RegionManager.GetRegionIndex(name); + Regions[ID].RegionAllowedIPs.Add(settingr.Value); + } + else + Log.Warn("PlayerIP " + i + " for region " + name + " is empty"); + } + } + } + break; + } + } + } + } + } + Log.Info("Read Regions"); + } + catch + { + Log.Warn("Could not read Regions"); + WriteSettings(); + } + } + } + + public class Region + { + public Rectangle RegionArea { get; set; } + public string RegionName { get; set; } + public bool DisableBuild { get; set; } + public string WorldRegionName { get; set; } + public List RegionAllowedIPs = new List(); + + public Region(Rectangle region, string name, bool disablebuild, string worldname) + { + RegionArea = region; + RegionName = name; + DisableBuild = disablebuild; + WorldRegionName = worldname; + } + + public Region() + { + RegionArea = Rectangle.Empty; + RegionName = string.Empty; + DisableBuild = true; + WorldRegionName = string.Empty; + } + } +} diff --git a/TShockAPI/RememberPosManager.cs b/TShockAPI/RememberPosManager.cs new file mode 100644 index 00000000..bcab39c8 --- /dev/null +++ b/TShockAPI/RememberPosManager.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using Terraria; +using Microsoft.Xna.Framework; +using System.Xml; + +namespace TShockAPI +{ + class RemeberedPosManager + { + public static List RemeberedPosistions = new List(); + + public static void LoadPos() + { + try + { + XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); + xmlReaderSettings.IgnoreWhitespace = true; + + using (XmlReader settingr = XmlReader.Create(FileTools.RememberedPosPath, xmlReaderSettings)) + { + while (settingr.Read()) + { + if (settingr.IsStartElement()) + { + switch (settingr.Name) + { + case "Positions": + { + break; + } + case "Player": + { + if (settingr.Read()) + { + string IP = null; + float X = 0; + float Y = 0; + + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + IP = settingr.Value; + else + Log.Warn("IP is empty"); + + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + float.TryParse(settingr.Value, out X); + else + Log.Warn("X for IP " + IP + " is empty"); + + settingr.Read(); + settingr.Read(); + settingr.Read(); + if (settingr.Value != "" || settingr.Value != null) + float.TryParse(settingr.Value, out Y); + else + Log.Warn("Y for IP " + IP + " is empty"); + + if (X != 0 && Y != 0) + RemeberedPosistions.Add(new RemeberedPos(IP, new Vector2(X, Y))); + } + break; + } + } + } + } + } + Log.Info("Read Remembered Positions"); + } + catch + { + Log.Warn("Could not read Remembered Positions"); + WriteSettings(); + } + } + + public static void WriteSettings() + { + try + { + XmlWriterSettings xmlWriterSettings = new XmlWriterSettings(); + xmlWriterSettings.Indent = true; + xmlWriterSettings.NewLineChars = Environment.NewLine; + + using (XmlWriter settingsw = XmlWriter.Create(FileTools.RememberedPosPath, xmlWriterSettings)) + { + settingsw.WriteStartDocument(); + settingsw.WriteStartElement("Positions"); + + foreach (RemeberedPos player in RemeberedPosistions) + { + settingsw.WriteStartElement("Player"); + settingsw.WriteElementString("IP", player.IP); + settingsw.WriteElementString("X", player.Pos.X.ToString()); + settingsw.WriteElementString("Y", player.Pos.Y.ToString()); + settingsw.WriteEndElement(); + } + + settingsw.WriteEndElement(); + settingsw.WriteEndDocument(); + } + Log.Info("Wrote Remembered Positions"); + } + catch + { + Log.Warn("Could not write Remembered Positions"); + } + } + } + + + public class RemeberedPos + { + public string IP { get; set; } + public Vector2 Pos { get; set; } + + public RemeberedPos(string ip, Vector2 pos) + { + IP = ip; + Pos = pos; + } + + public RemeberedPos() + { + IP = string.Empty; + Pos = Vector2.Zero; + } + } +} diff --git a/TShockAPI/Resources.Designer.cs b/TShockAPI/Resources.Designer.cs index 24f858b6..69d5beef 100644 --- a/TShockAPI/Resources.Designer.cs +++ b/TShockAPI/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.225 +// Runtime Version:4.0.30319.1 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -71,9 +71,9 @@ namespace TShockAPI { ///#ALWAYS DECLARE A GROUP'S PARENT BEFORE YOU DECLARE THE GROUP /// ///#currently avaliable permissions: - ///#kick ban ignorecheatdetection - ///#maintenance cfg causeevents spawnboss tp - ///#spawnmob che [rest of string was truncated]";. + ///#reservedslot - reserved slot for player + ///#canwater - allow players to use water + ///#canlav [rest of string was truncated]";. /// internal static string groups { get { @@ -81,6 +81,16 @@ namespace TShockAPI { } } + /// + /// Looks up a localized string similar to #see https://github.com/TShock/TShock/wiki/Item-List for a list of groups + ///#List each banned item below this with spaces. + /// + internal static string itembans { + get { + return ResourceManager.GetString("itembans", resourceCulture); + } + } + /// /// Looks up a localized string similar to #format ///#ip group diff --git a/TShockAPI/Resources.resx b/TShockAPI/Resources.resx index e260f5f5..21b8b3ab 100644 --- a/TShockAPI/Resources.resx +++ b/TShockAPI/Resources.resx @@ -1,21 +1,4 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\TShockAPI\bin\Release\TShockAPI.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Update/Update.csproj b/Update/Update.csproj deleted file mode 100644 index f37c3dee..00000000 --- a/Update/Update.csproj +++ /dev/null @@ -1,74 +0,0 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {AF322FAB-9A32-43AA-A01A-76B2A039F711} - Exe - Properties - Update - UpdateTShock - v4.0 - Client - 512 - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - True - True - Resources.resx - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - - - - - - - \ No newline at end of file