diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 588b9b407..d3d70b98c 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -105,6 +105,37 @@ function Initialize(Plugin) BA1:SaveToSchematicFile("schematics/rot4.schematic"); end + -- Debug block area rotation: + if (BA1:LoadFromSchematicFile("schematics/rotm.schematic")) then + BA1:RotateCCW(); + BA1:SaveToSchematicFile("schematics/rotm1.schematic"); + BA1:RotateCCW(); + BA1:SaveToSchematicFile("schematics/rotm2.schematic"); + BA1:RotateCCW(); + BA1:SaveToSchematicFile("schematics/rotm3.schematic"); + BA1:RotateCCW(); + BA1:SaveToSchematicFile("schematics/rotm4.schematic"); + end + + -- Debug block area mirroring: + if (BA1:LoadFromSchematicFile("schematics/ltm.schematic")) then + BA1:MirrorXY(); + BA1:SaveToSchematicFile("schematics/ltm_XY.schematic"); + BA1:MirrorXY(); + BA1:SaveToSchematicFile("schematics/ltm_XY2.schematic"); + + BA1:MirrorXZ(); + BA1:SaveToSchematicFile("schematics/ltm_XZ.schematic"); + BA1:MirrorXZ(); + BA1:SaveToSchematicFile("schematics/ltm_XZ2.schematic"); + + BA1:MirrorYZ(); + BA1:SaveToSchematicFile("schematics/ltm_YZ.schematic"); + BA1:MirrorYZ(); + BA1:SaveToSchematicFile("schematics/ltm_YZ2.schematic"); + end + + return true end diff --git a/source/BlockArea.cpp b/source/BlockArea.cpp index 8c4384ca3..b3ae4d916 100644 --- a/source/BlockArea.cpp +++ b/source/BlockArea.cpp @@ -9,6 +9,7 @@ #include "World.h" #include "OSSupport/GZipFile.h" #include "WorldStorage/FastNBT.h" +#include "Blocks/BlockHandler.h" @@ -923,12 +924,41 @@ void cBlockArea::RotateCCW(void) { if (!HasBlockTypes()) { - LOGWARNING("cBlockArea: Cannot rotate meta without blocktypes!"); + LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!"); return; } - ASSERT(!"Not implemented yet"); - // TODO + if (!HasBlockMetas()) + { + // There are no blockmetas to rotate, just use the NoMeta function + RotateCCWNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time: + BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; + NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = m_SizeX - x - 1; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = z; + for (int y = 0; y < m_SizeY; y++) + { + int NewIdx = NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ; + int OldIdx = MakeIndex(x, y, z); + NewTypes[NewIdx] = m_BlockTypes[OldIdx]; + NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCCW(m_BlockMetas[OldIdx]); + } // for y + } // for z + } // for x + std::swap(m_BlockTypes, NewTypes); + std::swap(m_BlockMetas, NewMetas); + delete[] NewTypes; + delete[] NewMetas; + + std::swap(m_SizeX, m_SizeZ); } @@ -939,12 +969,41 @@ void cBlockArea::RotateCW(void) { if (!HasBlockTypes()) { - LOGWARNING("cBlockArea: Cannot rotate meta without blocktypes!"); + LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!"); return; } - ASSERT(!"Not implemented yet"); - // TODO + if (!HasBlockMetas()) + { + // There are no blockmetas to rotate, just use the NoMeta function + RotateCWNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time: + BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; + NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = x; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = m_SizeZ - z - 1; + for (int y = 0; y < m_SizeY; y++) + { + int NewIdx = NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ; + int OldIdx = MakeIndex(x, y, z); + NewTypes[NewIdx] = m_BlockTypes[OldIdx]; + NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCW(m_BlockMetas[OldIdx]); + } // for y + } // for z + } // for x + std::swap(m_BlockTypes, NewTypes); + std::swap(m_BlockMetas, NewMetas); + delete[] NewTypes; + delete[] NewMetas; + + std::swap(m_SizeX, m_SizeZ); } @@ -958,9 +1017,33 @@ void cBlockArea::MirrorXY(void) LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); return; } + + if (!HasBlockMetas()) + { + // There are no blockmetas to mirror, just use the NoMeta function + MirrorXYNoMeta(); + return; + } - ASSERT(!"Not implemented yet"); - // TODO + // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: + int HalfZ = m_SizeZ / 2; + int MaxZ = m_SizeZ - 1; + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < HalfZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + int Idx1 = MakeIndex(x, y, z); + int Idx2 = MakeIndex(x, y, MaxZ - z); + std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); + NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorXY(m_BlockMetas[Idx1]); + NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorXY(m_BlockMetas[Idx2]); + m_BlockMetas[Idx1] = Meta2; + m_BlockMetas[Idx2] = Meta1; + } // for x + } // for z + } // for y } @@ -975,8 +1058,32 @@ void cBlockArea::MirrorXZ(void) return; } - ASSERT(!"Not implemented yet"); - // TODO + if (!HasBlockMetas()) + { + // There are no blockmetas to mirror, just use the NoMeta function + MirrorXZNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: + int HalfY = m_SizeY / 2; + int MaxY = m_SizeY - 1; + for (int y = 0; y < HalfY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + int Idx1 = MakeIndex(x, y, z); + int Idx2 = MakeIndex(x, MaxY - y, z); + std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); + NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorXZ(m_BlockMetas[Idx1]); + NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorXZ(m_BlockMetas[Idx2]); + m_BlockMetas[Idx1] = Meta2; + m_BlockMetas[Idx2] = Meta1; + } // for x + } // for z + } // for y } @@ -991,8 +1098,32 @@ void cBlockArea::MirrorYZ(void) return; } - ASSERT(!"Not implemented yet"); - // TODO + if (!HasBlockMetas()) + { + // There are no blockmetas to mirror, just use the NoMeta function + MirrorYZNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: + int HalfX = m_SizeX / 2; + int MaxX = m_SizeX - 1; + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < HalfX; x++) + { + int Idx1 = MakeIndex(x, y, z); + int Idx2 = MakeIndex(MaxX - x, y, z); + std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); + NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorYZ(m_BlockMetas[Idx1]); + NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorYZ(m_BlockMetas[Idx2]); + m_BlockMetas[Idx1] = Meta2; + m_BlockMetas[Idx2] = Meta1; + } // for x + } // for z + } // for y } diff --git a/source/Blocks/BlockHandler.h b/source/Blocks/BlockHandler.h index 4c91463bc..cb52be497 100644 --- a/source/Blocks/BlockHandler.h +++ b/source/Blocks/BlockHandler.h @@ -112,6 +112,21 @@ public: */ virtual void Check(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk); + /// Returns the meta for a block after rotating it counter-clockwise from the specified meta. Default: no change + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) { return a_Meta; } + + /// Returns the meta for a block after rotating it clockwise from the specified meta. Default: no change + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) { return a_Meta; } + + /// Returns the meta for a block after mirroring it around the XY plane. Default: no change + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) { return a_Meta; } + + /// Returns the meta for a block after mirroring it around the XZ plane. Default: no change + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) { return a_Meta; } + + /// Returns the meta for a block after mirroring it around the YZ plane. Default: no change + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; } + /// Get the blockhandler for a specific block id static cBlockHandler * GetBlockHandler(BLOCKTYPE a_BlockType); diff --git a/source/Blocks/BlockStairs.h b/source/Blocks/BlockStairs.h index 6fcbc2cba..9f135b37d 100644 --- a/source/Blocks/BlockStairs.h +++ b/source/Blocks/BlockStairs.h @@ -49,6 +49,77 @@ public: } // TODO: step sound + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + // Bits 3 and 4 stay, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x0c); + switch (a_Meta & 0x03) + { + case 0x00: return TopBits | 0x03; // East -> North + case 0x01: return TopBits | 0x02; // West -> South + case 0x02: return TopBits | 0x00; // South -> East + case 0x03: return TopBits | 0x01; // North -> West + } + // Not reachable, but to avoid a compiler warning: + return 0; + } + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + // Bits 3 and 4 stay, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x0c); + switch (a_Meta & 0x03) + { + case 0x00: return TopBits | 0x02; // East -> South + case 0x01: return TopBits | 0x03; // West -> North + case 0x02: return TopBits | 0x01; // South -> West + case 0x03: return TopBits | 0x00; // North -> East + } + // Not reachable, but to avoid a compiler warning: + return 0; + } + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + // Bits 3 and 4 stay, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x0c); + switch (a_Meta & 0x03) + { + case 0x00: return TopBits | 0x00; // East -> East + case 0x01: return TopBits | 0x01; // West -> West + case 0x02: return TopBits | 0x03; // South -> North + case 0x03: return TopBits | 0x02; // North -> South + } + // Not reachable, but to avoid a compiler warning: + return 0; + } + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override + { + // Toggle bit 3: + return (a_Meta & 0x0b) | ((~a_Meta) & 0x04); + } + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + // Bits 3 and 4 stay, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x0c); + switch (a_Meta & 0x03) + { + case 0x00: return TopBits | 0x01; // East -> West + case 0x01: return TopBits | 0x00; // West -> East + case 0x02: return TopBits | 0x02; // South -> South + case 0x03: return TopBits | 0x03; // North -> North + } + // Not reachable, but to avoid a compiler warning: + return 0; + } } ; diff --git a/source/Blocks/BlockTorch.h b/source/Blocks/BlockTorch.h index 3cc487421..97e31533b 100644 --- a/source/Blocks/BlockTorch.h +++ b/source/Blocks/BlockTorch.h @@ -132,6 +132,67 @@ public: { return "step.wood"; } + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + // Bit 4 stays, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x08); + switch (a_Meta & 0x07) + { + case 0x01: return TopBits | 0x04; // East -> North + case 0x02: return TopBits | 0x03; // West -> South + case 0x03: return TopBits | 0x01; // South -> East + case 0x04: return TopBits | 0x02; // North -> West + default: return a_Meta; // Floor -> Floor + } + } + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + // Bit 4 stays, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x08); + switch (a_Meta & 0x07) + { + case 0x01: return TopBits | 0x03; // East -> South + case 0x02: return TopBits | 0x04; // West -> North + case 0x03: return TopBits | 0x02; // South -> West + case 0x04: return TopBits | 0x01; // North -> East + default: return a_Meta; // Floor -> Floor + } + } + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + // Bit 4 stays, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x08); + switch (a_Meta & 0x07) + { + case 0x03: return TopBits | 0x04; // South -> North + case 0x04: return TopBits | 0x03; // North -> South + default: return a_Meta; // Keep the rest + } + } + + + // Mirroring around the XZ plane doesn't make sense for floor torches, + // the others stay the same, so let's keep all the metas the same. + // The base class does tht for us, no need to override MetaMirrorXZ() + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + // Bit 4 stays, the rest is swapped around according to a table: + NIBBLETYPE TopBits = (a_Meta & 0x08); + switch (a_Meta & 0x07) + { + case 0x01: return TopBits | 0x02; // East -> West + case 0x02: return TopBits | 0x01; // West -> East + default: return a_Meta; // Keep the rest + } + } } ; diff --git a/source/Blocks/BlockVine.h b/source/Blocks/BlockVine.h index 88338e86d..67376a4d8 100644 --- a/source/Blocks/BlockVine.h +++ b/source/Blocks/BlockVine.h @@ -138,10 +138,36 @@ public: } - bool DoesDropOnUnsuitable(void) + virtual bool DoesDropOnUnsuitable(void) override { return false; } + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right + } + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left + } + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + // Bits 2 and 4 stay, bits 1 and 3 swap + return ((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); + } + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + // Bits 1 and 3 stay, bits 2 and 4 swap + return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); + } } ;