Browse Source

full implementation of lazy block storage on heap

Kajetan Johannes Hammerle 3 years ago
parent
commit
786e4b6041

+ 29 - 0
common/world/BlockMap.cpp

@@ -0,0 +1,29 @@
+#include "common/world/BlockMap.h"
+
+static constexpr BlockId EMPTY_BLOCK = 65535;
+
+BlockMap::BlockMap(int length, BlockId id) : blocks(length, 1), map(2, EMPTY_BLOCK) {
+    map[0] = id;
+}
+
+BlockId BlockMap::get(int index) const {
+    return map[blocks.get(index)];
+}
+
+void BlockMap::set(int index, BlockId id) {
+    for(int i = 0; i < map.getLength(); i++) {
+        if(map[i] == id) {
+            blocks.set(index, i);
+            return;
+        } else if(map[i] == EMPTY_BLOCK) {
+            map[i] = id;
+            blocks.set(index, i);
+            return;
+        }
+    }
+    blocks.resize(blocks.getBits() + 1);
+    int i = map.getLength();
+    map.grow(map.getLength(), EMPTY_BLOCK);
+    map[i] = id;
+    blocks.set(index, i);
+}

+ 7 - 28
common/world/BlockMap.h

@@ -1,40 +1,19 @@
 #ifndef BLOCKMAP_H
 #define BLOCKMAP_H
 
-#include "gaming-core/utils/BitArray.h"
-#include "gaming-core/utils/Array.h"
 #include "common/block/BlockTypes.h"
+#include "gaming-core/utils/BitArray.h"
+#include "gaming-core/utils/HeapArray.h"
 
-template<int N, int B>
 class BlockMap {
-    static constexpr int EMPTY_BLOCK_ID = 65535;
-
-    BitArray<N, B> blocks;
-    Array<BlockId, 1 << B> map;
+    BitArray blocks;
+    HeapArray<BlockId> map;
 
 public:
+    BlockMap(int length, BlockId id);
 
-    BlockMap(BlockId id) : map(EMPTY_BLOCK_ID) {
-        map[0] = id;
-    }
-
-    BlockId get(int index) const {
-        return map[blocks[index]];
-    }
-
-    bool set(int index, BlockId id) {
-        for(int i = 0; i < map.getLength(); i++) {
-            if(map[i] == id) {
-                blocks[index] = i;
-                return false;
-            } else if(map[i] == 65535) {
-                map[i] = id;
-                blocks[index] = i;
-                return false;
-            }
-        }
-        return true;
-    }
+    BlockId get(int index) const;
+    void set(int index, BlockId id);
 };
 
 #endif

+ 52 - 0
common/world/BlockStorage.cpp

@@ -0,0 +1,52 @@
+#include "common/world/BlockStorage.h"
+
+static constexpr int SEGMENT_BITS = 6;
+static constexpr int SEGMENT = 1 << SEGMENT_BITS;
+static constexpr int SEGMENT_MASK = (1 << SEGMENT_BITS) - 1;
+
+BlockStorage::BlockStorage(int sizeBits, int heightBits)
+    : size(1 << sizeBits), height(1 << heightBits), sizeMask(size - 1), maps((size * size * height) / SEGMENT) {
+}
+
+BlockId BlockStorage::get(int x, int y, int z) const {
+    if(y < 0 || y >= height) {
+        return 0;
+    }
+    x &= (size - 1);
+    z &= (size - 1);
+
+    int index = y * size * size + x * size + z;
+    int segmentIndex = index >> SEGMENT_BITS;
+
+    if(maps[segmentIndex] == nullptr) {
+        return 0;
+    }
+    return maps[segmentIndex]->get(index & SEGMENT_MASK);
+}
+
+void BlockStorage::set(int x, int y, int z, BlockId id) {
+    if(y < 0 || y >= height) {
+        return;
+    }
+    x &= (size - 1);
+    z &= (size - 1);
+
+    int index = y * size * size + x * size + z;
+    int segmentIndex = index >> SEGMENT_BITS;
+
+    if(maps[segmentIndex] == nullptr) {
+        if(id == 0) {
+            return;
+        }
+        maps[segmentIndex] = new BlockMap(SEGMENT, 0);
+    }
+    maps[segmentIndex]->set(index & SEGMENT_MASK, id);
+}
+
+int BlockStorage::getSize() const {
+    return size;
+}
+
+int BlockStorage::getHeight() const {
+    return height;
+}

