[ServerWorld] New function added to send spawn data to connecting clients.

This commit is contained in:
Quentin Bazin 2020-01-16 10:07:01 +09:00
parent 12dcb38ebd
commit 1dc66fd9e2
8 changed files with 149 additions and 153 deletions

View File

@ -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<gk::Vector3i, std::unique_ptr<ClientChunk>> m_chunks;
std::unordered_map<gk::Vector3i, std::unique_ptr<ClientChunk>> m_chunks;
gk::Texture &m_texture;

View File

@ -55,8 +55,11 @@ void ClientApplication::init() {
Registry::setInstance(m_registry);
// m_stateStack.push<TitleScreenState>();
auto &game = m_stateStack.push<GameState>(m_host, m_port);
m_stateStack.push<ServerLoadingState>(game);
m_stateStack.push<GameState>(m_host, m_port);
// auto &game = m_stateStack.push<GameState>(m_host, m_port);
// m_stateStack.push<ServerLoadingState>(game);
}
void ClientApplication::initOpenGL() {

View File

@ -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<std::pair<ClientChunk*, gk::Transform>> 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;

View File

@ -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;
};

View File

@ -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);
}

View File

@ -29,18 +29,11 @@ class ServerWorld : public World {
void update(Server &server, std::unordered_map<u16, ServerPlayer> &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<gk::Vector3i, std::unique_ptr<ServerChunk>> m_chunks;

View File

@ -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) {

View File

@ -41,6 +41,68 @@ void ServerWorld::update(Server &server, std::unordered_map<u16, ServerPlayer> &
}
}
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<ServerChunk *> 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);
}