From 7c47fbb3f2bb6dbddf54cf7e2a19c767031e2b53 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 4 Dec 2017 21:45:25 -0700 Subject: [PATCH 01/74] Move FixChestStacks() to utils --- TShockAPI/TShock.cs | 21 +-------------------- TShockAPI/Utils.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 7c2d1ab8..4d0a8dbd 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -876,7 +876,7 @@ namespace TShockAPI Warps.ReloadWarps(); ComputeMaxStyles(); - FixChestStacks(); + Utils.FixChestStacks(); Utils.UpgradeMotD(); @@ -909,25 +909,6 @@ namespace TShockAPI } } - /// FixChestStacks - Verifies that each stack in each chest is valid and not over the max stack count. - private void FixChestStacks() - { - if (Config.IgnoreChestStacksOnLoad) - return; - - foreach (Chest chest in Main.chest) - { - if (chest != null) - { - foreach (Item item in chest.item) - { - if (item != null && item.stack > item.maxStack) - item.stack = item.maxStack; - } - } - } - } - /// LastCheck - Used to keep track of the last check for basically all time based checks. private DateTime LastCheck = DateTime.UtcNow; diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 5081f8e4..3304acb4 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1427,5 +1427,24 @@ namespace TShockAPI } } } + + /// FixChestStacks - Verifies that each stack in each chest is valid and not over the max stack count. + public void FixChestStacks() + { + if (TShock.Config.IgnoreChestStacksOnLoad) + return; + + foreach (Chest chest in Main.chest) + { + if (chest != null) + { + foreach (Item item in chest.item) + { + if (item != null && item.stack > item.maxStack) + item.stack = item.maxStack; + } + } + } + } } } From 17982bd766791da2bbb1f02d739b6924954fb3b0 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 4 Dec 2017 21:49:56 -0700 Subject: [PATCH 02/74] Move SetConsoleTitle to utils --- TShockAPI/TShock.cs | 16 +++------------- TShockAPI/Utils.cs | 12 +++++++++++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 4d0a8dbd..b3e91a02 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -822,7 +822,7 @@ namespace TShockAPI /// args - The EventArgs object. private void OnPostInit(EventArgs args) { - SetConsoleTitle(false); + Utils.SetConsoleTitle(false); //This is to prevent a bug where a CLI-defined password causes packets to be //sent in an unexpected order, resulting in clients being unable to connect @@ -1179,17 +1179,7 @@ namespace TShockAPI } } } - SetConsoleTitle(false); - } - - /// SetConsoleTitle - Updates the console title with some pertinent information. - /// empty - True/false if the server is empty; determines if we should use Utils.ActivePlayers() for player count or 0. - private void SetConsoleTitle(bool empty) - { - Console.Title = string.Format("{0}{1}/{2} on {3} @ {4}:{5} (TShock for Terraria v{6})", - !string.IsNullOrWhiteSpace(Config.ServerName) ? Config.ServerName + " - " : "", - empty ? 0 : Utils.ActivePlayers(), - Config.MaxSlots, Main.worldName, Netplay.ServerIP.ToString(), Netplay.ListenPort, Version); + Utils.SetConsoleTitle(false); } /// OnHardUpdate - Fired when a hardmode tile update event happens. @@ -1435,7 +1425,7 @@ namespace TShockAPI { if (Config.SaveWorldOnLastPlayerExit) SaveManager.Instance.SaveWorld(); - SetConsoleTitle(true); + Utils.SetConsoleTitle(true); } } diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 3304acb4..eaa62dd3 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1429,7 +1429,7 @@ namespace TShockAPI } /// FixChestStacks - Verifies that each stack in each chest is valid and not over the max stack count. - public void FixChestStacks() + internal void FixChestStacks() { if (TShock.Config.IgnoreChestStacksOnLoad) return; @@ -1446,5 +1446,15 @@ namespace TShockAPI } } } + + /// SetConsoleTitle - Updates the console title with some pertinent information. + /// empty - True/false if the server is empty; determines if we should use Utils.ActivePlayers() for player count or 0. + internal void SetConsoleTitle(bool empty) + { + Console.Title = string.Format("{0}{1}/{2} on {3} @ {4}:{5} (TShock for Terraria v{6})", + !string.IsNullOrWhiteSpace(TShock.Config.ServerName) ? TShock.Config.ServerName + " - " : "", + empty ? 0 : ActivePlayers(), + TShock.Config.MaxSlots, Main.worldName, Netplay.ServerIP.ToString(), Netplay.ListenPort, TShock.VersionNum); + } } } From e85d79e23d2487cd89481e5dec9110016da2329d Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 4 Dec 2017 21:53:46 -0700 Subject: [PATCH 03/74] Move Distance to Utils.Distance --- TShockAPI/TShock.cs | 8 +++----- TShockAPI/Utils.cs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index b3e91a02..4edf40d5 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1978,19 +1978,17 @@ namespace TShockAPI { Vector2 tile = new Vector2(x, y); Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY); - return Distance(spawn, tile) <= Config.SpawnProtectionRadius; + return Utils.Distance(spawn, tile) <= Config.SpawnProtectionRadius; } /// Distance - Determines the distance between two vectors. /// value1 - The first vector location. /// value2 - The second vector location. /// float - The distance between the two vectors. + [Obsolete("Use TShock.Utils.Distance(Vector2, Vector2) instead.", true)] public static float Distance(Vector2 value1, Vector2 value2) { - float num2 = value1.X - value2.X; - float num = value1.Y - value2.Y; - float num3 = (num2 * num2) + (num * num); - return (float)Math.Sqrt(num3); + return Utils.Distance(value1, value2); } /// HackedInventory - Checks to see if a user has a hacked inventory. In addition, messages players the result. diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index eaa62dd3..5175934d 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1456,5 +1456,17 @@ namespace TShockAPI empty ? 0 : ActivePlayers(), TShock.Config.MaxSlots, Main.worldName, Netplay.ServerIP.ToString(), Netplay.ListenPort, TShock.VersionNum); } + + /// Distance - Determines the distance between two vectors. + /// value1 - The first vector location. + /// value2 - The second vector location. + /// float - The distance between the two vectors. + public static float Distance(Vector2 value1, Vector2 value2) + { + float num2 = value1.X - value2.X; + float num = value1.Y - value2.Y; + float num3 = (num2 * num2) + (num * num); + return (float)Math.Sqrt(num3); + } } } From fc233bd3f1abae9b544a0fcbdf3d899fa3c27467 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 4 Dec 2017 21:57:59 -0700 Subject: [PATCH 04/74] Move ComputeMaxStyles to Utils --- TShockAPI/TShock.cs | 22 +--------------------- TShockAPI/Utils.cs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 4edf40d5..27ae3fc2 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -875,7 +875,7 @@ namespace TShockAPI Regions.Reload(); Warps.ReloadWarps(); - ComputeMaxStyles(); + Utils.ComputeMaxStyles(); Utils.FixChestStacks(); Utils.UpgradeMotD(); @@ -889,26 +889,6 @@ namespace TShockAPI StatTracker.Start(); } - /// ComputeMaxStyles - Computes the max styles... - private void ComputeMaxStyles() - { - var item = new Item(); - for (int i = 0; i < Main.maxItemTypes; i++) - { - item.netDefaults(i); - if (item.placeStyle > 0) - { - if (GetDataHandlers.MaxPlaceStyles.ContainsKey(item.createTile)) - { - if (item.placeStyle > GetDataHandlers.MaxPlaceStyles[item.createTile]) - GetDataHandlers.MaxPlaceStyles[item.createTile] = item.placeStyle; - } - else - GetDataHandlers.MaxPlaceStyles.Add(item.createTile, item.placeStyle); - } - } - } - /// LastCheck - Used to keep track of the last check for basically all time based checks. private DateTime LastCheck = DateTime.UtcNow; diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 5175934d..3626775e 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1468,5 +1468,25 @@ namespace TShockAPI float num3 = (num2 * num2) + (num * num); return (float)Math.Sqrt(num3); } + + /// ComputeMaxStyles - Computes the max styles... + internal void ComputeMaxStyles() + { + var item = new Item(); + for (int i = 0; i < Main.maxItemTypes; i++) + { + item.netDefaults(i); + if (item.placeStyle > 0) + { + if (GetDataHandlers.MaxPlaceStyles.ContainsKey(item.createTile)) + { + if (item.placeStyle > GetDataHandlers.MaxPlaceStyles[item.createTile]) + GetDataHandlers.MaxPlaceStyles[item.createTile] = item.placeStyle; + } + else + GetDataHandlers.MaxPlaceStyles.Add(item.createTile, item.placeStyle); + } + } + } } } From e782a07564cff2b54082bf653238bd80cc419872 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Tue, 5 Dec 2017 02:32:33 -0700 Subject: [PATCH 05/74] Move SendTileSquare handling for Bouncer into Bouncer --- TShockAPI/Bouncer.cs | 258 +++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 175 ++---------------------- TShockAPI/TShock.cs | 2 + TShockAPI/TShockAPI.csproj | 1 + 4 files changed, 276 insertions(+), 160 deletions(-) create mode 100644 TShockAPI/Bouncer.cs diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs new file mode 100644 index 00000000..804531eb --- /dev/null +++ b/TShockAPI/Bouncer.cs @@ -0,0 +1,258 @@ +/* +TShock, a server mod for Terraria +Copyright (C) 2011-2017 Nyx Studios (fka. The TShock Team) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +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 Terraria; +using TerrariaApi.Server; +using TShockAPI.Hooks; +using TShockAPI; +using TerrariaApi.Server; +using Terraria.ID; +using Terraria.ObjectData; +using Terraria.DataStructures; +using Terraria.GameContent.Tile_Entities; +using Terraria.Localization; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.IO.Streams; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Terraria.ID; +using TShockAPI.Net; + +namespace TShockAPI +{ + /// Bouncer - The TShock anti-hack and build guardian system + public class Bouncer + { + /// Bouncer - Constructor call initializes Bouncer & related functionality. + /// A new Bouncer. + public Bouncer(TerrariaPlugin pluginInstance) + { + // Setup hooks + + // SendTileSquareEventArgs args = new GetDataHandlers.SendTileSquareEventArgs(); + GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); + } + + public void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args) + { + short size = args.Size; + int tileX = args.TileX; + int tileY = args.TileY; + + if (args.Player.HasPermission(Permissions.allowclientsideworldedit)) + { + args.Handled = false; + return; + } + + if (size > 5) + { + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendTileSquare(tileX, tileY, size); + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY, size); + args.Handled = true; + return; + } + + try + { + var tiles = new NetTile[size, size]; + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + tiles[x, y] = new NetTile(args.Data); + } + } + + bool changed = false; + for (int x = 0; x < size; x++) + { + int realx = tileX + x; + if (realx < 0 || realx >= Main.maxTilesX) + continue; + + for (int y = 0; y < size; y++) + { + int realy = tileY + y; + if (realy < 0 || realy >= Main.maxTilesY) + continue; + + var tile = Main.tile[realx, realy]; + var newtile = tiles[x, y]; + if (TShock.CheckTilePermission(args.Player, realx, realy) || + TShock.CheckRangePermission(args.Player, realx, realy)) + { + continue; + } + + // Fixes the Flower Boots not creating flowers issue + if (size == 1 && args.Player.Accessories.Any(i => i.active && i.netID == ItemID.FlowerBoots)) + { + if (Main.tile[realx, realy + 1].type == TileID.Grass && (newtile.Type == TileID.Plants || newtile.Type == TileID.Plants2)) + { + args.Handled = false; + return; + } + + if (Main.tile[realx, realy + 1].type == TileID.HallowedGrass && (newtile.Type == TileID.HallowedPlants || newtile.Type == TileID.HallowedPlants2)) + { + args.Handled = false; + return; + } + + if (Main.tile[realx, realy + 1].type == TileID.JungleGrass && newtile.Type == TileID.JunglePlants2) + { + args.Handled = false; + return; + } + } + + // Junction Box + if (tile.type == TileID.WirePipe) + { + args.Handled = false; + return; + } + + // Orientable tiles + if (tile.type == newtile.Type && orientableTiles.Contains(tile.type)) + { + Main.tile[realx, realy].frameX = newtile.FrameX; + Main.tile[realx, realy].frameY = newtile.FrameY; + changed = true; + } + // Landmine + if (tile.type == TileID.LandMine && !newtile.Active) + { + Main.tile[realx, realy].active(false); + changed = true; + } + // Sensors + if(newtile.Type == TileID.LogicSensor && !Main.tile[realx, realy].active()) + { + Main.tile[realx, realy].type = newtile.Type; + Main.tile[realx, realy].frameX = newtile.FrameX; + Main.tile[realx, realy].frameY = newtile.FrameY; + Main.tile[realx, realy].active(true); + changed = true; + } + + if (tile.active() && newtile.Active && tile.type != newtile.Type) + { + // Grass <-> Grass + if ((TileID.Sets.Conversion.Grass[tile.type] && TileID.Sets.Conversion.Grass[newtile.Type]) || + // Dirt <-> Dirt + ((tile.type == 0 || tile.type == 59) && + (newtile.Type == 0 || newtile.Type == 59)) || + // Ice <-> Ice + (TileID.Sets.Conversion.Ice[tile.type] && TileID.Sets.Conversion.Ice[newtile.Type]) || + // Stone <-> Stone + ((TileID.Sets.Conversion.Stone[tile.type] || Main.tileMoss[tile.type]) && + (TileID.Sets.Conversion.Stone[newtile.Type] || Main.tileMoss[newtile.Type])) || + // Sand <-> Sand + (TileID.Sets.Conversion.Sand[tile.type] && TileID.Sets.Conversion.Sand[newtile.Type]) || + // Sandstone <-> Sandstone + (TileID.Sets.Conversion.Sandstone[tile.type] && TileID.Sets.Conversion.Sandstone[newtile.Type]) || + // Hardened Sand <-> Hardened Sand + (TileID.Sets.Conversion.HardenedSand[tile.type] && TileID.Sets.Conversion.HardenedSand[newtile.Type])) + { + Main.tile[realx, realy].type = newtile.Type; + changed = true; + } + } + // Stone wall <-> Stone wall + if (((tile.wall == 1 || tile.wall == 3 || tile.wall == 28 || tile.wall == 83) && + (newtile.Wall == 1 || newtile.Wall == 3 || newtile.Wall == 28 || newtile.Wall == 83)) || + // Leaf wall <-> Leaf wall + (((tile.wall >= 63 && tile.wall <= 70) || tile.wall == 81) && + ((newtile.Wall >= 63 && newtile.Wall <= 70) || newtile.Wall == 81))) + { + Main.tile[realx, realy].wall = newtile.Wall; + changed = true; + } + + if ((tile.type == TileID.TrapdoorClosed && (newtile.Type == TileID.TrapdoorOpen || !newtile.Active)) || + (tile.type == TileID.TrapdoorOpen && (newtile.Type == TileID.TrapdoorClosed || !newtile.Active)) || + (!tile.active() && newtile.Active && (newtile.Type == TileID.TrapdoorOpen||newtile.Type == TileID.TrapdoorClosed))) + { + Main.tile[realx, realy].type = newtile.Type; + Main.tile[realx, realy].frameX = newtile.FrameX; + Main.tile[realx, realy].frameY = newtile.FrameY; + Main.tile[realx, realy].active(newtile.Active); + changed = true; + } + } + } + + if (changed) + { + TSPlayer.All.SendTileSquare(tileX, tileY, size + 1); + WorldGen.RangeFrame(tileX, tileY, tileX + size, tileY + size); + } + else + { + args.Player.SendTileSquare(tileX, tileY, size); + } + } + catch + { + args.Player.SendTileSquare(tileX, tileY, size); + } + args.Handled = true; + return; + } + + private static int[] orientableTiles = new int[] + { + TileID.Cannon, + TileID.Chairs, + TileID.Beds, + TileID.Bathtubs, + TileID.Statues, + TileID.Mannequin, + TileID.Traps, + TileID.MusicBoxes, + TileID.ChristmasTree, + TileID.WaterFountain, + TileID.Womannequin, + TileID.MinecartTrack, + TileID.WeaponsRack, + TileID.ItemFrame, + TileID.LunarMonolith, + TileID.TargetDummy, + TileID.Campfire + }; + + } +} \ No newline at end of file diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 2fa9cbd0..e9c7ae8a 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -537,14 +537,22 @@ namespace TShockAPI /// public class SendTileSquareEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } + + /// The raw memory stream from the original event + public MemoryStream Data { get; set; } + /// /// Size of the area /// public short Size { get; set; } + /// /// A corner of the section /// public int TileX { get; set; } + /// /// A corner of the section /// @@ -555,13 +563,15 @@ namespace TShockAPI /// public static HandlerList SendTileSquare; - private static bool OnSendTileSquare(short size, int tilex, int tiley) + private static bool OnSendTileSquare(TSPlayer player, MemoryStream data, short size, int tilex, int tiley) { if (SendTileSquare == null) return false; var args = new SendTileSquareEventArgs { + Player = player, + Data = data, Size = size, TileX = tilex, TileY = tiley, @@ -1726,171 +1736,16 @@ namespace TShockAPI private static bool HandleSendTileSquare(GetDataHandlerArgs args) { + var player = args.Player; var size = args.Data.ReadInt16(); var tileX = args.Data.ReadInt16(); var tileY = args.Data.ReadInt16(); + var data = args.Data; - if (args.Player.HasPermission(Permissions.allowclientsideworldedit)) - return false; - - if (OnSendTileSquare(size, tileX, tileY)) + if (OnSendTileSquare(player, data, size, tileX, tileY)) return true; - if (size > 5) - return true; - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendTileSquare(tileX, tileY, size); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY, size); - return true; - } - - try - { - var tiles = new NetTile[size, size]; - for (int x = 0; x < size; x++) - { - for (int y = 0; y < size; y++) - { - tiles[x, y] = new NetTile(args.Data); - } - } - - bool changed = false; - for (int x = 0; x < size; x++) - { - int realx = tileX + x; - if (realx < 0 || realx >= Main.maxTilesX) - continue; - - for (int y = 0; y < size; y++) - { - int realy = tileY + y; - if (realy < 0 || realy >= Main.maxTilesY) - continue; - - var tile = Main.tile[realx, realy]; - var newtile = tiles[x, y]; - if (TShock.CheckTilePermission(args.Player, realx, realy) || - TShock.CheckRangePermission(args.Player, realx, realy)) - { - continue; - } - - // Fixes the Flower Boots not creating flowers issue - if (size == 1 && args.Player.Accessories.Any(i => i.active && i.netID == ItemID.FlowerBoots)) - { - if (Main.tile[realx, realy + 1].type == TileID.Grass && (newtile.Type == TileID.Plants || newtile.Type == TileID.Plants2)) - { - return false; - } - - if (Main.tile[realx, realy + 1].type == TileID.HallowedGrass && (newtile.Type == TileID.HallowedPlants || newtile.Type == TileID.HallowedPlants2)) - { - return false; - } - - if (Main.tile[realx, realy + 1].type == TileID.JungleGrass && newtile.Type == TileID.JunglePlants2) - { - return false; - } - } - - // Junction Box - if (tile.type == TileID.WirePipe) - return false; - - // Orientable tiles - if (tile.type == newtile.Type && orientableTiles.Contains(tile.type)) - { - Main.tile[realx, realy].frameX = newtile.FrameX; - Main.tile[realx, realy].frameY = newtile.FrameY; - changed = true; - } - // Landmine - if (tile.type == TileID.LandMine && !newtile.Active) - { - Main.tile[realx, realy].active(false); - changed = true; - } - // Sensors - if(newtile.Type == TileID.LogicSensor && !Main.tile[realx, realy].active()) - { - Main.tile[realx, realy].type = newtile.Type; - Main.tile[realx, realy].frameX = newtile.FrameX; - Main.tile[realx, realy].frameY = newtile.FrameY; - Main.tile[realx, realy].active(true); - changed = true; - } - - if (tile.active() && newtile.Active && tile.type != newtile.Type) - { - // Grass <-> Grass - if ((TileID.Sets.Conversion.Grass[tile.type] && TileID.Sets.Conversion.Grass[newtile.Type]) || - // Dirt <-> Dirt - ((tile.type == 0 || tile.type == 59) && - (newtile.Type == 0 || newtile.Type == 59)) || - // Ice <-> Ice - (TileID.Sets.Conversion.Ice[tile.type] && TileID.Sets.Conversion.Ice[newtile.Type]) || - // Stone <-> Stone - ((TileID.Sets.Conversion.Stone[tile.type] || Main.tileMoss[tile.type]) && - (TileID.Sets.Conversion.Stone[newtile.Type] || Main.tileMoss[newtile.Type])) || - // Sand <-> Sand - (TileID.Sets.Conversion.Sand[tile.type] && TileID.Sets.Conversion.Sand[newtile.Type]) || - // Sandstone <-> Sandstone - (TileID.Sets.Conversion.Sandstone[tile.type] && TileID.Sets.Conversion.Sandstone[newtile.Type]) || - // Hardened Sand <-> Hardened Sand - (TileID.Sets.Conversion.HardenedSand[tile.type] && TileID.Sets.Conversion.HardenedSand[newtile.Type])) - { - Main.tile[realx, realy].type = newtile.Type; - changed = true; - } - } - // Stone wall <-> Stone wall - if (((tile.wall == 1 || tile.wall == 3 || tile.wall == 28 || tile.wall == 83) && - (newtile.Wall == 1 || newtile.Wall == 3 || newtile.Wall == 28 || newtile.Wall == 83)) || - // Leaf wall <-> Leaf wall - (((tile.wall >= 63 && tile.wall <= 70) || tile.wall == 81) && - ((newtile.Wall >= 63 && newtile.Wall <= 70) || newtile.Wall == 81))) - { - Main.tile[realx, realy].wall = newtile.Wall; - changed = true; - } - - if ((tile.type == TileID.TrapdoorClosed && (newtile.Type == TileID.TrapdoorOpen || !newtile.Active)) || - (tile.type == TileID.TrapdoorOpen && (newtile.Type == TileID.TrapdoorClosed || !newtile.Active)) || - (!tile.active() && newtile.Active && (newtile.Type == TileID.TrapdoorOpen||newtile.Type == TileID.TrapdoorClosed))) - { - Main.tile[realx, realy].type = newtile.Type; - Main.tile[realx, realy].frameX = newtile.FrameX; - Main.tile[realx, realy].frameY = newtile.FrameY; - Main.tile[realx, realy].active(newtile.Active); - changed = true; - } - } - } - - if (changed) - { - TSPlayer.All.SendTileSquare(tileX, tileY, size + 1); - WorldGen.RangeFrame(tileX, tileY, tileX + size, tileY + size); - } - else - { - args.Player.SendTileSquare(tileX, tileY, size); - } - } - catch - { - args.Player.SendTileSquare(tileX, tileY, size); - } - return true; + return false; } public enum EditAction diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 27ae3fc2..01a7fd8a 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -378,6 +378,8 @@ namespace TShockAPI Log.ConsoleInfo("Welcome to TShock for Terraria!"); Log.ConsoleInfo("TShock comes with no warranty & is free software."); Log.ConsoleInfo("You can modify & distribute it under the terms of the GNU GPLv3."); + + Bouncer b = new Bouncer(this); } catch (Exception ex) { diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 08e9323d..e61ed3cb 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -134,6 +134,7 @@ + True True From 758e403b6656469261abb432929388280d89e9c2 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Tue, 5 Dec 2017 02:34:08 -0700 Subject: [PATCH 06/74] Mark Bouncer's OnSendTileSquare as internal --- TShockAPI/Bouncer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 804531eb..41a5f65a 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -52,7 +52,10 @@ namespace TShockAPI GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); } - public void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args) + /// OnSendTileSquare - The handler for SendTileSquare events in Bouncer + /// sender + /// args + internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args) { short size = args.Size; int tileX = args.TileX; From db7ae627ae9490292b9086295df1e4a5effdafd4 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Tue, 5 Dec 2017 02:35:04 -0700 Subject: [PATCH 07/74] Move orientable tiles into Bouncer --- TShockAPI/Bouncer.cs | 19 +++++++++++++++++ TShockAPI/GetDataHandlers.cs | 40 ------------------------------------ 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 41a5f65a..309712c9 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -236,6 +236,25 @@ namespace TShockAPI return; } + /// + /// Tile IDs that can be oriented: + /// Cannon, + /// Chairs, + /// Beds, + /// Bathtubs, + /// Statues, + /// Mannequin, + /// Traps, + /// MusicBoxes, + /// ChristmasTree, + /// WaterFountain, + /// Womannequin, + /// MinecartTrack, + /// WeaponsRack, + /// LunarMonolith, + /// TargetDummy, + /// Campfire + /// private static int[] orientableTiles = new int[] { TileID.Cannon, diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index e9c7ae8a..40eec2c5 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1694,46 +1694,6 @@ namespace TShockAPI return false; } - /// - /// Tile IDs that can be oriented: - /// Cannon, - /// Chairs, - /// Beds, - /// Bathtubs, - /// Statues, - /// Mannequin, - /// Traps, - /// MusicBoxes, - /// ChristmasTree, - /// WaterFountain, - /// Womannequin, - /// MinecartTrack, - /// WeaponsRack, - /// LunarMonolith, - /// TargetDummy, - /// Campfire - /// - private static int[] orientableTiles = new int[] - { - TileID.Cannon, - TileID.Chairs, - TileID.Beds, - TileID.Bathtubs, - TileID.Statues, - TileID.Mannequin, - TileID.Traps, - TileID.MusicBoxes, - TileID.ChristmasTree, - TileID.WaterFountain, - TileID.Womannequin, - TileID.MinecartTrack, - TileID.WeaponsRack, - TileID.ItemFrame, - TileID.LunarMonolith, - TileID.TargetDummy, - TileID.Campfire - }; - private static bool HandleSendTileSquare(GetDataHandlerArgs args) { var player = args.Player; From 0d2d50b3de208672b04134c18d51892720c73a0f Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Tue, 5 Dec 2017 02:35:30 -0700 Subject: [PATCH 08/74] Don't leave comments in code --- TShockAPI/Bouncer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 309712c9..27715e81 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -48,7 +48,6 @@ namespace TShockAPI { // Setup hooks - // SendTileSquareEventArgs args = new GetDataHandlers.SendTileSquareEventArgs(); GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); } From f065e99a0ea4569b863f0d05a700b5a2531861c1 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Tue, 5 Dec 2017 11:59:27 -0700 Subject: [PATCH 09/74] Add HealOtherPlayer hook; integrate with Bouncer --- TShockAPI/Bouncer.cs | 40 ++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 59 +++++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 21 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 27715e81..d76d488f 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -49,6 +49,46 @@ namespace TShockAPI // Setup hooks GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); + GetDataHandlers.HealOtherPlayer.Register(OnHealOtherPlayer); + } + + /// OnHealOtherPlayer - The handler for the HealOther events in Bouncer + /// sender + /// args + internal void OnHealOtherPlayer(object sender, GetDataHandlers.HealOtherPlayerEventArgs args) + { + short amount = args.Amount; + byte plr = args.TargetPlayerIndex; + + if (amount <= 0 || Main.player[plr] == null || !Main.player[plr].active) + { + args.Handled = true; + return; + } + + if (amount > TShock.Config.MaxDamage * 0.2) + { + args.Player.Disable("HealOtherPlayer cheat attempt!", DisableFlags.WriteToLogAndConsole); + args.Handled = true; + return; + } + + if (args.Player.HealOtherThreshold > TShock.Config.HealOtherThreshold) + { + args.Player.Disable("Reached HealOtherPlayer threshold.", DisableFlags.WriteToLogAndConsole); + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player) || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Handled = true; + return; + } + + args.Player.HealOtherThreshold++; + args.Handled = false; + return; } /// OnSendTileSquare - The handler for SendTileSquare events in Bouncer diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 40eec2c5..153bd7a1 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -532,6 +532,43 @@ namespace TShockAPI return false; } + /// HandledEventArgs - The event args object for the HealOtherPlayer event + public class HealOtherPlayerEventArgs : HandledEventArgs + { + /// Player - The TSPlayer object that caused the event + public TSPlayer Player { get; set; } + + /// TargetPlayerIndex - The Terraria player index of the target player + public byte TargetPlayerIndex { get; set; } + + /// Amount - The amount to heal by + public short Amount { get; set; } + } + + /// HealOtherPlayer - When a player heals another player + public static HandlerList HealOtherPlayer; + + /// OnHealOtherPlayer - Fires the HealOtherPlayer event + /// player - The TSPlayer that started the event + /// targetPlayerIndex - The Terraria player index that the event targets + /// amount - The amount to heal + /// bool + private static bool OnHealOtherPlayer(TSPlayer player, byte targetPlayerIndex, short amount) + { + if (HealOtherPlayer == null) + return false; + + var args = new HealOtherPlayerEventArgs + { + Player = player, + TargetPlayerIndex = targetPlayerIndex, + Amount = amount, + }; + + HealOtherPlayer.Invoke(null, args); + return args.Handled; + } + /// /// For use in a SendTileSquare event /// @@ -1312,29 +1349,9 @@ namespace TShockAPI byte plr = args.Data.ReadInt8(); short amount = args.Data.ReadInt16(); - if (amount <= 0 || Main.player[plr] == null || !Main.player[plr].active) - { + if (OnHealOtherPlayer(args.Player, plr, amount)) return true; - } - if (amount > TShock.Config.MaxDamage * 0.2) - { - args.Player.Disable("HealOtherPlayer cheat attempt!", DisableFlags.WriteToLogAndConsole); - return true; - } - - if (args.Player.HealOtherThreshold > TShock.Config.HealOtherThreshold) - { - args.Player.Disable("Reached HealOtherPlayer threshold.", DisableFlags.WriteToLogAndConsole); - return true; - } - - if (TShock.CheckIgnores(args.Player) || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - return true; - } - - args.Player.HealOtherThreshold++; return false; } From 9ba0907dc0bcbe38c1a9008095511481d77d62b3 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 17:02:23 -0700 Subject: [PATCH 10/74] Fix most of the stupid comments in Bouncer --- TShockAPI/Bouncer.cs | 8 ++++---- TShockAPI/GetDataHandlers.cs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index d76d488f..69455328 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -39,10 +39,10 @@ using TShockAPI.Net; namespace TShockAPI { - /// Bouncer - The TShock anti-hack and build guardian system + /// Bouncer is the TShock anti-hack and build guardian system public class Bouncer { - /// Bouncer - Constructor call initializes Bouncer & related functionality. + /// Constructor call initializes Bouncer & related functionality. /// A new Bouncer. public Bouncer(TerrariaPlugin pluginInstance) { @@ -52,7 +52,7 @@ namespace TShockAPI GetDataHandlers.HealOtherPlayer.Register(OnHealOtherPlayer); } - /// OnHealOtherPlayer - The handler for the HealOther events in Bouncer + /// The handler for the HealOther events in Bouncer /// sender /// args internal void OnHealOtherPlayer(object sender, GetDataHandlers.HealOtherPlayerEventArgs args) @@ -91,7 +91,7 @@ namespace TShockAPI return; } - /// OnSendTileSquare - The handler for SendTileSquare events in Bouncer + /// The handler for SendTileSquare events in Bouncer /// sender /// args internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 153bd7a1..9cae47e6 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -532,26 +532,26 @@ namespace TShockAPI return false; } - /// HandledEventArgs - The event args object for the HealOtherPlayer event + /// The event args object for the HealOtherPlayer event public class HealOtherPlayerEventArgs : HandledEventArgs { - /// Player - The TSPlayer object that caused the event + /// The TSPlayer object that caused the event public TSPlayer Player { get; set; } - /// TargetPlayerIndex - The Terraria player index of the target player + /// The Terraria player index of the target player public byte TargetPlayerIndex { get; set; } - /// Amount - The amount to heal by + /// The amount to heal by public short Amount { get; set; } } - /// HealOtherPlayer - When a player heals another player + /// When a player heals another player public static HandlerList HealOtherPlayer; - /// OnHealOtherPlayer - Fires the HealOtherPlayer event - /// player - The TSPlayer that started the event - /// targetPlayerIndex - The Terraria player index that the event targets - /// amount - The amount to heal + /// Fires the HealOtherPlayer event + /// The TSPlayer that started the event + /// The Terraria player index that the event targets + /// The amount to heal /// bool private static bool OnHealOtherPlayer(TSPlayer player, byte targetPlayerIndex, short amount) { @@ -596,7 +596,7 @@ namespace TShockAPI public int TileY { get; set; } } /// - /// SendTileSquare - When the player sends a tile square + /// When the player sends a tile square /// public static HandlerList SendTileSquare; From 1d5a013adb392a8b7910e1ed4bcb341a942d7cae Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 17:05:29 -0700 Subject: [PATCH 11/74] Seal the Bouncer inside his house --- TShockAPI/Bouncer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 69455328..c04682fe 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -40,11 +40,11 @@ using TShockAPI.Net; namespace TShockAPI { /// Bouncer is the TShock anti-hack and build guardian system - public class Bouncer + internal sealed class Bouncer { /// Constructor call initializes Bouncer & related functionality. /// A new Bouncer. - public Bouncer(TerrariaPlugin pluginInstance) + internal Bouncer(TerrariaPlugin pluginInstance) { // Setup hooks From 5abf0f9d8e279898a36673547fcbf9620eff356d Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 17:07:05 -0700 Subject: [PATCH 12/74] Comment magic number 5 --- TShockAPI/Bouncer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index c04682fe..96b5abb9 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -106,6 +106,8 @@ namespace TShockAPI return; } + // From White: + // IIRC it's because 5 means a 5x5 square which is normal for a tile square, and anything bigger is a non-vanilla tile modification attempt if (size > 5) { args.Handled = true; From 349770e6edf432d191853d8dd5f1483f10f3ab5e Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 17:10:05 -0700 Subject: [PATCH 13/74] Remove more silly comment style problems --- TShockAPI/Utils.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 3626775e..dcd142ea 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1428,7 +1428,7 @@ namespace TShockAPI } } - /// FixChestStacks - Verifies that each stack in each chest is valid and not over the max stack count. + /// Verifies that each stack in each chest is valid and not over the max stack count. internal void FixChestStacks() { if (TShock.Config.IgnoreChestStacksOnLoad) @@ -1447,8 +1447,8 @@ namespace TShockAPI } } - /// SetConsoleTitle - Updates the console title with some pertinent information. - /// empty - True/false if the server is empty; determines if we should use Utils.ActivePlayers() for player count or 0. + /// Updates the console title with some pertinent information. + /// If the server is empty; determines if we should use Utils.ActivePlayers() for player count or 0. internal void SetConsoleTitle(bool empty) { Console.Title = string.Format("{0}{1}/{2} on {3} @ {4}:{5} (TShock for Terraria v{6})", @@ -1457,10 +1457,10 @@ namespace TShockAPI TShock.Config.MaxSlots, Main.worldName, Netplay.ServerIP.ToString(), Netplay.ListenPort, TShock.VersionNum); } - /// Distance - Determines the distance between two vectors. - /// value1 - The first vector location. - /// value2 - The second vector location. - /// float - The distance between the two vectors. + /// Determines the distance between two vectors. + /// The first vector location. + /// The second vector location. + /// The distance between the two vectors. public static float Distance(Vector2 value1, Vector2 value2) { float num2 = value1.X - value2.X; @@ -1469,7 +1469,7 @@ namespace TShockAPI return (float)Math.Sqrt(num3); } - /// ComputeMaxStyles - Computes the max styles... + /// Computes the max styles... internal void ComputeMaxStyles() { var item = new Item(); From a4d9f0295a0858459c6ea6e5aab32ca3a7812d46 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 22:16:19 -0700 Subject: [PATCH 14/74] Move OnTileEdit stuff to Bouncer There are probably a few components in here that don't make sense for bouncer (looking at you, regions code). However, it's on my todo list rather than being an imminent thing. --- TShockAPI/Bouncer.cs | 378 ++++++++++++++++++++++++++++++++++- TShockAPI/GetDataHandlers.cs | 340 ++----------------------------- 2 files changed, 382 insertions(+), 336 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 96b5abb9..4a9e766a 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -15,16 +15,6 @@ 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 Terraria; -using TerrariaApi.Server; -using TShockAPI.Hooks; -using TShockAPI; -using TerrariaApi.Server; -using Terraria.ID; -using Terraria.ObjectData; -using Terraria.DataStructures; -using Terraria.GameContent.Tile_Entities; -using Terraria.Localization; using System; using System.Collections.Generic; using System.ComponentModel; @@ -35,7 +25,19 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Terraria.ID; +using TShockAPI.DB; using TShockAPI.Net; +using Terraria; +using Terraria.ObjectData; +using Terraria.DataStructures; +using Terraria.GameContent.Tile_Entities; +using Terraria.Localization; +using Microsoft.Xna.Framework; +using OTAPI.Tile; +using TShockAPI.Localization; +using static TShockAPI.GetDataHandlers; +using TerrariaApi.Server; + namespace TShockAPI { @@ -50,6 +52,360 @@ namespace TShockAPI GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); GetDataHandlers.HealOtherPlayer.Register(OnHealOtherPlayer); + GetDataHandlers.TileEdit.Register(OnTileEdit); + } + + internal void OnTileEdit(object sender, GetDataHandlers.TileEditEventArgs args) + { + EditAction action = args.Action; + int tileX = args.X; + int tileY = args.Y; + short editData = args.EditData; + EditType type = args.editDetail; + byte style = args.Style; + + try + { + if (editData < 0) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if (!TShock.Utils.TilePlacementValid(tileX, tileY)) + args.Handled = true; + return; + if (action == EditAction.KillTile && Main.tile[tileX, tileY].type == TileID.MagicalIceBlock) + args.Handled = false; + return; + if (args.Player.Dead && TShock.Config.PreventDeadModification) + args.Handled = true; + return; + + if (args.Player.AwaitingName) + { + bool includeUnprotected = false; + bool includeZIndexes = false; + bool persistentMode = false; + foreach (string parameter in args.Player.AwaitingNameParameters) + { + if (parameter.Equals("-u", StringComparison.InvariantCultureIgnoreCase)) + includeUnprotected = true; + if (parameter.Equals("-z", StringComparison.InvariantCultureIgnoreCase)) + includeZIndexes = true; + if (parameter.Equals("-p", StringComparison.InvariantCultureIgnoreCase)) + persistentMode = true; + } + + List outputRegions = new List(); + foreach (Region region in TShock.Regions.Regions.OrderBy(r => r.Z).Reverse()) + { + if (!includeUnprotected && !region.DisableBuild) + continue; + if (tileX < region.Area.Left || tileX > region.Area.Right) + continue; + if (tileY < region.Area.Top || tileY > region.Area.Bottom) + continue; + + string format = "{1}"; + if (includeZIndexes) + format = "{1} (z:{0})"; + + outputRegions.Add(string.Format(format, region.Z, region.Name)); + } + + if (outputRegions.Count == 0) + { + if (includeUnprotected) + args.Player.SendInfoMessage("There are no regions at this point."); + else + args.Player.SendInfoMessage("There are no regions at this point or they are not protected."); + } + else + { + if (includeUnprotected) + args.Player.SendSuccessMessage("Regions at this point:"); + else + args.Player.SendSuccessMessage("Protected regions at this point:"); + + foreach (string line in PaginationTools.BuildLinesFromTerms(outputRegions)) + args.Player.SendMessage(line, Color.White); + } + + if (!persistentMode) + { + args.Player.AwaitingName = false; + args.Player.AwaitingNameParameters = null; + } + + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if (args.Player.AwaitingTempPoint > 0) + { + args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].X = tileX; + args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].Y = tileY; + args.Player.SendInfoMessage("Set temp point {0}.", args.Player.AwaitingTempPoint); + args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.AwaitingTempPoint = 0; + args.Handled = true; + return; + } + + Item selectedItem = args.Player.SelectedItem; + int lastKilledProj = args.Player.LastKilledProjectile; + ITile tile = Main.tile[tileX, tileY]; + + if (action == EditAction.PlaceTile) + { + if (TShock.TileBans.TileIsBanned(editData, args.Player)) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendErrorMessage("You do not have permission to place this tile."); + args.Handled = true; + return; + } + } + + if (action == EditAction.KillTile && !Main.tileCut[tile.type] && !breakableTiles.Contains(tile.type)) + { + //TPlayer.mount.Type 8 => Drill Containment Unit. + + // If the tile is an axe tile and they aren't selecting an axe, they're hacking. + if (Main.tileAxe[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.axe == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + // If the tile is a hammer tile and they aren't selecting a hammer, they're hacking. + else if (Main.tileHammer[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.hammer == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + // If the tile is a pickaxe tile and they aren't selecting a pickaxe, they're hacking. + // Item frames can be modified without pickaxe tile. + else if (tile.type != TileID.ItemFrame + && !Main.tileAxe[tile.type] && !Main.tileHammer[tile.type] && tile.wall == 0 && args.Player.TPlayer.mount.Type != 8 && selectedItem.pick == 0 && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + } + else if (action == EditAction.KillWall) + { + // If they aren't selecting a hammer, they could be hacking. + if (selectedItem.hammer == 0 && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0 && selectedItem.createWall == 0) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } + else if (action == EditAction.PlaceTile && (projectileCreatesTile.ContainsKey(lastKilledProj) && editData == projectileCreatesTile[lastKilledProj])) + { + args.Player.LastKilledProjectile = 0; + } + else if (action == EditAction.PlaceTile || action == EditAction.PlaceWall) + { + if ((action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle) && + (MaxPlaceStyles.ContainsKey(editData) && style > MaxPlaceStyles[editData]) && + (ExtraneousPlaceStyles.ContainsKey(editData) && style > ExtraneousPlaceStyles[editData])) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + // If they aren't selecting the item which creates the tile or wall, they're hacking. + if (!(selectedItem.netID == ItemID.IceRod && editData == TileID.MagicalIceBlock) && + (editData != (action == EditAction.PlaceTile ? selectedItem.createTile : selectedItem.createWall) && + !(ropeCoilPlacements.ContainsKey(selectedItem.netID) && editData == ropeCoilPlacements[selectedItem.netID]))) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + // Using the actuation accessory can lead to actuator hacking + if (TShock.Itembans.ItemIsBanned("Actuator", args.Player) && args.Player.TPlayer.autoActuator) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendErrorMessage("You do not have permission to place actuators."); + args.Handled = true; + return; + } + if (TShock.Itembans.ItemIsBanned(EnglishLanguage.GetItemNameById(selectedItem.netID), args.Player) || editData >= (action == EditAction.PlaceTile ? Main.maxTileSets : Main.maxWallTypes)) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + if (action == EditAction.PlaceTile && (editData == 29 || editData == 97) && Main.ServerSideCharacter) + { + args.Player.SendErrorMessage("You cannot place this tile because server side characters are enabled."); + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + if (action == EditAction.PlaceTile && (editData == TileID.Containers || editData == TileID.Containers2)) + { + if (TShock.Utils.MaxChests()) + { + args.Player.SendErrorMessage("The world's chest limit has been reached - unable to place more."); + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + if ((TShock.Utils.TilePlacementValid(tileX, tileY + 1) && Main.tile[tileX, tileY + 1].type == TileID.Boulder) || + (TShock.Utils.TilePlacementValid(tileX + 1, tileY + 1) && Main.tile[tileX + 1, tileY + 1].type == TileID.Boulder)) + { + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + } + } + else if (action == EditAction.PlaceWire || action == EditAction.PlaceWire2 || action == EditAction.PlaceWire3) + { + // If they aren't selecting a wrench, they're hacking. + // WireKite = The Grand Design + if (selectedItem.type != ItemID.Wrench + && selectedItem.type != ItemID.BlueWrench + && selectedItem.type != ItemID.GreenWrench + && selectedItem.type != ItemID.YellowWrench + && selectedItem.type != ItemID.MulticolorWrench + && selectedItem.type != ItemID.WireKite) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } + else if (action == EditAction.KillActuator || action == EditAction.KillWire || + action == EditAction.KillWire2 || action == EditAction.KillWire3) + { + // If they aren't selecting the wire cutter, they're hacking. + if (selectedItem.type != ItemID.WireCutter + && selectedItem.type != ItemID.WireKite + && selectedItem.type != ItemID.MulticolorWrench) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } + else if (action == EditAction.PlaceActuator) + { + // If they aren't selecting the actuator and don't have the Presserator equipped, they're hacking. + if (selectedItem.type != ItemID.Actuator && !args.Player.TPlayer.autoActuator) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } + if (TShock.Config.AllowCutTilesAndBreakables && Main.tileCut[tile.type]) + { + if (action == EditAction.KillWall) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + args.Handled = false; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if (TShock.CheckTilePermission(args.Player, tileX, tileY, editData, action)) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, tileX, tileY)) + { + if (action == EditAction.PlaceTile && (editData == TileID.Rope || editData == TileID.SilkRope || editData == TileID.VineRope || editData == TileID.WebRope)) + { + args.Handled = false; + return; + } + + if (action == EditAction.KillTile || action == EditAction.KillWall && ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0) + { + args.Handled = false; + return; + } + + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if (args.Player.TileKillThreshold >= TShock.Config.TileKillThreshold) + { + args.Player.Disable("Reached TileKill threshold.", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if (args.Player.TilePlaceThreshold >= TShock.Config.TilePlaceThreshold) + { + args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } + + if ((action == EditAction.PlaceTile || action == EditAction.PlaceWall) && !args.Player.HasPermission(Permissions.ignoreplacetiledetection)) + { + args.Player.TilePlaceThreshold++; + var coords = new Vector2(tileX, tileY); + lock (args.Player.TilesCreated) + if (!args.Player.TilesCreated.ContainsKey(coords)) + args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY]); + } + + if ((action == EditAction.KillTile || action == EditAction.KillTileNoItem || action == EditAction.KillWall) && Main.tileSolid[Main.tile[tileX, tileY].type] && + !args.Player.HasPermission(Permissions.ignorekilltiledetection)) + { + args.Player.TileKillThreshold++; + var coords = new Vector2(tileX, tileY); + lock (args.Player.TilesDestroyed) + if (!args.Player.TilesDestroyed.ContainsKey(coords)) + args.Player.TilesDestroyed.Add(coords, Main.tile[tileX, tileY]); + } + args.Handled = false; + return; + } + catch + { + args.Player.SendTileSquare(tileX, tileY, 4); + args.Handled = true; + return; + } } /// The handler for the HealOther events in Bouncer @@ -273,7 +629,7 @@ namespace TShockAPI { args.Player.SendTileSquare(tileX, tileY, size); } - args.Handled = true; + args.Handled = false; return; } diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 9cae47e6..7fbfd560 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1756,7 +1756,7 @@ namespace TShockAPI /// /// Tiles that can be broken without any pickaxes/etc. /// - private static int[] breakableTiles = new int[] + internal static int[] breakableTiles = new int[] { TileID.Books, TileID.Bottles, @@ -1780,7 +1780,7 @@ namespace TShockAPI /// /// These projectiles create tiles on death. /// - private static Dictionary projectileCreatesTile = new Dictionary + internal static Dictionary projectileCreatesTile = new Dictionary { { ProjectileID.DirtBall, TileID.Dirt }, { ProjectileID.SandBallGun, TileID.Sand }, @@ -1789,7 +1789,7 @@ namespace TShockAPI { ProjectileID.CrimsandBallGun, TileID.Crimsand }, }; - private static Dictionary ropeCoilPlacements = new Dictionary + internal static Dictionary ropeCoilPlacements = new Dictionary { {ItemID.RopeCoil, TileID.Rope}, {ItemID.SilkRopeCoil, TileID.SilkRope}, @@ -1800,7 +1800,7 @@ namespace TShockAPI /// /// Extra place style limits for strange hardcoded values in Terraria /// - private static Dictionary ExtraneousPlaceStyles = new Dictionary + internal static Dictionary ExtraneousPlaceStyles = new Dictionary { {TileID.MinecartTrack, 3} }; @@ -1810,330 +1810,20 @@ namespace TShockAPI EditAction action = (EditAction)args.Data.ReadInt8(); var tileX = args.Data.ReadInt16(); var tileY = args.Data.ReadInt16(); + var editData = args.Data.ReadInt16(); + EditType type = (action == EditAction.KillTile || action == EditAction.KillWall || + action == EditAction.KillTileNoItem) + ? EditType.Fail + : (action == EditAction.PlaceTile || action == EditAction.PlaceWall) + ? EditType.Type + : EditType.Slope; - try - { - var editData = args.Data.ReadInt16(); - EditType type = (action == EditAction.KillTile || action == EditAction.KillWall || - action == EditAction.KillTileNoItem) - ? EditType.Fail - : (action == EditAction.PlaceTile || action == EditAction.PlaceWall) - ? EditType.Type - : EditType.Slope; + var style = args.Data.ReadInt8(); - var style = args.Data.ReadInt8(); - - if (editData < 0) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if (OnTileEdit(args.Player, tileX, tileY, action, type, editData, style)) - return true; - if (!TShock.Utils.TilePlacementValid(tileX, tileY)) - return true; - if (action == EditAction.KillTile && Main.tile[tileX, tileY].type == TileID.MagicalIceBlock) - return false; - if (args.Player.Dead && TShock.Config.PreventDeadModification) - return true; - - if (args.Player.AwaitingName) - { - Debug.Assert(args.Player.AwaitingNameParameters != null); - - bool includeUnprotected = false; - bool includeZIndexes = false; - bool persistentMode = false; - foreach (string parameter in args.Player.AwaitingNameParameters) - { - if (parameter.Equals("-u", StringComparison.InvariantCultureIgnoreCase)) - includeUnprotected = true; - if (parameter.Equals("-z", StringComparison.InvariantCultureIgnoreCase)) - includeZIndexes = true; - if (parameter.Equals("-p", StringComparison.InvariantCultureIgnoreCase)) - persistentMode = true; - } - - List outputRegions = new List(); - foreach (Region region in TShock.Regions.Regions.OrderBy(r => r.Z).Reverse()) - { - if (!includeUnprotected && !region.DisableBuild) - continue; - if (tileX < region.Area.Left || tileX > region.Area.Right) - continue; - if (tileY < region.Area.Top || tileY > region.Area.Bottom) - continue; - - string format = "{1}"; - if (includeZIndexes) - format = "{1} (z:{0})"; - - outputRegions.Add(string.Format(format, region.Z, region.Name)); - } - - if (outputRegions.Count == 0) - { - if (includeUnprotected) - args.Player.SendInfoMessage("There are no regions at this point."); - else - args.Player.SendInfoMessage("There are no regions at this point or they are not protected."); - } - else - { - if (includeUnprotected) - args.Player.SendSuccessMessage("Regions at this point:"); - else - args.Player.SendSuccessMessage("Protected regions at this point:"); - - foreach (string line in PaginationTools.BuildLinesFromTerms(outputRegions)) - args.Player.SendMessage(line, Color.White); - } - - if (!persistentMode) - { - args.Player.AwaitingName = false; - args.Player.AwaitingNameParameters = null; - } - - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if (args.Player.AwaitingTempPoint > 0) - { - args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].X = tileX; - args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].Y = tileY; - args.Player.SendInfoMessage("Set temp point {0}.", args.Player.AwaitingTempPoint); - args.Player.SendTileSquare(tileX, tileY, 4); - args.Player.AwaitingTempPoint = 0; - return true; - } - - Item selectedItem = args.Player.SelectedItem; - int lastKilledProj = args.Player.LastKilledProjectile; - ITile tile = Main.tile[tileX, tileY]; - - if (action == EditAction.PlaceTile) - { - if (TShock.TileBans.TileIsBanned(editData, args.Player)) - { - args.Player.SendTileSquare(tileX, tileY, 1); - args.Player.SendErrorMessage("You do not have permission to place this tile."); - return true; - } - } - - if (action == EditAction.KillTile && !Main.tileCut[tile.type] && !breakableTiles.Contains(tile.type)) - { - //TPlayer.mount.Type 8 => Drill Containment Unit. - - // If the tile is an axe tile and they aren't selecting an axe, they're hacking. - if (Main.tileAxe[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.axe == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - // If the tile is a hammer tile and they aren't selecting a hammer, they're hacking. - else if (Main.tileHammer[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.hammer == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - // If the tile is a pickaxe tile and they aren't selecting a pickaxe, they're hacking. - // Item frames can be modified without pickaxe tile. - else if (tile.type != TileID.ItemFrame - && !Main.tileAxe[tile.type] && !Main.tileHammer[tile.type] && tile.wall == 0 && args.TPlayer.mount.Type != 8 && selectedItem.pick == 0 && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - } - else if (action == EditAction.KillWall) - { - // If they aren't selecting a hammer, they could be hacking. - if (selectedItem.hammer == 0 && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0 && selectedItem.createWall == 0) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - } - else if (action == EditAction.PlaceTile && (projectileCreatesTile.ContainsKey(lastKilledProj) && editData == projectileCreatesTile[lastKilledProj])) - { - args.Player.LastKilledProjectile = 0; - } - else if (action == EditAction.PlaceTile || action == EditAction.PlaceWall) - { - if ((action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle) && - (MaxPlaceStyles.ContainsKey(editData) && style > MaxPlaceStyles[editData]) && - (ExtraneousPlaceStyles.ContainsKey(editData) && style > ExtraneousPlaceStyles[editData])) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - // If they aren't selecting the item which creates the tile or wall, they're hacking. - if (!(selectedItem.netID == ItemID.IceRod && editData == TileID.MagicalIceBlock) && - (editData != (action == EditAction.PlaceTile ? selectedItem.createTile : selectedItem.createWall) && - !(ropeCoilPlacements.ContainsKey(selectedItem.netID) && editData == ropeCoilPlacements[selectedItem.netID]))) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - // Using the actuation accessory can lead to actuator hacking - if (TShock.Itembans.ItemIsBanned("Actuator", args.Player) && args.Player.TPlayer.autoActuator) - { - args.Player.SendTileSquare(tileX, tileY, 1); - args.Player.SendErrorMessage("You do not have permission to place actuators."); - return true; - } - if (TShock.Itembans.ItemIsBanned(EnglishLanguage.GetItemNameById(selectedItem.netID), args.Player) || editData >= (action == EditAction.PlaceTile ? Main.maxTileSets : Main.maxWallTypes)) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - if (action == EditAction.PlaceTile && (editData == 29 || editData == 97) && Main.ServerSideCharacter) - { - args.Player.SendErrorMessage("You cannot place this tile because server side characters are enabled."); - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - if (action == EditAction.PlaceTile && (editData == TileID.Containers || editData == TileID.Containers2)) - { - if (TShock.Utils.MaxChests()) - { - args.Player.SendErrorMessage("The world's chest limit has been reached - unable to place more."); - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - if ((TShock.Utils.TilePlacementValid(tileX, tileY + 1) && Main.tile[tileX, tileY + 1].type == TileID.Boulder) || - (TShock.Utils.TilePlacementValid(tileX + 1, tileY + 1) && Main.tile[tileX + 1, tileY + 1].type == TileID.Boulder)) - { - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - } - } - else if (action == EditAction.PlaceWire || action == EditAction.PlaceWire2 || action == EditAction.PlaceWire3) - { - // If they aren't selecting a wrench, they're hacking. - // WireKite = The Grand Design - if (selectedItem.type != ItemID.Wrench - && selectedItem.type != ItemID.BlueWrench - && selectedItem.type != ItemID.GreenWrench - && selectedItem.type != ItemID.YellowWrench - && selectedItem.type != ItemID.MulticolorWrench - && selectedItem.type != ItemID.WireKite) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - } - else if (action == EditAction.KillActuator || action == EditAction.KillWire || - action == EditAction.KillWire2 || action == EditAction.KillWire3) - { - // If they aren't selecting the wire cutter, they're hacking. - if (selectedItem.type != ItemID.WireCutter - && selectedItem.type != ItemID.WireKite - && selectedItem.type != ItemID.MulticolorWrench) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - } - else if (action == EditAction.PlaceActuator) - { - // If they aren't selecting the actuator and don't have the Presserator equipped, they're hacking. - if (selectedItem.type != ItemID.Actuator && !args.Player.TPlayer.autoActuator) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - } - if (TShock.Config.AllowCutTilesAndBreakables && Main.tileCut[tile.type]) - { - if (action == EditAction.KillWall) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - return false; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if (TShock.CheckTilePermission(args.Player, tileX, tileY, editData, action)) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if (TShock.CheckRangePermission(args.Player, tileX, tileY)) - { - if (action == EditAction.PlaceTile && (editData == TileID.Rope || editData == TileID.SilkRope || editData == TileID.VineRope || editData == TileID.WebRope)) - { - return false; - } - - if (action == EditAction.KillTile || action == EditAction.KillWall && ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0) - { - return false; - } - - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if (args.Player.TileKillThreshold >= TShock.Config.TileKillThreshold) - { - args.Player.Disable("Reached TileKill threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if (args.Player.TilePlaceThreshold >= TShock.Config.TilePlaceThreshold) - { - args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendTileSquare(tileX, tileY, 4); - return true; - } - - if ((action == EditAction.PlaceTile || action == EditAction.PlaceWall) && !args.Player.HasPermission(Permissions.ignoreplacetiledetection)) - { - args.Player.TilePlaceThreshold++; - var coords = new Vector2(tileX, tileY); - lock (args.Player.TilesCreated) - if (!args.Player.TilesCreated.ContainsKey(coords)) - args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY]); - } - - if ((action == EditAction.KillTile || action == EditAction.KillTileNoItem || action == EditAction.KillWall) && Main.tileSolid[Main.tile[tileX, tileY].type] && - !args.Player.HasPermission(Permissions.ignorekilltiledetection)) - { - args.Player.TileKillThreshold++; - var coords = new Vector2(tileX, tileY); - lock (args.Player.TilesDestroyed) - if (!args.Player.TilesDestroyed.ContainsKey(coords)) - args.Player.TilesDestroyed.Add(coords, Main.tile[tileX, tileY]); - } - return false; - } - catch - { - args.Player.SendTileSquare(tileX, tileY, 4); + if (OnTileEdit(args.Player, tileX, tileY, action, type, editData, style)) return true; - } + + return false; } From c46dae328df57c2805e8f32e638e083ad5816f16 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 23:37:09 -0700 Subject: [PATCH 15/74] Optimize imports I now have VSCode installed for one reason: to optimize imports. This required: 1. Installing VSCode. 2. Installing OmniSharp in VSCode. 3. Installing .NET Core so that OmniSharp could start in VSCode. VSCode is a Microsoft product. It doesn't ship .NET Core. Or Omni Sharp. Instead, you have to do all of this yourself. It's not batteries included or anything. It's actually harder to use OmniSharp in VSCode than it is to use it in Sublime Text. Except Sublime Text's OmniSharp maintainer went off and abandoned the project without telling anyone at OmniS harp. Which gave me the idea that OmniSharp still was maintained on Sublime Text. And I just upgraded my Sublime Text license today. Thanks OmniSharp developer. --- TShockAPI/Bouncer.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 4a9e766a..e8e732be 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -17,21 +17,11 @@ along with this program. If not, see . */ using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.IO.Streams; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Terraria.ID; using TShockAPI.DB; using TShockAPI.Net; using Terraria; -using Terraria.ObjectData; -using Terraria.DataStructures; -using Terraria.GameContent.Tile_Entities; -using Terraria.Localization; using Microsoft.Xna.Framework; using OTAPI.Tile; using TShockAPI.Localization; @@ -41,8 +31,8 @@ using TerrariaApi.Server; namespace TShockAPI { - /// Bouncer is the TShock anti-hack and build guardian system - internal sealed class Bouncer + /// Bouncer is the TShock anti-hack and build guardian system + internal sealed class Bouncer { /// Constructor call initializes Bouncer & related functionality. /// A new Bouncer. From 6630b70ae1e8cef50e51b887053f706269123476 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 6 Dec 2017 23:42:14 -0700 Subject: [PATCH 16/74] Un-botch tab/spacing in this file. Thanks VS Code! Now I know that if I merely open and save a file using Visual Studi o code, it will automatically munge my tab/spaces on two lines just for kicks. Thanks Microsoft! You're great at this! --- TShockAPI/Bouncer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index e8e732be..5199dcb0 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -31,8 +31,8 @@ using TerrariaApi.Server; namespace TShockAPI { - /// Bouncer is the TShock anti-hack and build guardian system - internal sealed class Bouncer + /// Bouncer is the TShock anti-hack and build guardian system + internal sealed class Bouncer { /// Constructor call initializes Bouncer & related functionality. /// A new Bouncer. From 914782ab9ebb6f00b76e324b2fe00779ff625b51 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 7 Dec 2017 21:43:33 -0700 Subject: [PATCH 17/74] Create hook PlaceObject; move anti-hack to Bouncer --- TShockAPI/Bouncer.cs | 136 +++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 132 +++++++++++----------------------- 2 files changed, 179 insertions(+), 89 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 5199dcb0..d11cac4d 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -27,6 +27,7 @@ using OTAPI.Tile; using TShockAPI.Localization; using static TShockAPI.GetDataHandlers; using TerrariaApi.Server; +using Terraria.ObjectData; namespace TShockAPI @@ -40,11 +41,138 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlaceObject.Register(OnPlaceObject); GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); GetDataHandlers.HealOtherPlayer.Register(OnHealOtherPlayer); GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnPlaceObject(object sender, GetDataHandlers.PlaceObjectEventArgs args) + { + short x = args.X; + short y = args.Y; + short type = args.Type; + short style = args.Style; + byte alternate = args.Alternate; + bool direction = args.Direction; + + if (type < 0 || type >= Main.maxTileSets) + { + args.Handled = true; + return; + } + + if (x < 0 || x >= Main.maxTilesX) + { + args.Handled = true; + return; + } + + if (y < 0 || y >= Main.maxTilesY) + { + args.Handled = true; + return; + } + + //style 52 and 53 are used by ItemID.Fake_newchest1 and ItemID.Fake_newchest2 + //These two items cause localised lag and rendering issues + if (type == TileID.FakeContainers && (style == 52 || style == 53)) + { + args.Player.SendTileSquare(x, y, 4); + args.Handled = true; + return; + } + + if (TShock.TileBans.TileIsBanned(type, args.Player)) + { + args.Player.SendTileSquare(x, y, 1); + args.Player.SendErrorMessage("You do not have permission to place this tile."); + args.Handled = true; + return; + } + + if (!TShock.Utils.TilePlacementValid(x, y)) + { + args.Handled = true; + return; + } + + if (args.Player.Dead && TShock.Config.PreventDeadModification) + { + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(x, y, 4); + args.Handled = true; + return; + } + + // This is neccessary to check in order to prevent special tiles such as + // queen bee larva, paintings etc that use this packet from being placed + // without selecting the right item. + if (type != args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].createTile) + { + args.Player.SendTileSquare(x, y, 4); + args.Handled = true; + return; + } + + TileObjectData tileData = TileObjectData.GetTileData(type, style, 0); + if (tileData == null) + { + args.Handled = true; + return; + } + + x -= tileData.Origin.X; + y -= tileData.Origin.Y; + + for (int i = x; i < x + tileData.Width; i++) + { + for (int j = y; j < y + tileData.Height; j++) + { + if (TShock.CheckTilePermission(args.Player, i, j, type, EditAction.PlaceTile)) + { + args.Player.SendTileSquare(i, j, 4); + args.Handled = true; + return; + } + } + } + + // Ignore rope placement range + if ((type != TileID.Rope + || type != TileID.SilkRope + || type != TileID.VineRope + || type != TileID.WebRope) + && TShock.CheckRangePermission(args.Player, x, y)) + { + args.Player.SendTileSquare(x, y, 4); + args.Handled = true; + return; + } + + if (args.Player.TilePlaceThreshold >= TShock.Config.TilePlaceThreshold) + { + args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(x, y, 4); + args.Handled = true; + return; + } + + if (!args.Player.HasPermission(Permissions.ignoreplacetiledetection)) + { + args.Player.TilePlaceThreshold++; + var coords = new Vector2(x, y); + lock (args.Player.TilesCreated) + if (!args.Player.TilesCreated.ContainsKey(coords)) + args.Player.TilesCreated.Add(coords, Main.tile[x, y]); + } + } + internal void OnTileEdit(object sender, GetDataHandlers.TileEditEventArgs args) { EditAction action = args.Action; @@ -64,14 +192,22 @@ namespace TShockAPI } if (!TShock.Utils.TilePlacementValid(tileX, tileY)) + { args.Handled = true; return; + } + if (action == EditAction.KillTile && Main.tile[tileX, tileY].type == TileID.MagicalIceBlock) + { args.Handled = false; return; + } + if (args.Player.Dead && TShock.Config.PreventDeadModification) + { args.Handled = true; return; + } if (args.Player.AwaitingName) { diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 7fbfd560..1997c554 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -613,9 +613,51 @@ namespace TShockAPI TileX = tilex, TileY = tiley, }; + SendTileSquare.Invoke(null, args); return args.Handled; } + + public class PlaceObjectEventArgs : HandledEventArgs + { + public TSPlayer Player { get; set; } + + public short X { get; set ; } + + public short Y { get; set; } + + public short Type { get; set; } + + public short Style { get; set; } + + public byte Alternate { get; set; } + + public bool Direction { get; set; } + } + + public static HandlerList PlaceObject; + + private static bool OnPlaceObject(TSPlayer player, short x, short y, short type, short style, byte alternate, bool direction) + { + if (PlaceObject == null) + return false; + + var args = new PlaceObjectEventArgs + { + Player = player, + X = x, + Y = y, + Type = type, + Style = style, + Alternate = alternate, + Direction = direction + }; + + PlaceObject.Invoke(null, args); + return args.Handled; + } + + /// /// For use in a NewProjectile event /// @@ -1826,7 +1868,6 @@ namespace TShockAPI return false; } - /// /// Handle PlaceObject event /// @@ -1839,96 +1880,9 @@ namespace TShockAPI byte alternate = args.Data.ReadInt8(); bool direction = args.Data.ReadBoolean(); - if (type < 0 || type >= Main.maxTileSets) + if (OnPlaceObject(args.Player, x, y, type, style, alternate, direction)) return true; - if (x < 0 || x >= Main.maxTilesX) - return true; - - if (y < 0 || y >= Main.maxTilesY) - return true; - - //style 52 and 53 are used by ItemID.Fake_newchest1 and ItemID.Fake_newchest2 - //These two items cause localised lag and rendering issues - if (type == TileID.FakeContainers && (style == 52 || style == 53)) - { - args.Player.SendTileSquare(x, y, 4); - return true; - } - - if (TShock.TileBans.TileIsBanned(type, args.Player)) - { - args.Player.SendTileSquare(x, y, 1); - args.Player.SendErrorMessage("You do not have permission to place this tile."); - return true; - } - - if (!TShock.Utils.TilePlacementValid(x, y)) - return true; - if (args.Player.Dead && TShock.Config.PreventDeadModification) - return true; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(x, y, 4); - return true; - } - - // This is neccessary to check in order to prevent special tiles such as - // queen bee larva, paintings etc that use this packet from being placed - // without selecting the right item. - if (type != args.TPlayer.inventory[args.TPlayer.selectedItem].createTile) - { - args.Player.SendTileSquare(x, y, 4); - return true; - } - - TileObjectData tileData = TileObjectData.GetTileData(type, style, 0); - if (tileData == null) - return true; - - x -= tileData.Origin.X; - y -= tileData.Origin.Y; - - for (int i = x; i < x + tileData.Width; i++) - { - for (int j = y; j < y + tileData.Height; j++) - { - if (TShock.CheckTilePermission(args.Player, i, j, type, EditAction.PlaceTile)) - { - args.Player.SendTileSquare(i, j, 4); - return true; - } - } - } - - // Ignore rope placement range - if ((type != TileID.Rope - || type != TileID.SilkRope - || type != TileID.VineRope - || type != TileID.WebRope) - && TShock.CheckRangePermission(args.Player, x, y)) - { - args.Player.SendTileSquare(x, y, 4); - return true; - } - - if (args.Player.TilePlaceThreshold >= TShock.Config.TilePlaceThreshold) - { - args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(x, y, 4); - return true; - } - - if (!args.Player.HasPermission(Permissions.ignoreplacetiledetection)) - { - args.Player.TilePlaceThreshold++; - var coords = new Vector2(x, y); - lock (args.Player.TilesCreated) - if (!args.Player.TilesCreated.ContainsKey(coords)) - args.Player.TilesCreated.Add(coords, Main.tile[x, y]); - } - return false; } From b5a40a4472e9a3d4e33d527559f6fb8a74a7cc77 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 7 Dec 2017 21:46:45 -0700 Subject: [PATCH 18/74] Comment OnPlaceObject related hook stuff --- TShockAPI/GetDataHandlers.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 1997c554..99c3e8be 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -613,30 +613,48 @@ namespace TShockAPI TileX = tilex, TileY = tiley, }; - + SendTileSquare.Invoke(null, args); return args.Handled; } + /// The arguments to the PlaceObject hook. public class PlaceObjectEventArgs : HandledEventArgs { + /// The calling Player. public TSPlayer Player { get; set; } + /// The X location where the object was placed. public short X { get; set ; } + /// The Y location where the object was placed. public short Y { get; set; } + /// The type of object that was placed. public short Type { get; set; } + /// The style of the object was placed. public short Style { get; set; } + /// Alternate variation of the object placed. public byte Alternate { get; set; } + /// The direction the object was placed. public bool Direction { get; set; } } + /// Fired when an object is placed in the world. public static HandlerList PlaceObject; + /// Fires the PlaceObject hook. To be called when an object is placed in the world. + /// The originating player. + /// The x position where the object is placed. + /// The y position where the object is placed. + /// The type of object. + /// The object's style data. + /// The object's alternate data. + /// The direction of the object. + /// bool private static bool OnPlaceObject(TSPlayer player, short x, short y, short type, short style, byte alternate, bool direction) { if (PlaceObject == null) From c891a81f67cc85b3cba43526399b942742b92475 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:19:05 -0700 Subject: [PATCH 19/74] Move NewProjectile into Bouncer --- TShockAPI/Bouncer.cs | 107 +++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 95 ++----------------------------- 2 files changed, 112 insertions(+), 90 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index d11cac4d..3e16c10a 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -41,12 +41,119 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.NewProjectile.Register(OnNewProjectile); GetDataHandlers.PlaceObject.Register(OnPlaceObject); GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); GetDataHandlers.HealOtherPlayer.Register(OnHealOtherPlayer); GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnNewProjectile(object sender, GetDataHandlers.NewProjectileEventArgs args) + { + short ident = args.Identity; + Vector2 pos = args.Position; + Vector2 vel = args.Velocity; + float knockback = args.Knockback; + short dmg = args.Damage; + byte owner = args.Owner; + short type = args.Type; + int index = args.Index; + + if (index > Main.maxProjectiles || index < 0) + { + args.Player.RemoveProjectile(ident, owner); + args.Handled = true; + return; + } + + if (TShock.ProjectileBans.ProjectileIsBanned(type, args.Player)) + { + args.Player.Disable("Player does not have permission to create that projectile.", DisableFlags.WriteToLogAndConsole); + args.Player.SendErrorMessage("You do not have permission to create that projectile."); + args.Player.RemoveProjectile(ident, owner); + args.Handled = true; + return; + } + + if (dmg > TShock.Config.MaxProjDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) + { + args.Player.Disable(String.Format("Projectile damage is higher than {0}.", TShock.Config.MaxProjDamage), DisableFlags.WriteToLogAndConsole); + args.Player.RemoveProjectile(ident, owner); + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.RemoveProjectile(ident, owner); + args.Handled = true; + return; + } + + bool hasPermission = !TShock.CheckProjectilePermission(args.Player, index, type); + if (!TShock.Config.IgnoreProjUpdate && !hasPermission && !args.Player.HasPermission(Permissions.ignoreprojectiledetection)) + { + if (type == ProjectileID.BlowupSmokeMoonlord + || type == ProjectileID.PhantasmalEye + || type == ProjectileID.CultistBossIceMist + || (type >= ProjectileID.MoonlordBullet && type <= ProjectileID.MoonlordTurretLaser) + || type == ProjectileID.DeathLaser || type == ProjectileID.Landmine + || type == ProjectileID.BulletDeadeye || type == ProjectileID.BoulderStaffOfEarth + || (type > ProjectileID.ConfettiMelee && type < ProjectileID.SpiritHeal) + || (type >= ProjectileID.FlamingWood && type <= ProjectileID.GreekFire3) + || (type >= ProjectileID.PineNeedleHostile && type <= ProjectileID.Spike) + || (type >= ProjectileID.MartianTurretBolt && type <= ProjectileID.RayGunnerLaser) + || type == ProjectileID.CultistBossLightningOrb) + { + TShock.Log.Debug("Certain projectiles have been ignored for cheat detection."); + } + else + { + args.Player.Disable(String.Format("Does not have projectile permission to update projectile. ({0})", type), DisableFlags.WriteToLogAndConsole); + args.Player.RemoveProjectile(ident, owner); + } + args.Handled = true; + return; + } + + if (args.Player.ProjectileThreshold >= TShock.Config.ProjectileThreshold) + { + args.Player.Disable("Reached projectile update threshold.", DisableFlags.WriteToLogAndConsole); + args.Player.RemoveProjectile(ident, owner); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.RemoveProjectile(ident, owner); + args.Handled = true; + return; + } + + if (!args.Player.HasPermission(Permissions.ignoreprojectiledetection)) + { + if (type == ProjectileID.CrystalShard && TShock.Config.ProjIgnoreShrapnel) // Ignore crystal shards + { + TShock.Log.Debug("Ignoring shrapnel per config.."); + } + else if (!Main.projectile[index].active) + { + args.Player.ProjectileThreshold++; // Creating new projectile + } + } + + if (hasPermission && + (type == ProjectileID.Bomb + || type == ProjectileID.Dynamite + || type == ProjectileID.StickyBomb + || type == ProjectileID.StickyDynamite)) + { + // Denotes that the player has recently set a fuse - used for cheat detection. + args.Player.RecentFuse = 10; + } + } + internal void OnPlaceObject(object sender, GetDataHandlers.PlaceObjectEventArgs args) { short x = args.X; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 99c3e8be..bde25e27 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -681,6 +681,8 @@ namespace TShockAPI /// public class NewProjectileEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the new projectile. + public TSPlayer Player { get; set; } /// /// ??? /// @@ -719,7 +721,7 @@ namespace TShockAPI /// public static HandlerList NewProjectile; - private static bool OnNewProjectile(short ident, Vector2 pos, Vector2 vel, float knockback, short dmg, byte owner, short type, int index) + private static bool OnNewProjectile(short ident, Vector2 pos, Vector2 vel, float knockback, short dmg, byte owner, short type, int index, TSPlayer player) { if (NewProjectile == null) return false; @@ -734,6 +736,7 @@ namespace TShockAPI Owner = owner, Type = type, Index = index, + Player = player, }; NewProjectile.Invoke(null, args); return args.Handled; @@ -2261,97 +2264,9 @@ namespace TShockAPI var index = TShock.Utils.SearchProjectile(ident, owner); - if (OnNewProjectile(ident, pos, vel, knockback, dmg, owner, type, index)) + if (OnNewProjectile(ident, pos, vel, knockback, dmg, owner, type, index, args.Player)) return true; - if (index > Main.maxProjectiles || index < 0) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (TShock.ProjectileBans.ProjectileIsBanned(type, args.Player)) - { - args.Player.Disable("Player does not have permission to create that projectile.", DisableFlags.WriteToLogAndConsole); - args.Player.SendErrorMessage("You do not have permission to create that projectile."); - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (dmg > TShock.Config.MaxProjDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) - { - args.Player.Disable(String.Format("Projectile damage is higher than {0}.", TShock.Config.MaxProjDamage), DisableFlags.WriteToLogAndConsole); - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - bool hasPermission = !TShock.CheckProjectilePermission(args.Player, index, type); - if (!TShock.Config.IgnoreProjUpdate && !hasPermission && !args.Player.HasPermission(Permissions.ignoreprojectiledetection)) - { - if (type == ProjectileID.BlowupSmokeMoonlord - || type == ProjectileID.PhantasmalEye - || type == ProjectileID.CultistBossIceMist - || (type >= ProjectileID.MoonlordBullet && type <= ProjectileID.MoonlordTurretLaser) - || type == ProjectileID.DeathLaser || type == ProjectileID.Landmine - || type == ProjectileID.BulletDeadeye || type == ProjectileID.BoulderStaffOfEarth - || (type > ProjectileID.ConfettiMelee && type < ProjectileID.SpiritHeal) - || (type >= ProjectileID.FlamingWood && type <= ProjectileID.GreekFire3) - || (type >= ProjectileID.PineNeedleHostile && type <= ProjectileID.Spike) - || (type >= ProjectileID.MartianTurretBolt && type <= ProjectileID.RayGunnerLaser) - || type == ProjectileID.CultistBossLightningOrb) - { - TShock.Log.Debug("Certain projectiles have been ignored for cheat detection."); - } - else - { - args.Player.Disable(String.Format("Does not have projectile permission to update projectile. ({0})", type), DisableFlags.WriteToLogAndConsole); - args.Player.RemoveProjectile(ident, owner); - } - return true; - } - - if (args.Player.ProjectileThreshold >= TShock.Config.ProjectileThreshold) - { - args.Player.Disable("Reached projectile update threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (!args.Player.HasPermission(Permissions.ignoreprojectiledetection)) - { - if (type == ProjectileID.CrystalShard && TShock.Config.ProjIgnoreShrapnel) // Ignore crystal shards - { - TShock.Log.Debug("Ignoring shrapnel per config.."); - } - else if (!Main.projectile[index].active) - { - args.Player.ProjectileThreshold++; // Creating new projectile - } - } - - if (hasPermission && - (type == ProjectileID.Bomb - || type == ProjectileID.Dynamite - || type == ProjectileID.StickyBomb - || type == ProjectileID.StickyDynamite)) - { - // Denotes that the player has recently set a fuse - used for cheat detection. - args.Player.RecentFuse = 10; - //return true; - } - return false; } From 46617e61d02a885097e0fcfcf09050e592041f3e Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:29:23 -0700 Subject: [PATCH 20/74] Update changelog re. new hook changes --- CHANGELOG.md | 3 +++ TShockAPI/GetDataHandlers.cs | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14bce826..46bfb0bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Fixed /savessc not bothering to save ssc data for people who bypass ssc. (@hakusaro) * Default permission sets for new databases are more modern. (@hakusaro) * Added the ability to ban by account name instead of just banning a character name assuming its an account name. (@hakusaro) +* `GetDataHandlers.SendTileSquare` hook now sends a `TSPlayer` and a `MemoryStream` of raw data. (@hakusaro) +* Added `GetDataHandlers.HealOtherPlayer` hook. (@hakusaro) +* Added `GetDataHandlers.PlaceObject` hook. (@hakusaro) ## TShock 4.3.24 * Updated OpenTerraria API to 1.3.5.3 (@DeathCradle) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index bde25e27..0cf305a0 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2261,7 +2261,6 @@ namespace TShockAPI ai[i] = 0f; } - var index = TShock.Utils.SearchProjectile(ident, owner); if (OnNewProjectile(ident, pos, vel, knockback, dmg, owner, type, index, args.Player)) From cdfb05690304d7b7df4c25bcd72ea35b19d5ff42 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:31:40 -0700 Subject: [PATCH 21/74] Include feedback from @bartico6 on a magic number --- TShockAPI/Bouncer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 3e16c10a..4a4df270 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -655,6 +655,8 @@ namespace TShockAPI return; } + // Why 0.2? + // @bartico6: Because heal other player only happens when you are using the spectre armor with the hood, and the healing you can do with that is 20% of your damage. if (amount > TShock.Config.MaxDamage * 0.2) { args.Player.Disable("HealOtherPlayer cheat attempt!", DisableFlags.WriteToLogAndConsole); From eed7b3fad234e81db0b8922d8f85bd880951d686 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:35:27 -0700 Subject: [PATCH 22/74] Document what TSPlayer.SendTileSquare does --- TShockAPI/TSPlayer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index e2eedd1a..39dbb551 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -808,6 +808,15 @@ namespace TShockAPI } } + /// Sends a tile square at a location with a given size. + /// Typically used to revert changes by Bouncer through sending the + /// "old" version of modified data back to a client. + /// Prevents desync issues. + /// + /// The x coordinate to send. + /// The y coordinate to send. + /// The size square set of tiles to send. + /// Status if the tile square was sent successfully (i.e. no exceptions). public virtual bool SendTileSquare(int x, int y, int size = 10) { try From ce822caf2a5f75d0c9be602b3044ce385d14c735 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:39:54 -0700 Subject: [PATCH 23/74] Implement re-transmit of data if event handled in OnTilEdit Thanks to the suggestion of @bartico6, we now re-transmit packets of world data to prevent desync issues with respect to stopping a server action but not fixing the client's view of the world. --- TShockAPI/Bouncer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 4a4df270..adbfd759 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -300,6 +300,7 @@ namespace TShockAPI if (!TShock.Utils.TilePlacementValid(tileX, tileY)) { + args.Player.SendTileSquare(tileX, tileY, 4); args.Handled = true; return; } @@ -312,6 +313,7 @@ namespace TShockAPI if (args.Player.Dead && TShock.Config.PreventDeadModification) { + args.Player.SendTileSquare(tileX, tileY, 4); args.Handled = true; return; } @@ -377,6 +379,7 @@ namespace TShockAPI return; } + // TODO: REMOVE. This does NOT look like Bouncer code. if (args.Player.AwaitingTempPoint > 0) { args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].X = tileX; @@ -656,7 +659,8 @@ namespace TShockAPI } // Why 0.2? - // @bartico6: Because heal other player only happens when you are using the spectre armor with the hood, and the healing you can do with that is 20% of your damage. + // @bartico6: Because heal other player only happens when you are using the spectre armor with the hood, + // and the healing you can do with that is 20% of your damage. if (amount > TShock.Config.MaxDamage * 0.2) { args.Player.Disable("HealOtherPlayer cheat attempt!", DisableFlags.WriteToLogAndConsole); From aa527496dc87a47a81430f28780de17c3feb515d Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:48:43 -0700 Subject: [PATCH 24/74] Replace a coule TileID magic numbers with direc Tcalls. Thanks @mistzzt & @QuiCM! --- TShockAPI/Bouncer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index adbfd759..6d0bfe20 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -28,6 +28,7 @@ using TShockAPI.Localization; using static TShockAPI.GetDataHandlers; using TerrariaApi.Server; using Terraria.ObjectData; +using Terraria.ID; namespace TShockAPI @@ -333,6 +334,8 @@ namespace TShockAPI persistentMode = true; } + + // TODO: REMOVE. This does NOT look like Bouncer code. List outputRegions = new List(); foreach (Region region in TShock.Regions.Regions.OrderBy(r => r.Z).Reverse()) { @@ -483,7 +486,7 @@ namespace TShockAPI args.Handled = true; return; } - if (action == EditAction.PlaceTile && (editData == 29 || editData == 97) && Main.ServerSideCharacter) + if (action == EditAction.PlaceTile && (editData == TileID.PiggyBank || editData == TileID.Safes) && Main.ServerSideCharacter) { args.Player.SendErrorMessage("You cannot place this tile because server side characters are enabled."); args.Player.SendTileSquare(tileX, tileY, 3); From 760f5518da6a38e81224b4726238386ace501688 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 01:50:58 -0700 Subject: [PATCH 25/74] More patching to fix potential desync (thanks @bartico6)! --- TShockAPI/Bouncer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 6d0bfe20..c37db4ab 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -201,12 +201,14 @@ namespace TShockAPI if (!TShock.Utils.TilePlacementValid(x, y)) { + args.Player.SendTileSquare(tileX, tileY, 4); args.Handled = true; return; } if (args.Player.Dead && TShock.Config.PreventDeadModification) { + args.Player.SendTileSquare(tileX, tileY, 4); args.Handled = true; return; } From a5cbeb166b0fe034c63372af7d99454d5485008f Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 02:15:31 -0700 Subject: [PATCH 26/74] Fix some SendTileSquare calls with proper args --- TShockAPI/Bouncer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index c37db4ab..f472b40b 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -201,14 +201,14 @@ namespace TShockAPI if (!TShock.Utils.TilePlacementValid(x, y)) { - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquare(x, y, 4); args.Handled = true; return; } if (args.Player.Dead && TShock.Config.PreventDeadModification) { - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquare(x, y, 4); args.Handled = true; return; } From 436e91c1f11654f625e5bdf21273f6a5ba130773 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 10:30:20 -0700 Subject: [PATCH 27/74] Change STS to 1 tile for @bartico6's quality of life changes Since these reverts are on a per-tile basis, we only need to revert the first block not surrounding ones. Note: May cause problems with dropped sand because of gravity. --- TShockAPI/Bouncer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index f472b40b..ed1caba1 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -201,7 +201,7 @@ namespace TShockAPI if (!TShock.Utils.TilePlacementValid(x, y)) { - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquare(x, y, 1); args.Handled = true; return; } @@ -303,7 +303,7 @@ namespace TShockAPI if (!TShock.Utils.TilePlacementValid(tileX, tileY)) { - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquare(tileX, tileY, 1); args.Handled = true; return; } From dd7ffe2d3a6453368eff0d562d9c507ee32fde69 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 9 Dec 2017 13:46:45 -0700 Subject: [PATCH 28/74] Move PlayerKillMeV2 anti-crash to Bouncer Removed PacketTypes.PlayerKillMe since it's out of the protocol. Removed handler method for PlayerKillMe since it's out of the protocol. Updated changelog to reflect new hook changes. --- CHANGELOG.md | 2 +- TShockAPI/Bouncer.cs | 34 ++++++++++++- TShockAPI/GetDataHandlers.cs | 93 ++++-------------------------------- 3 files changed, 42 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d08b8527..dc1a0b01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * `GetDataHandlers.SendTileSquare` hook now sends a `TSPlayer` and a `MemoryStream` of raw data. (@hakusaro) * Added `GetDataHandlers.HealOtherPlayer` hook. (@hakusaro) * Added `GetDataHandlers.PlaceObject` hook. (@hakusaro) - +* `GetDataHandlers.KillMe` now sends a `TSPlayer` and a `PlayerDeathReason`. (@hakusaro) ## TShock 4.3.24 * Updated OpenTerraria API to 1.3.5.3 (@DeathCradle) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index ed1caba1..6fc7f640 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -29,7 +29,7 @@ using static TShockAPI.GetDataHandlers; using TerrariaApi.Server; using Terraria.ObjectData; using Terraria.ID; - +using Terraria.DataStructures; namespace TShockAPI { @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.KillMe.Register(OnKillMe); GetDataHandlers.NewProjectile.Register(OnNewProjectile); GetDataHandlers.PlaceObject.Register(OnPlaceObject); GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); @@ -49,6 +50,37 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnKillMe(object sender, GetDataHandlers.KillMeEventArgs args) + { + short dmg = args.Damage; + short id = args.PlayerId; + PlayerDeathReason playerDeathReason = args.PlayerDeathReason; + + if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server. + { + TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); + TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg); + args.Handled = true; + return; + } + + if (id >= Main.maxPlayers) + { + args.Handled = true; + return; + } + + if (playerDeathReason != null) + { + if (playerDeathReason.GetDeathText(TShock.Players[id].Name).ToString().Length > 500) + { + TShock.Utils.Kick(TShock.Players[id], "Crash attempt", true); + args.Handled = true; + return; + } + } + } + internal void OnNewProjectile(object sender, GetDataHandlers.NewProjectileEventArgs args) { short ident = args.Identity; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 0d59a7ec..c57ab351 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -389,6 +389,8 @@ namespace TShockAPI /// public class KillMeEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } /// /// The Terraria playerID of the player /// @@ -405,23 +407,27 @@ namespace TShockAPI /// Player's current pvp setting /// public bool Pvp { get; set; } + /// The reason the player died. + public PlayerDeathReason PlayerDeathReason { get; set; } } /// /// KillMe - Terraria's crappy way of handling damage from players /// public static HandlerList KillMe; - private static bool OnKillMe(byte plr, byte direction, short damage, bool pvp) + private static bool OnKillMe(TSPlayer player, byte plr, byte direction, short damage, bool pvp, PlayerDeathReason playerDeathReason) { if (KillMe == null) return false; var args = new KillMeEventArgs { + Player = player, PlayerId = plr, Direction = direction, Damage = damage, Pvp = pvp, + PlayerDeathReason = playerDeathReason, }; KillMe.Invoke(null, args); return args.Handled; @@ -1341,7 +1347,6 @@ namespace TShockAPI { PacketTypes.TogglePvp, HandleTogglePvp }, { PacketTypes.PlayerTeam, HandlePlayerTeam }, { PacketTypes.TileKill, HandleTileKill }, - { PacketTypes.PlayerKillMe, HandlePlayerKillMe }, { PacketTypes.LiquidSet, HandleLiquidSet }, { PacketTypes.PlayerSpawn, HandleSpawn }, { PacketTypes.ChestGetContents, HandleChestOpen }, @@ -2315,71 +2320,6 @@ namespace TShockAPI return false; } - private static bool HandlePlayerKillMe(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var direction = (byte)(args.Data.ReadInt8() - 1); - var dmg = args.Data.ReadInt16(); - var pvp = args.Data.ReadInt8() == 0; - var text = args.Data.ReadString(); - if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server. - { - TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); - TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg); - return false; - } - - if (id >= Main.maxPlayers) - { - return true; - } - - if (OnKillMe(id, direction, dmg, pvp)) - return true; - - if (text.Length > 500) - { - TShock.Utils.Kick(TShock.Players[id], "Crash attempt", true); - return true; - } - - args.Player.Dead = true; - args.Player.RespawnTimer = TShock.Config.RespawnSeconds; - - foreach (NPC npc in Main.npc) - { - if (npc.active && (npc.boss || npc.type == 13 || npc.type == 14 || npc.type == 15) && - Math.Abs(args.TPlayer.Center.X - npc.Center.X) + Math.Abs(args.TPlayer.Center.Y - npc.Center.Y) < 4000f) - { - args.Player.RespawnTimer = TShock.Config.RespawnBossSeconds; - break; - } - } - - if (args.TPlayer.difficulty == 2 && (TShock.Config.KickOnHardcoreDeath || TShock.Config.BanOnHardcoreDeath)) - { - if (TShock.Config.BanOnHardcoreDeath) - { - if (!TShock.Utils.Ban(args.Player, TShock.Config.HardcoreBanReason, false, "hardcore-death")) - TShock.Utils.ForceKick(args.Player, "Death results in a ban, but you are immune to bans.", true); - } - else - { - TShock.Utils.ForceKick(args.Player, TShock.Config.HardcoreKickReason, true, false); - } - } - - if (args.TPlayer.difficulty == 2 && Main.ServerSideCharacter && args.Player.IsLoggedIn) - { - if (TShock.CharacterDB.RemovePlayer(args.Player.Account.ID)) - { - TShock.CharacterDB.SeedInitialData(args.Player.Account); - } - } - - return false; - } - private static bool HandlePlayerKillMeV2(GetDataHandlerArgs args) { var id = args.Data.ReadInt8(); @@ -2388,26 +2328,9 @@ namespace TShockAPI var direction = (byte)(args.Data.ReadInt8() - 1); BitsByte bits = (BitsByte)args.Data.ReadByte(); bool pvp = bits[0]; - if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server. - { - TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); - TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg); - return false; - } - if (id >= Main.maxPlayers) - { + if (OnKillMe(args.Player, id, direction, dmg, pvp, playerDeathReason)) return true; - } - - if (OnKillMe(id, direction, dmg, pvp)) - return true; - - if (playerDeathReason.GetDeathText(TShock.Players[id].Name).ToString().Length > 500) - { - TShock.Utils.Kick(TShock.Players[id], "Crash attempt", true); - return true; - } args.Player.Dead = true; args.Player.RespawnTimer = TShock.Config.RespawnSeconds; From 79802cd9e06f54fdfa5e278462754aaa05f04bac Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 10 Dec 2017 08:54:32 -0700 Subject: [PATCH 29/74] Comment more things in Bouncer --- TShockAPI/Bouncer.cs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 6fc7f640..d1810c38 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -50,6 +50,9 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Bouncer's KillMe hook stops crash exploits from out of bounds values. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnKillMe(object sender, GetDataHandlers.KillMeEventArgs args) { short dmg = args.Damage; @@ -81,6 +84,9 @@ namespace TShockAPI } } + /// Bouncer's projectile trigger hook stops world damaging projectiles from destroying the world. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnNewProjectile(object sender, GetDataHandlers.NewProjectileEventArgs args) { short ident = args.Identity; @@ -187,6 +193,9 @@ namespace TShockAPI } } + /// Bouncer's PlaceObject hook reverts malicious tile placement. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnPlaceObject(object sender, GetDataHandlers.PlaceObjectEventArgs args) { short x = args.X; @@ -315,6 +324,9 @@ namespace TShockAPI } } + /// Bouncer's TileEdit hook is used to revert malicious tile changes. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnTileEdit(object sender, GetDataHandlers.TileEditEventArgs args) { EditAction action = args.Action; @@ -681,9 +693,9 @@ namespace TShockAPI } } - /// The handler for the HealOther events in Bouncer - /// sender - /// args + /// Bouncer's HealOther handler prevents gross misuse of HealOther packets by hackers. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnHealOtherPlayer(object sender, GetDataHandlers.HealOtherPlayerEventArgs args) { short amount = args.Amount; @@ -723,9 +735,9 @@ namespace TShockAPI return; } - /// The handler for SendTileSquare events in Bouncer - /// sender - /// args + /// Bouncer's SendTileSquare hook halts large scope world destruction. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args) { short size = args.Size; From 949d0e0ffa7452c1ad0dc0cedbdf588a713612a4 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 10 Dec 2017 08:56:17 -0700 Subject: [PATCH 30/74] More remove notes --- TShockAPI/Bouncer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index d1810c38..3d5d5ebe 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -232,6 +232,7 @@ namespace TShockAPI return; } + // TODO: REMOVE. This does NOT look like Bouncer code. if (TShock.TileBans.TileIsBanned(type, args.Player)) { args.Player.SendTileSquare(x, y, 1); From d3c566db83d1b273b8108d3f177337fc3f901633 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 10 Dec 2017 10:04:27 -0700 Subject: [PATCH 31/74] Move a large majority of OnPlayerUpdate to Bouncer I really really don't understand why we're doing Terraria's data sync for them (see HandlePlayerUpdate). Someone know why? --- TShockAPI/Bouncer.cs | 104 +++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 98 +++++---------------------------- 2 files changed, 119 insertions(+), 83 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 3d5d5ebe..e99233a9 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlayerUpdate.Register(OnPlayerUpdate); GetDataHandlers.KillMe.Register(OnKillMe); GetDataHandlers.NewProjectile.Register(OnNewProjectile); GetDataHandlers.PlaceObject.Register(OnPlaceObject); @@ -50,6 +51,109 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles disabling enforcement & minor anti-exploit stuff + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnPlayerUpdate(object sender, GetDataHandlers.PlayerUpdateEventArgs args) + { + byte plr = args.PlayerId; + BitsByte control = args.Control; + BitsByte pulley = args.Pulley; + byte item = args.Item; + var pos = args.Position; + var vel = args.Velocity; + + if (pos.X < 0 || pos.Y < 0 || pos.X >= Main.maxTilesX * 16 - 16 || pos.Y >= Main.maxTilesY * 16 - 16) + { + args.Handled = true; + return; + } + + if (item < 0 || item >= args.Player.TPlayer.inventory.Length) + { + args.Handled = true; + return; + } + + if (args.Player.LastNetPosition == Vector2.Zero) + { + args.Handled = true; + return; + } + + if (!pos.Equals(args.Player.LastNetPosition)) + { + float distance = Vector2.Distance(new Vector2(pos.X / 16f, pos.Y / 16f), + new Vector2(args.Player.LastNetPosition.X / 16f, args.Player.LastNetPosition.Y / 16f)); + + if (TShock.CheckIgnores(args.Player)) + { + // If the player has moved outside the disabled zone... + if (distance > TShock.Config.MaxRangeForDisabled) + { + // We need to tell them they were disabled and why, then revert the change. + if (args.Player.IgnoreActionsForCheating != "none") + { + args.Player.SendErrorMessage("Disabled for cheating: " + args.Player.IgnoreActionsForCheating); + } + else if (args.Player.IgnoreActionsForDisabledArmor != "none") + { + args.Player.SendErrorMessage("Disabled for banned armor: " + args.Player.IgnoreActionsForDisabledArmor); + } + else if (args.Player.IgnoreActionsForInventory != "none") + { + args.Player.SendErrorMessage("Disabled for Server Side Inventory: " + args.Player.IgnoreActionsForInventory); + } + else if (TShock.Config.RequireLogin && !args.Player.IsLoggedIn) + { + args.Player.SendErrorMessage("Please /register or /login to play!"); + } + else if (args.Player.IgnoreActionsForClearingTrashCan) + { + args.Player.SendErrorMessage("You need to rejoin to ensure your trash can is cleared!"); + } + + // ?? + var lastTileX = args.Player.LastNetPosition.X; + var lastTileY = args.Player.LastNetPosition.Y - 48; + if (!args.Player.Teleport(lastTileX, lastTileY)) + { + args.Player.Spawn(); + } + args.Handled = true; + return; + } + args.Handled = true; + return; + } + + // Corpses don't move + if (args.Player.Dead) + { + args.Handled = true; + return; + } + + // Noclip detection + if (!args.Player.HasPermission(Permissions.ignorenoclipdetection) && + TSCheckNoclip(pos, args.Player.TPlayer.width, args.Player.TPlayer.height - (args.Player.TPlayer.mount.Active ? args.Player.TPlayer.mount.HeightBoost : 0)) && !TShock.Config.IgnoreNoClip + && !args.Player.TPlayer.tongued) + { + var lastTileX = args.Player.LastNetPosition.X; + var lastTileY = args.Player.LastNetPosition.Y; + if (!args.Player.Teleport(lastTileX, lastTileY)) + { + args.Player.SendErrorMessage("You got stuck in a solid object, Sent to spawn point."); + args.Player.Spawn(); + } + args.Handled = true; + return; + } + } + + return; + } + /// Bouncer's KillMe hook stops crash exploits from out of bounds values. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index c57ab351..fb1ac16b 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -438,16 +438,18 @@ namespace TShockAPI /// public class PlayerUpdateEventArgs : HandledEventArgs { + /// The TSPlayer object that triggered the event + public TSPlayer Player { get; set; } /// /// The Terraria playerID of the player /// public byte PlayerId { get; set; } /// - /// ??? + /// Control direction (BitFlags) /// public byte Control { get; set; } /// - /// Current item? + /// Selected item /// public byte Item { get; set; } /// @@ -458,7 +460,7 @@ namespace TShockAPI /// Velocity of the player /// public Vector2 Velocity { get; set; } - + /// Pulley update (BitFlags) public byte Pulley { get; set; } } /// @@ -466,14 +468,15 @@ namespace TShockAPI /// public static HandlerList PlayerUpdate; - private static bool OnPlayerUpdate(byte player, byte control, byte item, Vector2 position, Vector2 velocity, byte pulley) + private static bool OnPlayerUpdate(TSPlayer player, byte plr, byte control, byte item, Vector2 position, Vector2 velocity, byte pulley) { if (PlayerUpdate == null) return false; var args = new PlayerUpdateEventArgs { - PlayerId = player, + Player = player, + PlayerId = plr, Control = control, Item = item, Position = position, @@ -2034,6 +2037,9 @@ namespace TShockAPI { if (args.Player == null || args.TPlayer == null || args.Data == null) { + // Is this really the best option? + // If we're getting a packet that doesn't have a player or a TPlayer or data... + // Should we really let it through? return false; } @@ -2046,86 +2052,12 @@ namespace TShockAPI if (pulley[2]) vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - if (OnPlayerUpdate(plr, control, item, pos, vel, pulley)) + if (OnPlayerUpdate(args.Player, plr, control, item, pos, vel, pulley)) return true; - if (pos.X < 0 || pos.Y < 0 || pos.X >= Main.maxTilesX * 16 - 16 || pos.Y >= Main.maxTilesY * 16 - 16) - { - return true; - } - - if (item < 0 || item >= args.TPlayer.inventory.Length) - { - return true; - } - - if (args.Player.LastNetPosition == Vector2.Zero) - { - return true; - } - - if (!pos.Equals(args.Player.LastNetPosition)) - { - float distance = Vector2.Distance(new Vector2(pos.X / 16f, pos.Y / 16f), - new Vector2(args.Player.LastNetPosition.X / 16f, args.Player.LastNetPosition.Y / 16f)); - if (TShock.CheckIgnores(args.Player)) - { - if (distance > TShock.Config.MaxRangeForDisabled) - { - if (args.Player.IgnoreActionsForCheating != "none") - { - args.Player.SendErrorMessage("Disabled for cheating: " + args.Player.IgnoreActionsForCheating); - } - else if (args.Player.IgnoreActionsForDisabledArmor != "none") - { - args.Player.SendErrorMessage("Disabled for banned armor: " + args.Player.IgnoreActionsForDisabledArmor); - } - else if (args.Player.IgnoreActionsForInventory != "none") - { - args.Player.SendErrorMessage("Disabled for Server Side Inventory: " + args.Player.IgnoreActionsForInventory); - } - else if (TShock.Config.RequireLogin && !args.Player.IsLoggedIn) - { - args.Player.SendErrorMessage("Please /register or /login to play!"); - } - else if (args.Player.IgnoreActionsForClearingTrashCan) - { - args.Player.SendErrorMessage("You need to rejoin to ensure your trash can is cleared!"); - } - var lastTileX = args.Player.LastNetPosition.X; - var lastTileY = args.Player.LastNetPosition.Y - 48; - if (!args.Player.Teleport(lastTileX, lastTileY)) - { - args.Player.Spawn(); - } - return true; - } - return true; - } - - if (args.Player.Dead) - { - return true; - } - - if (!args.Player.HasPermission(Permissions.ignorenoclipdetection) && - TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height - (args.TPlayer.mount.Active ? args.Player.TPlayer.mount.HeightBoost : 0)) && !TShock.Config.IgnoreNoClip - && !args.TPlayer.tongued) - { - var lastTileX = args.Player.LastNetPosition.X; - var lastTileY = args.Player.LastNetPosition.Y; - if (!args.Player.Teleport(lastTileX, lastTileY)) - { - args.Player.SendErrorMessage("You got stuck in a solid object, Sent to spawn point."); - args.Player.Spawn(); - } - return true; - } - args.Player.LastNetPosition = pos; - } - if (control[5]) { + // ItemBan system string itemName = args.TPlayer.inventory[item].Name; if (TShock.Itembans.ItemIsBanned(EnglishLanguage.GetItemNameById(args.TPlayer.inventory[item].netID), args.Player)) { @@ -2134,6 +2066,7 @@ namespace TShockAPI args.Player.SendErrorMessage("You cannot use {0} on this server. Your actions are being ignored.", itemName); } + // Reimplementation of normal Terraria stuff? if (args.TPlayer.inventory[item].Name == "Mana Crystal" && args.Player.TPlayer.statManaMax <= 180) { args.Player.TPlayer.statMana += 20; @@ -2154,6 +2087,7 @@ namespace TShockAPI } } + // Where we rebuild sync data for Terraria? args.TPlayer.selectedItem = item; args.TPlayer.position = pos; args.TPlayer.oldVelocity = args.TPlayer.velocity; @@ -2210,7 +2144,6 @@ namespace TShockAPI args.TPlayer.direction = -1; } - if (args.Player.Confused && Main.ServerSideCharacter && args.Player.IsLoggedIn) { if (args.TPlayer.controlUp) @@ -2235,7 +2168,6 @@ namespace TShockAPI args.TPlayer.controlLeft = true; } - args.TPlayer.Update(args.TPlayer.whoAmI); NetMessage.SendData((int)PacketTypes.PlayerUpdate, -1, -1, NetworkText.Empty, args.Player.Index); return true; From 2cfa633df4d1a5ad3b059a26c0567d91b91c3d71 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 10 Dec 2017 11:26:01 -0700 Subject: [PATCH 32/74] Remove commented out code from HandleProjectileKill --- TShockAPI/GetDataHandlers.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index fb1ac16b..888bce64 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2220,14 +2220,6 @@ namespace TShockAPI var type = Main.projectile[index].type; - // Players can no longer destroy projectiles that are not theirs as of 1.1.2 - /*if (args.Player.Index != Main.projectile[index].owner && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) // workaround for skeletron prime projectiles - { - args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to kill projectile of type: {3}", Main.projectile[index].owner, args.Player.Index, type)); - args.Player.RemoveProjectile(ident, owner); - return true; - }*/ - if (TShock.CheckIgnores(args.Player)) { args.Player.RemoveProjectile(ident, owner); From c5f9a518023bd1d3f2803a38b0f87b8d9cfe871b Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 10 Dec 2017 23:05:50 -0700 Subject: [PATCH 33/74] Move most of HandleProjectileKill to Bouncer Added GetDataHandlers.ProjectileKill hook and related arguments. Fired when a projectile kill packet is accepted by the server. --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 28 ++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 56 +++++++++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 010e16e7..7359fbfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Added `GetDataHandlers.HealOtherPlayer` hook. (@hakusaro) * Added `GetDataHandlers.PlaceObject` hook. (@hakusaro) * `GetDataHandlers.KillMe` now sends a `TSPlayer` and a `PlayerDeathReason`. (@hakusaro) +* Added `GetDataHandlers.ProjectileKill` hook. (@hakusaro) ## TShock 4.3.24 * Updated OpenTerraria API to 1.3.5.3 (@DeathCradle) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index e99233a9..87ea3c72 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.ProjectileKill.Register(OnProjectileKill); GetDataHandlers.PlayerUpdate.Register(OnPlayerUpdate); GetDataHandlers.KillMe.Register(OnKillMe); GetDataHandlers.NewProjectile.Register(OnNewProjectile); @@ -51,6 +52,33 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles ProjectileKill events for throttling & out of bounds projectiles. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnProjectileKill(object sender, GetDataHandlers.ProjectileKillEventArgs args) + { + if (args.ProjectileIndex > Main.maxProjectiles || args.ProjectileIndex < 0) + { + // TODO: Should this be /true/ to stop the server from processing it? + args.Handled = false; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.RemoveProjectile(args.ProjectileIdentity, args.ProjectileOwner); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.RemoveProjectile(args.ProjectileIdentity, args.ProjectileOwner); + args.Handled = true; + return; + } + } + /// Handles disabling enforcement & minor anti-exploit stuff /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 888bce64..3eb03926 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -384,6 +384,45 @@ namespace TShockAPI return args.Handled; } + /// The arguments to the ProjectileKill packet. + public class ProjectileKillEventArgs : HandledEventArgs + { + /// The TSPlayer that fired the event. + public TSPlayer Player; + /// The projectile's identity...? + public int ProjectileIdentity; + /// The the player index of the projectile's owner (Main.players). + public byte ProjectileOwner; + /// The index of the projectile in Main.projectile. + public int ProjectileIndex; + } + + /// The event fired when a projectile kill packet is received. + public static HandlerList ProjectileKill; + + /// Fires the ProjectileKill event. + /// The TSPlayer that caused the event. + /// The projectile identity (from the packet). + /// The projectile's owner (from the packet). + /// The projectile's index (from Main.projectiles). + /// bool + private static bool OnProjectileKill(TSPlayer player, int identity, byte owner, int index) + { + if (ProjectileKill == null) + return false; + + var args = new ProjectileKillEventArgs + { + Player = player, + ProjectileIdentity = identity, + ProjectileOwner = owner, + ProjectileIndex = index, + }; + + ProjectileKill.Invoke(null, args); + return args.Handled; + } + /// /// For use in a KillMe event /// @@ -2213,19 +2252,14 @@ namespace TShockAPI owner = (byte)args.Player.Index; var index = TShock.Utils.SearchProjectile(ident, owner); - if (index > Main.maxProjectiles || index < 0) + if (OnProjectileKill(args.Player, ident, owner, index)) { - return false; + return true; } var type = Main.projectile[index].type; - if (TShock.CheckIgnores(args.Player)) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - + // TODO: This needs to be moved somewhere else. if (TShock.CheckProjectilePermission(args.Player, index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) { args.Player.Disable("Does not have projectile permission to kill projectile.", DisableFlags.WriteToLogAndConsole); @@ -2233,12 +2267,6 @@ namespace TShockAPI return true; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - args.Player.LastKilledProjectile = type; return false; From ba851d3570f6efae73aa8a8c953ffa3775133efc Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 10 Dec 2017 23:36:16 -0700 Subject: [PATCH 34/74] Remove TShock.CheckProjectilePermission Add TSPlayer.HasProjectilePermission() and its inverse: TSPlayer.LacksProjectilePermission() --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 2 +- TShockAPI/GetDataHandlers.cs | 2 +- TShockAPI/TSPlayer.cs | 51 ++++++++++++++++++++++++++++++++++++ TShockAPI/TShock.cs | 35 ------------------------- 5 files changed, 54 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7359fbfb..2327f753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Added `GetDataHandlers.PlaceObject` hook. (@hakusaro) * `GetDataHandlers.KillMe` now sends a `TSPlayer` and a `PlayerDeathReason`. (@hakusaro) * Added `GetDataHandlers.ProjectileKill` hook. (@hakusaro) +* Removed `TShock.CheckProjectilePermission` and replaced it with `TSPlayer.HasProjectilePermission` and `TSPlayer.LacksProjectilePermission` respectively. (@hakusaro) ## TShock 4.3.24 * Updated OpenTerraria API to 1.3.5.3 (@DeathCradle) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 87ea3c72..dd1257db 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -261,7 +261,7 @@ namespace TShockAPI return; } - bool hasPermission = !TShock.CheckProjectilePermission(args.Player, index, type); + bool hasPermission = args.Player.HasProjectilePermission(index, type); if (!TShock.Config.IgnoreProjUpdate && !hasPermission && !args.Player.HasPermission(Permissions.ignoreprojectiledetection)) { if (type == ProjectileID.BlowupSmokeMoonlord diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 3eb03926..2545a2f0 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2260,7 +2260,7 @@ namespace TShockAPI var type = Main.projectile[index].type; // TODO: This needs to be moved somewhere else. - if (TShock.CheckProjectilePermission(args.Player, index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) + if (args.Player.LacksProjectilePermission(index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) { args.Player.Disable("Does not have projectile permission to kill projectile.", DisableFlags.WriteToLogAndConsole); args.Player.RemoveProjectile(ident, owner); diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 78d3ef74..73a2bce0 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -789,6 +789,57 @@ namespace TShockAPI } } + /// Checks to see if this player object lacks access rights to a given projectile. Used by projectile bans. + /// The projectile index from Main.projectiles (NOT from a packet directly). + /// The type of projectile, from Main.projectiles. + /// If the player has lacks access rights to the projectile. + public bool LacksProjectilePermission(int index, int type) + { + return !HasProjectilePermission(index, type); + } + + /// Checks to see if this player object has access rights to a given projectile. Used by projectile bans. + /// The projectile index from Main.projectiles (NOT from a packet directly). + /// The type of projectile, from Main.projectiles. + /// If the player has access rights to the projectile. + public bool HasProjectilePermission(int index, int type) + { + // Players never have the rights to tombstones. + if (type == ProjectileID.Tombstone) + { + return false; + } + + // Dirt balls are the projectiles from dirt rods. + // If the dirt rod item is banned, they probably shouldn't have this projectile. + if (type == ProjectileID.DirtBall && TShock.Itembans.ItemIsBanned("Dirt Rod", this)) + { + return false; + } + + // If the sandgun is banned, block sand bullets. + if (TShock.Itembans.ItemIsBanned("Sandgun", this)) + { + if (type == ProjectileID.SandBallGun + || type == ProjectileID.EbonsandBallGun + || type == ProjectileID.PearlSandBallGun) + { + return false; + } + } + + // If the projectile is hostile, block it? + Projectile tempProjectile = new Projectile(); + tempProjectile.SetDefaults(type); + + if (Main.projHostile[type]) + { + return false; + } + + return true; + } + /// /// Removes the projectile with the given index and owner. /// diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 40003217..a4245e09 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1772,41 +1772,6 @@ namespace TShockAPI Main.StartInvasion(type); } - /// CheckProjectilePermission - Checks if a projectile is banned. - /// player - The TSPlayer object that created the projectile. - /// index - The projectile index. - /// type - The projectile type. - /// bool - True if the player does not have permission to use a projectile. - public static bool CheckProjectilePermission(TSPlayer player, int index, int type) - { - if (type == 43) - { - return true; - } - - if (type == 17 && Itembans.ItemIsBanned("Dirt Rod", player)) - //Dirt Rod Projectile - { - return true; - } - - if ((type == 42 || type == 65 || type == 68) && Itembans.ItemIsBanned("Sandgun", player)) //Sandgun Projectiles - { - return true; - } - - Projectile proj = new Projectile(); - proj.SetDefaults(type); - - if (Main.projHostile[type]) - { - //player.SendMessage( proj.name, Color.Yellow); - return true; - } - - return false; - } - /// CheckRangePermission - Checks if a player has permission to modify a tile dependent on range checks. /// player - The TSPlayer object. /// x - The x coordinate of the tile. From 4b08d616733fa6350442d2b46ce161820c6c0a9d Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 00:17:58 -0700 Subject: [PATCH 35/74] Change null check to return true in HandlePlayerUpdate After confirming with @QuiCM on this, we couldn't figure out why this was set to false in the first place. As a result, we changed it to true to conform with usual logic (bad stuff? reject it.). --- TShockAPI/GetDataHandlers.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 2545a2f0..0ef703af 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2076,10 +2076,7 @@ namespace TShockAPI { if (args.Player == null || args.TPlayer == null || args.Data == null) { - // Is this really the best option? - // If we're getting a packet that doesn't have a player or a TPlayer or data... - // Should we really let it through? - return false; + return true; } byte plr = args.Data.ReadInt8(); From 6ed110f862cfc600ceb6ad874579b8d08ae95ef5 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 00:28:08 -0700 Subject: [PATCH 36/74] Change a bounds check to handle a packet instead of letting it go. This change reverts mod to line 1525 of GetDataHandlers.cs in 672d360e9dbe6c93997f4d17ac0f5e2c987db6ea by Deathamx. We couldn't think of a reason why a bounds check would ever return false, thus not handling the packet and letting the server accept it. Therefore, it's now true. In the future, we need to document handling better. --- TShockAPI/Bouncer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index dd1257db..5b802cef 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -59,8 +59,7 @@ namespace TShockAPI { if (args.ProjectileIndex > Main.maxProjectiles || args.ProjectileIndex < 0) { - // TODO: Should this be /true/ to stop the server from processing it? - args.Handled = false; + args.Handled = true; return; } From e19fd22fe0a5600af0c47c07eade94aff119f343 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 08:18:23 -0700 Subject: [PATCH 37/74] Change Utils.SearchProjectile to return -1 in error Thanks for checking this out, @bartico6. Fixes #1549. Note: this method only returns 1 because the game won't allocate more identity/index combo. Apparently, according to RL. --- TShockAPI/Utils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 0ad2d0ad..3451f5f1 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -943,7 +943,7 @@ namespace TShockAPI /// /// identity /// owner - /// projectile ID + /// projectile ID or -1 if not found public int SearchProjectile(short identity, int owner) { for (int i = 0; i < Main.maxProjectiles; i++) @@ -951,7 +951,7 @@ namespace TShockAPI if (Main.projectile[i].identity == identity && Main.projectile[i].owner == owner) return i; } - return 1000; + return -1; } /// From 5c9d2ed870c1254d4d2d38f062d22b6ceb504321 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 08:23:36 -0700 Subject: [PATCH 38/74] Simpler check (thanks @bartico6) on OPK's nullcheck. --- TShockAPI/Bouncer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 5b802cef..48613832 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -57,7 +57,7 @@ namespace TShockAPI /// The packet arguments that the event has. internal void OnProjectileKill(object sender, GetDataHandlers.ProjectileKillEventArgs args) { - if (args.ProjectileIndex > Main.maxProjectiles || args.ProjectileIndex < 0) + if (args.ProjectileIndex < 0) { args.Handled = true; return; From 903b5b124ecaaef164e1dec182bc3c8f4971395e Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 10:04:21 -0700 Subject: [PATCH 39/74] Remove more randomly commented out code with no apparent reason --- TShockAPI/GetDataHandlers.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 0ef703af..205bf0b7 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -3097,16 +3097,6 @@ namespace TShockAPI { var buff = args.Data.ReadInt8(); - /*if (TShock.Itembans.ItemBans.Any(s => - { - Item item = new Item(); - item.SetDefaults(s.Name); - return item.buffType == buff; - })) - { - buff = 0; - }*/ - if (buff == 10 && TShock.Config.DisableInvisPvP && args.TPlayer.hostile) buff = 0; From 12701e54bab1409fe4133a13544b4c457dceffb7 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 15:53:34 -0700 Subject: [PATCH 40/74] Update submodule again? --- TerrariaServerAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TerrariaServerAPI b/TerrariaServerAPI index bc9f7c69..faa3b956 160000 --- a/TerrariaServerAPI +++ b/TerrariaServerAPI @@ -1 +1 @@ -Subproject commit bc9f7c69becb60816fc1e4587bbca15991231317 +Subproject commit faa3b95697bbf675503b2823c5f59593cf825bb3 From 98aa01c620137ee73c084dc4f41f7e8163f9fa0e Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Mon, 11 Dec 2017 19:07:53 -0700 Subject: [PATCH 41/74] Add note about crash check & change reaosn on OnKillMe --- TShockAPI/Bouncer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 48613832..2710fbd4 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -204,11 +204,12 @@ namespace TShockAPI return; } + // This was formerly marked as a crash check; does not actually crash on this specific packet. if (playerDeathReason != null) { if (playerDeathReason.GetDeathText(TShock.Players[id].Name).ToString().Length > 500) { - TShock.Utils.Kick(TShock.Players[id], "Crash attempt", true); + TShock.Utils.Kick(TShock.Players[id], "Death reason outside of normal bounds.", true); args.Handled = true; return; } From 5cd5bdaaa04aa06a22d43b3216ea211db4def91d Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 07:46:29 -0700 Subject: [PATCH 42/74] Move OnLiquidSet to Bouncer --- CHANGELOG.md | 7 +- TShockAPI/Bouncer.cs | 141 +++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 119 ++--------------------------- 3 files changed, 150 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2602044a..f4bc853d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,9 +34,6 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Removed REST `/v3/server/restart/` route and `/server/restart/` route. (@hakusaro) * The "auth system" is now referred to as the initial setup system (what it actually is). This is better verbiage for basically all situations. Who really wants to turn off the "authentication system?" In addition, the system now makes it more clear what the point of it is, rather than that it grants permissions. (@hakusaro) -## TShock 4.3.25 -* Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. - @@ -68,6 +65,10 @@ Putting this stuff down here so things don't conflict as often. * `GetDataHandlers.KillMe` now sends a `TSPlayer` and a `PlayerDeathReason`. (@hakusaro) * Added `GetDataHandlers.ProjectileKill` hook. (@hakusaro) * Removed `TShock.CheckProjectilePermission` and replaced it with `TSPlayer.HasProjectilePermission` and `TSPlayer.LacksProjectilePermission` respectively. (@hakusaro) +* Added `TSPlayer` object to `GetDataHandlers.LiquidSetEventArgs`. (@hakusaro) + +## TShock 4.3.25 +* Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. ## TShock 4.3.24 * Updated OpenTerraria API to 1.3.5.3 (@DeathCradle) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 2710fbd4..31b31173 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.LiquidSet.Register(OnLiquidSet); GetDataHandlers.ProjectileKill.Register(OnProjectileKill); GetDataHandlers.PlayerUpdate.Register(OnPlayerUpdate); GetDataHandlers.KillMe.Register(OnKillMe); @@ -52,6 +53,146 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles Bouncer's liquid set anti-cheat. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args) + { + int tileX = args.TileX; + int tileY = args.TileY; + byte amount = args.Amount; + byte type = args.Type; + + if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification)) + { + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (args.Player.TileLiquidThreshold >= TShock.Config.TileLiquidThreshold) + { + args.Player.Disable("Reached TileLiquid threshold.", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (!args.Player.HasPermission(Permissions.ignoreliquidsetdetection)) + { + args.Player.TileLiquidThreshold++; + } + + // Liquid anti-cheat + // Arguably the banned buckets bit should be in the item bans system + if (amount != 0) + { + int bucket = -1; + if (args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type == ItemID.EmptyBucket) + { + bucket = 0; + } + else if (args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type == ItemID.WaterBucket) + { + bucket = 1; + } + else if (args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type == ItemID.LavaBucket) + { + bucket = 2; + } + else if (args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type == ItemID.HoneyBucket) + { + bucket = 3; + } + else if (args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type == ItemID.BottomlessBucket || + args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type == ItemID.SuperAbsorbantSponge) + { + bucket = 4; + } + + if (type == 1 && !(bucket == 2 || bucket == 0)) + { + args.Player.SendErrorMessage("You do not have permission to perform this action."); + args.Player.Disable("Spreading lava without holding a lava bucket", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (type == 1 && TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)) + { + args.Player.SendErrorMessage("You do not have permission to perform this action."); + args.Player.Disable("Using banned lava bucket without permissions", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (type == 0 && !(bucket == 1 || bucket == 0 || bucket == 4)) + { + args.Player.SendErrorMessage("You do not have permission to perform this action."); + args.Player.Disable("Spreading water without holding a water bucket", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (type == 0 && TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)) + { + args.Player.SendErrorMessage("You do not have permission to perform this action."); + args.Player.Disable("Using banned water bucket without permissions", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (type == 2 && !(bucket == 3 || bucket == 0)) + { + args.Player.SendErrorMessage("You do not have permission to perform this action."); + args.Player.Disable("Spreading honey without holding a honey bucket", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (type == 2 && TShock.Itembans.ItemIsBanned("Honey Bucket", args.Player)) + { + args.Player.SendErrorMessage("You do not have permission to perform this action."); + args.Player.Disable("Using banned honey bucket without permissions", DisableFlags.WriteToLogAndConsole); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } + + if (TShock.CheckTilePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, tileX, tileY, 16)) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } + /// Handles ProjectileKill events for throttling & out of bounds projectiles. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 205bf0b7..7dca2509 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -795,6 +795,8 @@ namespace TShockAPI /// public class LiquidSetEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } /// /// X location of the tile /// @@ -817,13 +819,14 @@ namespace TShockAPI /// public static HandlerList LiquidSet; - private static bool OnLiquidSet(int tilex, int tiley, byte amount, byte type) + private static bool OnLiquidSet(TSPlayer player, int tilex, int tiley, byte amount, byte type) { if (LiquidSet == null) return false; var args = new LiquidSetEventArgs { + Player = player, TileX = tilex, TileY = tiley, Amount = amount, @@ -2325,121 +2328,9 @@ namespace TShockAPI byte amount = args.Data.ReadInt8(); byte type = args.Data.ReadInt8(); - if (OnLiquidSet(tileX, tileY, amount, type)) + if (OnLiquidSet(args.Player, tileX, tileY, amount, type)) return true; - if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification)) - return true; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (args.Player.TileLiquidThreshold >= TShock.Config.TileLiquidThreshold) - { - args.Player.Disable("Reached TileLiquid threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (!args.Player.HasPermission(Permissions.ignoreliquidsetdetection)) - { - args.Player.TileLiquidThreshold++; - } - if (amount != 0) - { - int bucket = -1; - if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 205) - { - bucket = 0; - } - else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206) - { - bucket = 1; - } - else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 207) - { - bucket = 2; - } - else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 1128) - { - bucket = 3; - } - else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 3031 || - args.TPlayer.inventory[args.TPlayer.selectedItem].type == 3032) - { - bucket = 4; - } - - if (type == 1 && !(bucket == 2 || bucket == 0)) - { - args.Player.SendErrorMessage("You do not have permission to perform this action."); - args.Player.Disable("Spreading lava without holding a lava bucket", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (type == 1 && TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)) - { - args.Player.SendErrorMessage("You do not have permission to perform this action."); - args.Player.Disable("Using banned lava bucket without permissions", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (type == 0 && !(bucket == 1 || bucket == 0 || bucket == 4)) - { - args.Player.SendErrorMessage("You do not have permission to perform this action."); - args.Player.Disable("Spreading water without holding a water bucket", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (type == 0 && TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)) - { - args.Player.SendErrorMessage("You do not have permission to perform this action."); - args.Player.Disable("Using banned water bucket without permissions", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (type == 2 && !(bucket == 3 || bucket == 0)) - { - args.Player.SendErrorMessage("You do not have permission to perform this action."); - args.Player.Disable("Spreading honey without holding a honey bucket", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (type == 2 && TShock.Itembans.ItemIsBanned("Honey Bucket", args.Player)) - { - args.Player.SendErrorMessage("You do not have permission to perform this action."); - args.Player.Disable("Using banned honey bucket without permissions", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - } - - if (TShock.CheckTilePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if (TShock.CheckRangePermission(args.Player, tileX, tileY, 16)) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendTileSquare(tileX, tileY, 1); - return true; - } - return false; } From 3f22c52698ccfe1fbffbce7b990f83c5dc4027b9 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 07:56:41 -0700 Subject: [PATCH 43/74] Move StartInvasion() out of the TShock main class --- CHANGELOG.md | 1 + TShockAPI/Commands.cs | 8 ++++---- TShockAPI/TShock.cs | 20 -------------------- TShockAPI/Utils.cs | 21 +++++++++++++++++++++ 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4bc853d..d8a7890a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Putting this stuff down here so things don't conflict as often. * Added `GetDataHandlers.ProjectileKill` hook. (@hakusaro) * Removed `TShock.CheckProjectilePermission` and replaced it with `TSPlayer.HasProjectilePermission` and `TSPlayer.LacksProjectilePermission` respectively. (@hakusaro) * Added `TSPlayer` object to `GetDataHandlers.LiquidSetEventArgs`. (@hakusaro) +* Removed `TShock.StartInvasion` for public use (moved to Utils and marked internal). (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 1d8545ca..039d14b3 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -2044,19 +2044,19 @@ namespace TShockAPI case "goblin": case "goblins": TSPlayer.All.SendInfoMessage("{0} has started a goblin army invasion.", args.Player.Name); - TShock.StartInvasion(1); + TShock.Utils.StartInvasion(1); break; case "snowman": case "snowmen": TSPlayer.All.SendInfoMessage("{0} has started a snow legion invasion.", args.Player.Name); - TShock.StartInvasion(2); + TShock.Utils.StartInvasion(2); break; case "pirate": case "pirates": TSPlayer.All.SendInfoMessage("{0} has started a pirate invasion.", args.Player.Name); - TShock.StartInvasion(3); + TShock.Utils.StartInvasion(3); break; case "pumpkin": @@ -2098,7 +2098,7 @@ namespace TShockAPI case "martian": case "martians": TSPlayer.All.SendInfoMessage("{0} has started a martian invasion.", args.Player.Name); - TShock.StartInvasion(4); + TShock.Utils.StartInvasion(4); break; } } diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 8ad27859..232d9e36 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1755,27 +1755,7 @@ namespace TShockAPI } - /// StartInvasion - Starts an invasion on the server. - /// type - The invasion type id. - //TODO: Why is this in TShock's main class? - public static void StartInvasion(int type) - { - int invasionSize = 0; - if (Config.InfiniteInvasion) - { - invasionSize = 20000000; - } - else - { - invasionSize = 100 + (Config.InvasionMultiplier * Utils.ActivePlayers()); - } - - // Note: This is a workaround to previously providing the size as a parameter in StartInvasion - Main.invasionSize = invasionSize; - - Main.StartInvasion(type); - } /// CheckRangePermission - Checks if a player has permission to modify a tile dependent on range checks. /// player - The TSPlayer object. diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 2cd87e9c..f831a249 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1457,6 +1457,27 @@ namespace TShockAPI } } + /// Starts an invasion on the server. + /// The invasion type id. + internal void StartInvasion(int type) + { + int invasionSize = 0; + + if (TShock.Config.InfiniteInvasion) + { + invasionSize = 20000000; + } + else + { + invasionSize = 100 + (TShock.Config.InvasionMultiplier * ActivePlayers()); + } + + // Note: This is a workaround to previously providing the size as a parameter in StartInvasion + Main.invasionSize = invasionSize; + + Main.StartInvasion(type); + } + /// Verifies that each stack in each chest is valid and not over the max stack count. internal void FixChestStacks() { From 5f647f087ca74905ae0bc01bef9782b52dfd5534 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 08:08:57 -0700 Subject: [PATCH 44/74] (Probably) fix invasions started by TShock being weird TShock used to call the StartInvasion method in Main with a type and a size, but then in some update it stopped taking a size. So you have to change a field to change the size, but the problem is that the field is reset when StartInavsion is called. This means that any effort to manually change the size would have failed due to the fact that the field is reset at the end. The order has been changed to account for this. In addition, the start size is now set, so the game can report progress correctly on the current invasion. --- CHANGELOG.md | 1 + TShockAPI/Utils.cs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8a7890a..4c6df366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Putting this stuff down here so things don't conflict as often. * Removed `TShock.CheckProjectilePermission` and replaced it with `TSPlayer.HasProjectilePermission` and `TSPlayer.LacksProjectilePermission` respectively. (@hakusaro) * Added `TSPlayer` object to `GetDataHandlers.LiquidSetEventArgs`. (@hakusaro) * Removed `TShock.StartInvasion` for public use (moved to Utils and marked internal). (@hakusaro) +* Fixed invasions started by TShock not reporting size correctly and probably not working at all. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index f831a249..b27bee5d 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1465,6 +1465,7 @@ namespace TShockAPI if (TShock.Config.InfiniteInvasion) { + // Not really an infinite size invasionSize = 20000000; } else @@ -1472,10 +1473,15 @@ namespace TShockAPI invasionSize = 100 + (TShock.Config.InvasionMultiplier * ActivePlayers()); } - // Note: This is a workaround to previously providing the size as a parameter in StartInvasion - Main.invasionSize = invasionSize; + // Order matters + // StartInvasion will reset the invasion size Main.StartInvasion(type); + + // Note: This is a workaround to previously providing the size as a parameter in StartInvasion + // Have to set start size to report progress correctly + Main.invasionSizeStart = invasionSize; + Main.invasionSize = invasionSize; } /// Verifies that each stack in each chest is valid and not over the max stack count. From 0ac486ab5ebc5600a1c1d691d9b15ebe668bae63 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 08:33:34 -0700 Subject: [PATCH 45/74] Remove TShockRestTestPlugin 1. It hasn't been updated in 6 years. 2. Nobody is going to update it. --- .../Properties/AssemblyInfo.cs | 54 ----- TShockRestTestPlugin/TShockRestTestPlugin.cs | 210 ------------------ .../TShockRestTestPlugin.csproj | 62 ------ 3 files changed, 326 deletions(-) delete mode 100644 TShockRestTestPlugin/Properties/AssemblyInfo.cs delete mode 100644 TShockRestTestPlugin/TShockRestTestPlugin.cs delete mode 100644 TShockRestTestPlugin/TShockRestTestPlugin.csproj diff --git a/TShockRestTestPlugin/Properties/AssemblyInfo.cs b/TShockRestTestPlugin/Properties/AssemblyInfo.cs deleted file mode 100644 index dfb6c9aa..00000000 --- a/TShockRestTestPlugin/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011-2016 Nyx Studios (fka. The TShock Team) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -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.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ClassLibrary1")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Multiplay")] -[assembly: AssemblyProduct("ClassLibrary1")] -[assembly: AssemblyCopyright("Copyright © Multiplay 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c6aed7ee-6282-49a2-8177-b79cad20d6d3")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TShockRestTestPlugin/TShockRestTestPlugin.cs b/TShockRestTestPlugin/TShockRestTestPlugin.cs deleted file mode 100644 index 250ff087..00000000 --- a/TShockRestTestPlugin/TShockRestTestPlugin.cs +++ /dev/null @@ -1,210 +0,0 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011-2016 Nyx Studios (fka. The TShock Team) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -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.ComponentModel; -using System.Text; -using System.Web; -using System.Web.Script.Serialization; -using System.Text.RegularExpressions; -using Microsoft.VisualStudio.TestTools.WebTesting; -using Microsoft.VisualStudio.TestTools.WebTesting.Rules; -using Rests; - -namespace TshockRestTestPlugin -{ - [DisplayName("JSON Status")] - [Description("Checks to see the that the JSON response has the specified status response")] - public class JsonValidateStatus : JsonValidate - { - public override void Validate(object sender, ValidationEventArgs e) - { - if (null != ValidateJson(sender, e)) - e.IsValid = true; - } - } - - [DisplayName("JSON Regexp Property")] - [Description("Checks to see the that the JSON response contains the specified property and is matches the specified regexp")] - public class JsonValidateRegexpProperty : JsonValidateProperty - { - // The name of the desired JSON property - [DisplayName("Regexp")] - [DefaultValue(true)] - public new bool UseRegularExpression { get { return base.UseRegularExpression; } set { base.UseRegularExpression = value; } } - } - - [DisplayName("JSON Error")] - [Description("Checks to see the that the JSON response contains the specified error")] - public class JsonValidateError : JsonValidateProperty - { - // The status of the JSON request - [DisplayName("JSON Status")] - [DefaultValue("400")] - public new string JSonStatus { get { return base.JSonStatus; } set { base.JSonStatus = value; } } - - // The name of the desired JSON property - [DisplayName("Property")] - [DefaultValue("error")] - public new string PropertyName { get { return base.PropertyName; } set { base.PropertyName = value; } } - } - - [DisplayName("JSON Missing Parameter")] - [Description("Checks to see the that the JSON response indicates a missing or invalid parameter")] - public class JsonValidateMissingParameter : JsonValidateError - { - // The value of the desired JSON property - [DisplayName("Missing Value")] - public new string PropertyValue { get { return base.PropertyValue; } set { base.PropertyValue = String.Format("Missing or empty {0} parameter", value); } } - } - - [DisplayName("JSON Invalid Parameter")] - [Description("Checks to see the that the JSON response indicates a missing or invalid parameter")] - public class JsonValidateInvalidParameter : JsonValidateError - { - // The value of the desired JSON property - [DisplayName("Invalid Value")] - public new string PropertyValue { get { return base.PropertyValue; } set { base.PropertyValue = String.Format("Missing or invalid {0} parameter", value); } } - } - - [DisplayName("JSON Response")] - [Description("Checks to see the that the JSON response contains the specified message")] - public class JsonValidateResponse : JsonValidateProperty - { - // The name of the desired JSON property - [DisplayName("Response")] - [DefaultValue("response")] - public new string PropertyName { get { return base.PropertyName; } set { base.PropertyName = value; } } - } - - [DisplayName("JSON Property")] - [Description("Checks to see the that the JSON response contains the specified property and is set to the specified value")] - public class JsonValidateProperty : JsonValidate - { - // The name of the desired JSON property - [DisplayName("Property")] - public string PropertyName { get; set; } - - // The value of the desired JSON property - [DisplayName("Value")] - public string PropertyValue { get; set; } - - // Is the value a regexp of the desired JSON property - [DisplayName("Regexp")] - [DefaultValue(false)] - public bool UseRegularExpression { get; set; } - - public override void Validate(object sender, ValidationEventArgs e) - { - RestObject response = ValidateJson(sender, e); - if (null == response) - return; - - if (null == response[PropertyName]) - { - e.Message = String.Format("{0} Not Found", PropertyName); - e.IsValid = false; - return; - } - - if (UseRegularExpression) - { - var re = new Regex(PropertyValue); - if (!re.IsMatch((string)response[PropertyName])) - { - e.Message = String.Format("{0} => '{1}' !~ '{2}'", PropertyName, response[PropertyName], PropertyValue); - e.IsValid = false; - return; - } - } - else - { - if (PropertyValue != (string)response[PropertyName]) - { - e.Message = String.Format("{0} => '{1}' != '{2}'", PropertyName, response[PropertyName], PropertyValue); - e.IsValid = false; - return; - } - } - - e.IsValid = true; - //e.WebTest.Context.Add(ContextParameterName, propertyValue); - } - } - - [DisplayName("JSON Has Properties")] - [Description("Checks to see the that the JSON response contains the specified properties (comma seperated)")] - public class JsonHasProperties : JsonValidate - { - // The name of the desired JSON properties to check - [DisplayName("Properties")] - [Description("A comma seperated list of property names to check exist")] - public string PropertyNames { get; set; } - - //--------------------------------------------------------------------- - public override void Validate(object sender, ValidationEventArgs e) - { - RestObject response = ValidateJson(sender, e); - if (null == response) - return; - foreach (var p in PropertyNames.Split(',')) - { - if (null == response[p]) - { - e.Message = String.Format("'{0}' Not Found", p); - e.IsValid = false; - return; - } - } - e.IsValid = true; - - //e.WebTest.Context.Add(ContextParameterName, propertyValue); - } - } - - public abstract class JsonValidate : ValidationRule - { - // The status of the JSON request - [DisplayName("JSON Status")] - [DefaultValue("200")] - public string JSonStatus { get; set; } - - public RestObject ValidateJson(object sender, ValidationEventArgs e) - { - if (string.IsNullOrWhiteSpace(e.Response.BodyString)) - { - e.IsValid = false; - e.Message = String.Format("Empty or null response {0}", e.Response.StatusCode); - return null; - } - JavaScriptSerializer serialiser = new JavaScriptSerializer(); - //dynamic data = serialiser.Deserialize(e.Response.BodyString); - RestObject response = serialiser.Deserialize(e.Response.BodyString); - - if (JSonStatus != response.Status) - { - e.IsValid = false; - e.Message = String.Format("Response Status '{0}' not '{1}'", response.Status, JSonStatus); - return null; - } - - return response; - } - } -} \ No newline at end of file diff --git a/TShockRestTestPlugin/TShockRestTestPlugin.csproj b/TShockRestTestPlugin/TShockRestTestPlugin.csproj deleted file mode 100644 index e315c7d3..00000000 --- a/TShockRestTestPlugin/TShockRestTestPlugin.csproj +++ /dev/null @@ -1,62 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {F2FEDAFB-58DE-4611-9168-A86112C346C7} - Library - Properties - TshockRestTestPlugin - TshockRestTestPlugin - v4.0 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - {49606449-072B-4CF5-8088-AA49DA586694} - TShockAPI - - - - - \ No newline at end of file From 9f8db9618841786c25e79c104ee6a1b61c9dd876 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 09:18:44 -0700 Subject: [PATCH 46/74] Make death in hardcore sting a little more --- TShockAPI/GetDataHandlers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 7dca2509..624e6285 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2314,6 +2314,7 @@ namespace TShockAPI { if (TShock.CharacterDB.RemovePlayer(args.Player.Account.ID)) { + args.Player.SendErrorMessage("You have fallen in hardcore mode, and your items have been lost forever."); TShock.CharacterDB.SeedInitialData(args.Player.Account); } } From 6d7c8aa01999b8de23faeeb9f6cac1c7efa127a8 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 20:13:25 -0700 Subject: [PATCH 47/74] TileKill -> PlaceChest (hook changed, so did packet); +Bouncer --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 56 +++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 74 ++++++++++-------------------------- 3 files changed, 77 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6df366..11b1dad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` object to `GetDataHandlers.LiquidSetEventArgs`. (@hakusaro) * Removed `TShock.StartInvasion` for public use (moved to Utils and marked internal). (@hakusaro) * Fixed invasions started by TShock not reporting size correctly and probably not working at all. (@hakusaro) +* Removed `GetDataHandlers.TileKill` and replaced it with `GetDataHandlers.PlaceChest` as the packet originally designated as tile kill is now only used for chests. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 31b31173..17bd69ef 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlaceChest.Register(OnPlaceChest); GetDataHandlers.LiquidSet.Register(OnLiquidSet); GetDataHandlers.ProjectileKill.Register(OnProjectileKill); GetDataHandlers.PlayerUpdate.Register(OnPlayerUpdate); @@ -53,6 +54,61 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnPlaceChest(object sender, GetDataHandlers.PlaceChestEventArgs args) + { + int tileX = args.TileX; + int tileY = args.TileY; + int flag = args.Flag; + + if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification)) + args.Handled = true; + return; + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + + if (flag != 0 && flag != 4 // if no container or container2 placement + && Main.tile[tileX, tileY].type != TileID.Containers + && Main.tile[tileX, tileY].type != TileID.Dressers + && Main.tile[tileX, tileY].type != TileID.Containers2 + && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != TileID.Dirt)) //Chest + { + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + + if (flag == 2) //place dresser + { + if ((TShock.Utils.TilePlacementValid(tileX, tileY + 1) && Main.tile[tileX, tileY + 1].type == TileID.Teleporter) || + (TShock.Utils.TilePlacementValid(tileX + 1, tileY + 1) && Main.tile[tileX + 1, tileY + 1].type == TileID.Teleporter)) + { + //Prevent a dresser from being placed on a teleporter, as this can cause client and server crashes. + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + } + + if (TShock.CheckTilePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY, 3); + args.Handled = true; + return; + } + } + /// Handles Bouncer's liquid set anti-cheat. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 624e6285..a519bc23 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -352,35 +352,41 @@ namespace TShockAPI } /// - /// For use in a TileKill event + /// For use in a PlaceChest event /// - public class TileKillEventArgs : HandledEventArgs + public class PlaceChestEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event + public TSPlayer Player { get; set; } + /// What the packet is doing (see MP packet docs). + public int Flag { get; set; } /// - /// The X coordinate that is being killed + /// The X coordinate /// public int TileX { get; set; } /// - /// The Y coordinate that is being killed + /// The Y coordinate /// public int TileY { get; set; } } /// - /// TileKill - When a tile is removed from the world + /// When a chest is added or removed from the world. /// - public static HandlerList TileKill; + public static HandlerList PlaceChest; - private static bool OnTileKill(int tilex, int tiley) + private static bool OnPlaceChest(TSPlayer player, int flag, int tilex, int tiley) { - if (TileKill == null) + if (PlaceChest == null) return false; - var args = new TileKillEventArgs + var args = new PlaceChestEventArgs { + Player = player, + Flag = flag, TileX = tilex, TileY = tiley, }; - TileKill.Invoke(null, args); + PlaceChest.Invoke(null, args); return args.Handled; } @@ -1391,7 +1397,7 @@ namespace TShockAPI { PacketTypes.ProjectileNew, HandleProjectileNew }, { PacketTypes.TogglePvp, HandleTogglePvp }, { PacketTypes.PlayerTeam, HandlePlayerTeam }, - { PacketTypes.TileKill, HandleTileKill }, + { PacketTypes.TileKill, HandlePlaceChest }, { PacketTypes.LiquidSet, HandleLiquidSet }, { PacketTypes.PlayerSpawn, HandleSpawn }, { PacketTypes.ChestGetContents, HandleChestOpen }, @@ -2335,56 +2341,16 @@ namespace TShockAPI return false; } - private static bool HandleTileKill(GetDataHandlerArgs args) + private static bool HandlePlaceChest(GetDataHandlerArgs args) { int flag = args.Data.ReadByte(); int tileX = args.Data.ReadInt16(); int tileY = args.Data.ReadInt16(); args.Data.ReadInt16(); // Ignore style - if (OnTileKill(tileX, tileY)) + if (OnPlaceChest(args.Player, flag, tileX, tileY)) return true; - if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification)) - return true; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - - if (flag != 0 && flag != 4 // if no container or container2 placement - && Main.tile[tileX, tileY].type != TileID.Containers - && Main.tile[tileX, tileY].type != TileID.Dressers - && Main.tile[tileX, tileY].type != TileID.Containers2 - && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != TileID.Dirt)) //Chest - { - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - - if (flag == 2) //place dresser - { - if ((TShock.Utils.TilePlacementValid(tileX, tileY + 1) && Main.tile[tileX, tileY + 1].type == TileID.Teleporter) || - (TShock.Utils.TilePlacementValid(tileX + 1, tileY + 1) && Main.tile[tileX + 1, tileY + 1].type == TileID.Teleporter)) - { - //Prevent a dresser from being placed on a teleporter, as this can cause client and server crashes. - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - } - - if (TShock.CheckTilePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } - - if (TShock.CheckRangePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY, 3); - return true; - } + return false; } From 863fa706c2e24c7cb1316f3d0163e1855d9bad5b Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 20:28:50 -0700 Subject: [PATCH 48/74] Document OnPlaceChest in Bouncer --- TShockAPI/Bouncer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 17bd69ef..6e9bdbf1 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -54,6 +54,9 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// The place chest event that Bouncer hooks to prevent accidental damage. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnPlaceChest(object sender, GetDataHandlers.PlaceChestEventArgs args) { int tileX = args.TileX; From be8cffddfd02e254a717607e036dc7facd0f19a0 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 20:31:54 -0700 Subject: [PATCH 49/74] Move OnChestOpen to Bouncer --- TShockAPI/Bouncer.cs | 26 ++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 18 ------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 6e9bdbf1..30268f41 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.ChestOpen.Register(OnChestOpen); GetDataHandlers.PlaceChest.Register(OnPlaceChest); GetDataHandlers.LiquidSet.Register(OnLiquidSet); GetDataHandlers.ProjectileKill.Register(OnProjectileKill); @@ -54,6 +55,31 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnChestOpen(object sender, GetDataHandlers.ChestOpenEventArgs args) + { + + if (TShock.CheckIgnores(args.Player)) + { + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, args.X, args.Y)) + { + args.Handled = true; + return; + } + + if (TShock.CheckTilePermission(args.Player, args.X, args.Y) && TShock.Config.RegionProtectChests) + { + args.Handled = true; + return; + } + + int id = Chest.FindChest(args.X, args.Y); + args.Player.ActiveChest = id; + } + /// The place chest event that Bouncer hooks to prevent accidental damage. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index da75b529..5606c50b 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2413,24 +2413,6 @@ namespace TShockAPI if (OnChestOpen(x, y, args.Player)) return true; - if (TShock.CheckIgnores(args.Player)) - { - return true; - } - - if (TShock.CheckRangePermission(args.Player, x, y)) - { - return true; - } - - if (TShock.CheckTilePermission(args.Player, x, y) && TShock.Config.RegionProtectChests) - { - return true; - } - - int id = Chest.FindChest(x, y); - args.Player.ActiveChest = id; - return false; } From 943f86615a5f893630f64963e71aab27192bdd5f Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 20:46:26 -0700 Subject: [PATCH 50/74] Move UpdateNPCHome to Bouncer --- TShockAPI/Bouncer.cs | 35 ++++++++++++++++++++++++++++++++++- TShockAPI/GetDataHandlers.cs | 23 +++++------------------ 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 30268f41..8bb255a0 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.NPCHome.Register(OnUpdateNPCHome); GetDataHandlers.ChestOpen.Register(OnChestOpen); GetDataHandlers.PlaceChest.Register(OnPlaceChest); GetDataHandlers.LiquidSet.Register(OnLiquidSet); @@ -55,9 +56,41 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// The Bouncer handler for when an NPC is rehomed. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnUpdateNPCHome(object sender, GetDataHandlers.NPCHomeChangeEventArgs args) + { + int id = args.ID; + short x = args.X; + short y = args.Y; + byte homeless = args.Homeless; + + // Calls to TShock.CheckTilePermission need to be broken up into different subsystems + // In particular, this handles both regions and other things. Ouch. + if (TShock.CheckTilePermission(args.Player, x, y)) + { + args.Player.SendErrorMessage("You do not have access to modify this area."); + args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, + Convert.ToByte(Main.npc[id].homeless)); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, x, y)) + { + args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, + Convert.ToByte(Main.npc[id].homeless)); + args.Handled = true; + return; + } + } + + /// The Bouncer handler for when chests are opened. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnChestOpen(object sender, GetDataHandlers.ChestOpenEventArgs args) { - if (TShock.CheckIgnores(args.Player)) { args.Handled = true; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 5606c50b..dead02ec 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1008,6 +1008,8 @@ namespace TShockAPI /// public class NPCHomeChangeEventArgs : HandledEventArgs { + /// The TSPlayer that caused the event. + public TSPlayer Player { get; set; } /// /// The Terraria playerID of the player /// @@ -1030,13 +1032,14 @@ namespace TShockAPI /// public static HandlerList NPCHome; - private static bool OnUpdateNPCHome(short id, short x, short y, byte homeless) + private static bool OnUpdateNPCHome(TSPlayer player, short id, short x, short y, byte homeless) { if (NPCHome == null) return false; var args = new NPCHomeChangeEventArgs { + Player = player, ID = id, X = x, Y = y, @@ -2514,7 +2517,7 @@ namespace TShockAPI var y = args.Data.ReadInt16(); var homeless = args.Data.ReadInt8(); - if (OnUpdateNPCHome(id, x, y, homeless)) + if (OnUpdateNPCHome(args.Player, id, x, y, homeless)) return true; if (!args.Player.HasPermission(Permissions.movenpc)) @@ -2524,22 +2527,6 @@ namespace TShockAPI Convert.ToByte(Main.npc[id].homeless)); return true; } - - if (TShock.CheckTilePermission(args.Player, x, y)) - { - args.Player.SendErrorMessage("You do not have access to modify this area."); - args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, - Convert.ToByte(Main.npc[id].homeless)); - return true; - } - - //removed until NPC Home packet actually sends their home coords. - /*if (TShock.CheckRangePermission(args.Player, x, y)) - { - args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, - Convert.ToByte(Main.npc[id].homeless)); - return true; - }*/ return false; } From bcc18160715ca36e1d33fdcb5c05a4889c50f52c Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 14 Dec 2017 20:54:04 -0700 Subject: [PATCH 51/74] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11b1dad9..4673edc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ Putting this stuff down here so things don't conflict as often. * Removed `TShock.StartInvasion` for public use (moved to Utils and marked internal). (@hakusaro) * Fixed invasions started by TShock not reporting size correctly and probably not working at all. (@hakusaro) * Removed `GetDataHandlers.TileKill` and replaced it with `GetDataHandlers.PlaceChest` as the packet originally designated as tile kill is now only used for chests. (@hakusaro) +* Added `TSPlayer` to `GetDataHandlers.NPCHome`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. From 845fc3b7c80d7df870dd241681abfce2ea9a41c9 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 12:12:21 -0700 Subject: [PATCH 52/74] Move OnChestItemChange to Bouncer Fix issue where TShock didn't properly do anti-cheat on chest item changes. --- CHANGELOG.md | 2 ++ TShockAPI/Bouncer.cs | 35 +++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 30 ++++++------------------------ 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4673edc0..b627f6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,8 @@ Putting this stuff down here so things don't conflict as often. * Fixed invasions started by TShock not reporting size correctly and probably not working at all. (@hakusaro) * Removed `GetDataHandlers.TileKill` and replaced it with `GetDataHandlers.PlaceChest` as the packet originally designated as tile kill is now only used for chests. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.NPCHome`. (@hakusaro) +* Added a `TSPlayer` to `GetDataHandlers.ChestItemChanged`. (@hakusaro) +* Fixed chest item changes not triggering any range checks, tile checks, or correct chest checks. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 8bb255a0..1aa6b22e 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.ChestItemChange.Register(OnChestItemChange); GetDataHandlers.NPCHome.Register(OnUpdateNPCHome); GetDataHandlers.ChestOpen.Register(OnChestOpen); GetDataHandlers.PlaceChest.Register(OnPlaceChest); @@ -56,6 +57,40 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnChestItemChange(object sender, GetDataHandlers.ChestItemEventArgs args) + { + short id = args.ID; + byte slot = args.Slot; + short stacks = args.Stacks; + byte prefix = args.Prefix; + short type = args.Type; + + if (args.Player.TPlayer.chest != id) + { + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.ChestItem, "", id, slot); + args.Handled = true; + return; + } + + if (TShock.CheckTilePermission(args.Player, Main.chest[id].x, Main.chest[id].y) && TShock.Config.RegionProtectChests) + { + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, Main.chest[id].x, Main.chest[id].y)) + { + args.Handled = true; + return; + } + } + /// The Bouncer handler for when an NPC is rehomed. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index dead02ec..8431a27d 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -922,6 +922,8 @@ namespace TShockAPI /// public class ChestItemEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } /// /// ChestID /// @@ -948,13 +950,14 @@ namespace TShockAPI /// public static HandlerList ChestItemChange; - private static bool OnChestItemChange(short id, byte slot, short stacks, byte prefix, short type) + private static bool OnChestItemChange(TSPlayer player, short id, byte slot, short stacks, byte prefix, short type) { if (ChestItemChange == null) return false; var args = new ChestItemEventArgs { + Player = player, ID = id, Slot = slot, Stacks = stacks, @@ -2452,35 +2455,14 @@ namespace TShockAPI var prefix = args.Data.ReadInt8(); var type = args.Data.ReadInt16(); - if (OnChestItemChange(id, slot, stacks, prefix, type)) + if (OnChestItemChange(args.Player, id, slot, stacks, prefix, type)) return true; - if (args.TPlayer.chest != id) - { - return false; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.ChestItem, "", id, slot); - return true; - } - Item item = new Item(); item.netDefaults(type); if (stacks > item.maxStack || TShock.Itembans.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), args.Player)) { - return false; - } - - if (TShock.CheckTilePermission(args.Player, Main.chest[id].x, Main.chest[id].y) && TShock.Config.RegionProtectChests) - { - return false; - } - - if (TShock.CheckRangePermission(args.Player, Main.chest[id].x, Main.chest[id].y)) - { - return false; + return true; } return false; From c9955a74ec4e471e5aaf51b367018540155d23c7 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 12:14:10 -0700 Subject: [PATCH 53/74] Document OnChestItemChange --- TShockAPI/Bouncer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 1aa6b22e..5dbf22db 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -57,6 +57,9 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles when a chest item is changed. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnChestItemChange(object sender, GetDataHandlers.ChestItemEventArgs args) { short id = args.ID; From 5cdb38675cacc231932820516a695c02b822a9cc Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 17:51:16 -0700 Subject: [PATCH 54/74] Move OnPlayerBuff logic to Bouncer --- CHANGELOG.md | 3 +- TShockAPI/Bouncer.cs | 58 ++++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 42 +++----------------------- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b627f6c6..a84786df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,8 +70,9 @@ Putting this stuff down here so things don't conflict as often. * Fixed invasions started by TShock not reporting size correctly and probably not working at all. (@hakusaro) * Removed `GetDataHandlers.TileKill` and replaced it with `GetDataHandlers.PlaceChest` as the packet originally designated as tile kill is now only used for chests. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.NPCHome`. (@hakusaro) -* Added a `TSPlayer` to `GetDataHandlers.ChestItemChanged`. (@hakusaro) +* Added `TSPlayer` to `GetDataHandlers.ChestItemChanged`. (@hakusaro) * Fixed chest item changes not triggering any range checks, tile checks, or correct chest checks. (@hakusaro) +* Added `TSPlayer` to `GetDataHandlers.PlayerBuff`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 5dbf22db..59eab38e 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlayerBuff.Register(OnPlayerBuff); GetDataHandlers.ChestItemChange.Register(OnChestItemChange); GetDataHandlers.NPCHome.Register(OnUpdateNPCHome); GetDataHandlers.ChestOpen.Register(OnChestOpen); @@ -57,6 +58,63 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles Buff events. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnPlayerBuff(object sender, GetDataHandlers.PlayerBuffEventArgs args) + { + byte id = args.ID; + byte type = args.Type; + int time = args.Time; + + if (TShock.Players[id] == null) + { + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Handled = true; + return; + } + + if (id >= Main.maxPlayers) + { + args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Handled = true; + return; + } + + if (!TShock.Players[id].TPlayer.hostile || !Main.pvpBuff[type]) + { + args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 50)) + { + args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Handled = true; + return; + } + + if (WhitelistBuffMaxTime[type] > 0 && time <= WhitelistBuffMaxTime[type]) + { + args.Handled = false; + return; + } + } + /// Handles when a chest item is changed. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 8431a27d..25115035 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1057,6 +1057,7 @@ namespace TShockAPI /// public class PlayerBuffEventArgs : HandledEventArgs { + public TSPlayer Player { get; set; } /// /// The Terraria playerID of the player /// @@ -1075,13 +1076,14 @@ namespace TShockAPI /// public static HandlerList PlayerBuff; - private static bool OnPlayerBuff(byte id, byte type, int time) + private static bool OnPlayerBuff(TSPlayer player, byte id, byte type, int time) { if (PlayerBuff == null) return false; var args = new PlayerBuffEventArgs { + Player = player, ID = id, Type = type, Time = time @@ -2518,45 +2520,9 @@ namespace TShockAPI var type = args.Data.ReadInt8(); var time = args.Data.ReadInt32(); - if (OnPlayerBuff(id, type, time)) + if (OnPlayerBuff(args.Player, id, type, time)) return true; - if (TShock.Players[id] == null) - return false; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - return true; - } - - if (id >= Main.maxPlayers) - { - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - return true; - } - - if (!TShock.Players[id].TPlayer.hostile || !Main.pvpBuff[type]) - { - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - return true; - } - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 50)) - { - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - return true; - } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - return true; - } - - if (WhitelistBuffMaxTime[type] > 0 && time <= WhitelistBuffMaxTime[type]) - { - return false; - } - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); return true; } From 82e2ecb66247db7fd6145c48c24abf78c5f9906d Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 18:11:35 -0700 Subject: [PATCH 55/74] Move OnItemDrop to Bouncer --- TShockAPI/Bouncer.cs | 91 ++++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 59 ----------------------- 2 files changed, 91 insertions(+), 59 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 59eab38e..90b2e461 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.ItemDrop.Register(OnItemDrop); GetDataHandlers.PlayerBuff.Register(OnPlayerBuff); GetDataHandlers.ChestItemChange.Register(OnChestItemChange); GetDataHandlers.NPCHome.Register(OnUpdateNPCHome); @@ -58,6 +59,96 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Registered when items fall to the ground to prevent cheating. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnItemDrop(object sender, GetDataHandlers.ItemDropEventArgs args) + { + short id = args.ID; + Vector2 pos = args.Position; + Vector2 vel = args.Velocity; + short stacks = args.Stacks; + short prefix = args.Prefix; + bool noDelay = args.NoDelay; + short type = args.Type; + + // player is attempting to crash clients + if (type < -48 || type >= Main.maxItemTypes) + { + // Causes item duplications. Will be re added later if necessary + //args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + + //make sure the prefix is a legit value + if (prefix > PrefixID.Count) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + + //Item removed, let client do this to prevent item duplication + // client side (but only if it passed the range check) + if (type == 0) + { + if (TShock.CheckRangePermission(args.Player, (int)(Main.item[id].position.X / 16f), (int)(Main.item[id].position.Y / 16f))) + { + // Causes item duplications. Will be re added if necessary + //args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, (int)(pos.X / 16f), (int)(pos.Y / 16f))) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + + // stop the client from changing the item type of a drop but + // only if the client isn't picking up the item + if (Main.item[id].active && Main.item[id].netID != type) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + + Item item = new Item(); + item.netDefaults(type); + if ((stacks > item.maxStack || stacks <= 0) || (TShock.Itembans.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), args.Player) && !args.Player.HasPermission(Permissions.allowdroppingbanneditems))) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + + // TODO: Remove item ban part of this check + if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.LogonDiscardThreshold)) + { + //Player is probably trying to sneak items onto the server in their hands!!! + TShock.Log.ConsoleInfo("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.Name); + args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + args.Handled = true; + return; + } + } + /// Handles Buff events. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 25115035..cc472d38 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2540,65 +2540,6 @@ namespace TShockAPI if (OnItemDrop(args.Player, id, pos, vel, stacks, prefix, noDelay, type)) return true; - // player is attempting to crash clients - if (type < -48 || type >= Main.maxItemTypes) - { - // Causes item duplications. Will be re added later if necessary - //args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - if (prefix > PrefixID.Count) //make sure the prefix is a legit value - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - if (type == 0) //Item removed, let client do this to prevent item duplication client side (but only if it passed the range check) - { - if (TShock.CheckRangePermission(args.Player, (int)(Main.item[id].position.X / 16f), (int)(Main.item[id].position.Y / 16f))) - { - // Causes item duplications. Will be re added if necessary - //args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - return false; - } - - if (TShock.CheckRangePermission(args.Player, (int)(pos.X / 16f), (int)(pos.Y / 16f))) - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - if (Main.item[id].active && Main.item[id].netID != type) //stop the client from changing the item type of a drop but only if the client isn't picking up the item - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - Item item = new Item(); - item.netDefaults(type); - if ((stacks > item.maxStack || stacks <= 0) || (TShock.Itembans.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), args.Player) && !args.Player.HasPermission(Permissions.allowdroppingbanneditems))) - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.LogonDiscardThreshold)) - { - //Player is probably trying to sneak items onto the server in their hands!!! - TShock.Log.ConsoleInfo("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.Name); - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - - } - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - return false; } From 01d865fddca261075ecc37e4b3fb786536925b08 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 18:27:55 -0700 Subject: [PATCH 56/74] Move OnPlayerDamage to Bouncer Remove reference to PlayerDamage v1 hook --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 76 +++++++++++++++++++-- TShockAPI/GetDataHandlers.cs | 129 ++--------------------------------- 3 files changed, 80 insertions(+), 126 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84786df..ba907aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` to `GetDataHandlers.ChestItemChanged`. (@hakusaro) * Fixed chest item changes not triggering any range checks, tile checks, or correct chest checks. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.PlayerBuff`. (@hakusaro) +* Added `TSPlayer` and `PlayerDeathReason` to `GetDataHandlers.PlayerDamage`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 90b2e461..dfc53968 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -28,7 +28,6 @@ using TShockAPI.Localization; using static TShockAPI.GetDataHandlers; using TerrariaApi.Server; using Terraria.ObjectData; -using Terraria.ID; using Terraria.DataStructures; namespace TShockAPI @@ -36,7 +35,7 @@ namespace TShockAPI /// Bouncer is the TShock anti-hack and build guardian system internal sealed class Bouncer { - /// Constructor call initializes Bouncer & related functionality. + /// Constructor call initializes Bouncer and related functionality. /// A new Bouncer. internal Bouncer(TerrariaPlugin pluginInstance) { @@ -59,6 +58,75 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Called when a player is damaged. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnPlayerDamage(object sender, GetDataHandlers.PlayerDamageEventArgs args) + { + byte id = args.ID; + short dmg = args.Damage; + bool pvp = args.PVP; + bool crit = args.Critical; + byte direction = args.Direction; + + if (id >= Main.maxPlayers || TShock.Players[id] == null) + { + args.Handled = true; + return; + } + + if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) + { + if (TShock.Config.KickOnDamageThresholdBroken) + { + TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); + args.Handled = true; + return; + } + else + { + args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); + } + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if (!TShock.Players[id].TPlayer.hostile && pvp && id != args.Player.Index) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + } + /// Registered when items fall to the ground to prevent cheating. /// The object that triggered the event. /// The packet arguments that the event has. @@ -498,7 +566,7 @@ namespace TShockAPI } } - /// Handles ProjectileKill events for throttling & out of bounds projectiles. + /// Handles ProjectileKill events for throttling and out of bounds projectiles. /// The object that triggered the event. /// The packet arguments that the event has. internal void OnProjectileKill(object sender, GetDataHandlers.ProjectileKillEventArgs args) @@ -524,7 +592,7 @@ namespace TShockAPI } } - /// Handles disabling enforcement & minor anti-exploit stuff + /// Handles disabling enforcement and minor anti-exploit stuff /// The object that triggered the event. /// The packet arguments that the event has. internal void OnPlayerUpdate(object sender, GetDataHandlers.PlayerUpdateEventArgs args) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index cc472d38..27bd2dd8 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1161,6 +1161,7 @@ namespace TShockAPI /// public class PlayerDamageEventArgs : HandledEventArgs { + public TSPlayer Player { get; set; } /// /// The Terraria playerID of the player /// @@ -1181,24 +1182,28 @@ namespace TShockAPI /// Is the damage critical? /// public bool Critical { get; set; } + /// The reason the player took damage and/or died. + public PlayerDeathReason PlayerDeathReason { get; set; } } /// /// PlayerDamage - Called when a player is damaged /// public static HandlerList PlayerDamage; - private static bool OnPlayerDamage(byte id, byte dir, short dmg, bool pvp, bool crit) + private static bool OnPlayerDamage(TSPlayer player, byte id, byte dir, short dmg, bool pvp, bool crit, PlayerDeathReason playerDeathReason) { if (PlayerDamage == null) return false; var args = new PlayerDamageEventArgs { + Player = player, ID = id, Direction = dir, Damage = dmg, PVP = pvp, Critical = crit, + PlayerDeathReason = playerDeathReason, }; PlayerDamage.Invoke(null, args); return args.Handled; @@ -1421,7 +1426,6 @@ namespace TShockAPI { PacketTypes.ItemOwner, HandleItemOwner }, { PacketTypes.PlayerHp, HandlePlayerHp }, { PacketTypes.PlayerMana, HandlePlayerMana }, - { PacketTypes.PlayerDamage, HandlePlayerDamage }, { PacketTypes.NpcStrike, HandleNpcStrike }, { PacketTypes.NpcSpecial, HandleSpecial }, { PacketTypes.PlayerAnimation, HandlePlayerAnimation }, @@ -2560,76 +2564,6 @@ namespace TShockAPI return false; } - private static bool HandlePlayerDamage(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var direction = (byte)(args.Data.ReadInt8() - 1); - var dmg = args.Data.ReadInt16(); - args.Data.ReadString(); // don't store damage text - var bits = (BitsByte)args.Data.ReadInt8(); - var pvp = bits[0]; - var crit = bits[1]; - - if (OnPlayerDamage(id, direction, dmg, pvp, crit)) - return true; - - if (id >= Main.maxPlayers || TShock.Players[id] == null) - { - return true; - } - - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) - { - if (TShock.Config.KickOnDamageThresholdBroken) - { - TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); - return true; - } - else - { - args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); - } - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (!TShock.Players[id].TPlayer.hostile && pvp && id != args.Player.Index) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.Players[id].GodMode) - { - TShock.Players[id].Heal(args.TPlayer.statLifeMax); - } - - return false; - } - private static bool HandlePlayerDamageV2(GetDataHandlerArgs args) { var id = args.Data.ReadInt8(); @@ -2640,58 +2574,9 @@ namespace TShockAPI var crit = bits[0]; var pvp = bits[1]; - if (OnPlayerDamage(id, direction, dmg, pvp, crit)) + if (OnPlayerDamage(args.Player, id, direction, dmg, pvp, crit, playerDeathReason)) return true; - if (id >= Main.maxPlayers || TShock.Players[id] == null) - { - return true; - } - - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) - { - if (TShock.Config.KickOnDamageThresholdBroken) - { - TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); - return true; - } - else - { - args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); - } - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (!TShock.Players[id].TPlayer.hostile && pvp && id != args.Player.Index) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - if (TShock.Players[id].GodMode) { TShock.Players[id].Heal(args.TPlayer.statLifeMax); From 007c685c19f627cd0b9957d1af61882bfdd7bfc8 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 21:42:20 -0700 Subject: [PATCH 57/74] Move OnNPCStrike to Bouncer --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 58 ++++++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 44 ++++----------------------- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 907240f0..abd236ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Putting this stuff down here so things don't conflict as often. * Fixed chest item changes not triggering any range checks, tile checks, or correct chest checks. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.PlayerBuff`. (@hakusaro) * Added `TSPlayer` and `PlayerDeathReason` to `GetDataHandlers.PlayerDamage`. (@hakusaro) +* Added `TSPlayer` to `GetDataHandlers.NPCStrike`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index dfc53968..5a759abd 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -41,6 +41,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.NPCStrike.Register(OnNPCStrike); GetDataHandlers.ItemDrop.Register(OnItemDrop); GetDataHandlers.PlayerBuff.Register(OnPlayerBuff); GetDataHandlers.ChestItemChange.Register(OnChestItemChange); @@ -58,6 +59,63 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles the NPC Strike event for Bouncer. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnNPCStrike(object sender, GetDataHandlers.NPCStrikeEventArgs args) + { + short id = args.ID; + byte direction = args.Direction; + short dmg = args.Damage; + float knockback = args.Knockback; + byte crit = args.Critical; + + if (Main.npc[id] == null) + { + args.Handled = true; + return; + } + + if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) + { + if (TShock.Config.KickOnDamageThresholdBroken) + { + TShock.Utils.Kick(args.Player, string.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage)); + args.Handled = true; + return; + } + else + { + args.Player.Disable(String.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); + } + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + args.Handled = true; + return; + } + + if (TShock.Config.RangeChecks && + TShock.CheckRangePermission(args.Player, (int)(Main.npc[id].position.X / 16f), (int)(Main.npc[id].position.Y / 16f), 128)) + { + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + args.Handled = true; + return; + } + } + /// Called when a player is damaged. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 27bd2dd8..e6555cc3 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1214,6 +1214,8 @@ namespace TShockAPI /// public class NPCStrikeEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } /// /// ??? /// @@ -1240,13 +1242,14 @@ namespace TShockAPI /// public static HandlerList NPCStrike; - private static bool OnNPCStrike(short id, byte dir, short dmg, float knockback, byte crit) + private static bool OnNPCStrike(TSPlayer player, short id, byte dir, short dmg, float knockback, byte crit) { if (NPCStrike == null) return false; var args = new NPCStrikeEventArgs { + Player = player, ID = id, Direction = dir, Damage = dmg, @@ -2593,33 +2596,9 @@ namespace TShockAPI var direction = (byte)(args.Data.ReadInt8() - 1); var crit = args.Data.ReadInt8(); - if (OnNPCStrike(id, direction, dmg, knockback, crit)) + if (OnNPCStrike(args.Player, id, direction, dmg, knockback, crit)) return true; - if (Main.npc[id] == null) - return true; - - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) - { - if (TShock.Config.KickOnDamageThresholdBroken) - { - TShock.Utils.Kick(args.Player, string.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage)); - return true; - } - else - { - args.Player.Disable(String.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); - } - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - if (Main.npc[id].townNPC && !args.Player.HasPermission(Permissions.hurttownnpc)) { args.Player.SendErrorMessage("You do not have permission to hurt this NPC."); @@ -2627,19 +2606,6 @@ namespace TShockAPI return true; } - if (TShock.Config.RangeChecks && - TShock.CheckRangePermission(args.Player, (int)(Main.npc[id].position.X / 16f), (int)(Main.npc[id].position.Y / 16f), 128)) - { - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - return false; } From d03e899452847e0a387ff305adf8db79f4c21146 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 21:43:21 -0700 Subject: [PATCH 58/74] dmg -> damage --- TShockAPI/Bouncer.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 5a759abd..f1e62ab8 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -66,7 +66,7 @@ namespace TShockAPI { short id = args.ID; byte direction = args.Direction; - short dmg = args.Damage; + short damage = args.Damage; float knockback = args.Knockback; byte crit = args.Critical; @@ -76,7 +76,7 @@ namespace TShockAPI return; } - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) + if (damage > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) { if (TShock.Config.KickOnDamageThresholdBroken) { @@ -122,7 +122,7 @@ namespace TShockAPI internal void OnPlayerDamage(object sender, GetDataHandlers.PlayerDamageEventArgs args) { byte id = args.ID; - short dmg = args.Damage; + short damage = args.Damage; bool pvp = args.PVP; bool crit = args.Critical; byte direction = args.Direction; @@ -133,7 +133,7 @@ namespace TShockAPI return; } - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) + if (damage > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) { if (TShock.Config.KickOnDamageThresholdBroken) { @@ -758,14 +758,14 @@ namespace TShockAPI /// The packet arguments that the event has. internal void OnKillMe(object sender, GetDataHandlers.KillMeEventArgs args) { - short dmg = args.Damage; + short damage = args.Damage; short id = args.PlayerId; PlayerDeathReason playerDeathReason = args.PlayerDeathReason; - if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server. + if (damage > 20000) //Abnormal values have the potential to cause infinite loops in the server. { TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); - TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg); + TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", damage); args.Handled = true; return; } @@ -797,7 +797,7 @@ namespace TShockAPI Vector2 pos = args.Position; Vector2 vel = args.Velocity; float knockback = args.Knockback; - short dmg = args.Damage; + short damage = args.Damage; byte owner = args.Owner; short type = args.Type; int index = args.Index; @@ -818,7 +818,7 @@ namespace TShockAPI return; } - if (dmg > TShock.Config.MaxProjDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) + if (damage > TShock.Config.MaxProjDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) { args.Player.Disable(String.Format("Projectile damage is higher than {0}.", TShock.Config.MaxProjDamage), DisableFlags.WriteToLogAndConsole); args.Player.RemoveProjectile(ident, owner); From cdba07c62e0fd268c2a3e9549f9072ef1f44f73e Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 21:50:20 -0700 Subject: [PATCH 59/74] Move OnPlayerAnimation to Bouncer --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 23 ++++++++++++++++++++++- TShockAPI/GetDataHandlers.cs | 23 ++++++++--------------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abd236ca..83383492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` to `GetDataHandlers.PlayerBuff`. (@hakusaro) * Added `TSPlayer` and `PlayerDeathReason` to `GetDataHandlers.PlayerDamage`. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.NPCStrike`. (@hakusaro) +* Added `TSPlayer` to `GetDataHandlers.PlayerAnimation`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index f1e62ab8..ab291c3a 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -41,6 +41,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlayerAnimation.Register(OnPlayerAnimation); GetDataHandlers.NPCStrike.Register(OnNPCStrike); GetDataHandlers.ItemDrop.Register(OnItemDrop); GetDataHandlers.PlayerBuff.Register(OnPlayerBuff); @@ -59,6 +60,26 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles basic animation throttling for disabled players. + /// sender + /// args + internal void OnPlayerAnimation(object sender, GetDataHandlers.PlayerAnimationEventArgs args) + { + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); + args.Handled = true; + return; + } + } + /// Handles the NPC Strike event for Bouncer. /// The object that triggered the event. /// The packet arguments that the event has. @@ -69,7 +90,7 @@ namespace TShockAPI short damage = args.Damage; float knockback = args.Knockback; byte crit = args.Critical; - + if (Main.npc[id] == null) { args.Handled = true; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index e6555cc3..b6d182b7 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1298,6 +1298,8 @@ namespace TShockAPI /// public class PlayerAnimationEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } } /// @@ -1305,12 +1307,15 @@ namespace TShockAPI /// public static HandlerList PlayerAnimation; - private static bool OnPlayerAnimation() + private static bool OnPlayerAnimation(TSPlayer player) { if (PlayerAnimation == null) return false; - var args = new PlayerAnimationEventArgs { }; + var args = new PlayerAnimationEventArgs + { + Player = player, + }; PlayerAnimation.Invoke(null, args); return args.Handled; } @@ -2635,21 +2640,9 @@ namespace TShockAPI private static bool HandlePlayerAnimation(GetDataHandlerArgs args) { - if (OnPlayerAnimation()) + if (OnPlayerAnimation(args.Player)) return true; - 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; } From 681f2a2432b84e0dc9c3bbd60dbd862c6f329d13 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 22:15:17 -0700 Subject: [PATCH 60/74] Add & move OnMassWireOperation hook to Bouncer --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 37 ++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 73 +++++++++++++++++++++++------------- 3 files changed, 85 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83383492..574c1962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` and `PlayerDeathReason` to `GetDataHandlers.PlayerDamage`. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.NPCStrike`. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.PlayerAnimation`. (@hakusaro) +* Added `GetDataHandlers.MassWireOperation` hook and related arguments. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index ab291c3a..f7e1628e 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -60,6 +60,43 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + internal void OnMassWireOperation(object sender, GetDataHandlers.MassWireOperationEventArgs args) + { + short startX = args.StartX; + short startY = args.StartY; + short endX = args.EndX; + short endY = args.EndY; + + List points = Utils.Instance.GetMassWireOperationRange( + new Point(startX, startY), + new Point(endX, endY), + args.Player.TPlayer.direction == 1); + + int x; + int y; + foreach (Point p in points) + { + /* Perform similar checks to TileKill + * The server-side nature of this packet removes the need to use SendTileSquare + * Range checks are currently ignored here as the items that send this seem to have infinite range */ + + x = p.X; + y = p.Y; + + if (!TShock.Utils.TilePlacementValid(x, y) || (args.Player.Dead && TShock.Config.PreventDeadModification)) + args.Handled = true; + return; + + if (TShock.CheckIgnores(args.Player)) + args.Handled = true; + return; + + if (TShock.CheckTilePermission(args.Player, x, y)) + args.Handled = true; + return; + } + } + /// Handles basic animation throttling for disabled players. /// sender /// args diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index b6d182b7..eb7aa572 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1260,6 +1260,50 @@ namespace TShockAPI return args.Handled; } + /// The arguments to the MassWireOperation event. + public class MassWireOperationEventArgs : HandledEventArgs + { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } + + /// The start X point in the operation. + public short StartX { get; set; } + + /// The start Y point in the operation. + public short StartY { get; set; } + + /// The end X point in the operation. + public short EndX { get; set; } + + /// The end Y point in the operation. + public short EndY { get; set; } + + /// ToolMode + public byte ToolMode { get; set; } + } + + /// Fired on a mass wire edit operation. + public static HandlerList MassWireOperation; + + private static bool OnMassWireOperation(TSPlayer player, short startX, short startY, short endX, short endY, byte toolMode) + { + if (MassWireOperation == null) + return false; + + var args = new MassWireOperationEventArgs + { + Player = player, + StartX = startX, + StartY = startY, + EndX = endX, + EndY = endY, + ToolMode = toolMode, + }; + + MassWireOperation.Invoke(null, args); + return args.Handled; + } + /// /// For use with a NPCSpecial event /// @@ -2987,33 +3031,10 @@ namespace TShockAPI short startY = args.Data.ReadInt16(); short endX = args.Data.ReadInt16(); short endY = args.Data.ReadInt16(); - args.Data.ReadByte(); // Ignore toolmode + byte toolMode = (byte) args.Data.ReadByte(); - List points = Utils.Instance.GetMassWireOperationRange( - new Point(startX, startY), - new Point(endX, endY), - args.Player.TPlayer.direction == 1); - - int x; - int y; - foreach (Point p in points) - { - /* Perform similar checks to TileKill - * The server-side nature of this packet removes the need to use SendTileSquare - * Range checks are currently ignored here as the items that send this seem to have infinite range */ - - x = p.X; - y = p.Y; - - if (!TShock.Utils.TilePlacementValid(x, y) || (args.Player.Dead && TShock.Config.PreventDeadModification)) - return true; - - if (TShock.CheckIgnores(args.Player)) - return true; - - if (TShock.CheckTilePermission(args.Player, x, y)) - return true; - } + if (OnMassWireOperation(args.Player, startX, startY, endX, endY, toolMode)) + return true; return false; } From 64facfc10cffe9e84f4c148fe791dd94c2b49ac9 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 22:29:52 -0700 Subject: [PATCH 61/74] Document internal mass wire op in Bouncer --- TShockAPI/Bouncer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index f7e1628e..731abbda 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -60,6 +60,9 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles validation of of basic anti-cheat on mass wire operations. + /// The object that triggered the event. + /// The packet arguments that the event has. internal void OnMassWireOperation(object sender, GetDataHandlers.MassWireOperationEventArgs args) { short startX = args.StartX; From de017f2d416c20fc573445be5be2511369f58521 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 22:51:07 -0700 Subject: [PATCH 62/74] Create & move OnPlaceTileEntity to Bouncer; fix unreachable code --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 33 ++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 60 ++++++++++++++++++++++++++---------- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 574c1962..9b591efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` to `GetDataHandlers.NPCStrike`. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.PlayerAnimation`. (@hakusaro) * Added `GetDataHandlers.MassWireOperation` hook and related arguments. (@hakusaro) +* Added `GetDataHandlers.PlaceTileEntity` hook and related arguments. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 731abbda..b8df3ddb 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -41,6 +41,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlaceTileEntity.Register(OnPlaceTileEntity); GetDataHandlers.PlayerAnimation.Register(OnPlayerAnimation); GetDataHandlers.NPCStrike.Register(OnNPCStrike); GetDataHandlers.ItemDrop.Register(OnItemDrop); @@ -60,6 +61,30 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Fired when a PlaceTileEntity occurs for basic anti-cheat on perms and range. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnPlaceTileEntity(object sender, GetDataHandlers.PlaceTileEntityEventArgs args) + { + if (TShock.CheckIgnores(args.Player)) + { + args.Handled = true; + return; + } + + if (TShock.CheckTilePermission(args.Player, args.X, args.Y)) + { + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, args.X, args.Y)) + { + args.Handled = true; + return; + } + } + /// Handles validation of of basic anti-cheat on mass wire operations. /// The object that triggered the event. /// The packet arguments that the event has. @@ -87,16 +112,22 @@ namespace TShockAPI y = p.Y; if (!TShock.Utils.TilePlacementValid(x, y) || (args.Player.Dead && TShock.Config.PreventDeadModification)) + { args.Handled = true; return; + } if (TShock.CheckIgnores(args.Player)) + { args.Handled = true; return; + } if (TShock.CheckTilePermission(args.Player, x, y)) + { args.Handled = true; return; + } } } @@ -497,8 +528,10 @@ namespace TShockAPI int flag = args.Flag; if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification)) + { args.Handled = true; return; + } if (TShock.CheckIgnores(args.Player)) { diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index eb7aa572..6721d5a1 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1304,6 +1304,42 @@ namespace TShockAPI return args.Handled; } + /// For use in a PlaceTileEntity event. + public class PlaceTileEntityEventArgs : HandledEventArgs + { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } + + /// The X coordinate of the event. + public short X { get; set; } + + /// The Y coordinate of the event. + public short Y { get; set; } + + /// The Type of event. + public byte Type { get; set; } + } + + /// Fired when a PlaceTileEntity event occurs. + public static HandlerList PlaceTileEntity; + + private static bool OnPlaceTileEntity(TSPlayer player, short x, short y, byte type) + { + if (PlaceTileEntity == null) + return false; + + var args = new PlaceTileEntityEventArgs + { + Player = player, + X = x, + Y = y, + Type = type + }; + + PlaceTileEntity.Invoke(null, args); + return args.Handled; + } + /// /// For use with a NPCSpecial event /// @@ -3175,7 +3211,14 @@ namespace TShockAPI { var x = args.Data.ReadInt16(); var y = args.Data.ReadInt16(); - var type = args.Data.ReadByte(); + var type = (byte) args.Data.ReadByte(); + + if (OnPlaceTileEntity(args.Player, x, y, type)) + { + return true; + } + + // ItemBan subsystem if (TShock.TileBans.TileIsBanned((short)TileID.LogicSensor, args.Player)) { @@ -3184,21 +3227,6 @@ namespace TShockAPI return true; } - if (TShock.CheckIgnores(args.Player)) - { - return true; - } - - if (TShock.CheckTilePermission(args.Player, x, y)) - { - return true; - } - - if (TShock.CheckRangePermission(args.Player, x, y)) - { - return true; - } - return false; } From 748d7f7fab0e9cc3d25c82ae2bf2c74e8543fc60 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 22:58:41 -0700 Subject: [PATCH 63/74] Move OnGemLockToggle -> Bouncer --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 31 +++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 32 +++++++------------------------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b591efc..e48fd0cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,6 +79,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` to `GetDataHandlers.PlayerAnimation`. (@hakusaro) * Added `GetDataHandlers.MassWireOperation` hook and related arguments. (@hakusaro) * Added `GetDataHandlers.PlaceTileEntity` hook and related arguments. (@hakusaro) +* Added `TSPlayer` to `GetDataHandlers.GemLockToggle`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index b8df3ddb..d29b94ae 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -41,6 +41,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.GemLockToggle.Register(OnGemLockToggle); GetDataHandlers.PlaceTileEntity.Register(OnPlaceTileEntity); GetDataHandlers.PlayerAnimation.Register(OnPlayerAnimation); GetDataHandlers.NPCStrike.Register(OnNPCStrike); @@ -61,6 +62,36 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Handles the anti-cheat components of gem lock toggles. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnGemLockToggle(object sender, GetDataHandlers.GemLockToggleEventArgs args) + { + if (args.X < 0 || args.Y < 0 || args.X >= Main.maxTilesX || args.Y >= Main.maxTilesY) + { + args.Handled = true; + return; + } + + if (!TShock.Utils.TilePlacementValid(args.X, args.Y) || (args.Player.Dead && TShock.Config.PreventDeadModification)) + { + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Handled = true; + return; + } + + if (TShock.CheckTilePermission(args.Player, args.X, args.Y)) + { + args.Handled = true; + return; + } + } + /// Fired when a PlaceTileEntity occurs for basic anti-cheat on perms and range. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 6721d5a1..8e10eb98 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -3080,14 +3080,16 @@ namespace TShockAPI /// public class GemLockToggleEventArgs : HandledEventArgs { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } /// /// X Location /// - public Int32 X { get; set; } + public short X { get; set; } /// /// Y Location /// - public Int32 Y { get; set; } + public short Y { get; set; } /// /// On status /// @@ -3099,7 +3101,7 @@ namespace TShockAPI /// public static HandlerList GemLockToggle; - private static bool OnGemLockToggle(Int32 x, Int32 y, bool on) + private static bool OnGemLockToggle(short x, short y, bool on) { if (GemLockToggle == null) return false; @@ -3116,15 +3118,10 @@ namespace TShockAPI private static bool HandleGemLockToggle(GetDataHandlerArgs args) { - var x = (int)args.Data.ReadInt16(); - var y = (int)args.Data.ReadInt16(); + var x = args.Data.ReadInt16(); + var y = args.Data.ReadInt16(); var on = args.Data.ReadBoolean(); - if (x < 0 || y < 0 || x >= Main.maxTilesX || y >= Main.maxTilesY) - { - return true; - } - if (OnGemLockToggle(x, y, on)) { return true; @@ -3135,21 +3132,6 @@ namespace TShockAPI return false; } - if (!TShock.Utils.TilePlacementValid(x, y) || (args.Player.Dead && TShock.Config.PreventDeadModification)) - { - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - return true; - } - - if (TShock.CheckTilePermission(args.Player, x, y)) - { - return true; - } - return false; } From 9f7c3ead09bb090e686c59430297f7c328619a42 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Fri, 15 Dec 2017 23:15:43 -0700 Subject: [PATCH 64/74] Add & move OnPlaceItemFrame to Bouncer --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 29 +++++++++++++++++ TShockAPI/GetDataHandlers.cs | 63 ++++++++++++++++++++++++++++-------- 3 files changed, 79 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e48fd0cc..226bcfe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Putting this stuff down here so things don't conflict as often. * Added `GetDataHandlers.MassWireOperation` hook and related arguments. (@hakusaro) * Added `GetDataHandlers.PlaceTileEntity` hook and related arguments. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.GemLockToggle`. (@hakusaro) +* Added `GetDataHandlers.PlaceItemFrame` hook and related arguments. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index d29b94ae..ae522e19 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -29,6 +29,7 @@ using static TShockAPI.GetDataHandlers; using TerrariaApi.Server; using Terraria.ObjectData; using Terraria.DataStructures; +using Terraria.Localization; namespace TShockAPI { @@ -41,6 +42,7 @@ namespace TShockAPI { // Setup hooks + GetDataHandlers.PlaceItemFrame.Register(OnPlaceItemFrame); GetDataHandlers.GemLockToggle.Register(OnGemLockToggle); GetDataHandlers.PlaceTileEntity.Register(OnPlaceTileEntity); GetDataHandlers.PlayerAnimation.Register(OnPlayerAnimation); @@ -62,6 +64,33 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Fired when an item frame is placed for anti-cheat detection. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnPlaceItemFrame(object sender, GetDataHandlers.PlaceItemFrameEventArgs args) + { + if (TShock.CheckIgnores(args.Player)) + { + NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.ItemFrame.ID, 0, 1); + args.Handled = true; + return; + } + + if (TShock.CheckTilePermission(args.Player, args.X, args.Y)) + { + NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.ItemFrame.ID, 0, 1); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, args.X, args.Y)) + { + NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.ItemFrame.ID, 0, 1); + args.Handled = true; + return; + } + } + /// Handles the anti-cheat components of gem lock toggles. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 8e10eb98..82ef08c4 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -3075,6 +3075,54 @@ namespace TShockAPI return false; } + /// The arguments to the PlaceItemFrame event. + public class PlaceItemFrameEventArgs : HandledEventArgs + { + /// The TSPlayer that triggered the event. + public TSPlayer Player { get; set; } + + /// The X coordinate of the item frame. + public short X { get; set; } + + /// The Y coordinate of the item frame. + public short Y { get; set; } + + /// The ItemID of the item frame. + public short ItemID { get; set; } + + /// The prefix. + public byte Prefix { get; set; } + + /// The stack. + public short Stack { get; set; } + + /// The ItemFrame object associated with this event. + public TEItemFrame ItemFrame { get; set; } + } + + /// Fired when an ItemFrame is placed. + public static HandlerList PlaceItemFrame; + + private static bool OnPlaceItemFrame(TSPlayer player, short x, short y, short itemID, byte prefix, short stack, TEItemFrame itemFrame) + { + if (PlaceItemFrame == null) + return false; + + var args = new PlaceItemFrameEventArgs + { + Player = player, + X = x, + Y = y, + ItemID = itemID, + Prefix = prefix, + Stack = stack, + ItemFrame = itemFrame, + }; + + PlaceItemFrame.Invoke(null, args); + return args.Handled; + } + /// /// For use with a ToggleGemLock event /// @@ -3221,21 +3269,8 @@ namespace TShockAPI var stack = args.Data.ReadInt16(); var itemFrame = (TEItemFrame)TileEntity.ByID[TEItemFrame.Find(x, y)]; - if (TShock.CheckIgnores(args.Player)) + if (OnPlaceItemFrame(args.Player, x, y, itemID, prefix, stack, itemFrame)) { - NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, itemFrame.ID, 0, 1); - return true; - } - - if (TShock.CheckTilePermission(args.Player, x, y)) - { - NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, itemFrame.ID, 0, 1); - return true; - } - - if (TShock.CheckRangePermission(args.Player, x, y)) - { - NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, itemFrame.ID, 0, 1); return true; } From 1bee289dafd82e6e8c9822b77ff2c2229e96c740 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 16 Dec 2017 01:03:05 -0700 Subject: [PATCH 65/74] Move TShock.CheckIgnores(TSPlayer) -> TSPlayer.CheckIgnores() Note: This method really sucks and needs to be rebuilt anyway. --- TShockAPI/Bouncer.cs | 40 ++++++++++++++++++++-------------------- TShockAPI/TSPlayer.cs | 8 ++++++++ TShockAPI/TShock.cs | 12 ++---------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index ae522e19..38769b06 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -69,7 +69,7 @@ namespace TShockAPI /// The packet arguments that the event has. internal void OnPlaceItemFrame(object sender, GetDataHandlers.PlaceItemFrameEventArgs args) { - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.ItemFrame.ID, 0, 1); args.Handled = true; @@ -108,7 +108,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Handled = true; return; @@ -126,7 +126,7 @@ namespace TShockAPI /// The packet arguments that the event has. internal void OnPlaceTileEntity(object sender, GetDataHandlers.PlaceTileEntityEventArgs args) { - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Handled = true; return; @@ -177,7 +177,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Handled = true; return; @@ -196,7 +196,7 @@ namespace TShockAPI /// args internal void OnPlayerAnimation(object sender, GetDataHandlers.PlayerAnimationEventArgs args) { - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); args.Handled = true; @@ -245,7 +245,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendData(PacketTypes.NpcUpdate, "", id); args.Handled = true; @@ -311,7 +311,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendData(PacketTypes.PlayerHp, "", id); args.Player.SendData(PacketTypes.PlayerUpdate, "", id); @@ -419,7 +419,7 @@ namespace TShockAPI } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendData(PacketTypes.ItemDrop, "", id); args.Handled = true; @@ -442,7 +442,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); args.Handled = true; @@ -501,7 +501,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendData(PacketTypes.ChestItem, "", id, slot); args.Handled = true; @@ -556,7 +556,7 @@ namespace TShockAPI /// The packet arguments that the event has. internal void OnChestOpen(object sender, GetDataHandlers.ChestOpenEventArgs args) { - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Handled = true; return; @@ -593,7 +593,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendTileSquare(tileX, tileY, 3); args.Handled = true; @@ -654,7 +654,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendTileSquare(tileX, tileY, 1); args.Handled = true; @@ -789,7 +789,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.RemoveProjectile(args.ProjectileIdentity, args.ProjectileOwner); args.Handled = true; @@ -839,7 +839,7 @@ namespace TShockAPI float distance = Vector2.Distance(new Vector2(pos.X / 16f, pos.Y / 16f), new Vector2(args.Player.LastNetPosition.X / 16f, args.Player.LastNetPosition.Y / 16f)); - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { // If the player has moved outside the disabled zone... if (distance > TShock.Config.MaxRangeForDisabled) @@ -980,7 +980,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.RemoveProjectile(ident, owner); args.Handled = true; @@ -1113,7 +1113,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendTileSquare(x, y, 4); args.Handled = true; @@ -1467,7 +1467,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendTileSquare(tileX, tileY, 4); args.Handled = true; @@ -1583,7 +1583,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player) || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.CheckIgnores() || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) { args.Handled = true; return; @@ -1624,7 +1624,7 @@ namespace TShockAPI return; } - if (TShock.CheckIgnores(args.Player)) + if (args.Player.CheckIgnores()) { args.Player.SendTileSquare(tileX, tileY, size); args.Handled = true; diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 73a2bce0..5c732457 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -285,6 +285,14 @@ namespace TShockAPI public bool IgnoreActionsForClearingTrashCan; + /// CheckIgnores - Checks a players ignores...? + /// player - The TSPlayer object. + /// bool - True if any ignore is not none, false, or login state differs from the required state. + public bool CheckIgnores() + { + return IgnoreActionsForInventory != "none" || IgnoreActionsForCheating != "none" || IgnoreActionsForDisabledArmor != "none" || IgnoreActionsForClearingTrashCan || !IsLoggedIn && TShock.Config.RequireLogin; + } + /// /// The player's server side inventory data. /// diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 232d9e36..6f8b54e4 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1080,7 +1080,7 @@ namespace TShockAPI if (Main.ServerSideCharacter && !player.IsLoggedIn) { - if (CheckIgnores(player)) + if (player.CheckIgnores()) { player.Disable(flags: flags); } @@ -1160,7 +1160,7 @@ namespace TShockAPI } player.IgnoreActionsForDisabledArmor = check; - if (CheckIgnores(player)) + if (player.CheckIgnores()) { player.Disable(flags: flags); } @@ -2142,14 +2142,6 @@ namespace TShockAPI return check; } - /// CheckIgnores - Checks a players ignores...? - /// player - The TSPlayer object. - /// bool - True if any ignore is not none, false, or login state differs from the required state. - public static bool CheckIgnores(TSPlayer player) - { - return player.IgnoreActionsForInventory != "none" || player.IgnoreActionsForCheating != "none" || player.IgnoreActionsForDisabledArmor != "none" || player.IgnoreActionsForClearingTrashCan || !player.IsLoggedIn && Config.RequireLogin; - } - /// OnConfigRead - Fired when the config file has been read. /// file - The config file object. public void OnConfigRead(ConfigFile file) From 0260530848aa90228a406da1802e91aaf98f2f84 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 16 Dec 2017 01:06:41 -0700 Subject: [PATCH 66/74] Change Bouncer initialization to a more permanent home --- TShockAPI/Bouncer.cs | 4 ++-- TShockAPI/TShock.cs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 38769b06..b0f110ab 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -33,12 +33,12 @@ using Terraria.Localization; namespace TShockAPI { - /// Bouncer is the TShock anti-hack and build guardian system + /// Bouncer is the TShock anti-hack and anti-cheat system. internal sealed class Bouncer { /// Constructor call initializes Bouncer and related functionality. /// A new Bouncer. - internal Bouncer(TerrariaPlugin pluginInstance) + internal Bouncer() { // Setup hooks diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 6f8b54e4..9766b93d 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -138,6 +138,9 @@ namespace TShockAPI /// public static Dictionary RESTStartupTokens = new Dictionary(); + /// The TShock anti-cheat/anti-exploit system. + internal Bouncer Bouncer; + /// /// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded. /// @@ -322,6 +325,7 @@ namespace TShockAPI RestApi = new SecureRest(Netplay.ServerIP, Config.RestApiPort); RestManager = new RestManager(RestApi); RestManager.RegisterRestfulCommands(); + Bouncer = new Bouncer(); var geoippath = "GeoIP.dat"; if (Config.EnableGeoIP && File.Exists(geoippath)) @@ -379,7 +383,6 @@ namespace TShockAPI Log.ConsoleInfo("TShock comes with no warranty & is free software."); Log.ConsoleInfo("You can modify & distribute it under the terms of the GNU GPLv3."); - Bouncer b = new Bouncer(this); } catch (Exception ex) { From 1e9532a3162179aa9664502421cd4cdd7ed2fbd4 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 16 Dec 2017 01:14:39 -0700 Subject: [PATCH 67/74] Create TSPlayer.IsBouncerThrottled() to avoid code copypasta --- TShockAPI/Bouncer.cs | 20 ++++++++++---------- TShockAPI/GetDataHandlers.cs | 8 ++++---- TShockAPI/TSPlayer.cs | 7 +++++++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index b0f110ab..57b4554e 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -203,7 +203,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); args.Handled = true; @@ -260,7 +260,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendData(PacketTypes.NpcUpdate, "", id); args.Handled = true; @@ -327,7 +327,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendData(PacketTypes.PlayerHp, "", id); args.Player.SendData(PacketTypes.PlayerUpdate, "", id); @@ -470,7 +470,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); args.Handled = true; @@ -770,7 +770,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendTileSquare(tileX, tileY, 1); args.Handled = true; @@ -796,7 +796,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.RemoveProjectile(args.ProjectileIdentity, args.ProjectileOwner); args.Handled = true; @@ -1021,7 +1021,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.RemoveProjectile(ident, owner); args.Handled = true; @@ -1516,7 +1516,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendTileSquare(tileX, tileY, 4); args.Handled = true; @@ -1583,7 +1583,7 @@ namespace TShockAPI return; } - if (args.Player.CheckIgnores() || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.CheckIgnores() || args.Player.IsBouncerThrottled()) { args.Handled = true; return; @@ -1617,7 +1617,7 @@ namespace TShockAPI return; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { args.Player.SendTileSquare(tileX, tileY, size); args.Handled = true; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 82ef08c4..d21c0e36 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2761,7 +2761,7 @@ namespace TShockAPI private static bool HandleSpawnBoss(GetDataHandlerArgs args) { - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { return true; } @@ -2896,7 +2896,7 @@ namespace TShockAPI return true; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000 || + if (args.Player.IsBouncerThrottled() || TShock.CheckTilePermission(args.Player, x, y, true) || TShock.CheckRangePermission(args.Player, x, y)) { @@ -2940,7 +2940,7 @@ namespace TShockAPI return true; } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000 || + if (args.Player.IsBouncerThrottled() || TShock.CheckTilePermission(args.Player, x, y, true) || TShock.CheckRangePermission(args.Player, x, y)) { @@ -3320,7 +3320,7 @@ namespace TShockAPI private static bool HandleOldOnesArmy(GetDataHandlerArgs args) { - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + if (args.Player.IsBouncerThrottled()) { return true; } diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 5c732457..aae8ace8 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -285,6 +285,13 @@ namespace TShockAPI public bool IgnoreActionsForClearingTrashCan; + /// Checks to see if active throttling is happening on events by Bouncer. Rejects repeated events by malicious clients in a short window. + /// If the player is currently being throttled by Bouncer, or not. + public bool IsBouncerThrottled() + { + return (DateTime.UtcNow - LastThreat).TotalMilliseconds < 5000; + } + /// CheckIgnores - Checks a players ignores...? /// player - The TSPlayer object. /// bool - True if any ignore is not none, false, or login state differs from the required state. From cff91f39e8fc3edb43e8180429e8c4ec69152f14 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 16 Dec 2017 01:18:22 -0700 Subject: [PATCH 68/74] Update the changelog --- CHANGELOG.md | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 226bcfe0..30241bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,32 +34,6 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Removed `Permissions.updateplugins` permission. (@hakusaro) * Removed REST `/v3/server/restart/` route and `/server/restart/` route. (@hakusaro) * The "auth system" is now referred to as the initial setup system (what it actually is). This is better verbiage for basically all situations. Who really wants to turn off the "authentication system?" In addition, the system now makes it more clear what the point of it is, rather than that it grants permissions. (@hakusaro) - - - - - - - - - - - - - - - - - - - - - - -## Bouncer changes - -Putting this stuff down here so things don't conflict as often. - * `GetDataHandlers.SendTileSquare` hook now sends a `TSPlayer` and a `MemoryStream` of raw data. (@hakusaro) * Added `GetDataHandlers.HealOtherPlayer` hook. (@hakusaro) * Added `GetDataHandlers.PlaceObject` hook. (@hakusaro) @@ -81,6 +55,8 @@ Putting this stuff down here so things don't conflict as often. * Added `GetDataHandlers.PlaceTileEntity` hook and related arguments. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.GemLockToggle`. (@hakusaro) * Added `GetDataHandlers.PlaceItemFrame` hook and related arguments. (@hakusaro) +* Added `TSPlayer.IsBouncerThrottled()`. (@hakusaro) +* Added `TSPlayer.CheckIgnores()` and removed `TShock.CheckIgnores(TSPlayer)`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. From 9d0c84fd13b0a9825f8683a7f774175b0881accb Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 16 Dec 2017 10:37:44 -0700 Subject: [PATCH 69/74] Fix handler registration in Bouncer init constructor --- TShockAPI/Bouncer.cs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 57b4554e..91e3d6e8 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -42,26 +42,26 @@ namespace TShockAPI { // Setup hooks - GetDataHandlers.PlaceItemFrame.Register(OnPlaceItemFrame); - GetDataHandlers.GemLockToggle.Register(OnGemLockToggle); - GetDataHandlers.PlaceTileEntity.Register(OnPlaceTileEntity); - GetDataHandlers.PlayerAnimation.Register(OnPlayerAnimation); - GetDataHandlers.NPCStrike.Register(OnNPCStrike); - GetDataHandlers.ItemDrop.Register(OnItemDrop); - GetDataHandlers.PlayerBuff.Register(OnPlayerBuff); - GetDataHandlers.ChestItemChange.Register(OnChestItemChange); - GetDataHandlers.NPCHome.Register(OnUpdateNPCHome); - GetDataHandlers.ChestOpen.Register(OnChestOpen); - GetDataHandlers.PlaceChest.Register(OnPlaceChest); - GetDataHandlers.LiquidSet.Register(OnLiquidSet); - GetDataHandlers.ProjectileKill.Register(OnProjectileKill); - GetDataHandlers.PlayerUpdate.Register(OnPlayerUpdate); - GetDataHandlers.KillMe.Register(OnKillMe); - GetDataHandlers.NewProjectile.Register(OnNewProjectile); - GetDataHandlers.PlaceObject.Register(OnPlaceObject); - GetDataHandlers.SendTileSquare.Register(OnSendTileSquare); - GetDataHandlers.HealOtherPlayer.Register(OnHealOtherPlayer); - GetDataHandlers.TileEdit.Register(OnTileEdit); + GetDataHandlers.PlaceItemFrame += OnPlaceItemFrame; + GetDataHandlers.GemLockToggle += OnGemLockToggle; + GetDataHandlers.PlaceTileEntity += OnPlaceTileEntity; + GetDataHandlers.PlayerAnimation += OnPlayerAnimation; + GetDataHandlers.NPCStrike += OnNPCStrike; + GetDataHandlers.ItemDrop += OnItemDrop; + GetDataHandlers.PlayerBuff += OnPlayerBuff; + GetDataHandlers.ChestItemChange += OnChestItemChange; + GetDataHandlers.NPCHome += OnUpdateNPCHome; + GetDataHandlers.ChestOpen += OnChestOpen; + GetDataHandlers.PlaceChest += OnPlaceChest; + GetDataHandlers.LiquidSet += OnLiquidSet; + GetDataHandlers.ProjectileKill += OnProjectileKill; + GetDataHandlers.PlayerUpdate += OnPlayerUpdate; + GetDataHandlers.KillMe += OnKillMe; + GetDataHandlers.NewProjectile += OnNewProjectile; + GetDataHandlers.PlaceObject += OnPlaceObject; + GetDataHandlers.SendTileSquare += OnSendTileSquare; + GetDataHandlers.HealOtherPlayer += OnHealOtherPlayer; + GetDataHandlers.TileEdit += OnTileEdit; } /// Fired when an item frame is placed for anti-cheat detection. From 3f79a904daa43f13159502de05b6371f2f9c5192 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 17 Dec 2017 00:39:11 -0700 Subject: [PATCH 70/74] Bouncer: Handle case where prefix < 1 --- TShockAPI/Bouncer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 91e3d6e8..3e460013 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -360,7 +360,7 @@ namespace TShockAPI } //make sure the prefix is a legit value - if (prefix > PrefixID.Count) + if (prefix > PrefixID.Count || prefix < 1) { args.Player.SendData(PacketTypes.ItemDrop, "", id); args.Handled = true; From 14a6338b73152bf58ad3974db70f115982383eee Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 17 Dec 2017 00:44:19 -0700 Subject: [PATCH 71/74] Add a "remove from bouncer" todo item --- TShockAPI/Bouncer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 3e460013..4f4e6419 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -1224,6 +1224,7 @@ namespace TShockAPI return; } + // TODO: Remove from bouncer (does't look like Bouncer code) if (args.Player.AwaitingName) { bool includeUnprotected = false; From c1de974e16fc08d03482221798e584903304592f Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 17 Dec 2017 01:04:47 -0700 Subject: [PATCH 72/74] Remove happiness. http://rubyonrails.org/doctrine The problem with most programmers is that they refuse to see any logic in thinking about a problem from the other side, even just once. You can't argue with someone over what opinionated "programmer happiness" things are because logically you'll always be outmatched with "well you can just do it this other way." Take this example. How is !args.Player.HasProjectilePermission any easier to understand than args.Player.LacksProjectilePermission? -> One is direct: it focuses on what a player doesn't have. -> The other is indirect: it's the inverse of have. You can read one in a sentence and think "so if a player lacks a permission then this happens" whereas the other is like "invert if a player has a permission." In this soupy mess of a codebase where you're trying to sort out what 300 magic numbers mean and what everything else is trying to do, then it's kinda nice to be able to read something and understand it immediately. --- TShockAPI/GetDataHandlers.cs | 2 +- TShockAPI/TSPlayer.cs | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index d21c0e36..959ec454 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2366,7 +2366,7 @@ namespace TShockAPI var type = Main.projectile[index].type; // TODO: This needs to be moved somewhere else. - if (args.Player.LacksProjectilePermission(index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) + if (!args.Player.HasProjectilePermission(index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) { args.Player.Disable("Does not have projectile permission to kill projectile.", DisableFlags.WriteToLogAndConsole); args.Player.RemoveProjectile(ident, owner); diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index aae8ace8..868f20b2 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -804,15 +804,6 @@ namespace TShockAPI } } - /// Checks to see if this player object lacks access rights to a given projectile. Used by projectile bans. - /// The projectile index from Main.projectiles (NOT from a packet directly). - /// The type of projectile, from Main.projectiles. - /// If the player has lacks access rights to the projectile. - public bool LacksProjectilePermission(int index, int type) - { - return !HasProjectilePermission(index, type); - } - /// Checks to see if this player object has access rights to a given projectile. Used by projectile bans. /// The projectile index from Main.projectiles (NOT from a packet directly). /// The type of projectile, from Main.projectiles. From 263c0bc402414d5440e1b6153271c0ca86e15dad Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 17 Dec 2017 12:25:23 -0700 Subject: [PATCH 73/74] Revert "Bouncer: Handle case where prefix < 1" This reverts commit 3f79a904daa43f13159502de05b6371f2f9c5192. If prefix is < 1 and we block this event, clients can no longer delete picked up items. This is what caused what Joshwoo reported. --- TShockAPI/Bouncer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 4f4e6419..65d1865f 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -359,8 +359,10 @@ namespace TShockAPI return; } - //make sure the prefix is a legit value - if (prefix > PrefixID.Count || prefix < 1) + // make sure the prefix is a legit value + // Note: Not checking if prefix is less than 1 because if it is, this check + // will break item pickups on the client. + if (prefix > PrefixID.Count) { args.Player.SendData(PacketTypes.ItemDrop, "", id); args.Handled = true; From 713dd2614a66255e7aea10237b95036e8b62208b Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 17 Dec 2017 12:40:24 -0700 Subject: [PATCH 74/74] Fix regression where Bouncer would create dupe items on drop --- TShockAPI/Bouncer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 65d1865f..a65f840c 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -370,7 +370,7 @@ namespace TShockAPI } //Item removed, let client do this to prevent item duplication - // client side (but only if it passed the range check) + // client side (but only if it passed the range check) (i.e., return false) if (type == 0) { if (TShock.CheckRangePermission(args.Player, (int)(Main.item[id].position.X / 16f), (int)(Main.item[id].position.Y / 16f))) @@ -381,7 +381,7 @@ namespace TShockAPI return; } - args.Handled = true; + args.Handled = false; return; }