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