From 01df186d0e6e55ef185c907a2d6f4fef9beb9f10 Mon Sep 17 00:00:00 2001 From: Lars Date: Wed, 21 May 2025 17:20:57 -0700 Subject: [PATCH] loose ends and a unit test --- src/mapblock.cpp | 15 +++++- src/mapblock.h | 20 ++++---- src/unittest/test_mapblock.cpp | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 12 deletions(-) diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 516df8bcc..3b59c5b63 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -211,10 +211,13 @@ void MapBlock::copyTo(VoxelManipulator &dst) v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE); VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1)); + bool was_mono_block = m_is_mono_block; deconvertMonoblock(); // Copy from data to VoxelManipulator dst.copyFrom(data, data_area, v3s16(0,0,0), getPosRelative(), data_size); + if (was_mono_block) + tryConvertToMonoblock(); } void MapBlock::copyFrom(const VoxelManipulator &src) @@ -226,10 +229,20 @@ void MapBlock::copyFrom(const VoxelManipulator &src) // Copy from VoxelManipulator to data src.copyTo(data, data_area, v3s16(0,0,0), getPosRelative(), data_size); - tryConvertToMonoblock(); } +void MapBlock::reallocate(u32 c, MapNode n) +{ + delete[] data; + if (c == 1) + porting::TrackFreedMemory(sizeof(MapNode) * nodecount); + + data = new MapNode[c]; + for (u32 i = 0; i < c; i++) + data[i] = n; +} + void MapBlock::tryConvertToMonoblock() { if (m_is_mono_block) diff --git a/src/mapblock.h b/src/mapblock.h index ac4710b62..c5b156b50 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -21,6 +21,9 @@ class NodeMetadataList; class IGameDef; class MapBlockMesh; class VoxelManipulator; +#if BUILD_UNITTESTS +class TestMapBlock; +#endif #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff @@ -429,6 +432,11 @@ public: static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; private: +#if BUILD_UNITTESTS + // access to data, tryConvertToMonoBlock, deconvertMonoblock + friend class TestMapBlock; +#endif + /* Private methods */ @@ -436,17 +444,7 @@ private: void deSerialize_pre22(std::istream &is, u8 version, bool disk); void tryConvertToMonoblock(); void deconvertMonoblock(); - - void reallocate(u32 c, MapNode n) - { - delete[] data; - if (c == 1) - porting::TrackFreedMemory(sizeof(MapNode) * nodecount); - - data = new MapNode[c]; - for (u32 i = 0; i < c; i++) - data[i] = n; - } + void reallocate(u32 c, MapNode n); /* * PLEASE NOTE: When adding something here be mindful of position and size diff --git a/src/unittest/test_mapblock.cpp b/src/unittest/test_mapblock.cpp index e4071efd5..d94497335 100644 --- a/src/unittest/test_mapblock.cpp +++ b/src/unittest/test_mapblock.cpp @@ -10,6 +10,7 @@ #include "serialization.h" #include "noise.h" #include "inventory.h" +#include "voxel.h" class TestMapBlock : public TestBase { @@ -33,6 +34,9 @@ public: // Tests loading a non-standard MapBlock void testLoadNonStd(IGameDef *gamedef); + + // Tests blocks with a single node recurring node + void testMonoblock(IGameDef *gamedef); }; static TestMapBlock g_test_instance; @@ -45,10 +49,89 @@ void TestMapBlock::runTests(IGameDef *gamedef) TEST(testLoad29, gamedef); TEST(testLoad20, gamedef); TEST(testLoadNonStd, gamedef); + TEST(testMonoblock, gamedef); } //////////////////////////////////////////////////////////////////////////////// +void TestMapBlock::testMonoblock(IGameDef *gamedef) +{ + MapBlock block({}, gamedef); + UASSERT(!block.m_is_mono_block); + MapNode *t = block.data; + for (size_t i = 0; i < MapBlock::nodecount; ++i) { + block.data[i] = MapNode(CONTENT_AIR); + } + // covert to monoblock + block.tryConvertToMonoblock(); + UASSERT(block.m_is_mono_block); + UASSERT(block.data[0].param0 == CONTENT_AIR); + UASSERT(block.data != t); + t = block.data; + + // get the data(), should deconvert the block + MapNode *d1 = block.getData(); + UASSERT(!block.m_is_mono_block); + UASSERT(block.data != t); + UASSERT(block.data == d1); + + // covert back to mono block + block.tryConvertToMonoblock(); + UASSERT(block.m_is_mono_block); + t = block.data; + + // deconvert explicitly + block.deconvertMonoblock(); + UASSERT(!block.m_is_mono_block); + UASSERT(block.data != t); + + // covert back to mono block + block.tryConvertToMonoblock(); + UASSERT(block.m_is_mono_block); + t = block.data; + + // set a node, should deconvert the block + block.setNode(5,5,5, MapNode(42)); + UASSERT(!block.m_is_mono_block); + UASSERT(block.data != t); + t = block.data; + + // cannot covert to mono block + block.tryConvertToMonoblock(); + UASSERT(!block.m_is_mono_block); + UASSERT(block.data == t); + + // set all nodes to 42 + for (size_t i = 0; i < MapBlock::nodecount; ++i) { + block.data[i] = MapNode(42); + } + + // can covert to mono block + block.tryConvertToMonoblock(); + UASSERT(block.m_is_mono_block); + UASSERT(block.data[0].param0 == 42); + UASSERT(block.data != t); + t = block.data; + + VoxelManipulator vmm; + v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE); + vmm.addArea(VoxelArea(block.getPosRelative(), block.getPosRelative() + data_size + v3s16(1,1,1))); + block.copyTo(vmm); + UASSERT(block.m_is_mono_block); + UASSERT(vmm.getNode({5,5,5}).param0 == 42); + + block.setNode(5,5,5,MapNode(23)); + t = block.data; + + block.copyFrom(vmm); + UASSERT(block.m_is_mono_block); + UASSERT(block.data[0].param0 == 42); + + vmm.setNode({5,5,5}, MapNode(23)); + block.copyFrom(vmm); + UASSERT(!block.m_is_mono_block); +} + void TestMapBlock::testSaveLoad(IGameDef *gamedef, const u8 version) { // Use the bottom node ids for this test