diff --git a/ClassicalSharp/Map/Formats/MapLvl.Importer.cs b/ClassicalSharp/Map/Formats/MapLvl.Importer.cs index 26b5917ec..d629437a8 100644 --- a/ClassicalSharp/Map/Formats/MapLvl.Importer.cs +++ b/ClassicalSharp/Map/Formats/MapLvl.Importer.cs @@ -50,25 +50,42 @@ namespace ClassicalSharp.Map { byte[] chunk = new byte[16 * 16 * 16]; byte[] data = new byte[1]; + // skip bounds checks when we know chunk is entirely inside map + int adjWidth = width & ~0x0F; + int adjHeight = height & ~0x0F; + int adjLength = length & ~0x0F; + for (int y = 0; y < height; y += 16) for (int z = 0; z < length; z += 16) - for (int x = 0; x < width; x += 16) + for (int x = 0; x < width; x += 16) { int read = s.Read(data, 0, 1); if (read == 0 || data[0] != 1) continue; - s.Read(chunk, 0, chunk.Length); - + s.Read(chunk, 0, chunk.Length); int baseIndex = (y * length + z) * width + x; - for (int i = 0; i < chunk.Length; i++) { - int xx = i & 0xF, yy = (i >> 8) & 0xF, zz = (i >> 4) & 0xF; - int index = baseIndex + (yy * length + zz) * width + xx; - - if (blocks[index] != customTile) continue; - blocks[index] = chunk[i]; + + if ((x + 16) <= adjWidth && (y + 16) <= adjHeight && (z + 16) <= adjLength) { + for (int i = 0; i < chunk.Length; i++) { + int xx = i & 0xF, yy = (i >> 8) & 0xF, zz = (i >> 4) & 0xF; + int index = baseIndex + (yy * length + zz) * width + xx; + + if (blocks[index] != customTile) continue; + blocks[index] = chunk[i]; + } + } else { + for (int i = 0; i < chunk.Length; i++) { + int xx = i & 0xF, yy = (i >> 8) & 0xF, zz = (i >> 4) & 0xF; + if ((x + xx) >= width || (y + yy) >= height || (z + zz) >= length) continue; + int index = baseIndex + (yy * length + zz) * width + xx; + + if (blocks[index] != customTile) continue; + blocks[index] = chunk[i]; + } } + } } - + unsafe void ConvertPhysicsBlocks(byte[] blocks) { byte* conv = stackalloc byte[256]; int count = Block.CpeCount; diff --git a/src/Client/Formats.c b/src/Client/Formats.c index f1fe6a85c..7dca3d20c 100644 --- a/src/Client/Formats.c +++ b/src/Client/Formats.c @@ -33,6 +33,11 @@ UInt8 Lvl_table[256 - BLOCK_CPE_COUNT] = { 0, 0, 0, 0, 39, 36, 36, 10, 46, 21, 2 void Lvl_ReadCustomBlocks(Stream* stream) { Int32 x, y, z, i; UInt8 chunk[LVL_CHUNKSIZE * LVL_CHUNKSIZE * LVL_CHUNKSIZE]; + /* skip bounds checks when we know chunk is entirely inside map */ + Int32 adjWidth = World_Width & ~0x0F; + Int32 adjHeight = World_Height & ~0x0F; + Int32 adjLength = World_Length & ~0x0F; + for (y = 0; y < World_Height; y += LVL_CHUNKSIZE) { for (z = 0; z < World_Length; z += LVL_CHUNKSIZE) { for (x = 0; x < World_Width; x += LVL_CHUNKSIZE) { @@ -40,11 +45,21 @@ void Lvl_ReadCustomBlocks(Stream* stream) { Stream_Read(stream, chunk, sizeof(chunk)); Int32 baseIndex = World_Pack(x, y, z); - for (i = 0; i < sizeof(chunk); i++) { - Int32 xx = i & 0xF, yy = (i >> 8) & 0xF, zz = (i >> 4) & 0xF; - Int32 index = baseIndex + World_Pack(xx, yy, zz); - World_Blocks[index] = World_Blocks[index] == LVL_CUSTOMTILE ? chunk[i] : World_Blocks[index]; + if ((x + LVL_CHUNKSIZE) <= adjWidth && (y + LVL_CHUNKSIZE) <= adjHeight && (z + LVL_CHUNKSIZE) <= adjLength) { + for (i = 0; i < sizeof(chunk); i++) { + Int32 xx = i & 0xF, yy = (i >> 8) & 0xF, zz = (i >> 4) & 0xF; + Int32 index = baseIndex + World_Pack(xx, yy, zz); + World_Blocks[index] = World_Blocks[index] == LVL_CUSTOMTILE ? chunk[i] : World_Blocks[index]; + } + } else { + for (i = 0; i < sizeof(chunk); i++) { + Int32 xx = i & 0xF, yy = (i >> 8) & 0xF, zz = (i >> 4) & 0xF; + if ((x + xx) >= World_Width || (y + yy) >= World_Height || (z + zz) >= World_Length) continue; + Int32 index = baseIndex + World_Pack(xx, yy, zz); + World_Blocks[index] = World_Blocks[index] == LVL_CUSTOMTILE ? chunk[i] : World_Blocks[index]; + } } + } } }