diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs
new file mode 100644
index 00000000..48210f09
--- /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.Error(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/ConfigFile.cs b/TShockAPI/ConfigFile.cs
index f0a37a22..a197a333 100644
--- a/TShockAPI/ConfigFile.cs
+++ b/TShockAPI/ConfigFile.cs
@@ -41,7 +41,15 @@ namespace TShockAPI
public bool RangeChecks = true;
public bool SpamChecks = false;
public bool DisableBuild = false;
+
public float[] AdminChatRGB = {255, 0, 0};
public string AdminChatPrefix = "(Admin) ";
+
+ public int PvpThrottle = 0;
+
+ public int BackupInterval = 0;
+ public int BackupKeepFor = 60;
+
+ public bool ListServer = false;
}
}
\ No newline at end of file
diff --git a/TShockAPI/ConfigurationManager.cs b/TShockAPI/ConfigurationManager.cs
index c826d134..00fc8d6c 100644
--- a/TShockAPI/ConfigurationManager.cs
+++ b/TShockAPI/ConfigurationManager.cs
@@ -55,6 +55,25 @@ namespace TShockAPI
public static float[] AdminChatRGB = {255, 0, 0};
public static string AdminChatPrefix = "(Admin) ";
+ ///
+ /// 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;
+
+ ///
+ /// Server will broadcast itself to the server list.
+ ///
+ public static bool ListServer = false;
+
public static void ReadJsonConfiguration()
{
TextReader tr = new StreamReader(FileTools.ConfigPath);
@@ -87,6 +106,10 @@ namespace TShockAPI
NPC.defaultSpawnRate = DefaultSpawnRate;
AdminChatRGB = cfg.AdminChatRGB;
AdminChatPrefix = cfg.AdminChatPrefix;
+ PvpThrottle = cfg.PvpThrottle;
+ BackupInterval = cfg.BackupInterval;
+ BackupKeepFor = cfg.BackupKeepFor;
+ ListServer = cfg.ListServer;
}
public static void WriteJsonConfiguration()
@@ -115,6 +138,10 @@ namespace TShockAPI
cfg.DisableBuild = DisableBuild;
cfg.AdminChatRGB = AdminChatRGB;
cfg.AdminChatPrefix = AdminChatPrefix;
+ cfg.PvpThrottle = PvpThrottle;
+ cfg.BackupInterval = BackupInterval;
+ cfg.BackupKeepFor = BackupKeepFor;
+ cfg.ListServer = ListServer;
string json = JsonConvert.SerializeObject(cfg, Formatting.Indented);
TextWriter tr = new StreamWriter(FileTools.ConfigPath);
tr.Write(json);
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index 10d9d088..74a56a71 100755
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -14,86 +14,86 @@ 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
-
+*/
+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},
@@ -108,316 +108,325 @@ namespace TShockAPI
{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 (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 (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]);
- }
-
- return false;
- }
-
- private static bool HandleTogglePvp(GetDataHandlerArgs args)
- {
- int id = args.Data.ReadByte();
- bool pvp = args.Data.ReadBoolean();
-
- 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));
- 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);
- 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;
- }
- }
-}
+ };
+ }
+
+ 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 (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 (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]);
+ }
+
+ 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));
+ 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);
+ 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;
+ }
+ }
+}
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index e6d1722d..7a4b9835 100644
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -34,6 +34,7 @@ namespace TShockAPI
public Group Group { get; set; }
public bool ReceivedInfo { get; set; }
public int Index { get; protected set; }
+ public DateTime LastPvpChange { get; protected set; }
public bool RealPlayer
{
get { return Index >= 0 && Index < Main.maxNetPlayers; }
@@ -171,10 +172,12 @@ namespace TShockAPI
{
if (TPlayer.hostile != pvp)
{
+ LastPvpChange = DateTime.UtcNow;
TPlayer.hostile = pvp;
- NetMessage.SendData((int)PacketTypes.TogglePVP, -1, -1, "", Index);
All.SendMessage(string.Format("{0} has {1} PvP!", Name, pvp ? "enabled" : "disabled"), Main.teamColor[Team]);
}
+ //Broadcast anyways to keep players synced
+ NetMessage.SendData((int)PacketTypes.TogglePVP, -1, -1, "", Index);
}
}
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index 7fe102f7..5dd14940 100755
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -39,6 +39,7 @@ namespace TShockAPI
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
public static BanManager Bans = new BanManager(Path.Combine(SavePath, "bans.txt"));
+ public static BackupManager Backups = new BackupManager(Path.Combine(SavePath, "backups"));
public override Version Version
{
@@ -101,6 +102,9 @@ namespace TShockAPI
Commands.InitCommands();
Log.Info("Commands initialized");
+ Backups.KeepFor = ConfigurationManager.BackupKeepFor;
+ Backups.Interval = ConfigurationManager.BackupInterval;
+
HandleCommandLine(Environment.GetCommandLineArgs());
}
@@ -178,6 +182,10 @@ namespace TShockAPI
private void OnUpdate(GameTime time)
{
UpdateManager.UpdateProcedureCheck();
+
+ if (Backups.IsBackupTime)
+ Backups.Backup();
+
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj
index 8938288a..473f3abd 100644
--- a/TShockAPI/TShockAPI.csproj
+++ b/TShockAPI/TShockAPI.csproj
@@ -12,6 +12,7 @@
TShockAPI
v4.0
512
+ false
publish\
true
Disk
@@ -24,7 +25,6 @@
true
0
1.0.0.%2a
- false
false
true
@@ -69,6 +69,7 @@
+
@@ -133,7 +134,7 @@
-
+