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 @@ - +