diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 0c7beb84..8275735a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ # These are supported funding model platforms -github: [DeathCradle, hakusaro, Stealownz, QuiCM] +github: [SignatureBeef, hakusaro, Stealownz, QuiCM] diff --git a/CHANGELOG.md b/CHANGELOG.md index c423850c..ddd198e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,9 +14,11 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin ## Upcoming changes * Added hook `GetDataHandlers.OnReleaseNpc` to handling ReleaseNPC packet and a bouncer to stops unregistered and logged out players on SSC servers from releasing critters NPC. The bouncer has additional filter to stops players who tried to release different critter using crafted packet, e.g. using bunny item to release golden bunny. (@tru321) * Added filter in `GetDataHandlers.HandleCatchNpc` that stops unregistered and logged out players on SSC servers to catch critters. (@tru321) - -## Upcoming changes * Fixed rejection check inside of `HandlePaintTile` to account for the Paint Sprayer (or Architect Gizmo Pack) being inside your inventory, rather than on an accessory slot. (@drunderscore) +* Added the lanterns night event to the `/worldevent` command. (@0x3fcf1bbd) +* Marked `TSPlayer.SendTileSquare` as deprecated, and created `TSPlayer.SendTileSquareCentered` that sends a tile square centered around the passed coordinates. (@0x3fcf1bbd) +* Added coordinates clamping to `TSPlayer.SendTileRect` so as to avoid OOBs. (@0x3fcf1bbd) +* Removed extraneous space causing build commands in README to fail. (@EtherTyper) ## TShock 4.5.12 * Fixed the ability to spawn Zenith projectile with non-original items. (@AgaSpace) diff --git a/README.md b/README.md index 9e700f98..e0fdf8a6 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ You need to re-run the patcher any time `OTAPI` updates. You need to rebuild `Te $ cd ./TerrariaServerAPI/TShock.Modifications.Bootstrapper/bin/$BUILD_MODE/ $ mono TShock.Modifications.Bootstrapper.exe -in=OTAPI.dll \ - -mod=../../../TShock.Modifications.**/bin/$BUILD_MODE/TShock.Modifications.*.dll \ + -mod=../../../TShock.Modifications.**/bin/$BUILD_MODE/TShock.Modifications.*.dll \ -o=Output/OTAPI.dll 1. Verify that non-zero modifications ran successfully. Then, build the Terraria Server API executable. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 22017c09..d6f2181a 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -405,7 +405,7 @@ namespace TShockAPI ((action == EditAction.PlaceWall || action == EditAction.ReplaceWall) && editData >= Main.maxWallTypes)) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from editData out of bounds {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -420,7 +420,7 @@ namespace TShockAPI if (args.Player.Dead && TShock.Config.Settings.PreventDeadModification) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (pdm) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -434,7 +434,7 @@ namespace TShockAPI if (TShock.TileBans.TileIsBanned(editData, args.Player)) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (tb) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Player.SendErrorMessage("You do not have permission to place this tile."); args.Handled = true; return; @@ -457,7 +457,7 @@ namespace TShockAPI { TShock.Log.ConsoleError("Bouncer / OnTileEdit rejected from (placestyle) {0} {1} {2} placeStyle: {3} expectedStyle: {4}", args.Player.Name, action, editData, requestedPlaceStyle, actualItemPlaceStyle); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -468,7 +468,7 @@ namespace TShockAPI { TShock.Log.ConsoleError("Bouncer / OnTileEdit rejected from (placestyle) {0} {1} {2} placeStyle: {3} expectedStyle: {4}", args.Player.Name, action, editData, requestedPlaceStyle, correctedPlaceStyle); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -483,7 +483,7 @@ namespace TShockAPI if (Main.tileAxe[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.axe == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (axe) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -491,7 +491,7 @@ namespace TShockAPI else if (Main.tileHammer[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.hammer == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (hammer) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -502,7 +502,7 @@ namespace TShockAPI && !Main.tileAxe[tile.type] && !Main.tileHammer[tile.type] && tile.wall == 0 && args.Player.TPlayer.mount.Type != 8 && selectedItem.pick == 0 && selectedItem.type != ItemID.GravediggerShovel && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (pick) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -513,7 +513,7 @@ namespace TShockAPI if (selectedItem.hammer == 0 && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0 && selectedItem.createWall == 0) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (hammer2) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -532,7 +532,7 @@ namespace TShockAPI !p.Killed && 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 rope coil) {0} {1} {2} selectedItem:{3} itemCreateTile:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createTile); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -543,7 +543,7 @@ namespace TShockAPI requestedPlaceStyle > GetMaxPlaceStyle(editData)) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (ms1) {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -552,7 +552,7 @@ namespace TShockAPI if (selectedItem.netID == ItemID.IceRod && editData != TileID.MagicalIceBlock) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from using ice rod but not placing ice block {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; } /// If they aren't selecting the item which creates the tile, they're hacking. @@ -562,7 +562,7 @@ namespace TShockAPI if (selectedItem.netID != ItemID.IceRod && selectedItem.netID != ItemID.DirtBomb && selectedItem.netID != ItemID.StickyBomb) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from tile placement not matching selected item createTile {0} {1} {2} selectedItemID:{3} createTile:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createTile); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -571,7 +571,7 @@ namespace TShockAPI if ((action == EditAction.PlaceWall || action == EditAction.ReplaceWall) && editData != selectedItem.createWall) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from wall placement not matching selected item createWall {0} {1} {2} selectedItemID:{3} createWall:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createWall); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -581,7 +581,7 @@ namespace TShockAPI { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (chestcap) {0} {1} {2}", args.Player.Name, action, editData); args.Player.SendErrorMessage("The world's chest limit has been reached - unable to place more."); - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -599,7 +599,7 @@ namespace TShockAPI && selectedItem.type != ItemID.WireKite) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from place wire from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -613,7 +613,7 @@ namespace TShockAPI && selectedItem.type != ItemID.MulticolorWrench) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from wire cutter from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -624,7 +624,7 @@ namespace TShockAPI if (selectedItem.type != ItemID.Actuator && !args.Player.TPlayer.autoActuator) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from actuator/presserator from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -634,7 +634,7 @@ namespace TShockAPI if (action == EditAction.KillWall || action == EditAction.ReplaceWall) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from sts allow cut from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -645,7 +645,7 @@ namespace TShockAPI if (args.Player.IsBeingDisabled()) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from disable from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -684,7 +684,7 @@ namespace TShockAPI } TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from explosives/fuses from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -698,7 +698,7 @@ namespace TShockAPI else { args.Player.Disable("Reached TileKill threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); } TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from tile kill threshold from {0}, (value: {1})", args.Player.Name, args.Player.TileKillThreshold); @@ -716,7 +716,7 @@ namespace TShockAPI else { args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); } TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from tile place threshold from {0}, (value: {1})", args.Player.Name, args.Player.TilePlaceThreshold); @@ -728,7 +728,7 @@ namespace TShockAPI if (args.Player.IsBouncerThrottled()) { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from throttled from {0} {1} {2}", args.Player.Name, action, editData); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -762,7 +762,7 @@ namespace TShockAPI { TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from weird confusing flow control from {0}", args.Player.Name); TShock.Log.ConsoleDebug("If you're seeing this message and you know what that player did, please report it to TShock for further investigation."); - args.Player.SendTileSquare(tileX, tileY, 4); + args.Player.SendTileSquareCentered(tileX, tileY, 4); args.Handled = true; return; } @@ -1317,7 +1317,7 @@ namespace TShockAPI if (args.Player.IsBeingDisabled()) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from disabled from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -1325,7 +1325,7 @@ namespace TShockAPI if (args.Player.SelectedItem.placeStyle != style) { TShock.Log.ConsoleError(string.Format("Bouncer / OnPlaceChest / rejected from invalid place style from {0}", args.Player.Name)); - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -1337,7 +1337,7 @@ namespace TShockAPI && (!TShock.Utils.HasWorldReachedMaxChests() && Main.tile[tileX, tileY].type != TileID.Dirt)) //Chest { TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from weird check from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -1349,7 +1349,7 @@ namespace TShockAPI { TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from weird placement check from {0}", args.Player.Name); //Prevent a dresser from being placed on a teleporter, as this can cause client and server crashes. - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -1358,7 +1358,7 @@ namespace TShockAPI if (!args.Player.HasBuildPermission(tileX, tileY)) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from invalid permission from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -1366,7 +1366,7 @@ namespace TShockAPI if (!args.Player.IsInRange(tileX, tileY)) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from range check from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 3); + args.Player.SendTileSquareCentered(tileX, tileY, 3); args.Handled = true; return; } @@ -1451,7 +1451,7 @@ namespace TShockAPI if (args.Player.IsBeingDisabled()) { TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected disabled from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1465,7 +1465,7 @@ namespace TShockAPI else { args.Player.Disable("Reached TileLiquid threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); } TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected from liquid threshold from {0} {1}/{2}", args.Player.Name, args.Player.TileLiquidThreshold, TShock.Config.Settings.TileLiquidThreshold); @@ -1538,7 +1538,7 @@ namespace TShockAPI TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 1 from {0}", args.Player.Name); 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.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1548,7 +1548,7 @@ namespace TShockAPI TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected lava bucket from {0}", args.Player.Name); 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.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1558,7 +1558,7 @@ namespace TShockAPI TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 2 from {0}", args.Player.Name); 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.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1568,7 +1568,7 @@ namespace TShockAPI TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 3 from {0}", args.Player.Name); 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.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1578,7 +1578,7 @@ namespace TShockAPI TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 4 from {0}", args.Player.Name); 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.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1588,7 +1588,7 @@ namespace TShockAPI TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 5 from {0}", args.Player.Name); 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.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1597,7 +1597,7 @@ namespace TShockAPI if (!args.Player.HasBuildPermission(tileX, tileY)) { TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected build permission from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1605,7 +1605,7 @@ namespace TShockAPI if (!wasThereABombNearby && !args.Player.IsInRange(tileX, tileY, 16)) { TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected range checks from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1613,7 +1613,7 @@ namespace TShockAPI if (args.Player.IsBouncerThrottled()) { TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected throttle from {0}", args.Player.Name); - args.Player.SendTileSquare(tileX, tileY, 1); + args.Player.SendTileSquareCentered(tileX, tileY, 1); args.Handled = true; return; } @@ -1925,7 +1925,7 @@ namespace TShockAPI if (type == TileID.FakeContainers && (style == 52 || style == 53)) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected fake containers from {0}", args.Player.Name); - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquareCentered(x, y, 4); args.Handled = true; return; } @@ -1934,7 +1934,7 @@ namespace TShockAPI if (TShock.TileBans.TileIsBanned(type, args.Player)) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected banned tiles from {0}", args.Player.Name); - args.Player.SendTileSquare(x, y, 1); + args.Player.SendTileSquareCentered(x, y, 1); args.Player.SendErrorMessage("You do not have permission to place this tile."); args.Handled = true; return; @@ -1943,7 +1943,7 @@ namespace TShockAPI if (args.Player.Dead && TShock.Config.Settings.PreventDeadModification) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected dead people don't do things from {0}", args.Player.Name); - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquareCentered(x, y, 4); args.Handled = true; return; } @@ -1951,7 +1951,7 @@ namespace TShockAPI if (args.Player.IsBeingDisabled()) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected disabled from {0}", args.Player.Name); - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquareCentered(x, y, 4); args.Handled = true; return; } @@ -1962,7 +1962,7 @@ namespace TShockAPI if (type != args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].createTile) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected awkward tile creation/selection from {0}", args.Player.Name); - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquareCentered(x, y, 4); args.Handled = true; return; } @@ -1986,7 +1986,7 @@ namespace TShockAPI && !args.Player.HasBuildPermission(i, j)) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected mad loop from {0}", args.Player.Name); - args.Player.SendTileSquare(i, j, 4); + args.Player.SendTileSquareCentered(i, j, 4); args.Handled = true; return; } @@ -2002,7 +2002,7 @@ namespace TShockAPI && !args.Player.IsInRange(x, y)) { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected range checks from {0}", args.Player.Name); - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquareCentered(x, y, 4); args.Handled = true; return; } @@ -2011,7 +2011,7 @@ namespace TShockAPI { TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected tile place threshold from {0} {1}/{2}", args.Player.Name, args.Player.TilePlaceThreshold, TShock.Config.Settings.TilePlaceThreshold); args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole); - args.Player.SendTileSquare(x, y, 4); + args.Player.SendTileSquareCentered(x, y, 4); args.Handled = true; return; } @@ -2409,7 +2409,7 @@ namespace TShockAPI if ((args.Player.SelectedItem.type != args.ItemID && args.Player.ItemInHand.type != args.ItemID)) { TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected item not placed by hand from {0}", args.Player.Name); - args.Player.SendTileSquare(args.TileX, args.TileY, 1); + args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1); args.Handled = true; return; } @@ -2419,7 +2419,7 @@ namespace TShockAPI Item item = new Item(); item.netDefaults(args.ItemID); args.Player.GiveItemCheck(args.ItemID, item.Name, args.Stack, args.Prefix); - args.Player.SendTileSquare(args.TileX, args.TileY, 1); + args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1); args.Handled = true; return; } @@ -2430,7 +2430,7 @@ namespace TShockAPI Item item = new Item(); item.netDefaults(args.ItemID); args.Player.GiveItemCheck(args.ItemID, item.Name, args.Stack, args.Prefix); - args.Player.SendTileSquare(args.TileX, args.TileY, 1); + args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1); args.Handled = true; return; } @@ -2438,7 +2438,7 @@ namespace TShockAPI if (!args.Player.IsInRange(args.TileX, args.TileY, range: 13)) // To my knowledge, max legit tile reach with accessories. { TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected range checks from {0}", args.Player.Name); - args.Player.SendTileSquare(args.TileX, args.TileY, 1); + args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1); args.Handled = true; return; } diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 9e61000a..8488bcfb 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -2059,7 +2059,8 @@ namespace TShockAPI "eclipse", "invasion", "sandstorm", - "rain" + "rain", + "lanternsnight" }; static readonly List _validInvasions = new List() { @@ -2158,6 +2159,16 @@ namespace TShockAPI Rain(args); return; + case "lanternsnight": + case "lanterns": + if (!args.Player.HasPermission(Permissions.managelanternsnightevent)) + { + FailedPermissionCheck(); + return; + } + LanternsNight(args); + return; + default: args.Player.SendErrorMessage("Invalid event type! Valid event types: {0}", String.Join(", ", _validEvents)); return; @@ -2373,6 +2384,20 @@ namespace TShockAPI } } + private static void LanternsNight(CommandArgs args) + { + LanternNight.ToggleManualLanterns(); + string msg = $" st{(LanternNight.LanternsUp ? "art" : "opp")}ed a lantern night."; + if (args.Silent) + { + args.Player.SendInfoMessage("You" + msg); + } + else + { + TSPlayer.All.SendInfoMessage(args.Player.Name + msg); + } + } + private static void ClearAnglerQuests(CommandArgs args) { if (args.Parameters.Count > 0) @@ -4873,7 +4898,7 @@ namespace TShockAPI try { - args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1); + args.Player.SendTileSquareCentered(boundaryPoint.X, boundaryPoint.Y, 1); } finally { @@ -4887,7 +4912,7 @@ namespace TShockAPI { foreach (Point boundaryPoint in Utils.Instance.EnumerateRegionBoundaries(regionArea)) if ((boundaryPoint.X + boundaryPoint.Y & 1) == 0) - args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1); + args.Player.SendTileSquareCentered(boundaryPoint.X, boundaryPoint.Y, 1); Debug.Assert(boundaryHideTimer != null); boundaryHideTimer.Dispose(); @@ -5644,7 +5669,7 @@ namespace TShockAPI private static void SyncLocalArea(CommandArgs args) { - args.Player.SendTileSquare((int) args.Player.TileX, (int) args.Player.TileY, 32); + args.Player.SendTileSquareCentered(args.Player.TileX, args.Player.TileY, 32); args.Player.SendWarningMessage("Sync'd!"); return; } @@ -6650,7 +6675,7 @@ namespace TShockAPI } if (args.Parameters.Count == 1) { - args.Player.SendTileSquare(x - 2, y - 20, 25); + args.Player.SendTileSquareCentered(x - 2, y - 20, 25); args.Player.SendSuccessMessage("Tried to grow a " + name + "."); } } diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 5555a883..5a880494 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -3894,7 +3894,7 @@ namespace TShockAPI if (TShock.TileBans.TileIsBanned((short)TileID.LogicSensor, args.Player)) { - args.Player.SendTileSquare(x, y, 1); + args.Player.SendTileSquareCentered(x, y, 1); args.Player.SendErrorMessage("You do not have permission to place Logic Sensors."); return true; } diff --git a/TShockAPI/ItemBans.cs b/TShockAPI/ItemBans.cs index 4e0594ae..9f951ed2 100644 --- a/TShockAPI/ItemBans.cs +++ b/TShockAPI/ItemBans.cs @@ -198,7 +198,7 @@ namespace TShockAPI { if (args.Player.TPlayer.autoActuator && DataModel.ItemIsBanned("Actuator", args.Player)) { - args.Player.SendTileSquare(args.X, args.Y, 1); + args.Player.SendTileSquareCentered(args.X, args.Y, 1); args.Player.SendErrorMessage("You do not have permission to place actuators."); args.Handled = true; return; @@ -206,7 +206,7 @@ namespace TShockAPI if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(args.Player.SelectedItem.netID), args.Player)) { - args.Player.SendTileSquare(args.X, args.Y, 4); + args.Player.SendTileSquareCentered(args.X, args.Y, 4); args.Handled = true; return; } diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index 7de195d2..378f79fd 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -307,6 +307,9 @@ namespace TShockAPI [Description("User can use the 'rain' subcommand of the 'worldevent' command")] public static readonly string managerainevent = "tshock.world.events.rain"; + [Description("User can use the 'lanternsnight' subcommand of the 'worldevent' command")] + public static readonly string managelanternsnightevent = "tshock.world.events.lanternsnight"; + [Description("User can change expert state.")] public static readonly string toggleexpert = "tshock.world.toggleexpert"; diff --git a/TShockAPI/RegionHandler.cs b/TShockAPI/RegionHandler.cs index 671e9933..48d5421a 100644 --- a/TShockAPI/RegionHandler.cs +++ b/TShockAPI/RegionHandler.cs @@ -171,7 +171,7 @@ namespace TShockAPI } // Revert all tile changes and handle the event - player.SendTileSquare(e.X, e.Y, 4); + player.SendTileSquareCentered(e.X, e.Y, 4); e.Handled = true; } @@ -190,7 +190,7 @@ namespace TShockAPI player.AwaitingTempPoint = 0; // Revert all tile changes and handle the event - player.SendTileSquare(e.X, e.Y, 4); + player.SendTileSquareCentered(e.X, e.Y, 4); e.Handled = true; } diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 7ce4cb51..9927cfee 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -1226,7 +1226,7 @@ namespace TShockAPI y = 992; } - SendTileSquare((int)(x / 16), (int)(y / 16), 15); + SendTileSquareCentered((int)(x / 16), (int)(y / 16), 15); TPlayer.Teleport(new Vector2(x, y), style); NetMessage.SendData((int)PacketTypes.Teleport, -1, -1, NetworkText.Empty, 0, TPlayer.whoAmI, x, y, style); return true; @@ -1308,11 +1308,27 @@ namespace TShockAPI /// The y coordinate to send. /// The size square set of tiles to send. /// true if the tile square was sent successfully, else false + [Obsolete("This method may not send tiles the way you would expect it to. The (x,y) coordinates are the top left corner of the tile square, switch to " + nameof(SendTileSquareCentered) + " if you wish for the coordindates to be the center of the square.")] public virtual bool SendTileSquare(int x, int y, int size = 10) { return SendTileRect((short)x, (short)y, (byte)size, (byte)size); } + /// + /// Sends a tile square at a center 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 coordinates of the center of the square. + /// The y coordinates of the center of the square. + /// The size square set of tiles to send. + /// true if the tile square was sent successfully, else false + public virtual bool SendTileSquareCentered(int x, int y, byte size = 10) + { + return SendTileRect((short)(x - (size / 2)), (short)(y - (size / 2)), size, size); + } + /// /// Sends a rectangle of tiles at a location with the given length and width. /// @@ -1347,7 +1363,7 @@ namespace TShockAPI public bool GiveItemCheck(int type, string name, int stack, int prefix = 0) { if ((TShock.ItemBans.DataModel.ItemIsBanned(name) && TShock.Config.Settings.PreventBannedItemSpawn) && - (TShock.ItemBans.DataModel.ItemIsBanned(name, this) || !TShock.Config.Settings.AllowAllowedGroupsToSpawnBannedItems)) + (TShock.ItemBans.DataModel.ItemIsBanned(name, this) || !TShock.Config.Settings.AllowAllowedGroupsToSpawnBannedItems)) return false; GiveItem(type, stack, prefix); diff --git a/TShockAPI/TSServerPlayer.cs b/TShockAPI/TSServerPlayer.cs index f6066267..ae9dc4cb 100644 --- a/TShockAPI/TSServerPlayer.cs +++ b/TShockAPI/TSServerPlayer.cs @@ -189,7 +189,7 @@ namespace TShockAPI // Send all players updated tile squares foreach (Vector2 coords in tiles.Keys) { - All.SendTileSquare((int)coords.X, (int)coords.Y, 3); + All.SendTileSquareCentered((int)coords.X, (int)coords.Y, 3); } }