diff --git a/TShockAPI/Handlers/SendTileRectHandlerRefactor.cs b/TShockAPI/Handlers/SendTileRectHandlerRefactor.cs
index b3a2d1e7..34f8a495 100644
--- a/TShockAPI/Handlers/SendTileRectHandlerRefactor.cs
+++ b/TShockAPI/Handlers/SendTileRectHandlerRefactor.cs
@@ -214,11 +214,11 @@ namespace TShockAPI.Handlers
// this is the only tile type sent in a tile rect where the frame have a different pattern (56, 74, 92 instead of 54, 72, 90)
if (!(TileType == TileID.LunarMonolith && tile.FrameY % FrameYStep == 2))
{
- return false;
+ return false;
+ }
}
}
}
- }
if (Type == MatchType.Removal)
{
if (tile.Active)
@@ -578,7 +578,7 @@ namespace TShockAPI.Handlers
///
- /// Checks whether the tile rect is a valid conversion spread (Clentaminator, Powders, etc.)
+ /// Checks whether the tile rect is a valid conversion spread (Clentaminator, Powders, etc.).
///
/// The player the operation originates from.
/// The tile rectangle of the operation.
@@ -593,81 +593,48 @@ namespace TShockAPI.Handlers
ITile oldTile = Main.tile[rect.X, rect.Y];
NetTile newTile = rect[0, 0];
- bool matchedTileOrWall = false;
+ WorldGenMock.SimulateConversionChange(rect.X, rect.Y, out HashSet validTiles, out HashSet validWalls);
- if (oldTile.active())
+ if (newTile.Type != oldTile.type && validTiles.Contains(newTile.Type))
{
- if (
- (
- (TileID.Sets.Conversion.Stone[oldTile.type] || Main.tileMoss[oldTile.type]) &&
- (TileID.Sets.Conversion.Stone[newTile.Type] || Main.tileMoss[newTile.Type])
- ) ||
- (
- (oldTile.type == TileID.Dirt || oldTile.type == TileID.Mud) &&
- (newTile.Type == TileID.Dirt || newTile.Type == TileID.Mud)
- ) ||
- TileID.Sets.Conversion.Grass[oldTile.type] && TileID.Sets.Conversion.Grass[newTile.Type] ||
- TileID.Sets.Conversion.Ice[oldTile.type] && TileID.Sets.Conversion.Ice[newTile.Type] ||
- TileID.Sets.Conversion.Sand[oldTile.type] && TileID.Sets.Conversion.Sand[newTile.Type] ||
- TileID.Sets.Conversion.Sandstone[oldTile.type] && TileID.Sets.Conversion.Sandstone[newTile.Type] ||
- TileID.Sets.Conversion.HardenedSand[oldTile.type] && TileID.Sets.Conversion.HardenedSand[newTile.Type] ||
- TileID.Sets.Conversion.Thorn[oldTile.type] && TileID.Sets.Conversion.Thorn[newTile.Type] ||
- TileID.Sets.Conversion.Moss[oldTile.type] && TileID.Sets.Conversion.Moss[newTile.Type] ||
- TileID.Sets.Conversion.MossBrick[oldTile.type] && TileID.Sets.Conversion.MossBrick[newTile.Type]
- )
+ if (TShock.TileBans.TileIsBanned((short)newTile.Type, player))
{
- if (TShock.TileBans.TileIsBanned((short)newTile.Type, player))
- {
- // for simplicity, let's pretend that the edit was valid, but do not execute it
- matchedTileOrWall = true;
- }
- else if (!player.HasBuildPermission(rect.X, rect.Y))
- {
- // for simplicity, let's pretend that the edit was valid, but do not execute it
- matchedTileOrWall = true;
- }
- else
- {
- Main.tile[rect.X, rect.Y].type = newTile.Type;
- Main.tile[rect.X, rect.Y].frameX = newTile.FrameX;
- Main.tile[rect.X, rect.Y].frameY = newTile.FrameY;
+ // for simplicity, let's pretend that the edit was valid, but do not execute it
+ return true;
+ }
+ else if (!player.HasBuildPermission(rect.X, rect.Y))
+ {
+ // for simplicity, let's pretend that the edit was valid, but do not execute it
+ return true;
+ }
+ else
+ {
+ Main.tile[rect.X, rect.Y].type = newTile.Type;
+ Main.tile[rect.X, rect.Y].frameX = newTile.FrameX;
+ Main.tile[rect.X, rect.Y].frameY = newTile.FrameY;
- matchedTileOrWall = true;
- }
+ return true;
}
}
- if (oldTile.wall != 0)
+ if (newTile.Wall != oldTile.wall && validWalls.Contains(newTile.Wall))
{
- if (
- WallID.Sets.Conversion.Stone[oldTile.wall] && WallID.Sets.Conversion.Stone[newTile.Wall] ||
- WallID.Sets.Conversion.Grass[oldTile.wall] && WallID.Sets.Conversion.Grass[newTile.Wall] ||
- WallID.Sets.Conversion.Sandstone[oldTile.wall] && WallID.Sets.Conversion.Sandstone[newTile.Wall] ||
- WallID.Sets.Conversion.HardenedSand[oldTile.wall] && WallID.Sets.Conversion.HardenedSand[newTile.Wall] ||
- WallID.Sets.Conversion.PureSand[oldTile.wall] && WallID.Sets.Conversion.PureSand[newTile.Wall] ||
- WallID.Sets.Conversion.NewWall1[oldTile.wall] && WallID.Sets.Conversion.NewWall1[newTile.Wall] ||
- WallID.Sets.Conversion.NewWall2[oldTile.wall] && WallID.Sets.Conversion.NewWall2[newTile.Wall] ||
- WallID.Sets.Conversion.NewWall3[oldTile.wall] && WallID.Sets.Conversion.NewWall3[newTile.Wall] ||
- WallID.Sets.Conversion.NewWall4[oldTile.wall] && WallID.Sets.Conversion.NewWall4[newTile.Wall]
- )
+ // wallbans when?
+
+ if (!player.HasBuildPermission(rect.X, rect.Y))
{
- // wallbans when?
+ // for simplicity, let's pretend that the edit was valid, but do not execute it
+ return true;
+ }
+ else
+ {
+ Main.tile[rect.X, rect.Y].wall = newTile.Wall;
- if (!player.HasBuildPermission(rect.X, rect.Y))
- {
- // for simplicity, let's pretend that the edit was valid, but do not execute it
- matchedTileOrWall = true;
- }
- else
- {
- Main.tile[rect.X, rect.Y].wall = newTile.Wall;
-
- matchedTileOrWall = true;
- }
+ return true;
}
}
- return matchedTileOrWall;
+ return false;
}
@@ -881,4 +848,483 @@ namespace TShockAPI.Handlers
return false;
}
}
+
+ ///
+ /// This helper class allows simulating a `WorldGen.Convert` call and retrieving all valid changes for a given tile.
+ ///
+ internal static class WorldGenMock
+ {
+ ///
+ /// This is a mock tile which collects all possible changes the `WorldGen.Convert` code could make in its property setters.
+ ///
+ private sealed class MockTile
+ {
+ private readonly HashSet _setTypes;
+ private readonly HashSet _setWalls;
+
+ private ushort _type;
+ private ushort _wall;
+
+ public MockTile(ushort type, ushort wall, HashSet setTypes, HashSet setWalls)
+ {
+ _setTypes = setTypes;
+ _setWalls = setWalls;
+ _type = type;
+ _wall = wall;
+ }
+
+#pragma warning disable IDE1006
+
+ public ushort type
+ {
+ get => _type;
+ set
+ {
+ _setTypes.Add(value);
+ _type = value;
+ }
+ }
+
+ public ushort wall
+ {
+ get => _wall;
+ set
+ {
+ _setWalls.Add(value);
+ _wall = value;
+ }
+ }
+
+#pragma warning restore IDE1006
+ }
+
+ ///
+ /// Simulates what would happen if `WorldGen.Convert` was called on the given coordinates and returns two sets with the possible tile type and wall types that the conversion could change the tile to.
+ ///
+ public static void SimulateConversionChange(int x, int y, out HashSet validTiles, out HashSet validWalls)
+ {
+ validTiles = new HashSet();
+ validWalls = new HashSet();
+
+ // all the conversion types used in the code, most apparent in Projectile ai 31
+ foreach (int conversionType in new int[] { 0, 1, 2, 3, 4, 5, 6, 7 })
+ {
+ MockTile mock = new(Main.tile[x, y].type, Main.tile[x, y].wall, validTiles, validWalls);
+ Convert(mock, x, y, conversionType);
+ }
+ }
+
+ /*
+ * This is a copy of the `WorldGen.Convert` method with the following precise changes:
+ * - Added a `MockTile tile` parameter
+ * - Changed the `i` and `j` parameters to `k` and `l`
+ * - Removed the size parameter
+ * - Removed the area loop and `Tile tile = Main.tile[k, l]` access in favor of using the tile parameter
+ * - Removed all calls to `WorldGen.SquareWallFrame`, `NetMessage.SendTileSquare`, `WorldGen.TryKillingTreesAboveIfTheyWouldBecomeInvalid`
+ * - Changed all `continue` statements to `break` statements
+ * - Removed the ifs checking the bounds of the tile and wall types
+ * - Removed branches that would call `WorldGen.KillTile`
+ * - Changed branches depending on randomness to instead set the property to both values after one another
+ *
+ * This overall leads to a method that can be called on a MockTile and real-world coordinates and will spit out the proper conversion changes into the MockTile.
+ */
+
+ private static void Convert(MockTile tile, int k, int l, int conversionType)
+ {
+ int type = tile.type;
+ int wall = tile.wall;
+ switch (conversionType)
+ {
+ case 4:
+ if (WallID.Sets.Conversion.Grass[wall] && wall != 81)
+ {
+ tile.wall = 81;
+ }
+ else if (WallID.Sets.Conversion.Stone[wall] && wall != 83)
+ {
+ tile.wall = 83;
+ }
+ else if (WallID.Sets.Conversion.HardenedSand[wall] && wall != 218)
+ {
+ tile.wall = 218;
+ }
+ else if (WallID.Sets.Conversion.Sandstone[wall] && wall != 221)
+ {
+ tile.wall = 221;
+ }
+ else if (WallID.Sets.Conversion.NewWall1[wall] && wall != 192)
+ {
+ tile.wall = 192;
+ }
+ else if (WallID.Sets.Conversion.NewWall2[wall] && wall != 193)
+ {
+ tile.wall = 193;
+ }
+ else if (WallID.Sets.Conversion.NewWall3[wall] && wall != 194)
+ {
+ tile.wall = 194;
+ }
+ else if (WallID.Sets.Conversion.NewWall4[wall] && wall != 195)
+ {
+ tile.wall = 195;
+ }
+ if ((Main.tileMoss[type] || TileID.Sets.Conversion.Stone[type]) && type != 203)
+ {
+ tile.type = 203;
+ }
+ else if (TileID.Sets.Conversion.JungleGrass[type] && type != 662)
+ {
+ tile.type = 662;
+ }
+ else if (TileID.Sets.Conversion.Grass[type] && type != 199)
+ {
+ tile.type = 199;
+ }
+ else if (TileID.Sets.Conversion.Ice[type] && type != 200)
+ {
+ tile.type = 200;
+ }
+ else if (TileID.Sets.Conversion.Sand[type] && type != 234)
+ {
+ tile.type = 234;
+ }
+ else if (TileID.Sets.Conversion.HardenedSand[type] && type != 399)
+ {
+ tile.type = 399;
+ }
+ else if (TileID.Sets.Conversion.Sandstone[type] && type != 401)
+ {
+ tile.type = 401;
+ }
+ else if (TileID.Sets.Conversion.Thorn[type] && type != 352)
+ {
+ tile.type = 352;
+ }
+ break;
+ case 2:
+ if (WallID.Sets.Conversion.Grass[wall] && wall != 70)
+ {
+ tile.wall = 70;
+ }
+ else if (WallID.Sets.Conversion.Stone[wall] && wall != 28)
+ {
+ tile.wall = 28;
+ }
+ else if (WallID.Sets.Conversion.HardenedSand[wall] && wall != 219)
+ {
+ tile.wall = 219;
+ }
+ else if (WallID.Sets.Conversion.Sandstone[wall] && wall != 222)
+ {
+ tile.wall = 222;
+ }
+ else if (WallID.Sets.Conversion.NewWall1[wall] && wall != 200)
+ {
+ tile.wall = 200;
+ }
+ else if (WallID.Sets.Conversion.NewWall2[wall] && wall != 201)
+ {
+ tile.wall = 201;
+ }
+ else if (WallID.Sets.Conversion.NewWall3[wall] && wall != 202)
+ {
+ tile.wall = 202;
+ }
+ else if (WallID.Sets.Conversion.NewWall4[wall] && wall != 203)
+ {
+ tile.wall = 203;
+ }
+ if ((Main.tileMoss[type] || TileID.Sets.Conversion.Stone[type]) && type != 117)
+ {
+ tile.type = 117;
+ }
+ else if (TileID.Sets.Conversion.GolfGrass[type] && type != 492)
+ {
+ tile.type = 492;
+ }
+ else if (TileID.Sets.Conversion.Grass[type] && type != 109 && type != 492)
+ {
+ tile.type = 109;
+ }
+ else if (TileID.Sets.Conversion.Ice[type] && type != 164)
+ {
+ tile.type = 164;
+ }
+ else if (TileID.Sets.Conversion.Sand[type] && type != 116)
+ {
+ tile.type = 116;
+ }
+ else if (TileID.Sets.Conversion.HardenedSand[type] && type != 402)
+ {
+ tile.type = 402;
+ }
+ else if (TileID.Sets.Conversion.Sandstone[type] && type != 403)
+ {
+ tile.type = 403;
+ }
+ if (type == 59 && (Main.tile[k - 1, l].type == 109 || Main.tile[k + 1, l].type == 109 || Main.tile[k, l - 1].type == 109 || Main.tile[k, l + 1].type == 109))
+ {
+ tile.type = 0;
+ }
+ break;
+ case 1:
+ if (WallID.Sets.Conversion.Grass[wall] && wall != 69)
+ {
+ tile.wall = 69;
+ }
+ else if (TileID.Sets.Conversion.JungleGrass[type] && type != 661)
+ {
+ tile.type = 661;
+ }
+ else if (WallID.Sets.Conversion.Stone[wall] && wall != 3)
+ {
+ tile.wall = 3;
+ }
+ else if (WallID.Sets.Conversion.HardenedSand[wall] && wall != 217)
+ {
+ tile.wall = 217;
+ }
+ else if (WallID.Sets.Conversion.Sandstone[wall] && wall != 220)
+ {
+ tile.wall = 220;
+ }
+ else if (WallID.Sets.Conversion.NewWall1[wall] && wall != 188)
+ {
+ tile.wall = 188;
+ }
+ else if (WallID.Sets.Conversion.NewWall2[wall] && wall != 189)
+ {
+ tile.wall = 189;
+ }
+ else if (WallID.Sets.Conversion.NewWall3[wall] && wall != 190)
+ {
+ tile.wall = 190;
+ }
+ else if (WallID.Sets.Conversion.NewWall4[wall] && wall != 191)
+ {
+ tile.wall = 191;
+ }
+ if ((Main.tileMoss[type] || TileID.Sets.Conversion.Stone[type]) && type != 25)
+ {
+ tile.type = 25;
+ }
+ else if (TileID.Sets.Conversion.Grass[type] && type != 23)
+ {
+ tile.type = 23;
+ }
+ else if (TileID.Sets.Conversion.Ice[type] && type != 163)
+ {
+ tile.type = 163;
+ }
+ else if (TileID.Sets.Conversion.Sand[type] && type != 112)
+ {
+ tile.type = 112;
+ }
+ else if (TileID.Sets.Conversion.HardenedSand[type] && type != 398)
+ {
+ tile.type = 398;
+ }
+ else if (TileID.Sets.Conversion.Sandstone[type] && type != 400)
+ {
+ tile.type = 400;
+ }
+ else if (TileID.Sets.Conversion.Thorn[type] && type != 32)
+ {
+ tile.type = 32;
+ }
+ break;
+ case 3:
+ if (WallID.Sets.CanBeConvertedToGlowingMushroom[wall])
+ {
+ tile.wall = 80;
+ }
+ if (tile.type == 60)
+ {
+ tile.type = 70;
+ }
+ break;
+ case 5:
+ if ((WallID.Sets.Conversion.Stone[wall] || WallID.Sets.Conversion.NewWall1[wall] || WallID.Sets.Conversion.NewWall2[wall] || WallID.Sets.Conversion.NewWall3[wall] || WallID.Sets.Conversion.NewWall4[wall] || WallID.Sets.Conversion.Ice[wall] || WallID.Sets.Conversion.Sandstone[wall]) && wall != 187)
+ {
+ tile.wall = 187;
+ }
+ else if ((WallID.Sets.Conversion.HardenedSand[wall] || WallID.Sets.Conversion.Dirt[wall] || WallID.Sets.Conversion.Snow[wall]) && wall != 216)
+ {
+ tile.wall = 216;
+ }
+ if ((TileID.Sets.Conversion.Grass[type] || TileID.Sets.Conversion.Sand[type] || TileID.Sets.Conversion.Snow[type] || TileID.Sets.Conversion.Dirt[type]) && type != 53)
+ {
+ int num = 53;
+ if (WorldGen.BlockBelowMakesSandConvertIntoHardenedSand(k, l))
+ {
+ num = 397;
+ }
+ tile.type = (ushort)num;
+ }
+ else if (TileID.Sets.Conversion.HardenedSand[type] && type != 397)
+ {
+ tile.type = 397;
+ }
+ else if ((Main.tileMoss[type] || TileID.Sets.Conversion.Stone[type] || TileID.Sets.Conversion.Ice[type] || TileID.Sets.Conversion.Sandstone[type]) && type != 396)
+ {
+ tile.type = 396;
+ }
+ break;
+ case 6:
+ if ((WallID.Sets.Conversion.Stone[wall] || WallID.Sets.Conversion.NewWall1[wall] || WallID.Sets.Conversion.NewWall2[wall] || WallID.Sets.Conversion.NewWall3[wall] || WallID.Sets.Conversion.NewWall4[wall] || WallID.Sets.Conversion.Ice[wall] || WallID.Sets.Conversion.Sandstone[wall]) && wall != 71)
+ {
+ tile.wall = 71;
+ }
+ else if ((WallID.Sets.Conversion.HardenedSand[wall] || WallID.Sets.Conversion.Dirt[wall] || WallID.Sets.Conversion.Snow[wall]) && wall != 40)
+ {
+ tile.wall = 40;
+ }
+ if ((TileID.Sets.Conversion.Grass[type] || TileID.Sets.Conversion.Sand[type] || TileID.Sets.Conversion.HardenedSand[type] || TileID.Sets.Conversion.Snow[type] || TileID.Sets.Conversion.Dirt[type]) && type != 147)
+ {
+ tile.type = 147;
+ }
+ else if ((Main.tileMoss[type] || TileID.Sets.Conversion.Stone[type] || TileID.Sets.Conversion.Ice[type] || TileID.Sets.Conversion.Sandstone[type]) && type != 161)
+ {
+ tile.type = 161;
+ }
+ break;
+ case 7:
+ if ((WallID.Sets.Conversion.Stone[wall] || WallID.Sets.Conversion.Ice[wall] || WallID.Sets.Conversion.Sandstone[wall]) && wall != 1)
+ {
+ tile.wall = 1;
+ }
+ else if ((WallID.Sets.Conversion.HardenedSand[wall] || WallID.Sets.Conversion.Snow[wall] || WallID.Sets.Conversion.Dirt[wall]) && wall != 2)
+ {
+ tile.wall = 2;
+ }
+ else if (WallID.Sets.Conversion.NewWall1[wall] && wall != 196)
+ {
+ tile.wall = 196;
+ }
+ else if (WallID.Sets.Conversion.NewWall2[wall] && wall != 197)
+ {
+ tile.wall = 197;
+ }
+ else if (WallID.Sets.Conversion.NewWall3[wall] && wall != 198)
+ {
+ tile.wall = 198;
+ }
+ else if (WallID.Sets.Conversion.NewWall4[wall] && wall != 199)
+ {
+ tile.wall = 199;
+ }
+ if ((TileID.Sets.Conversion.Stone[type] || TileID.Sets.Conversion.Ice[type] || TileID.Sets.Conversion.Sandstone[type]) && type != 1)
+ {
+ tile.type = 1;
+ }
+ else if (TileID.Sets.Conversion.GolfGrass[type] && type != 477)
+ {
+ tile.type = 477;
+ }
+ else if (TileID.Sets.Conversion.Grass[type] && type != 2 && type != 477)
+ {
+ tile.type = 2;
+ }
+ else if ((TileID.Sets.Conversion.Sand[type] || TileID.Sets.Conversion.HardenedSand[type] || TileID.Sets.Conversion.Snow[type] || TileID.Sets.Conversion.Dirt[type]) && type != 0)
+ {
+ int num2 = 0;
+ if (WorldGen.TileIsExposedToAir(k, l))
+ {
+ num2 = 2;
+ }
+ tile.type = (ushort)num2;
+ }
+ break;
+ }
+ if (tile.wall == 69 || tile.wall == 70 || tile.wall == 81)
+ {
+ if (l < Main.worldSurface)
+ {
+ tile.wall = 65;
+ tile.wall = 63;
+ }
+ else
+ {
+ tile.wall = 64;
+ }
+ }
+ else if (WallID.Sets.Conversion.Stone[wall] && wall != 1 && wall != 262 && wall != 274 && wall != 61 && wall != 185)
+ {
+ tile.wall = 1;
+ }
+ else if (WallID.Sets.Conversion.Stone[wall] && wall == 262)
+ {
+ tile.wall = 61;
+ }
+ else if (WallID.Sets.Conversion.Stone[wall] && wall == 274)
+ {
+ tile.wall = 185;
+ }
+ if (WallID.Sets.Conversion.NewWall1[wall] && wall != 212)
+ {
+ tile.wall = 212;
+ }
+ else if (WallID.Sets.Conversion.NewWall2[wall] && wall != 213)
+ {
+ tile.wall = 213;
+ }
+ else if (WallID.Sets.Conversion.NewWall3[wall] && wall != 214)
+ {
+ tile.wall = 214;
+ }
+ else if (WallID.Sets.Conversion.NewWall4[wall] && wall != 215)
+ {
+ tile.wall = 215;
+ }
+ else if (tile.wall == 80)
+ {
+ tile.wall = 15;
+ tile.wall = 64;
+ }
+ else if (WallID.Sets.Conversion.HardenedSand[wall] && wall != 216)
+ {
+ tile.wall = 216;
+ }
+ else if (WallID.Sets.Conversion.Sandstone[wall] && wall != 187)
+ {
+ tile.wall = 187;
+ }
+ if (tile.type == 492)
+ {
+ tile.type = 477;
+ }
+ else if (TileID.Sets.Conversion.JungleGrass[type] && type != 60)
+ {
+ tile.type = 60;
+ }
+ else if (TileID.Sets.Conversion.Grass[type] && type != 2 && type != 477)
+ {
+ tile.type = 2;
+ }
+ else if (TileID.Sets.Conversion.Stone[type] && type != 1)
+ {
+ tile.type = 1;
+ }
+ else if (TileID.Sets.Conversion.Sand[type] && type != 53)
+ {
+ tile.type = 53;
+ }
+ else if (TileID.Sets.Conversion.HardenedSand[type] && type != 397)
+ {
+ tile.type = 397;
+ }
+ else if (TileID.Sets.Conversion.Sandstone[type] && type != 396)
+ {
+ tile.type = 396;
+ }
+ else if (TileID.Sets.Conversion.Ice[type] && type != 161)
+ {
+ tile.type = 161;
+ }
+ else if (TileID.Sets.Conversion.MushroomGrass[type])
+ {
+ tile.type = 60;
+ }
+ }
+ }
}