From e2afd4a745f8d6b480caff630b59c7379cc627c6 Mon Sep 17 00:00:00 2001 From: SGKoishi Date: Sat, 23 May 2020 20:27:56 -0700 Subject: [PATCH 01/27] Update workflow --- .github/workflows/build.yml | 92 ++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 67a3ae87..b4f9a045 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,67 +6,83 @@ jobs: build: runs-on: windows-latest steps: - - uses: actions/checkout@v1 + - name: Git checkout + uses: actions/checkout@v1 with: submodules: recursive - - name: Install nuget - run: choco install nuget.commandline - - name: OTAPI Debug - shell: cmd + - name: Add MSBuild to environment variable + shell: pwsh + run: | + $msbuildPath = Split-Path (& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.Component.MSBuild -find MSBuild\Current\Bin\amd64\MSBuild.exe | Select-Object -First 1) -Parent + echo "::set-env name=PATH::$msbuildPath;$env:PATH" + - name: Installer NuGet client + uses: nuget/setup-nuget@v1 + - name: Restore NuGet packages run: | nuget restore .\TerrariaServerAPI\TShock.4.OTAPI.sln - "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Debug + nuget restore TShock.sln + - name: Build OTAPI (Debug) + shell: cmd + run: | + MSBuild.exe .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Debug cd .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Debug TShock.Modifications.Bootstrapper.exe - - name: OTAPI Release - shell: cmd - run: | - nuget restore .\TerrariaServerAPI\TShock.4.OTAPI.sln - "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Release - cd .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Release - TShock.Modifications.Bootstrapper.exe - - name: TerrariaServerAPI Debug + - name: Build TerrariaServerAPI (Debug) shell: cmd run: | cd .\TerrariaServerAPI - "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Debug - - name: TShock Debug + MSBuild.exe .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Debug + - name: Build TShock (Debug) shell: cmd run: | nuget restore TShock.sln - "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TShockAPI\TShockAPI.csproj /p:Configuration=Debug - - name: TerrariaServerAPI Release + MSBuild.exe .\TShockAPI\TShockAPI.csproj /p:Configuration=Debug + - name: Prepare packaging shell: cmd run: | - cd .\TerrariaServerAPI - "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Release - - name: TShock Release - shell: cmd - run: | - nuget restore TShock.sln - "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TShockAPI\TShockAPI.csproj /p:Configuration=Release - - name: Normalize release packaging - shell: cmd - run: | - xcopy /Y prebuilts\*.* TShockAPI\bin\Release xcopy /Y prebuilts\*.* TShockAPI\bin\Debug mkdir TShockAPI\bin\Debug\ServerPlugins - mkdir TShockAPI\bin\Release\ServerPlugins - move TShockAPI\bin\Release\TShockAPI.dll TShockAPI\bin\Release\ServerPlugins move TShockAPI\bin\Debug\TShockAPI.dll TShockAPI\bin\Debug\ServerPlugins - - uses: actions/upload-artifact@master - with: - name: Experimental TShock (not debug) - path: TShockAPI\bin\Release - - uses: actions/upload-artifact@master + - name: Upload TShock (Debug) + uses: actions/upload-artifact@master with: name: Experimental TShock (debug) path: TShockAPI\bin\Debug - - uses: actions/upload-artifact@master + - name: Upload OTAPI Bootstrapper (Debug) + uses: actions/upload-artifact@master with: name: Experimental (debug) OTAPI Bootstrapper path: .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Debug\TShock.Modifications.Bootstrapper.exe - - uses: actions/upload-artifact@master + - name: Build OTAPI (Release) + shell: cmd + run: | + nuget restore .\TerrariaServerAPI\TShock.4.OTAPI.sln + MSBuild.exe .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Release + cd .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Release + TShock.Modifications.Bootstrapper.exe + - name: Build TerrariaServerAPI (Release) + shell: cmd + run: | + cd .\TerrariaServerAPI + MSBuild.exe .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Release + - name: Build TShock (Release) + shell: cmd + run: | + nuget restore TShock.sln + MSBuild.exe .\TShockAPI\TShockAPI.csproj /p:Configuration=Release + - name: Prepare packaging + shell: cmd + run: | + xcopy /Y prebuilts\*.* TShockAPI\bin\Release + mkdir TShockAPI\bin\Release\ServerPlugins + move TShockAPI\bin\Release\TShockAPI.dll TShockAPI\bin\Release\ServerPlugins + - name: Upload TShock (Release) + uses: actions/upload-artifact@master + with: + name: Experimental TShock (not debug) + path: TShockAPI\bin\Release + - name: Upload OTAPI Bootstrapper (Release) + uses: actions/upload-artifact@master with: name: Experimental (not debug) OTAPI Bootstrapper path: .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Release\TShock.Modifications.Bootstrapper.exe From f999e3dbe922b7567569b87664d1901db65d8097 Mon Sep 17 00:00:00 2001 From: SGKoishi Date: Sat, 23 May 2020 23:35:22 -0700 Subject: [PATCH 02/27] Use 'not debug' instead of release to avoid ambiguity --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4f9a045..52245365 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,19 +53,19 @@ jobs: with: name: Experimental (debug) OTAPI Bootstrapper path: .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Debug\TShock.Modifications.Bootstrapper.exe - - name: Build OTAPI (Release) + - name: Build OTAPI (Not Debug) shell: cmd run: | nuget restore .\TerrariaServerAPI\TShock.4.OTAPI.sln MSBuild.exe .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Release cd .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Release TShock.Modifications.Bootstrapper.exe - - name: Build TerrariaServerAPI (Release) + - name: Build TerrariaServerAPI (Not Debug) shell: cmd run: | cd .\TerrariaServerAPI MSBuild.exe .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Release - - name: Build TShock (Release) + - name: Build TShock (Not Debug) shell: cmd run: | nuget restore TShock.sln @@ -76,12 +76,12 @@ jobs: xcopy /Y prebuilts\*.* TShockAPI\bin\Release mkdir TShockAPI\bin\Release\ServerPlugins move TShockAPI\bin\Release\TShockAPI.dll TShockAPI\bin\Release\ServerPlugins - - name: Upload TShock (Release) + - name: Upload TShock (Not Debug) uses: actions/upload-artifact@master with: name: Experimental TShock (not debug) path: TShockAPI\bin\Release - - name: Upload OTAPI Bootstrapper (Release) + - name: Upload OTAPI Bootstrapper (Not Debug) uses: actions/upload-artifact@master with: name: Experimental (not debug) OTAPI Bootstrapper From 7e5490a9993899b452c86cbf5bce1988adab8bb0 Mon Sep 17 00:00:00 2001 From: SGKoishi Date: Sun, 24 May 2020 00:41:06 -0700 Subject: [PATCH 03/27] Update 'release' wording --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52245365..ef4cd3b0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,7 +70,7 @@ jobs: run: | nuget restore TShock.sln MSBuild.exe .\TShockAPI\TShockAPI.csproj /p:Configuration=Release - - name: Prepare packaging + - name: Normalize release packaging shell: cmd run: | xcopy /Y prebuilts\*.* TShockAPI\bin\Release From 50b246c4a34b9c3f6563a4072eeb3a5d5e55c963 Mon Sep 17 00:00:00 2001 From: SGKoishi Date: Sun, 24 May 2020 14:05:57 -0700 Subject: [PATCH 04/27] Revert MSBuild PATH variable --- .github/workflows/build.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef4cd3b0..a796464b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,11 +10,6 @@ jobs: uses: actions/checkout@v1 with: submodules: recursive - - name: Add MSBuild to environment variable - shell: pwsh - run: | - $msbuildPath = Split-Path (& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.Component.MSBuild -find MSBuild\Current\Bin\amd64\MSBuild.exe | Select-Object -First 1) -Parent - echo "::set-env name=PATH::$msbuildPath;$env:PATH" - name: Installer NuGet client uses: nuget/setup-nuget@v1 - name: Restore NuGet packages @@ -24,19 +19,19 @@ jobs: - name: Build OTAPI (Debug) shell: cmd run: | - MSBuild.exe .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Debug + "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Debug cd .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Debug TShock.Modifications.Bootstrapper.exe - name: Build TerrariaServerAPI (Debug) shell: cmd run: | cd .\TerrariaServerAPI - MSBuild.exe .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Debug + "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Debug - name: Build TShock (Debug) shell: cmd run: | nuget restore TShock.sln - MSBuild.exe .\TShockAPI\TShockAPI.csproj /p:Configuration=Debug + "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TShockAPI\TShockAPI.csproj /p:Configuration=Debug - name: Prepare packaging shell: cmd run: | @@ -57,19 +52,19 @@ jobs: shell: cmd run: | nuget restore .\TerrariaServerAPI\TShock.4.OTAPI.sln - MSBuild.exe .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Release + "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TShock.4.OTAPI.sln /p:Configuration=Release cd .\TerrariaServerAPI\TShock.Modifications.Bootstrapper\bin\Release TShock.Modifications.Bootstrapper.exe - name: Build TerrariaServerAPI (Not Debug) shell: cmd run: | cd .\TerrariaServerAPI - MSBuild.exe .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Release + "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TerrariaServerAPI\TerrariaServerAPI.csproj /p:Configuration=Release - name: Build TShock (Not Debug) shell: cmd run: | nuget restore TShock.sln - MSBuild.exe .\TShockAPI\TShockAPI.csproj /p:Configuration=Release + "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" .\TShockAPI\TShockAPI.csproj /p:Configuration=Release - name: Normalize release packaging shell: cmd run: | From 079541d4c949387fff36f7a9fe8ca282478949ce Mon Sep 17 00:00:00 2001 From: Olink Date: Wed, 27 May 2020 23:05:45 -0400 Subject: [PATCH 05/27] Initial working commit. --- TShockAPI/Bouncer.cs | 13 +++++++++++++ TShockAPI/PlayerData.cs | 2 +- TShockAPI/TShock.cs | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index ad6e516a..0ea594e7 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -295,6 +295,19 @@ namespace TShockAPI { args.Player.LastKilledProjectile = 0; } + else if (editData == TileID.MysticSnakeRope) + { + //projectile should be the same X coordinate as all tile places + if (!args.Player.RecentlyCreatedProjectiles.Any(p => Main.projectile[p.Index].type == ProjectileID.MysticSnakeCoil && + Math.Abs((int)(Main.projectile[p.Index].position.X / 16f) - tileX) <= Math.Abs(Main.projectile[p.Index].velocity.X))) + { + TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (inconceivable mystic snake rope) {0} {1} {2}", args.Player.Name, action, editData); + Console.WriteLine("Bouncer / OnTileEdit rejected from (inconceivable mystic snake rope) {0} {1} {2}", args.Player.Name, action, editData); + args.Player.SendTileSquare(tileX, tileY, 1); + args.Handled = true; + return; + } + } else if (action == EditAction.PlaceTile || action == EditAction.PlaceWall) { if ((action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle) && diff --git a/TShockAPI/PlayerData.cs b/TShockAPI/PlayerData.cs index 562dea80..d6540e34 100644 --- a/TShockAPI/PlayerData.cs +++ b/TShockAPI/PlayerData.cs @@ -496,7 +496,7 @@ namespace TShockAPI } var response = NetCreativeUnlocksModule.SerializeItemSacrifice(i, amount); - NetManager.Instance.SendToClient(response, player.TPlayer.whoAmI); + NetManager.Instance.SendToClient(response, player.Index); } } } diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 0d19a6fb..84c12dab 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1640,7 +1640,8 @@ namespace TShockAPI if (e.number >= 0 && e.number < Main.projectile.Length) { var projectile = Main.projectile[e.number]; - if (projectile.active && projectile.owner >= 0 && GetDataHandlers.projectileCreatesLiquid.ContainsKey(projectile.type)) + if (projectile.active && projectile.owner >= 0 && + (GetDataHandlers.projectileCreatesLiquid.ContainsKey(projectile.type) || GetDataHandlers.projectileCreatesTile.ContainsKey(projectile.type))) { var player = Players[projectile.owner]; if (player != null) From 9cd46704362bdb81089632ea017b86ea603b251b Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Fri, 29 May 2020 03:25:11 +0200 Subject: [PATCH 06/27] Add FishOutNPC event handler. --- CHANGELOG.md | 1 + TShockAPI/Bouncer.cs | 36 +++++++++++++++ TShockAPI/GetDataHandlers.cs | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94b9e1ba..c79a1ea9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Fixed kick on hardcore death / kick on mediumcore death / ban on either from taking action against journey mode players. (@hakusaro) * Attempted to fix the problem with the magic mirror spawn problems. You should be able to remove your spawn point in SSC by right clicking on a bed now. (@hakusaro, @AxeelAnder) * Add HandleFoodPlatterTryPlacing event, which is called whenever a player places a food in a plate. Add antihack to bouncer, to prevent removing food from plates if the region is protected; To prevent placement if they are not in range; To prevent placement if the item is not placed from player hand. (@Patrikkk) +* Add FishOutNPC event handler, which is called whenever a player fishes out an NPC using a fishing rod. Added antihack to Bouncer, to prevent unathorized and invalid mob spawning, by checking player action, NPC IDs and range. (@Patrikkk, @moisterrific) ## TShock 4.4.0 (Pre-release 8) * Update for OTAPI 2.0.0.36 and Terraria 1.4.0.4. (@hakusaro, @Patrikkk, @DeathCradle) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index abd5fe05..b0bc2e9b 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -67,6 +67,7 @@ namespace TShockAPI GetDataHandlers.MassWireOperation += OnMassWireOperation; GetDataHandlers.PlayerDamage += OnPlayerDamage; GetDataHandlers.KillMe += OnKillMe; + GetDataHandlers.FishOutNPC += OnFishOutNPC; GetDataHandlers.FoodPlatterTryPlacing += OnFoodPlatterTryPlacing; } @@ -2063,6 +2064,41 @@ namespace TShockAPI } } + /// + /// Called when the player fishes out an NPC. + /// + /// + /// + internal void OnFishOutNPC(object sender, GetDataHandlers.FishOutNPCEventArgs args) + { + Projectile projectile = null; + foreach (var recentProjectile in args.Player.RecentlyCreatedProjectiles) + { + if (Main.projectile[recentProjectile.Index] != null && Main.projectile[recentProjectile.Index].Name == "Bobber") + { + projectile = Main.projectile[recentProjectile.Index]; + break; + } + } + if (!FishingRodItemIDs.Contains(args.Player.SelectedItem.type) || projectile == null || !FishableNpcIDs.Contains(args.NpcID)) + { + TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected invalid NPC spawning from {0}", args.Player.Name); + args.Handled = true; + return; + } + if (args.NpcID == NPCID.DukeFishron && !args.Player.HasPermission(Permissions.summonboss)) + { + TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected summon boss permissions from {0}", args.Player.Name); + args.Handled = true; + return; + } + if (args.Player.IsInRange(args.TileX, args.TileY, 55)) + { + TShock.Log.ConsoleDebug("Bouncer / OnFishOutNPC rejected range checks from {0}", args.Player.Name); + args.Handled = true; + } + } + /// /// Called when a player is trying to place an item into a food plate. /// diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 74dbff85..9d2b63ef 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -151,6 +151,7 @@ namespace TShockAPI { PacketTypes.CrystalInvasionStart, HandleOldOnesArmy }, { PacketTypes.PlayerHurtV2, HandlePlayerDamageV2 }, { PacketTypes.PlayerDeathV2, HandlePlayerKillMeV2 }, + { PacketTypes.FishOutNPC, HandleFishOutNPC }, { PacketTypes.FoodPlatterTryPlacing, HandleFoodPlatterTryPlacing } }; } @@ -1864,6 +1865,45 @@ namespace TShockAPI return args.Handled; } + /// + /// For use in a FishOutNPC event. + /// + public class FishOutNPCEventArgs : GetDataHandledEventArgs + { + /// + /// The X world position of the spawning NPC. + /// + public ushort TileX { get; set; } + /// + /// The Y world position of the spawning NPC. + /// + public ushort TileY { get; set; } + /// + /// The NPC type that is being spawned. + /// + public short NpcID { get; set; } + } + /// + /// Called when a player fishes out an NPC. + /// + public static HandlerList FishOutNPC = new HandlerList(); + private static bool OnFishOutNPC(TSPlayer player, MemoryStream data, ushort tileX, ushort tileY, short npcID) + { + if (FoodPlatterTryPlacing == null) + return false; + + var args = new FishOutNPCEventArgs + { + Player = player, + Data = data, + TileX = tileX, + TileY = tileY, + NpcID = npcID + }; + FishOutNPC.Invoke(null, args); + return args.Handled; + } + public class FoodPlatterTryPlacingEventArgs : GetDataHandledEventArgs { /// @@ -3606,6 +3646,19 @@ namespace TShockAPI return false; } + + private static bool HandleFishOutNPC(GetDataHandlerArgs args) + { + ushort tileX = args.Data.ReadUInt16(); + ushort tileY = args.Data.ReadUInt16(); + short npcType = args.Data.ReadInt16(); + + if (OnFishOutNPC(args.Player, args.Data, tileX, tileY, npcType)) + return true; + + return false; + } + private static bool HandleFoodPlatterTryPlacing(GetDataHandlerArgs args) { short tileX = args.Data.ReadInt16(); @@ -3679,6 +3732,39 @@ namespace TShockAPI TileID.Womannequin, }; + /// + /// List of Fishing rod item IDs. + /// + internal static readonly List FishingRodItemIDs = new List() + { + ItemID.WoodFishingPole, + ItemID.ReinforcedFishingPole, + ItemID.FiberglassFishingPole, + ItemID.FisherofSouls, + ItemID.GoldenFishingRod, + ItemID.MechanicsRod, + ItemID.SittingDucksFishingRod, + ItemID.Fleshcatcher, + ItemID.HotlineFishingHook, + ItemID.BloodFishingRod, + ItemID.ScarabFishingRod + }; + + /// + /// List of NPC IDs that can be fished out by the player. + /// + internal static readonly List FishableNpcIDs = new List() + { + NPCID.EyeballFlyingFish, + NPCID.ZombieMerman, + NPCID.GoblinShark, + NPCID.BloodEelHead, + NPCID.BloodEelBody, + NPCID.BloodEelTail, + NPCID.BloodNautilus, + NPCID.DukeFishron + }; + /// /// These projectiles create tiles on death. /// From 695ca52a9a6fd0eb6037525b6f0b87b2b1e49ba5 Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Fri, 29 May 2020 03:27:19 +0200 Subject: [PATCH 07/27] Fix FishOutNPC bouncer debug message. --- TShockAPI/Bouncer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index b0bc2e9b..74858b2f 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -2082,13 +2082,13 @@ namespace TShockAPI } if (!FishingRodItemIDs.Contains(args.Player.SelectedItem.type) || projectile == null || !FishableNpcIDs.Contains(args.NpcID)) { - TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected invalid NPC spawning from {0}", args.Player.Name); + TShock.Log.ConsoleDebug("Bouncer / OnFishOutNPC rejected invalid NPC spawning from {0}", args.Player.Name); args.Handled = true; return; } if (args.NpcID == NPCID.DukeFishron && !args.Player.HasPermission(Permissions.summonboss)) { - TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected summon boss permissions from {0}", args.Player.Name); + TShock.Log.ConsoleDebug("Bouncer / OnFishOutNPC rejected summon boss permissions from {0}", args.Player.Name); args.Handled = true; return; } From d4a0f47e451ccd095a8f1ea4e8d0e85dafe678e1 Mon Sep 17 00:00:00 2001 From: Chris <2648373+QuiCM@users.noreply.github.com> Date: Fri, 29 May 2020 14:05:43 +0930 Subject: [PATCH 08/27] WIP - splitting STS into new class and processing methods --- TShockAPI/Bouncer.cs | 204 +----------- TShockAPI/Handlers/SendTileSquareHandler.cs | 344 ++++++++++++++++++++ TShockAPI/Net/NetTile.cs | 7 +- TShockAPI/TSPlayer.cs | 28 +- TShockAPI/TShockAPI.csproj | 3 +- 5 files changed, 384 insertions(+), 202 deletions(-) create mode 100644 TShockAPI/Handlers/SendTileSquareHandler.cs diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index abd5fe05..7a5bc82c 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -36,15 +36,19 @@ namespace TShockAPI /// Bouncer is the TShock anti-hack and anti-cheat system. internal sealed class Bouncer { + internal Handlers.SendTileSquareHandler STSHandler { get; set; } + /// Constructor call initializes Bouncer and related functionality. /// A new Bouncer. internal Bouncer() { + STSHandler = new Handlers.SendTileSquareHandler(); + // Setup hooks GetDataHandlers.GetSection += OnGetSection; GetDataHandlers.PlayerUpdate += OnPlayerUpdate; GetDataHandlers.TileEdit += OnTileEdit; - GetDataHandlers.SendTileSquare += OnSendTileSquare; + GetDataHandlers.SendTileSquare += STSHandler.OnReceiveSendTileSquare; GetDataHandlers.ItemDrop += OnItemDrop; GetDataHandlers.NewProjectile += OnNewProjectile; GetDataHandlers.NPCStrike += OnNPCStrike; @@ -517,204 +521,6 @@ namespace TShockAPI } } - /// 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; - int tileX = args.TileX; - int tileY = args.TileY; - - if (args.Player.HasPermission(Permissions.allowclientsideworldedit)) - { - TShock.Log.ConsoleDebug("Bouncer / SendTileSquare accepted clientside world edit from {0}", args.Player.Name); - args.Handled = false; - 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) - { - TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from non-vanilla tilemod from {0}", args.Player.Name); - args.Handled = true; - return; - } - - if (args.Player.IsBouncerThrottled()) - { - TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from throttle from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, size); - args.Handled = true; - return; - } - - if (args.Player.IsBeingDisabled()) - { - TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from being disabled from {0}", args.Player.Name); - 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 (!args.Player.HasBuildPermission(realx, realy) || - !args.Player.IsInRange(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; - } - - // Tile entities: sensors, item frames, training dummies - // here it handles all tile entities listed in `TileEntityID` - if ((newtile.Type == TileID.LogicSensor || - newtile.Type == TileID.ItemFrame || - newtile.Type == TileID.TargetDummy) && - !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); - } - - TShock.Log.ConsoleDebug("Bouncer / SendTileSquare reimplemented from spaghetti from {0}", args.Player.Name); - args.Handled = true; - } - /// Registered when items fall to the ground to prevent cheating. /// The object that triggered the event. /// The packet arguments that the event has. diff --git a/TShockAPI/Handlers/SendTileSquareHandler.cs b/TShockAPI/Handlers/SendTileSquareHandler.cs new file mode 100644 index 00000000..273c4d35 --- /dev/null +++ b/TShockAPI/Handlers/SendTileSquareHandler.cs @@ -0,0 +1,344 @@ +using OTAPI.Tile; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Terraria; +using Terraria.ID; +using Terraria.ObjectData; +using TShockAPI.Net; + +namespace TShockAPI.Handlers +{ + public class SendTileSquareHandler + { + Dictionary> _grassToPlantMap = new Dictionary> + { + { TileID.Grass, new List { TileID.Plants, TileID.Plants2 } }, + { TileID.HallowedGrass, new List { TileID.HallowedPlants, TileID.HallowedPlants2 } }, + { TileID.JungleGrass, new List { TileID.JunglePlants, TileID.JunglePlants2 } } + }; + + List _flowerBootItems = new List + { + ItemID.FlowerBoots, + ItemID.FairyBoots + }; + + /// + /// Updates a single tile + /// + /// + /// + public void UpdateTile(ITile tile, NetTile newTile) + { + tile.active(newTile.Active); + + if (newTile.Active && !newTile.Inactive) + { + tile.type = newTile.Type; + } + + if (newTile.FrameImportant) + { + tile.frameX = newTile.FrameX; + tile.frameY = newTile.FrameY; + } + + if (newTile.HasWall) + { + tile.wall = newTile.Wall; + } + + if (newTile.HasLiquid) + { + tile.liquid = newTile.Liquid; + tile.liquidType(newTile.LiquidType); + } + + tile.wire(newTile.Wire); + tile.wire2(newTile.Wire2); + tile.wire3(newTile.Wire3); + tile.wire4(newTile.Wire4); + + tile.halfBrick(newTile.IsHalf); + + if (newTile.HasColor) + { + tile.color(newTile.TileColor); + } + + if (newTile.HasWallColor) + { + tile.wallColor(newTile.WallColor); + } + + byte slope = 0; + if (newTile.Slope) + { + slope += 1; + } + if (newTile.Slope2) + { + slope += 2; + } + if (newTile.Slope3) + { + slope += 4; + } + + tile.slope(slope); + } + + /// + /// Determines if a Tile Square for flower-growing boots should be accepted or not + /// + /// + /// + /// + /// + /// + internal bool HandleFlowerBoots(int realx, int realy, NetTile newTile, TSPlayer player) + { + // We need to get the tile below the tile square to determine what grass types are allowed + if (!WorldGen.InWorld(realx, realy + 1)) + { + return true; + } + + ITile tile = Main.tile[realx, realy + 1]; + if (!_grassToPlantMap.TryGetValue(tile.type, out List plantTiles) && !plantTiles.Contains(newTile.Type)) + { + return true; + } + + return false; + } + + internal void ProcessSingleTile(int realx, int realy, NetTile newTile, int squareSize, GetDataHandlers.SendTileSquareEventArgs args) + { + if (squareSize == 1 && args.Player.Accessories.Any(a => a != null && _flowerBootItems.Contains(a.type))) + { + args.Handled = HandleFlowerBoots(realx, realy, newTile, args.Player); + return; + } + + ITile tile = Main.tile[realx, realy]; + + if (tile.type == TileID.LandMine && !newTile.Active) + { + UpdateTile(tile, newTile); + } + + if (tile.type == TileID.WirePipe) + { + UpdateTile(tile, newTile); + } + + } + + /// + /// + /// + /// + /// + /// + /// + /// + public void ProcessTileObject(TileObjectData data, NetTile[,] newTiles, int realx, int realy, TSPlayer player) + { + + } + + /// + /// Invoked when a SendTileSquare packet is received + /// + /// + /// + public void OnReceiveSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args) + { + short size = args.Size; + int tileX = args.TileX; + int tileY = args.TileY; + + if (args.Player.HasPermission(Permissions.allowclientsideworldedit)) + { + TShock.Log.ConsoleDebug("Bouncer / SendTileSquare accepted clientside world edit from {0}", args.Player.Name); + args.Handled = false; + 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) + { + TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from non-vanilla tilemod from {0}", args.Player.Name); + args.Handled = true; + return; + } + + if (args.Player.IsBouncerThrottled()) + { + TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from throttle from {0}", args.Player.Name); + args.Player.SendTileSquare(tileX, tileY, size); + args.Handled = true; + return; + } + + if (args.Player.IsBeingDisabled()) + { + TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from being disabled from {0}", args.Player.Name); + args.Player.SendTileSquare(tileX, tileY, size); + args.Handled = true; + return; + } + + bool[,] processed = new bool[size, size]; + NetTile[,] 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); + } + } + + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + // Do not handle already processed tiles + if (processed[x, y]) + { + continue; + } + + int realx = tileX + x; + int realy = tileY + y; + + if ((realx < 0 || realx >= Main.maxTilesX) + || (realy < 0 || realy < Main.maxTilesY)) + { + processed[x, y] = true; + continue; + } + + if (!args.Player.HasBuildPermission(realx, realy) || + !args.Player.IsInRange(realx, realy)) + { + continue; + } + + NetTile newTile = tiles[x, y]; + TileObjectData data; + + if (newTile.Type < TileObjectData._data.Count && (data = TileObjectData._data[newTile.Type]) != null) + { + NetTile[,] newTiles = new NetTile[data.Width, data.Height]; + for (int i = 0; i < data.Width; i++) + { + for (int j = 0; j < data.Height; j++) + { + newTiles[i, j] = tiles[x + i, y + j]; + processed[x + i, y + j] = true; + } + } + + ProcessTileObject(data, newTiles, realx, realy, args.Player); + continue; + } + + ProcessSingleTile(realx, realy, newTile, size, args); + processed[x, y] = true; + } + } + + TShock.Log.ConsoleDebug("Bouncer / SendTileSquare reimplemented from spaghetti from {0}", args.Player.Name); + args.Handled = true; + } + } + + /* + 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]; + + // Junction Box + if (tile.type == TileID.WirePipe) + { + args.Handled = false; + return; + } + + 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); + } + }*/ +} diff --git a/TShockAPI/Net/NetTile.cs b/TShockAPI/Net/NetTile.cs index 76d8e943..c49aadea 100644 --- a/TShockAPI/Net/NetTile.cs +++ b/TShockAPI/Net/NetTile.cs @@ -36,6 +36,7 @@ namespace TShockAPI.Net public bool Wire { get; set; } public bool Wire2 { get; set; } public bool Wire3 { get; set; } + public bool Wire4 { get; set; } public byte HalfBrick { get; set; } public byte Actuator { get; set; } public bool Inactive { get; set; } @@ -83,6 +84,7 @@ namespace TShockAPI.Net Wire = false; Wire2 = false; Wire3 = false; + Wire4 = false; HalfBrick = 0; Actuator = 0; Inactive = false; @@ -151,8 +153,10 @@ namespace TShockAPI.Net if (Slope3) bits[6] = true; + if (Wire4) + bits[7] = true; - stream.WriteInt8((byte)bits); + stream.WriteByte(bits); if (HasColor) { @@ -194,6 +198,7 @@ namespace TShockAPI.Net Slope = flags2[4]; Slope2 = flags2[5]; Slope3 = flags2[6]; + Wire4 = flags2[7]; if (flags2[2]) { diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 1a204594..31de3282 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -620,7 +620,8 @@ namespace TShockAPI /// Determines if the player can build on a given point. /// The x coordinate they want to build at. - /// The y coordinate they want to paint at. + /// The y coordinate they want to build at. + /// Whether or not the player should be warned if their build attempt fails /// True if the player can build at the given point from build, spawn, and region protection. public bool HasBuildPermission(int x, int y, bool shouldWarnPlayer = true) { @@ -679,6 +680,31 @@ namespace TShockAPI return false; } + /// + /// Determines if the player can build a tile object on a given point. + /// + /// The x coordinate they want to build at. + /// The y coordinate they want to build at. + /// The width of the tile object + /// The height of the tile object + /// Whether or not the player should be warned if their build attempt fails + /// True if the player can build at the given point from build, spawn, and region protection. + public bool HasBuildPermissionForTileObject(int x, int y, int width, int height, bool shouldWarnPlayer = true) + { + for (int realx = x; realx < x + width; realx++) + { + for (int realy = y; realy < y + height; realy++) + { + if (!HasBuildPermission(realx, realy, shouldWarnPlayer)) + { + return false; + } + } + } + + return true; + } + /// Determines if the player can paint on a given point. Checks general build permissions, then paint. /// The x coordinate they want to paint at. /// The y coordinate they want to paint at. diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index f6a2d81c..ea6f4f48 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -88,6 +88,7 @@ + @@ -211,7 +212,7 @@ - +