Infinite world: First attempt.

This commit is contained in:
Quentin Bazin 2020-01-16 01:37:49 +09:00
parent 2f790ec723
commit 12dcb38ebd
7 changed files with 72 additions and 210 deletions

View File

@ -14,7 +14,7 @@
#ifndef CLIENTWORLD_HPP_
#define CLIENTWORLD_HPP_
#include <memory>
#include <unordered_map>
#include "ClientChunk.hpp"
#include "Network.hpp"
@ -36,16 +36,16 @@ class ClientWorld : public World, public gk::Drawable {
// FIXME: Duplicated with ServerWorld
u16 getBlock(int x, int y, int z) const override;
void setBlock(int x, int y, int z, u16 id) 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) override;
void setData(int x, int y, int z, u16 id) const override;
void setClient(ClientCommandHandler &client) { m_client = &client; }
private:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
std::vector<std::unique_ptr<ClientChunk>> m_chunks;
mutable std::unordered_map<gk::Vector3i, std::unique_ptr<ClientChunk>> m_chunks;
gk::Texture &m_texture;

View File

@ -21,42 +21,14 @@
#include "World.hpp"
ClientWorld::ClientWorld() : m_texture(gk::ResourceHandler::getInstance().get<gk::Texture>("texture-blocks")) {
for(s32 z = 0 ; z < m_depth ; z++) {
for(s32 y = 0 ; y < m_height ; y++) {
for(s32 x = 0 ; x < m_width ; x++) {
m_chunks.emplace_back(new ClientChunk(x - m_width / 2,
y - m_height / 2,
z - m_depth / 2, m_texture));
}
}
}
// FIXME: Duplicated with ServerWorld
for(s32 z = 0 ; z < m_depth ; ++z) {
for(s32 y = 0 ; y < m_height ; ++y) {
for(s32 x = 0 ; x < m_width ; ++x) {
s32 cx = x - m_width / 2;
s32 cy = y - m_height / 2;
s32 cz = z - m_depth / 2;
Chunk *chunk = getChunk(cx, cy, cz);
if(cx > -m_width / 2) chunk->setSurroundingChunk(Chunk::Left, getChunk(cx - 1, cy, cz));
if(cx < m_width / 2 - 1) chunk->setSurroundingChunk(Chunk::Right, getChunk(cx + 1, cy, cz));
if(cy > -m_height / 2) chunk->setSurroundingChunk(Chunk::Bottom, getChunk(cx, cy - 1, cz));
if(cy < m_height / 2 - 1) chunk->setSurroundingChunk(Chunk::Top, getChunk(cx, cy + 1, cz));
if(cz > -m_depth / 2) chunk->setSurroundingChunk(Chunk::Front, getChunk(cx, cy, cz - 1));
if(cz < m_depth / 2 - 1) chunk->setSurroundingChunk(Chunk::Back, getChunk(cx, cy, cz + 1));
}
}
}
}
void ClientWorld::update() {
for (auto &it : m_chunks) {
if (World::isReloadRequested)
it->setChanged(true);
it.second->setChanged(true);
it->update();
it.second->update();
}
World::isReloadRequested = false;
@ -97,82 +69,47 @@ void ClientWorld::receiveChunkData(sf::Packet &packet) {
}
ClientChunk *ClientWorld::getChunk(int cx, int cy, int cz) const {
cx += m_width / 2;
cy += m_height / 2;
cz += m_depth / 2;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
auto it = m_chunks.find({cx, cy, cz});
if (it == m_chunks.end())
return nullptr;
return m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
return it->second.get();
}
BlockData *ClientWorld::getBlockData(int x, int y, int z) const {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return 0;
Chunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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 0;
return nullptr;
}
u16 ClientWorld::getBlock(int x, int y, int z) const {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return 0;
ClientChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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) {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return;
ClientChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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 {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return 0;
ClientChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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) {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return;
ClientChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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->setData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id);
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 {
@ -193,9 +130,9 @@ void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const
std::vector<std::pair<ClientChunk*, gk::Transform>> chunks;
for(auto &it : m_chunks) {
states.transform = glm::translate(glm::mat4(1.0f),
glm::vec3(it->x() * CHUNK_WIDTH,
it->y() * CHUNK_HEIGHT,
it->z() * CHUNK_DEPTH));
glm::vec3(it.second->x() * CHUNK_WIDTH,
it.second->y() * CHUNK_HEIGHT,
it.second->z() * CHUNK_DEPTH));
// Is the chunk close enough?
glm::vec4 center = target.getView()->getViewTransform().getMatrix()
@ -225,25 +162,29 @@ void ClientWorld::draw(gk::RenderTarget &target, gk::RenderStates states) const
}
// If this chunk is not initialized, skip it
if(!it->isInitialized()) {
if(!it.second->isInitialized()) {
// But if it is the closest to the camera, mark it for initialization
if(d < ud) {
ud = d;
ux = it->x();
uy = it->y();
uz = it->z();
ux = it.second->x();
uy = it.second->y();
uz = it.second->z();
}
continue;
}
chunks.emplace_back(&*it, states.transform);
chunks.emplace_back(it.second.get(), states.transform);
}
ClientChunk *chunk = getChunk(ux, uy, uz);
if(ud < 1000 && chunk && !chunk->hasBeenRequested()) {
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);
chunk->setHasBeenRequested(true);
DEBUG("Chunk requested at", ux, uy, uz);
}
for (u8 i = 0 ; i < ChunkBuilder::layers ; ++i) {

View File

@ -31,10 +31,6 @@ namespace {
constexpr int CHUNK_HEIGHT = 32;
constexpr int CHUNK_DEPTH = 16;
constexpr int WORLD_WIDTH = 64;
constexpr int WORLD_HEIGHT = 4;
constexpr int WORLD_DEPTH = 64;
constexpr int SEALEVEL = 4;
}

View File

@ -25,16 +25,11 @@ class World {
virtual BlockData *getBlockData(int x, int y, int z) const = 0;
virtual u16 getBlock(int x, int y, int z) const = 0;
virtual void setBlock(int x, int y, int z, u16 id) = 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) = 0;
virtual void setData(int x, int y, int z, u16 id) const = 0;
static bool isReloadRequested;
protected:
const s32 m_width = WORLD_WIDTH;
const s32 m_height = WORLD_HEIGHT;
const s32 m_depth = WORLD_DEPTH;
};
#endif // WORLD_HPP_

View File

@ -14,8 +14,7 @@
#ifndef SERVERWORLD_HPP_
#define SERVERWORLD_HPP_
#include <memory>
#include <vector>
#include <unordered_map>
#include "ServerChunk.hpp"
#include "World.hpp"
@ -30,7 +29,6 @@ class ServerWorld : public World {
void update(Server &server, std::unordered_map<u16, ServerPlayer> &players);
void sendWorldData(Client &client);
void sendChunkData(Client &client, ServerChunk *chunk);
void sendRequestedData(Client &client, int cx, int cy, int cz);
@ -40,12 +38,12 @@ class ServerWorld : public World {
// FIXME: Duplicated with ClientWorld
u16 getBlock(int x, int y, int z) const override;
void setBlock(int x, int y, int z, u16 id) 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) override;
void setData(int x, int y, int z, u16 id) const override;
private:
std::vector<std::unique_ptr<ServerChunk>> m_chunks;
std::unordered_map<gk::Vector3i, std::unique_ptr<ServerChunk>> m_chunks;
u32 m_lastTick = 0;
};

View File

@ -53,7 +53,7 @@ void ServerCommandHandler::setupCallbacks() {
spawnPacket << m_spawnPosition.x << m_spawnPosition.y << m_spawnPosition.z;
m_server.sendToAllClients(spawnPacket);
// m_world.sendWorldData(client);
// m_world.sendWorldData(client); // FIXME
sf::Packet worldSentPacket;
worldSentPacket << Network::Command::WorldSent;

View File

@ -20,34 +20,6 @@
#include "ServerWorld.hpp"
ServerWorld::ServerWorld() {
for(s32 z = 0 ; z < m_depth ; z++) {
for(s32 y = 0 ; y < m_height ; y++) {
for(s32 x = 0 ; x < m_width ; x++) {
m_chunks.emplace_back(new ServerChunk(x - m_width / 2,
y - m_height / 2,
z - m_depth / 2));
}
}
}
// FIXME: Duplicated with ClientWorld
for(s32 z = 0 ; z < m_depth ; ++z) {
for(s32 y = 0 ; y < m_height ; ++y) {
for(s32 x = 0 ; x < m_width ; ++x) {
s32 cx = x - m_width / 2;
s32 cy = y - m_height / 2;
s32 cz = z - m_depth / 2;
Chunk *chunk = getChunk(cx, cy, cz);
if(cx > -m_width / 2) chunk->setSurroundingChunk(Chunk::Left, getChunk(cx - 1, cy, cz));
if(cx < m_width / 2 - 1) chunk->setSurroundingChunk(Chunk::Right, getChunk(cx + 1, cy, cz));
if(cy > -m_height / 2) chunk->setSurroundingChunk(Chunk::Bottom, getChunk(cx, cy - 1, cz));
if(cy < m_height / 2 - 1) chunk->setSurroundingChunk(Chunk::Top, getChunk(cx, cy + 1, cz));
if(cz > -m_depth / 2) chunk->setSurroundingChunk(Chunk::Front, getChunk(cx, cy, cz - 1));
if(cz < m_depth / 2 - 1) chunk->setSurroundingChunk(Chunk::Back, getChunk(cx, cy, cz + 1));
}
}
}
}
void ServerWorld::update(Server &server, std::unordered_map<u16, ServerPlayer> &players) {
@ -55,33 +27,23 @@ void ServerWorld::update(Server &server, std::unordered_map<u16, ServerPlayer> &
m_lastTick = gk::GameClock::getTicks() / 50;
for (auto &it : m_chunks) {
it->tick(players, *this, server);
it.second->tick(players, *this, server);
it->update();
it.second->update();
if (it->isGenerated() && !it->isSent()) {
if (it.second->isGenerated() && !it.second->isSent()) {
for (auto &client : server.info().clients())
sendChunkData(client, it.get());
sendChunkData(client, it.second.get());
// DEBUG("Chunk updated at", it->x(), it->y(), it->z());
it->setSent(true);
it.second->setSent(true);
}
}
}
}
void ServerWorld::sendWorldData(Client &client) {
// DEBUG("Sending world data...")
for(s32 z = -4 ; z < 4 ; z++) {
for(s32 x = -4 ; x < 4 ; x++) {
for(s32 y = -m_height / 2 ; y < m_height / 2 ; y++) {
sendChunkData(client, getChunk(x, y, z));
}
}
}
// DEBUG("Done sending world data")
}
void ServerWorld::sendChunkData(Client &client, ServerChunk *chunk) {
if (!chunk) return;
chunk->generate();
chunk->update();
chunk->setInitialized(true);
@ -101,92 +63,62 @@ void ServerWorld::sendChunkData(Client &client, ServerChunk *chunk) {
client.tcpSocket->send(packet);
chunk->setSent(true);
// std::cout << "Chunk at (" << chunk->x() << ", " << chunk->y() << ", " << chunk->z() << ") sent to client" << std::endl;
std::cout << "Chunk at (" << chunk->x() << ", " << chunk->y() << ", " << chunk->z() << ") sent to client" << std::endl;
}
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);
if (chunk) {
sendChunkData(client, chunk);
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);
}
ServerChunk *ServerWorld::getChunk(int cx, int cy, int cz) const {
cx += m_width / 2;
cy += m_height / 2;
cz += m_depth / 2;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
auto it = m_chunks.find({cx, cy, cz});
if (it == m_chunks.end())
return nullptr;
return m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
return it->second.get();
}
BlockData *ServerWorld::getBlockData(int x, int y, int z) const {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return 0;
Chunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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 0;
return nullptr;
}
u16 ServerWorld::getBlock(int x, int y, int z) const {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return 0;
ServerChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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) {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return;
ServerChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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 {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return 0;
ServerChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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) {
int cx = (x + CHUNK_WIDTH * (m_width / 2)) / CHUNK_WIDTH;
int cy = (y + CHUNK_HEIGHT * (m_height / 2)) / CHUNK_HEIGHT;
int cz = (z + CHUNK_DEPTH * (m_depth / 2)) / CHUNK_DEPTH;
if (cx < 0 || cx >= m_width || cy < 0 || cy >= m_height || cz < 0 || cz >= m_depth)
return;
ServerChunk *chunk = m_chunks.at(cx + cy * m_width + cz * m_width * m_height).get();
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->setData(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id);
chunk->setBlock(x & (CHUNK_WIDTH - 1), y & (CHUNK_HEIGHT - 1), z & (CHUNK_DEPTH - 1), id);
}