]> git.localhorst.tv Git - blank.git/commitdiff
made chunk neighbor linkage a little safer
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 22 Jul 2015 15:32:55 +0000 (17:32 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 22 Jul 2015 15:32:55 +0000 (17:32 +0200)
TODO
src/world/Chunk.hpp
src/world/ChunkLoader.hpp
src/world/chunk.cpp
tst/world/ChunkTest.cpp

diff --git a/TODO b/TODO
index 9d43155a0d96e9b78ec394f0e16112e7e29f18b3..7e52a23ba4b940e4b9bab1bc13a8474ac3a15f39 100644 (file)
--- a/TODO
+++ b/TODO
@@ -76,10 +76,6 @@ chunk traversal
        profiling indicates that this is not neccessary atm. maybe it will
        when there's some more action in the world
 
-       I got a segfault (sadly in release mode, so no sensible trace, but
-       it was in ChunkLoader::Update). I suspect it has something to do
-       with how chunks are relinked after a near death experience.
-
 transparency (blocks and entities)
 
        transparent blocks because awesome
index 02f146e12de2870793bf35f0a3275d8480b07e90..a75d8e202ddb3e5544fb0f7cc25e3b44c2a650f5 100644 (file)
@@ -102,7 +102,6 @@ public:
        const Chunk &GetNeighbor(Block::Face f) const noexcept { return *neighbor[f]; }
        void ClearNeighbors() noexcept;
        void Unlink() noexcept;
-       void Relink() noexcept;
 
        // check which faces of a block at given index are obstructed (and therefore invisible)
        Block::FaceSet Obstructed(const Pos &) const noexcept;
index 98b352fbc6e228c08b25c75e15954f01a5652184..c9fb8aa2f574e1721ef568ce2be95604f31ff2b0 100644 (file)
@@ -41,8 +41,14 @@ public:
 
 private:
        Chunk &Generate(const Chunk::Pos &pos);
+       // link given chunk to all loaded neighbors
        void Insert(Chunk &) noexcept;
-       void Remove(Chunk &) noexcept;
+       // remove a loaded chunk
+       // this unlinks it from its neighbors as well as moves it to the free list
+       // given iterator must point to a chunk from the loaded list
+       // returns an iterator to the chunk following the removed one
+       // in the loaded list (end for the last one)
+       std::list<Chunk>::iterator Remove(std::list<Chunk>::iterator) noexcept;
 
 private:
        Chunk::Pos base;
index 75f9c4f424c28d8babc77ef9322921a7db96a899..ef3c5fc869d80acb94d4ec054462ce2d85c9cc64 100644 (file)
@@ -295,23 +295,10 @@ void Chunk::SetNeighbor(Chunk &other) noexcept {
 }
 
 void Chunk::ClearNeighbors() noexcept {
-       for (int i = 0; i < Block::FACE_COUNT; ++i) {
-               neighbor[i] = nullptr;
-       }
-}
-
-void Chunk::Unlink() noexcept {
        for (int face = 0; face < Block::FACE_COUNT; ++face) {
                if (neighbor[face]) {
                        neighbor[face]->neighbor[Block::Opposite(Block::Face(face))] = nullptr;
-               }
-       }
-}
-
-void Chunk::Relink() noexcept {
-       for (int face = 0; face < Block::FACE_COUNT; ++face) {
-               if (neighbor[face]) {
-                       neighbor[face]->neighbor[Block::Opposite(Block::Face(face))] = this;
+                       neighbor[face] = nullptr;
                }
        }
 }
@@ -760,8 +747,15 @@ void ChunkLoader::Insert(Chunk &chunk) noexcept {
        }
 }
 
-void ChunkLoader::Remove(Chunk &chunk) noexcept {
-       chunk.Unlink();
+std::list<Chunk>::iterator ChunkLoader::Remove(std::list<Chunk>::iterator chunk) noexcept {
+       // fetch next entry while chunk's still in the list
+       std::list<Chunk>::iterator next = chunk;
+       ++next;
+       // unlink neighbors so they won't reference a dead chunk
+       chunk->ClearNeighbors();
+       // and move it from loaded to free list
+       to_free.splice(to_free.end(), loaded, chunk);
+       return next;
 }
 
 Chunk *ChunkLoader::Loaded(const Chunk::Pos &pos) noexcept {
@@ -818,10 +812,7 @@ void ChunkLoader::Rebase(const Chunk::Pos &new_base) {
        // unload far away chunks
        for (auto iter(loaded.begin()), end(loaded.end()); iter != end;) {
                if (OutOfRange(*iter)) {
-                       auto saved = iter;
-                       Remove(*saved);
-                       ++iter;
-                       to_free.splice(to_free.end(), loaded, saved);
+                       iter = Remove(iter);
                } else {
                        ++iter;
                }
@@ -844,27 +835,35 @@ void ChunkLoader::GenerateSurrounding(const Chunk::Pos &pos) {
 }
 
 void ChunkLoader::Update(int dt) {
+       // check if a chunk generation is scheduled for this frame
+       // and if there's a chunk waiting to be generated
        gen_timer.Update(dt);
        if (!gen_timer.Hit() || to_generate.empty()) {
                return;
        }
 
+       // take position of next chunk in queue
        Chunk::Pos pos(to_generate.front());
        to_generate.pop_front();
 
+       // look if the same chunk was already generated and still lingering
        for (auto iter(to_free.begin()), end(to_free.end()); iter != end; ++iter) {
                if (iter->Position() == pos) {
-                       iter->Relink();
                        loaded.splice(loaded.end(), to_free, iter);
+                       Insert(loaded.back());
+                       return;
                }
        }
 
+       // if the free list is empty, allocate a new chunk
+       // otherwise clear an unused one
        if (to_free.empty()) {
                loaded.emplace_back(reg);
        } else {
                to_free.front().ClearNeighbors();
                loaded.splice(loaded.end(), to_free, to_free.begin());
        }
+
        Chunk &chunk = loaded.back();
        chunk.Position(pos);
        gen(chunk);
index 408fec32dffaa5f3f4b8de747490d11f832a907c..6db245a2d7d5cd58182c0cef956abaa3c85745fa 100644 (file)
@@ -322,7 +322,6 @@ void ChunkTest::testNeighbor() {
                        "chunk did not link correct neighbor",
                        &*chunk, &neighbor->GetNeighbor(Block::Opposite(face))
                );
-               chunk->Unlink();
                chunk->ClearNeighbors();
        }