diff --git a/client/include/world/ClientWorld.hpp b/client/include/world/ClientWorld.hpp index 8a964431..773a2542 100644 --- a/client/include/world/ClientWorld.hpp +++ b/client/include/world/ClientWorld.hpp @@ -30,22 +30,14 @@ class ClientWorld : public World, public gk::Drawable { void receiveChunkData(sf::Packet &packet); - // FIXME: Duplicated with ServerWorld - ClientChunk *getChunk(int cx, int cy, int cz) const; - BlockData *getBlockData(int x, int y, int z) const override; - - // FIXME: Duplicated with ServerWorld - u16 getBlock(int x, int y, int z) const override; - void setBlock(int x, int y, int z, u16 id) const override; - u16 getData(int x, int y, int z) const override; - void setData(int x, int y, int z, u16 id) const override; + Chunk *getChunk(int cx, int cy, int cz) const override; void setClient(ClientCommandHandler &client) { m_client = &client; } private: void draw(gk::RenderTarget &target, gk::RenderStates states) const override; - mutable std::unordered_map> m_chunks; + std::unordered_map> m_chunks; gk::Texture &m_texture; diff --git a/client/source/core/ClientApplication.cpp b/client/source/core/ClientApplication.cpp index 57200acd..f39c5d16 100644 --- a/client/source/core/ClientApplication.cpp +++ b/client/source/core/ClientApplication.cpp @@ -55,8 +55,11 @@ void ClientApplication::init() { Registry::setInstance(m_registry); // m_stateStack.push(); - auto &game = m_stateStack.push(m_host, m_port); - m_stateStack.push(game); + + m_stateStack.push(m_host, m_port); + + // auto &game = m_stateStack.push(m_host, m_port); + // m_stateStack.push(game); } void ClientApplication::initOpenGL() { diff --git a/client/source/world/ClientWorld.cpp b/client/source/world/ClientWorld.cpp index 5291d2b4..e14fa917 100644 --- a/client/source/world/ClientWorld.cpp +++ b/client/source/world/ClientWorld.cpp @@ -38,37 +38,40 @@ void ClientWorld::receiveChunkData(sf::Packet &packet) { s32 cx, cy, cz; packet >> cx >> cy >> cz; - ClientChunk *chunk = getChunk(cx, cy, cz); - if (chunk) { - for (u16 z = 0 ; z < CHUNK_DEPTH ; ++z) { - for (u16 y = 0 ; y < CHUNK_HEIGHT ; ++y) { - for (u16 x = 0 ; x < CHUNK_WIDTH ; ++x) { - u16 block; - u8 light; + Chunk *chunk = getChunk(cx, cy, cz); + if (!chunk) { + auto it = m_chunks.emplace(gk::Vector3i{cx, cy, cz}, new ClientChunk(cx, cy, cz, m_texture)); + chunk = it.first->second.get(); + } - packet >> block >> light; + for (u16 z = 0 ; z < CHUNK_DEPTH ; ++z) { + for (u16 y = 0 ; y < CHUNK_HEIGHT ; ++y) { + for (u16 x = 0 ; x < CHUNK_WIDTH ; ++x) { + u16 block; + u8 light; - chunk->setBlockRaw(x, y, z, block & 0xffff); - // chunk->setData(x, y, z, block >> 16); - chunk->lightmap().setLightData(x, y, z, light); - } + packet >> block >> light; + + chunk->setBlockRaw(x, y, z, block & 0xffff); + // chunk->setData(x, y, z, block >> 16); + chunk->lightmap().setLightData(x, y, z, light); } } - - chunk->setInitialized(true); - - // if(chunk->getSurroundingChunk(Chunk::Left)) chunk->getSurroundingChunk(Chunk::Left)->setChanged(true); - // if(chunk->getSurroundingChunk(Chunk::Right)) chunk->getSurroundingChunk(Chunk::Right)->setChanged(true); - // if(chunk->getSurroundingChunk(Chunk::Bottom)) chunk->getSurroundingChunk(Chunk::Bottom)->setChanged(true); - // if(chunk->getSurroundingChunk(Chunk::Top)) chunk->getSurroundingChunk(Chunk::Top)->setChanged(true); - // if(chunk->getSurroundingChunk(Chunk::Front)) chunk->getSurroundingChunk(Chunk::Front)->setChanged(true); - // if(chunk->getSurroundingChunk(Chunk::Back)) chunk->getSurroundingChunk(Chunk::Back)->setChanged(true); - - // std::cout << "Chunk at (" << cx << ", " << cy << ", " << cz << ") received" << std::endl; } + + chunk->setInitialized(true); + + // if(chunk->getSurroundingChunk(Chunk::Left)) chunk->getSurroundingChunk(Chunk::Left)->setChanged(true); + // if(chunk->getSurroundingChunk(Chunk::Right)) chunk->getSurroundingChunk(Chunk::Right)->setChanged(true); + // if(chunk->getSurroundingChunk(Chunk::Bottom)) chunk->getSurroundingChunk(Chunk::Bottom)->setChanged(true); + // if(chunk->getSurroundingChunk(Chunk::Top)) chunk->getSurroundingChunk(Chunk::Top)->setChanged(true); + // if(chunk->getSurroundingChunk(Chunk::Front)) chunk->getSurroundingChunk(Chunk::Front)->setChanged(true); + // if(chunk->getSurroundingChunk(Chunk::Back)) chunk->getSurroundingChunk(Chunk::Back)->setChanged(true); + + // std::cout << "Chunk at (" << cx << ", " << cy << ", " << cz << ") received" << std::endl; } -ClientChunk *ClientWorld::getChunk(int cx, int cy, int cz) const { +Chunk *ClientWorld::getChunk(int cx, int cy, int cz) const { auto it = m_chunks.find({cx, cy, cz}); if (it == m_chunks.end()) return nullptr; @@ -76,42 +79,6 @@ ClientChunk *ClientWorld::getChunk(int cx, int cy, int cz) const { return it->second.get(); } -BlockData *ClientWorld::getBlockData(int x, int y, int z) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - return chunk->getBlockData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); - - return nullptr; -} - -u16 ClientWorld::getBlock(int x, int y, int z) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - return chunk->getBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); - - return 0; -} - -void ClientWorld::setBlock(int x, int y, int z, u16 id) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id); -} - -u16 ClientWorld::getData(int x, int y, int z) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - return chunk->getData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); - - return 0; -} - -void ClientWorld::setData(int x, int y, int z, u16 id) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id); -} - void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const { if (!target.getView()) { DEBUG("ERROR: Trying to draw world without a camera"); @@ -122,11 +89,6 @@ void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const states.shader->setUniform("u_renderDistance", Config::renderDistance * CHUNK_WIDTH); gk::Shader::bind(nullptr); - float ud = 1000.0; - s32 ux = 0; - s32 uy = 0; - s32 uz = 0; - std::vector> chunks; for(auto &it : m_chunks) { states.transform = glm::translate(glm::mat4(1.0f), @@ -139,6 +101,7 @@ void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const * states.transform.getMatrix() * glm::vec4(CHUNK_WIDTH / 2, CHUNK_HEIGHT / 2, CHUNK_DEPTH / 2, 1); + // Nope, too far, don't render it if(glm::length(center) > (Config::renderDistance + 1) * CHUNK_WIDTH) { continue; } @@ -146,7 +109,7 @@ void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const // Is this chunk on the screen? center = target.getView()->getTransform().getMatrix() * center; - float d = glm::length(center); + // float d = glm::length(center); center.x /= center.w; center.y /= center.w; @@ -163,30 +126,12 @@ void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const // If this chunk is not initialized, skip it if(!it.second->isInitialized()) { - // But if it is the closest to the camera, mark it for initialization - if(d < ud) { - ud = d; - ux = it.second->x(); - uy = it.second->y(); - uz = it.second->z(); - } - continue; } chunks.emplace_back(it.second.get(), states.transform); } - ClientChunk *chunk = getChunk(ux, uy, uz); - if(ud <= 1000 && (!chunk || !chunk->hasBeenRequested())) { - auto it = m_chunks.emplace(gk::Vector3i(ux, uy, uz), new ClientChunk(ux, uy, uz, m_texture)); - it.first->second->setHasBeenRequested(true); - - m_client->sendChunkRequest(ux, uy, uz); - - DEBUG("Chunk requested at", ux, uy, uz); - } - for (u8 i = 0 ; i < ChunkBuilder::layers ; ++i) { for (auto &it : chunks) { states.transform = it.second; diff --git a/common/include/world/World.hpp b/common/include/world/World.hpp index b3723746..91e4b5fc 100644 --- a/common/include/world/World.hpp +++ b/common/include/world/World.hpp @@ -22,12 +22,13 @@ class World { public: virtual ~World() = default; - virtual BlockData *getBlockData(int x, int y, int z) const = 0; + virtual Chunk *getChunk(int cx, int cy, int cz) const = 0; + BlockData *getBlockData(int x, int y, int z) const; - virtual u16 getBlock(int x, int y, int z) const = 0; - virtual void setBlock(int x, int y, int z, u16 id) const = 0; - virtual u16 getData(int x, int y, int z) const = 0; - virtual void setData(int x, int y, int z, u16 id) const = 0; + u16 getBlock(int x, int y, int z) const; + void setBlock(int x, int y, int z, u16 id) const; + u16 getData(int x, int y, int z) const; + void setData(int x, int y, int z, u16 id) const; static bool isReloadRequested; }; diff --git a/common/source/world/World.cpp b/common/source/world/World.cpp index 7c993a54..191e85c4 100644 --- a/common/source/world/World.cpp +++ b/common/source/world/World.cpp @@ -20,3 +20,38 @@ bool World::isReloadRequested = false; +BlockData *World::getBlockData(int x, int y, int z) const { + Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); + if (chunk) + return chunk->getBlockData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); + + return nullptr; +} + +u16 World::getBlock(int x, int y, int z) const { + Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); + if (chunk) + return chunk->getBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); + + return 0; +} + +void World::setBlock(int x, int y, int z, u16 id) const { + Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); + if (chunk) + chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id); +} + +u16 World::getData(int x, int y, int z) const { + Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); + if (chunk) + return chunk->getData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); + + return 0; +} + +void World::setData(int x, int y, int z, u16 id) const { + Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); + if (chunk) + chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id); +} diff --git a/server/include/world/ServerWorld.hpp b/server/include/world/ServerWorld.hpp index 85cb3b6d..13561260 100644 --- a/server/include/world/ServerWorld.hpp +++ b/server/include/world/ServerWorld.hpp @@ -29,18 +29,11 @@ class ServerWorld : public World { void update(Server &server, std::unordered_map &players); + void sendSpawnData(Client &client, ServerPlayer &player); void sendChunkData(Client &client, ServerChunk *chunk); void sendRequestedData(Client &client, int cx, int cy, int cz); - // FIXME: Duplicated with ClientWorld - ServerChunk *getChunk(int cx, int cy, int cz) const; - BlockData *getBlockData(int x, int y, int z) const override; - - // FIXME: Duplicated with ClientWorld - u16 getBlock(int x, int y, int z) const override; - void setBlock(int x, int y, int z, u16 id) const override; - u16 getData(int x, int y, int z) const override; - void setData(int x, int y, int z, u16 id) const override; + Chunk *getChunk(int cx, int cy, int cz) const override; private: std::unordered_map> m_chunks; diff --git a/server/source/network/ServerCommandHandler.cpp b/server/source/network/ServerCommandHandler.cpp index f233f114..30494a5a 100644 --- a/server/source/network/ServerCommandHandler.cpp +++ b/server/source/network/ServerCommandHandler.cpp @@ -53,11 +53,12 @@ void ServerCommandHandler::setupCallbacks() { spawnPacket << m_spawnPosition.x << m_spawnPosition.y << m_spawnPosition.z; m_server.sendToAllClients(spawnPacket); - // m_world.sendWorldData(client); // FIXME + // FIXME: Temporarily useless + // sf::Packet worldSentPacket; + // worldSentPacket << Network::Command::WorldSent; + // client.tcpSocket->send(worldSentPacket); - sf::Packet worldSentPacket; - worldSentPacket << Network::Command::WorldSent; - client.tcpSocket->send(worldSentPacket); + m_world.sendSpawnData(client, player); }); m_server.setCommandCallback(Network::Command::ChunkRequest, [this](Client &client, sf::Packet &packet) { diff --git a/server/source/world/ServerWorld.cpp b/server/source/world/ServerWorld.cpp index d9295ed5..2868d448 100644 --- a/server/source/world/ServerWorld.cpp +++ b/server/source/world/ServerWorld.cpp @@ -41,6 +41,68 @@ void ServerWorld::update(Server &server, std::unordered_map & } } +void ServerWorld::sendSpawnData(Client &client, ServerPlayer &player) { + // Player chunk pos + int pcx = std::floor(player.x() / CHUNK_WIDTH); + int pcy = std::floor(player.y() / CHUNK_HEIGHT); + int pcz = std::floor(player.z() / CHUNK_DEPTH); + + // Create a chunk at the current player position + auto it = m_chunks.emplace(gk::Vector3i{pcx, pcy, pcz}, new ServerChunk(pcx, pcy, pcz)); + ServerChunk *chunk = it.first->second.get(); + + // Send the chunk to the client + sendChunkData(client, chunk); + + // Load surrounding chunks, starting from the one we generated above + std::queue chunks; + chunks.emplace(chunk); + while (!chunks.empty()) { + ServerChunk *chunk = chunks.front(); + chunks.pop(); + + gk::Vector3i surroundingChunks[6] = { + {chunk->x() - 1, chunk->y(), chunk->z()}, + {chunk->x() + 1, chunk->y(), chunk->z()}, + {chunk->x(), chunk->y(), chunk->z() - 1}, + {chunk->x(), chunk->y(), chunk->z() + 1}, + {chunk->x(), chunk->y() - 1, chunk->z()}, + {chunk->x(), chunk->y() + 1, chunk->z()}, + }; + + for (u8 i = 0 ; i < 6 ; ++i) { + // Create our neighbour + auto it = m_chunks.emplace( + gk::Vector3i{ + surroundingChunks[i].x, + surroundingChunks[i].y, + surroundingChunks[i].z + }, + new ServerChunk{ + surroundingChunks[i].x, + surroundingChunks[i].y, + surroundingChunks[i].z + } + ); + + // Assign surrounding chunk pointers + ServerChunk *neighbour = it.first->second.get(); + chunk->setSurroundingChunk(i, neighbour); + neighbour->setSurroundingChunk((i % 2 == 0) ? i + 1 : i - 1, chunk); + + // Compute distance to player chunk + int dx = std::abs(surroundingChunks[i].x - pcx); + int dy = std::abs(surroundingChunks[i].y - pcy); + int dz = std::abs(surroundingChunks[i].z - pcz); + int distance = std::max(dx, std::max(dy, dz)); + + // If the chunk is close enough, add it to the queue + if (distance < Config::renderDistance) + chunks.emplace(neighbour); + } + } +} + void ServerWorld::sendChunkData(Client &client, ServerChunk *chunk) { if (!chunk) return; @@ -69,16 +131,16 @@ void ServerWorld::sendChunkData(Client &client, ServerChunk *chunk) { void ServerWorld::sendRequestedData(Client &client, int cx, int cy, int cz) { std::cout << "Chunk at (" << cx << ", " << cy << ", " << cz << ") requested" << std::endl; - ServerChunk *chunk = getChunk(cx, cy, cz); + Chunk *chunk = getChunk(cx, cy, cz); if (!chunk) { auto it = m_chunks.emplace(gk::Vector3i(cx, cy, cz), new ServerChunk(cx, cy, cz)); chunk = it.first->second.get(); } - sendChunkData(client, chunk); + sendChunkData(client, (ServerChunk *)chunk); } -ServerChunk *ServerWorld::getChunk(int cx, int cy, int cz) const { +Chunk *ServerWorld::getChunk(int cx, int cy, int cz) const { auto it = m_chunks.find({cx, cy, cz}); if (it == m_chunks.end()) return nullptr; @@ -86,39 +148,3 @@ ServerChunk *ServerWorld::getChunk(int cx, int cy, int cz) const { return it->second.get(); } -BlockData *ServerWorld::getBlockData(int x, int y, int z) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - return chunk->getBlockData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); - - return nullptr; -} - -u16 ServerWorld::getBlock(int x, int y, int z) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - return chunk->getBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); - - return 0; -} - -void ServerWorld::setBlock(int x, int y, int z, u16 id) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id); -} - -u16 ServerWorld::getData(int x, int y, int z) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - return chunk->getData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1)); - - return 0; -} - -void ServerWorld::setData(int x, int y, int z, u16 id) const { - Chunk *chunk = getChunk(x / CHUNK_WIDTH, y / CHUNK_HEIGHT, z / CHUNK_DEPTH); - if (chunk) - chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id); -} -