]> git.localhorst.tv Git - blank.git/blobdiff - src/world/World.cpp
split chunk stuff
[blank.git] / src / world / World.cpp
index 06ccb62cfea1f97f0341ac313c3848f9ee81e9a6..8b43657d3b58b1520e40c25019762883e6f7e5fb 100644 (file)
@@ -1,5 +1,6 @@
 #include "World.hpp"
 
+#include "ChunkIndex.hpp"
 #include "EntityCollision.hpp"
 #include "WorldCollision.hpp"
 #include "../app/Assets.hpp"
 
 namespace blank {
 
-World::World(const BlockTypeRegistry &types, const Config &config, const WorldSave &save)
+World::World(const BlockTypeRegistry &types, const Config &config)
 : config(config)
 , block_type(types)
-, generate(config.gen)
-, chunks(config.load, types, generate, save)
+, chunks(types)
+// TODO: set spawn base and extent from config
+, spawn_index(chunks.MakeIndex(Chunk::Pos(0, 0, 0), 3))
 , players()
 , entities()
 , light_direction(config.light_direction)
 , fog_density(config.fog_density) {
-       generate.Space(0);
-       generate.Light(13);
-       generate.Solids({ 1, 4, 7, 10 });
+
+}
+
+World::~World() {
+       chunks.UnregisterIndex(spawn_index);
 }
 
 
-Entity *World::AddPlayer(const std::string &name) {
-       for (Entity *e : players) {
-               if (e->Name() == name) {
-                       return nullptr;
+Player World::AddPlayer(const std::string &name) {
+       for (Player &p : players) {
+               if (p.entity->Name() == name) {
+                       return { nullptr, nullptr };
                }
        }
-       Entity &player = AddEntity();
-       player.Name(name);
+       Entity &entity = AddEntity();
+       entity.Name(name);
        // TODO: load from save file here
-       player.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
-       player.WorldCollidable(true);
-       player.Position(config.spawn);
-       players.push_back(&player);
-       chunks.QueueSurrounding(player.ChunkCoords());
-       return &player;
+       entity.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
+       entity.WorldCollidable(true);
+       entity.Position(config.spawn);
+       ChunkIndex *index = &chunks.MakeIndex(entity.ChunkCoords(), 6);
+       players.emplace_back(&entity, index);
+       return players.back();
+}
+
+Player World::AddPlayer(const std::string &name, std::uint32_t id) {
+       for (Player &p : players) {
+               if (p.entity->Name() == name) {
+                       return { nullptr, nullptr };
+               }
+       }
+       Entity *entity = AddEntity(id);
+       if (!entity) {
+               return { nullptr, nullptr };
+       }
+       entity->Name(name);
+       // TODO: load from save file here
+       entity->Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
+       entity->WorldCollidable(true);
+       entity->Position(config.spawn);
+       ChunkIndex *index = &chunks.MakeIndex(entity->ChunkCoords(), 6);
+       players.emplace_back(entity, index);
+       return players.back();
+}
+
+Entity &World::AddEntity() {
+       if (entities.empty()) {
+               entities.emplace_back();
+               entities.back().ID(1);
+               return entities.back();
+       }
+       if (entities.back().ID() < std::numeric_limits<std::uint32_t>::max()) {
+               std::uint32_t id = entities.back().ID() + 1;
+               entities.emplace_back();
+               entities.back().ID(id);
+               return entities.back();
+       }
+       std::uint32_t id = 1;
+       auto position = entities.begin();
+       auto end = entities.end();
+       while (position != end && position->ID() == id) {
+               ++id;
+               ++position;
+       }
+       auto entity = entities.emplace(position);
+       entity->ID(id);
+       return *entity;
+}
+
+Entity *World::AddEntity(std::uint32_t id) {
+       if (entities.empty() || entities.back().ID() < id) {
+               entities.emplace_back();
+               entities.back().ID(id);
+               return &entities.back();
+       }
+
+       auto position = entities.begin();
+       auto end = entities.end();
+       while (position != end && position->ID() < id) {
+               ++position;
+       }
+       if (position != end && position->ID() == id) {
+               return nullptr;
+       }
+       auto entity = entities.emplace(position);
+       entity->ID(id);
+       return &*entity;
 }
 
 
@@ -70,7 +138,7 @@ bool World::Intersection(
 ) {
        candidates.clear();
 
-       for (Chunk &cur_chunk : chunks.Loaded()) {
+       for (Chunk &cur_chunk : chunks) {
                float cur_dist;
                if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(reference), cur_dist)) {
                        candidates.push_back({ &cur_chunk, cur_dist });
@@ -130,7 +198,7 @@ bool World::Intersection(const Entity &e, std::vector<WorldCollision> &col) {
        Chunk::Pos reference = e.ChunkCoords();
        glm::mat4 M = e.Transform(reference);
        bool any = false;
-       for (Chunk &cur_chunk : chunks.Loaded()) {
+       for (Chunk &cur_chunk : chunks) {
                if (manhattan_radius(cur_chunk.Position() - e.ChunkCoords()) > 1) {
                        // chunk is not one of the 3x3x3 surrounding the entity
                        // since there's no entity which can extent over 16 blocks, they can be skipped
@@ -161,16 +229,16 @@ void World::Update(int dt) {
                        Resolve(entity, col);
                }
        }
+       for (Player &player : players) {
+               player.chunks->Rebase(player.entity->ChunkCoords());
+       }
        for (auto iter = entities.begin(), end = entities.end(); iter != end;) {
                if (iter->CanRemove()) {
-                       iter = entities.erase(iter);
+                       iter = RemoveEntity(iter);
                } else {
                        ++iter;
                }
        }
-       // TODO: make flexible
-       chunks.Rebase(players[0]->ChunkCoords());
-       chunks.Update(dt);
 }
 
 void World::Resolve(Entity &e, std::vector<WorldCollision> &col) {
@@ -205,6 +273,19 @@ void World::Resolve(Entity &e, std::vector<WorldCollision> &col) {
        e.Move(final_disp);
 }
 
+World::EntityHandle World::RemoveEntity(EntityHandle &eh) {
+       // check for player
+       for (auto player = players.begin(), end = players.end(); player != end;) {
+               if (player->entity == &*eh) {
+                       chunks.UnregisterIndex(*player->chunks);
+                       player = players.erase(player);
+               } else {
+                       ++player;
+               }
+       }
+       return entities.erase(eh);
+}
+
 
 void World::Render(Viewport &viewport) {
        DirectionalLighting &entity_prog = viewport.EntityProgram();
@@ -212,7 +293,7 @@ void World::Render(Viewport &viewport) {
        entity_prog.SetFogDensity(fog_density);
 
        for (Entity &entity : entities) {
-               entity.Render(entity.ChunkTransform(players[0]->ChunkCoords()), entity_prog);
+               entity.Render(entity.ChunkTransform(players[0].entity->ChunkCoords()), entity_prog);
        }
 }