+ 11 - 28
common/world/BlockStorage.h

@@ -1,42 +1,25 @@
 #ifndef BLOCKSTORAGE_H
 #define BLOCKSTORAGE_H
 
-#include "common/block/BlockTypes.h"
 #include "common/world/BlockMap.h"
+#include "gaming-core/memory/UniquePointer.h"
+#include "gaming-core/utils/HeapArray.h"
 
-template<int S, int H>
 class BlockStorage final {
-    static constexpr int SIZE = 1 << S;
-    static constexpr int HEIGHT = 1 << H;
-    static constexpr int SIZE_MASK = SIZE - 1;
+    int size;
+    int height;
+    int sizeMask;
 
-    BlockMap<SIZE * SIZE * HEIGHT, 1> data;
+    HeapArray<UniquePointer<BlockMap>> maps;
 
 public:
+    BlockStorage(int sizeBits, int heightBits);
 
-    BlockStorage() : data(0) {
-    }
+    BlockId get(int x, int y, int z) const;
+    void set(int x, int y, int z, BlockId id);
 
-    BlockId get(int x, int y, int z) const {
-        if(y < 0 || y >= HEIGHT) {
-            return 0;
-        }
-        x &= SIZE_MASK;
-        z &= SIZE_MASK;
-        return data.get(x * SIZE * SIZE + y * SIZE + z);
-    }
-
-    void set(int x, int y, int z, BlockId id) {
-        data.set(x * SIZE * SIZE + y * SIZE + z, id);
-    }
-
-    constexpr int getSize() const {
-        return SIZE;
-    }
-
-    constexpr int getHeight() const {
-        return HEIGHT;
-    }
+    int getSize() const;
+    int getHeight() const;
 };
 
 #endif

+ 4 - 2
common/world/World.cpp

@@ -1,10 +1,11 @@
 #include "common/world/World.h"
-#include "gaming-core/utils/Random.h"
 #include "common/world/HighMap.h"
+#include "gaming-core/utils/Random.h"
 
-World::World(const BlockRegistry& blockRegistry) : blockRegistry(blockRegistry) {
+World::World(const BlockRegistry& blockRegistry) : blockRegistry(blockRegistry), blocks(5, 5) {
     Block air = blockRegistry.getBlock("air");
     Block stone = blockRegistry.getBlock("stone");
+    Block dirt = blockRegistry.getBlock("dirt");
     HighMap<32, 32> map;
     for(int x = 0; x < 32; x++) {
         for(int z = 0; z < 32; z++) {
@@ -12,6 +13,7 @@ World::World(const BlockRegistry& blockRegistry) : blockRegistry(blockRegistry)
             for(int y = 0; y < height; y++) {
                 setBlock(x, y, z, stone);
             }
+            setBlock(x, height - 1, z, dirt);
             for(int y = height; y < 32; y++) {
                 setBlock(x, y, z, air);
             }

+ 4 - 4
common/world/World.h

@@ -6,14 +6,14 @@
 
 class World final {
     const BlockRegistry& blockRegistry;
-    BlockStorage<5, 5> blocks;
-    
+    BlockStorage blocks;
+
 public:
     World(const BlockRegistry& blockRegistry);
-    
+
     void setBlock(int x, int y, int z, const Block& block);
     const Block& getBlock(int x, int y, int z) const;
-    
+
     int getSize() const;
     int getHeight() const;
 };

+ 1 - 1
gaming-core

@@ -1 +1 @@
-Subproject commit 90f503f17761ace8600f8aa85ac8121c73a1c9da
+Subproject commit b090b812bc425e99392fed6850827568b094d537

+ 5 - 2
meson.build

@@ -4,10 +4,13 @@ sourcesCommon = [
     'common/network/Packet.cpp', 
     'common/block/Block.cpp', 
     'common/block/BlockRegistry.cpp', 
+    'common/world/BlockMap.cpp',
+    'common/world/BlockStorage.cpp',
     'common/world/World.cpp', 
     'gaming-core/utils/Random.cpp', 
-    'gaming-core/math/Vector.cpp', 
-    'gaming-core/utils/Clock.cpp']
+    'gaming-core/utils/Clock.cpp',
+    'gaming-core/utils/BitArray.cpp',
+    'gaming-core/math/Vector.cpp']
 
 sourcesServer = ['server/Main.cpp',
     'server/network/Server.cpp',