]> 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
 
        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
 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;
        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;
 
        // 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);
 
 private:
        Chunk &Generate(const Chunk::Pos &pos);
+       // link given chunk to all loaded neighbors
        void Insert(Chunk &) noexcept;
        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;
 
 private:
        Chunk::Pos base;
index 75f9c4f424c28d8babc77ef9322921a7db96a899..ef3c5fc869d80acb94d4ec054462ce2d85c9cc64 100644 (file)
@@ -295,23 +295,10 @@ void Chunk::SetNeighbor(Chunk &other) noexcept {
 }
 
 void Chunk::ClearNeighbors() 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;
        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 {
 }
 
 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)) {
        // 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;
                }
                } else {
                        ++iter;
                }
@@ -844,27 +835,35 @@ void ChunkLoader::GenerateSurrounding(const Chunk::Pos &pos) {
 }
 
 void ChunkLoader::Update(int dt) {
 }
 
 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;
        }
 
        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();
 
        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) {
        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);
                        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());
        }
        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);
        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 did not link correct neighbor",
                        &*chunk, &neighbor->GetNeighbor(Block::Opposite(face))
                );
-               chunk->Unlink();
                chunk->ClearNeighbors();
        }
 
                chunk->ClearNeighbors();
        }