#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)
-: block_type(types)
-, generate(config.gen)
-, chunks(config.load, types, generate, save)
-, player()
+World::World(const BlockTypeRegistry &types, const Config &config)
+: config(config)
+, block_type(types)
+, 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 });
- player = &AddEntity();
- player->Name("player");
- player->Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
- player->WorldCollidable(true);
- player->Position(config.spawn);
+}
+
+World::~World() {
+ chunks.UnregisterIndex(spawn_index);
+}
- chunks.QueueSurrounding(player->ChunkCoords());
+
+Player World::AddPlayer(const std::string &name) {
+ for (Player &p : players) {
+ if (p.entity->Name() == name) {
+ return { nullptr, nullptr };
+ }
+ }
+ Entity &entity = AddEntity();
+ 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();
+}
+
+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;
+}
+
+Entity &World::ForceAddEntity(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 *position;
+ }
+ auto entity = entities.emplace(position);
+ entity->ID(id);
+ return *entity;
}
) {
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 });
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
}
-Chunk &World::PlayerChunk() {
- return chunks.ForceLoad(player->ChunkCoords());
-}
-
-
namespace {
std::vector<WorldCollision> col;
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;
}
}
- chunks.Rebase(player->ChunkCoords());
- chunks.Update(dt);
}
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);
+ end = players.end();
+ } else {
+ ++player;
+ }
+ }
+ return entities.erase(eh);
+}
+
void World::Render(Viewport &viewport) {
DirectionalLighting &entity_prog = viewport.EntityProgram();
entity_prog.SetFogDensity(fog_density);
for (Entity &entity : entities) {
- entity.Render(entity.ChunkTransform(player->ChunkCoords()), entity_prog);
+ entity.Render(entity.ChunkTransform(players[0].entity->ChunkCoords()), entity_prog);
}
}