From ad22a379d9ad21ca7db3080ae4227db901430988 Mon Sep 17 00:00:00 2001 From: Zidonuke Date: Tue, 20 Dec 2011 13:12:27 -0500 Subject: [PATCH] New config to disable dungeon guardian and instead send players to spawn (stops hack abuse) Changed AlwaysPvp to support new features better. Now checking ItemAnimation for stuff. Initial data structures for Server Side Inventory handling support. --- TShockAPI/ConfigFile.cs | 6 ++ TShockAPI/DB/InventoryManager.cs | 100 +++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 62 ++++++++++++++----- TShockAPI/TSPlayer.cs | 51 ++++++++++++++++ TShockAPI/TShock.cs | 22 ++++++- TShockAPI/TShockAPI.csproj | 3 +- 6 files changed, 228 insertions(+), 16 deletions(-) create mode 100644 TShockAPI/DB/InventoryManager.cs diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index 5aed7b6c..e1da8b94 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -177,6 +177,12 @@ namespace TShockAPI [Description("Disables hardmode, can't never be activated. Overrides /starthardmode")] public bool DisableHardmode = false; + [Description("Disables Dungeon Guardian from being spawned by player packets, this will instead force a respawn")] + public bool DisableDungeonGuardian = false; + + [Description("Enable Server Side Inventory checks, EXPERIMENTAL")] + public bool ServerSideInventory = false; + public static ConfigFile Read(string path) { if (!File.Exists(path)) diff --git a/TShockAPI/DB/InventoryManager.cs b/TShockAPI/DB/InventoryManager.cs new file mode 100644 index 00000000..28fc90e3 --- /dev/null +++ b/TShockAPI/DB/InventoryManager.cs @@ -0,0 +1,100 @@ +/* +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.Data; + +using MySql.Data.MySqlClient; +using Terraria; + +namespace TShockAPI.DB +{ + public class InventoryManager + { + public IDbConnection database; + + public InventoryManager(IDbConnection db) + { + database = db; + + var table = new SqlTable("Inventory", + new SqlColumn("AccountName", MySqlDbType.VarChar, 32) { Primary = true }, + new SqlColumn("CharacterName", MySqlDbType.VarChar, 50), + new SqlColumn("MaxHealth", MySqlDbType.Int32), + new SqlColumn("MaxMana", MySqlDbType.Int32), + new SqlColumn("Inventory", MySqlDbType.Text) + ); + var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator()); + creator.EnsureExists(table); + } + + public PlayerData GetPlayerData(TSPlayer player) + { + PlayerData playerData = new PlayerData(player); + + try + { + using (var reader = database.QueryReader("SELECT * FROM Inventory WHERE AccountName=@0 AND CharacterName=@1", player.UserAccountName, player.Name)) + { + if (reader.Read()) + { + playerData.exists = true; + playerData.maxHealth = reader.Get("MaxHealth"); + playerData.maxMana = reader.Get("MaxMana"); + playerData.inventory = NetItem.Parse(reader.Get("Inventory")); + return playerData; + } + } + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + + return playerData; + } + + public void InsertPlayerData(TSPlayer player) + { + PlayerData playerData = player.PlayerData; + + if (!GetPlayerData(player).exists) + { + try + { + database.Query("INSERT INTO Inventory (AccountName, CharacterName, MaxHealth, MaxMana, Inventory) VALUES (@0, @1, @2, @3, @4);", playerData.accountName, playerData.characterName, playerData.maxHealth, playerData.maxMana, NetItem.ToString(playerData.inventory)); + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + } + else + { + try + { + database.Query("UPDATE Inventory SET MaxHealth = @0, MaxMana = @1, Inventory = @3 WHERE AccountName = @4 AND CharacterName = @5;", playerData.maxHealth, playerData.maxMana, NetItem.ToString(playerData.inventory), playerData.accountName, playerData.characterName); + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + } + } + } +} diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 5cedfaab..73c2e849 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -90,6 +90,7 @@ namespace TShockAPI {PacketTypes.PlayerDamage, HandlePlayerDamage}, {PacketTypes.NpcStrike, HandleNpcStrike}, {PacketTypes.NpcSpecial, HandleSpecial}, + {PacketTypes.PlayerAnimation, HandlePlayerAnimation}, }; } @@ -254,7 +255,7 @@ namespace TShockAPI return true; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendTileSquare(tileX, tileY); return true; @@ -470,7 +471,7 @@ namespace TShockAPI } } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendTileSquare(tileX, tileY); return true; @@ -520,6 +521,12 @@ namespace TShockAPI } args.TPlayer.hostile = pvp; + + if (pvp == true && TShock.Config.AlwaysPvP) + args.Player.IgnoreActionsForPvP = false; + else + args.Player.IgnoreActionsForPvP = true; + NetMessage.SendData((int)PacketTypes.TogglePvp, -1, -1, "", args.Player.Index); return true; @@ -551,9 +558,12 @@ namespace TShockAPI if (!pos.Equals(args.Player.LastNetPosition)) { float distance = Vector2.Distance(new Vector2((pos.X / 16f), (pos.Y / 16f)), new Vector2(Main.spawnTileX, Main.spawnTileY)); - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile && distance > 6f) + if (TShock.CheckIgnores(args.Player) && distance > 6f) { - args.Player.SendMessage("PvP is forced! Enable PvP else you can't do anything!", Color.Red); + if (TShock.Config.AlwaysPvP) + { + args.Player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", Color.Red); + } args.Player.Spawn(); return true; } @@ -599,7 +609,7 @@ namespace TShockAPI return true; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.ProjectileNew, "", index); return true; @@ -640,7 +650,7 @@ namespace TShockAPI return true; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.ProjectileNew, "", index); return true; @@ -696,7 +706,7 @@ namespace TShockAPI if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) return false; - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendTileSquare(tileX, tileY); return true; @@ -751,7 +761,7 @@ namespace TShockAPI if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) return false; - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendTileSquare(tileX, tileY); return true; @@ -808,7 +818,7 @@ namespace TShockAPI var x = args.Data.ReadInt32(); var y = args.Data.ReadInt32(); - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { return true; } @@ -833,7 +843,7 @@ namespace TShockAPI return false; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.ChestItem, "", id, slot); return true; @@ -907,7 +917,7 @@ namespace TShockAPI var type = args.Data.ReadInt8(); var time = args.Data.ReadInt16(); - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.PlayerBuff, "", id); return true; @@ -964,7 +974,7 @@ namespace TShockAPI return true; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.ItemDrop, "", id); return true; @@ -1009,7 +1019,7 @@ namespace TShockAPI return true; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.PlayerHp, "", id); args.Player.SendData(PacketTypes.PlayerUpdate, "", id); @@ -1050,7 +1060,7 @@ namespace TShockAPI return true; } - if (TShock.Config.AlwaysPvP && !args.TPlayer.hostile) + if (TShock.CheckIgnores(args.Player)) { args.Player.SendData(PacketTypes.NpcUpdate, "", id); return true; @@ -1082,6 +1092,30 @@ namespace TShockAPI var id = args.Data.ReadInt8(); var type = args.Data.ReadInt8(); + if (type == 1 && TShock.Config.DisableDungeonGuardian) + { + args.Player.SendMessage("The Dungeon Guardian returned you to your spawn point", Color.Purple); + args.Player.Spawn(); + return true; + } + + return false; + } + + private static bool HandlePlayerAnimation(GetDataHandlerArgs args) + { + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); + return true; + } + return false; } } diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index c2994944..c5ec7a28 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -64,6 +64,9 @@ namespace TShockAPI public string Country = "??"; public int Difficulty; private string CacheIP; + public bool IgnoreActionsForPvP = false; + public bool IgnoreActionsForInventory = false; + public PlayerData PlayerData; public bool RealPlayer { @@ -429,4 +432,52 @@ namespace TShockAPI } } } + + public class PlayerData + { + public NetItem[] inventory = new NetItem[NetItem.maxNetInventory]; + public int maxHealth = 100; + public int maxMana = 100; + public string accountName; + public string characterName; + public bool exists = false; + + public PlayerData(TSPlayer player) + { + this.accountName = player.UserAccountName; + this.characterName = player.Name; + this.inventory[0].netID = -15; + this.inventory[0].stack = 1; + if(player.TPlayer.inventory[0].netID == -15) + this.inventory[0].prefix = player.TPlayer.inventory[0].prefix; + this.inventory[1].netID = -13; + this.inventory[1].stack = 1; + if (player.TPlayer.inventory[1].netID == -13) + this.inventory[1].prefix = player.TPlayer.inventory[1].prefix; + this.inventory[2].netID = -16; + this.inventory[2].stack = 1; + if (player.TPlayer.inventory[2].netID == -16) + this.inventory[2].prefix = player.TPlayer.inventory[2].prefix; + } + } + + public class NetItem + { + public static int maxNetInventory = 59; + public int netID = 0; + public int stack = 0; + public int prefix = 0; + + public static string ToString(NetItem[] inventory) + { + string inventoryString = ""; + return inventoryString; + } + + public static NetItem[] Parse(string data) + { + NetItem[] inventory = new NetItem[NetItem.maxNetInventory]; + return inventory; + } + } } \ No newline at end of file diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index ea14fba6..4af85358 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -62,6 +62,7 @@ namespace TShockAPI public static UserManager Users; public static ItemManager Itembans; public static RemeberedPosManager RememberedPos; + public static InventoryManager Inventory; public static ConfigFile Config { get; set; } public static IDbConnection DB; public static bool OverridePort; @@ -177,6 +178,7 @@ namespace TShockAPI Regions = new RegionManager(DB); Itembans = new ItemManager(DB); RememberedPos = new RemeberedPosManager(DB); + Inventory = new InventoryManager(DB); RestApi = new SecureRest(Netplay.serverListenIP, 8080); RestApi.Verify += RestApi_Verify; RestApi.Port = Config.RestApiPort; @@ -721,10 +723,12 @@ namespace TShockAPI TShock.Utils.HandleCheater(player, "Health/Mana cheat detected. Please use a different character."); } + NetMessage.syncPlayers(); - if (Config.AlwaysPvP) + if (Config.AlwaysPvP && !player.TPlayer.hostile) { + player.IgnoreActionsForPvP = true; player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", Color.Red); } if (player.Group.HasPermission(Permissions.causeevents) && Config.InfiniteInvasion) @@ -999,6 +1003,22 @@ namespace TShockAPI (player.TPlayer.statLife > 400); } + public static bool CheckInventory(TSPlayer player) + { + + return false; + } + + public static bool CheckIgnores(TSPlayer player) + { + bool check = false; + if (player.IgnoreActionsForPvP) + check = true; + if (player.IgnoreActionsForInventory) + check = true; + return check; + } + public static bool CheckPlayerCollision(int x, int y) { if (x + 1 <= Main.maxTilesX && y + 3 <= Main.maxTilesY diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 0fc0d777..3d024668 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -84,6 +84,7 @@ + @@ -180,7 +181,7 @@ - +