diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs
index 5dd9d3ce..94413bef 100644
--- a/TShockAPI/Bouncer.cs
+++ b/TShockAPI/Bouncer.cs
@@ -451,7 +451,7 @@ namespace TShockAPI
if (args.Player.IsBeingDisabled())
{
- TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from wire cutter from {0} {1} {2}", args.Player.Name, action, editData);
+ TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from disable from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Handled = true;
return;
@@ -461,7 +461,9 @@ namespace TShockAPI
&& !args.Player.HasBuildPermission(tileX, tileY))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from ice/build from {0} {1} {2}", args.Player.Name, action, editData);
- args.Player.SendTileSquare(tileX, tileY, 4);
+
+ GetRollbackRectSize(tileX, tileY, out byte width, out byte length, out int offsetY);
+ args.Player.SendTileRect((short)(tileX - width), (short)(tileY + offsetY), (byte)(width * 2), (byte)(length + 1));
args.Handled = true;
return;
}
@@ -573,6 +575,69 @@ namespace TShockAPI
}
}
+ ///
+ /// Gets the size of the rectangle required to rollback all tiles impacted by a single tile.
+ /// Eg, rolling back the destruction of a tile that had a Safe on top would require rolling back the safe as well as the
+ /// tile that was destroyed
+ ///
+ /// X position of the initial tile
+ /// Y position of the initial tile
+ /// The calculated width of the rectangle
+ /// The calculated length of the rectangle
+ /// The Y offset from the initial tile Y that the rectangle should begin at
+ private void GetRollbackRectSize(int tileX, int tileY, out byte width, out byte length, out int offsetY)
+ {
+ CheckForTileObjectsAbove(out byte topWidth, out byte topLength, out offsetY);
+ CheckForTileObjectsBelow(out byte botWidth, out byte botLength);
+
+ // If no tile object exists around the given tile, width will be 1. Else the width of the largest tile object will be used
+ width = Math.Max((byte)1, Math.Max(topWidth, botWidth));
+ // If no tile object exists around the given tile, length will be 1. Else the sum of all tile object lengths will be used
+ length = Math.Max((byte)1, (byte)(topLength + botLength));
+
+ // Checks for the presence of tile objects above the tile being checked
+ void CheckForTileObjectsAbove(out byte objWidth, out byte objLength, out int yOffset)
+ {
+ objWidth = 0;
+ objLength = 0;
+ yOffset = 0;
+
+ if (tileY <= 0)
+ {
+ return;
+ }
+
+ ITile above = Main.tile[tileX, tileY - 1];
+ if (above.type < TileObjectData._data.Count && TileObjectData._data[above.type] != null)
+ {
+ TileObjectData data = TileObjectData._data[above.type];
+ objWidth = (byte)data.Width;
+ objLength = (byte)data.Height;
+ yOffset = -data.Height; //y offset is the negative of the height of the tile object
+ }
+ }
+
+ //Checks for the presence of tile objects below the tile being checked
+ void CheckForTileObjectsBelow(out byte objWidth, out byte objLength)
+ {
+ objWidth = 0;
+ objLength = 0;
+
+ if (tileY == Main.maxTilesY)
+ {
+ return;
+ }
+
+ ITile below = Main.tile[tileX, tileY + 1];
+ if (below.type < TileObjectData._data.Count && TileObjectData._data[below.type] != null)
+ {
+ TileObjectData data = TileObjectData._data[below.type];
+ objWidth = (byte)data.Width;
+ objLength = (byte)data.Height;
+ }
+ }
+ }
+
/// Registered when items fall to the ground to prevent cheating.
/// The object that triggered the event.
/// The packet arguments that the event has.