Server Side Chunk Generation
* Server World Class * WorldGenStream class to handle multithreaded map generation * ServerPlayer stores active chunk boundaries * BlockChunk stores position * Renamed client World to LocalWorld * Disabled client side Generation * ServerConnection stores chunk packets to be used by the GameScene, which gives them to the world (change later?) * Reenabled "BlockChunk Packet Encoding" test in tests/BlockChunk.cpp
This commit is contained in:
parent
3bba3adf66
commit
b66ca8284b
@ -110,6 +110,6 @@ set(ZEUS_SRC_FILES
|
|||||||
client/engine/FrustumPlane.cpp
|
client/engine/FrustumPlane.cpp
|
||||||
client/engine/FrustumPlane.h
|
client/engine/FrustumPlane.h
|
||||||
client/engine/FrustumAABB.cpp
|
client/engine/FrustumAABB.cpp
|
||||||
client/engine/FrustumAABB.h)
|
client/engine/FrustumAABB.h server/world/World.cpp server/world/World.h server/world/WorldGenStream.cpp server/world/WorldGenStream.h)
|
||||||
|
|
||||||
add_library (zeusCore ${ZEUS_SRC_FILES})
|
add_library (zeusCore ${ZEUS_SRC_FILES})
|
@ -30,15 +30,15 @@ GameScene::GameScene(ClientState* state) :
|
|||||||
//The scene requires the blockAtlas for meshing and handling inputs.
|
//The scene requires the blockAtlas for meshing and handling inputs.
|
||||||
world = new LocalWorld(blockAtlas);
|
world = new LocalWorld(blockAtlas);
|
||||||
|
|
||||||
int SIZE = 16;
|
// int SIZE = 16;
|
||||||
int SIZEV = 8;
|
// int SIZEV = 8;
|
||||||
for (int i = -SIZE; i < SIZE; i++) {
|
// for (int i = -SIZE; i < SIZE; i++) {
|
||||||
for (int j = -SIZE; j < SIZEV; j++) {
|
// for (int j = -SIZE; j < SIZEV; j++) {
|
||||||
for (int k = -SIZE; k < SIZE; k++) {
|
// for (int k = -SIZE; k < SIZE; k++) {
|
||||||
world->genNewChunk(glm::vec3(i, j, k));
|
// world->genNewChunk(glm::vec3(i, j, k));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
player = new Player();
|
player = new Player();
|
||||||
player->create(world, state->renderer->getCamera());
|
player->create(world, state->renderer->getCamera());
|
||||||
@ -62,6 +62,14 @@ void GameScene::update() {
|
|||||||
state->renderer->resized = false;
|
state->renderer->resized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (!server->chunkPackets.empty()) {
|
||||||
|
auto it = server->chunkPackets.begin();
|
||||||
|
Packet p = *it;
|
||||||
|
server->chunkPackets.erase(it);
|
||||||
|
|
||||||
|
world->loadChunkPacket(&p);
|
||||||
|
}
|
||||||
|
|
||||||
debugGui.update(player, world, window, blockAtlas, state->fps, (int)world->getMeshChunks()->size(), drawCalls);
|
debugGui.update(player, world, window, blockAtlas, state->fps, (int)world->getMeshChunks()->size(), drawCalls);
|
||||||
world->update();
|
world->update();
|
||||||
}
|
}
|
||||||
|
@ -22,21 +22,21 @@ LocalWorld::LocalWorld(BlockAtlas *atlas) {
|
|||||||
|
|
||||||
void LocalWorld::genNewChunk(glm::vec3 pos) {
|
void LocalWorld::genNewChunk(glm::vec3 pos) {
|
||||||
if (!blockChunks.count(pos)) {
|
if (!blockChunks.count(pos)) {
|
||||||
pendingGen.insert(pos);
|
pendingGen.push_back(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalWorld::loadChunkPacket(Packet *p) {
|
void LocalWorld::loadChunkPacket(Packet *p) {
|
||||||
// auto b = new BlockChunk();
|
auto b = new BlockChunk();
|
||||||
//
|
|
||||||
// glm::vec3 pos = glm::vec3(Packet::decodeInt(&p->data[0]), Packet::decodeInt(&p->data[4]), Packet::decodeInt(&p->data[8]));
|
glm::vec3 pos = glm::vec3(Serializer::decodeInt(&p->data[0]), Serializer::decodeInt(&p->data[4]), Serializer::decodeInt(&p->data[8]));
|
||||||
//
|
|
||||||
// int len = Packet::decodeInt(&p->data[12]);
|
int len = Serializer::decodeInt(&p->data[12]);
|
||||||
// std::string data(p->data.begin() + 16, p->data.begin() + 16 + len);
|
std::string data(p->data.begin() + 16, p->data.begin() + 16 + len);
|
||||||
//
|
|
||||||
// b->deserialize(data);
|
b->deserialize(data);
|
||||||
//
|
|
||||||
// commitChunk(pos, b);
|
commitChunk(pos, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalWorld::commitChunk(glm::vec3 pos, BlockChunk *c) {
|
void LocalWorld::commitChunk(glm::vec3 pos, BlockChunk *c) {
|
||||||
@ -61,7 +61,7 @@ void LocalWorld::attemptMeshChunk(glm::vec3 pos) {
|
|||||||
thisChunk->adjacent[4] = getAdjacentExists(glm::vec3(pos.x, pos.y, pos.z + 1), pos);
|
thisChunk->adjacent[4] = getAdjacentExists(glm::vec3(pos.x, pos.y, pos.z + 1), pos);
|
||||||
thisChunk->adjacent[5] = getAdjacentExists(glm::vec3(pos.x, pos.y, pos.z - 1), pos);
|
thisChunk->adjacent[5] = getAdjacentExists(glm::vec3(pos.x, pos.y, pos.z - 1), pos);
|
||||||
|
|
||||||
if (thisChunk->allAdjacentsExist()) pendingMesh.insert(pos);
|
if (thisChunk->allAdjacentsExist()) pendingMesh.push_back(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocalWorld::getAdjacentExists(glm::vec3 pos, glm::vec3 otherPos) {
|
bool LocalWorld::getAdjacentExists(glm::vec3 pos, glm::vec3 otherPos) {
|
||||||
@ -77,7 +77,7 @@ bool LocalWorld::getAdjacentExists(glm::vec3 pos, glm::vec3 otherPos) {
|
|||||||
if (diff == glm::vec3(0, 0, 1)) chunk->adjacent[4] = true;
|
if (diff == glm::vec3(0, 0, 1)) chunk->adjacent[4] = true;
|
||||||
if (diff == glm::vec3(0, 0,-1)) chunk->adjacent[5] = true;
|
if (diff == glm::vec3(0, 0,-1)) chunk->adjacent[5] = true;
|
||||||
|
|
||||||
if (chunk->allAdjacentsExist()) pendingMesh.insert(pos);
|
if (chunk->allAdjacentsExist()) pendingMesh.push_back(pos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -133,6 +133,13 @@ std::vector<bool>* LocalWorld::getAdjacentsCull(glm::vec3 pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LocalWorld::update() {
|
void LocalWorld::update() {
|
||||||
|
// std::sort(pendingGen.begin(), pendingGen.begin()+min(1000, (int)pendingGen.size()), [](glm::vec3 a, glm::vec3 b) {
|
||||||
|
// return glm::distance(a, glm::vec3(0, 0, 0)) < glm::distance(b, glm::vec3(0, 0, 0));
|
||||||
|
// });
|
||||||
|
// std::sort(pendingMesh.begin(), pendingMesh.end()+min(1000, (int)pendingMesh.size()), [](glm::vec3 a, glm::vec3 b) {
|
||||||
|
// return glm::distance(a, glm::vec3(0, 0, 0)) < glm::distance(b, glm::vec3(0, 0, 0));
|
||||||
|
// });
|
||||||
|
//
|
||||||
handleChunkGenQueue();
|
handleChunkGenQueue();
|
||||||
handleMeshGenQueue();
|
handleMeshGenQueue();
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ private:
|
|||||||
const int GEN_QUEUE_SIZE = 8;
|
const int GEN_QUEUE_SIZE = 8;
|
||||||
const int GEN_FINISHED_SIZE = GEN_THREADS * GEN_QUEUE_SIZE;
|
const int GEN_FINISHED_SIZE = GEN_THREADS * GEN_QUEUE_SIZE;
|
||||||
|
|
||||||
std::unordered_set<glm::vec3, vec3cmp> pendingGen;
|
std::vector<glm::vec3> pendingGen;
|
||||||
std::vector<ChunkThreadDef*> genThreads;
|
std::vector<ChunkThreadDef*> genThreads;
|
||||||
std::vector<ChunkThreadData*> finishedGen;
|
std::vector<ChunkThreadData*> finishedGen;
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ private:
|
|||||||
const int MESH_QUEUE_SIZE = 8;
|
const int MESH_QUEUE_SIZE = 8;
|
||||||
const int MESH_FINISHED_SIZE = GEN_THREADS * GEN_QUEUE_SIZE;
|
const int MESH_FINISHED_SIZE = GEN_THREADS * GEN_QUEUE_SIZE;
|
||||||
|
|
||||||
std::unordered_set<glm::vec3, vec3cmp> pendingMesh;
|
std::vector<glm::vec3> pendingMesh;
|
||||||
std::vector<MeshThreadDef*> meshThreads;
|
std::vector<MeshThreadDef*> meshThreads;
|
||||||
std::vector<MeshThreadData*> finishedMesh;
|
std::vector<MeshThreadData*> finishedMesh;
|
||||||
|
|
||||||
|
@ -30,34 +30,45 @@ void ServerConnection::update(Player &player, std::vector<PlayerEntity*>& player
|
|||||||
case ENET_EVENT_TYPE_RECEIVE: {
|
case ENET_EVENT_TYPE_RECEIVE: {
|
||||||
Packet p(event.packet);
|
Packet p(event.packet);
|
||||||
|
|
||||||
if (p.type == Packet::PLAYER_INFO) {
|
switch (p.type) {
|
||||||
glm::vec3 playerPos = glm::vec3(
|
case Packet::PLAYER_INFO: {
|
||||||
Serializer::decodeFloat(&p.data[0]),
|
glm::vec3 playerPos = glm::vec3(
|
||||||
Serializer::decodeFloat(&p.data[4]),
|
Serializer::decodeFloat(&p.data[0]),
|
||||||
Serializer::decodeFloat(&p.data[8])
|
Serializer::decodeFloat(&p.data[4]),
|
||||||
);
|
Serializer::decodeFloat(&p.data[8])
|
||||||
player.setPos(playerPos);
|
);
|
||||||
}
|
player.setPos(playerPos);
|
||||||
else if (p.type == Packet::ENTITY_INFO) {
|
break;
|
||||||
int peer_id = Serializer::decodeInt(&p.data[0]);
|
}
|
||||||
|
case Packet::ENTITY_INFO: {
|
||||||
|
int peer_id = Serializer::decodeInt(&p.data[0]);
|
||||||
|
|
||||||
glm::vec3 playerPos = glm::vec3(
|
glm::vec3 playerPos = glm::vec3(
|
||||||
Serializer::decodeFloat(&p.data[4]),
|
Serializer::decodeFloat(&p.data[4]),
|
||||||
Serializer::decodeFloat(&p.data[8]),
|
Serializer::decodeFloat(&p.data[8]),
|
||||||
Serializer::decodeFloat(&p.data[12])
|
Serializer::decodeFloat(&p.data[12])
|
||||||
);
|
);
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto plrEnt : playerEntities) {
|
for (auto plrEnt : playerEntities) {
|
||||||
if (plrEnt->peer_id == peer_id) {
|
if (plrEnt->peer_id == peer_id) {
|
||||||
plrEnt->setPosition(playerPos);
|
plrEnt->setPosition(playerPos);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
playerEntities.push_back(new PlayerEntity(playerPos, peer_id));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!found) {
|
case Packet::CHUNK_INFO: {
|
||||||
playerEntities.push_back(new PlayerEntity(playerPos, peer_id));
|
chunkPackets.push_back(std::move(p));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
enet_packet_destroy(event.packet);
|
enet_packet_destroy(event.packet);
|
||||||
|
@ -25,6 +25,7 @@ public:
|
|||||||
|
|
||||||
~ServerConnection();
|
~ServerConnection();
|
||||||
|
|
||||||
|
std::vector<Packet> chunkPackets;
|
||||||
private:
|
private:
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ BlockChunk::BlockChunk(std::vector<int> blocks) {
|
|||||||
this->blocks = std::move(blocks);
|
this->blocks = std::move(blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockChunk::BlockChunk(std::vector<int> blocks, glm::vec3 pos) {
|
||||||
|
this->blocks = std::move(blocks);
|
||||||
|
this->pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
int BlockChunk::getBlock(glm::vec3* pos) {
|
int BlockChunk::getBlock(glm::vec3* pos) {
|
||||||
unsigned int ind = ArrayTrans3D::vecToInd(pos);
|
unsigned int ind = ArrayTrans3D::vecToInd(pos);
|
||||||
if (ind < 0 || ind >= 4096) return -1;
|
if (ind < 0 || ind >= 4096) return -1;
|
||||||
|
@ -15,6 +15,9 @@ class BlockChunk {
|
|||||||
public:
|
public:
|
||||||
BlockChunk();
|
BlockChunk();
|
||||||
explicit BlockChunk(std::vector<int> blocks);
|
explicit BlockChunk(std::vector<int> blocks);
|
||||||
|
BlockChunk(std::vector<int> blocks, glm::vec3 pos);
|
||||||
|
|
||||||
|
glm::vec3 pos;
|
||||||
|
|
||||||
bool adjacent[6] = {false, false, false, false, false, false};
|
bool adjacent[6] = {false, false, false, false, false, false};
|
||||||
bool allAdjacentsExist();
|
bool allAdjacentsExist();
|
||||||
|
@ -58,7 +58,7 @@ BlockChunk* MapGen::generate(glm::vec3 pos) {
|
|||||||
buildElevation(j);
|
buildElevation(j);
|
||||||
fillChunk(j);
|
fillChunk(j);
|
||||||
|
|
||||||
return new BlockChunk(j.blocks);
|
return new BlockChunk(j.blocks, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapGen::buildElevation(MapGenJob &j) {
|
void MapGen::buildElevation(MapGenJob &j) {
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
#include "ConnectionList.h"
|
#include "ConnectionList.h"
|
||||||
#include "../generic/network/PacketChannel.h"
|
#include "../generic/network/PacketChannel.h"
|
||||||
|
|
||||||
|
ConnectionList::ConnectionList(World* world) {
|
||||||
|
this->world = world;
|
||||||
|
}
|
||||||
|
|
||||||
ServerPeer* ConnectionList::addPeer(ENetPeer *eNetPeer) {
|
ServerPeer* ConnectionList::addPeer(ENetPeer *eNetPeer) {
|
||||||
printf("[INFO] %x:%u connected.\n", eNetPeer->address.host, eNetPeer->address.port);
|
printf("[INFO] %x:%u connected.\n", eNetPeer->address.host, eNetPeer->address.port);
|
||||||
|
|
||||||
@ -31,14 +35,14 @@ void ConnectionList::removePeer(ENetPeer *eNetPeer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerPlayer* ConnectionList::addPlayer(ServerPeer *peer, std::string uuid) {
|
ServerPlayer* ConnectionList::createPlayer(ServerPeer *peer, std::string uuid) {
|
||||||
printf("[INFO] Creating player %s for %x:%u.\n", uuid.c_str(), peer->peer->address.host, peer->peer->address.port);
|
printf("[INFO] Creating player %s for %x:%u.\n", uuid.c_str(), peer->peer->address.host, peer->peer->address.port);
|
||||||
auto player = new ServerPlayer(peer);
|
auto player = new ServerPlayer(peer);
|
||||||
player->pos = glm::vec3(-8, 32, -8);
|
player->setPos(glm::vec3(0, 16, 0));
|
||||||
|
|
||||||
//Send Initialization Data
|
//Send Initialization Data
|
||||||
auto packet = player->getInitPacket();
|
auto packet = player->getInitPacket();
|
||||||
packet.sendTo(peer->peer, PacketChannel::PLAYER_INFO);
|
packet.sendTo(peer->peer, PacketChannel::PLAYER_INFO);
|
||||||
|
|
||||||
players.push_back(player);
|
world->addPlayer(player);
|
||||||
}
|
}
|
@ -9,16 +9,19 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "ServerPlayer.h"
|
#include "ServerPlayer.h"
|
||||||
#include "ServerPeer.h"
|
#include "ServerPeer.h"
|
||||||
|
#include "world/World.h"
|
||||||
|
|
||||||
class ConnectionList {
|
class ConnectionList {
|
||||||
public:
|
public:
|
||||||
|
explicit ConnectionList(World* world);
|
||||||
|
|
||||||
ServerPeer* addPeer(ENetPeer* peer);
|
ServerPeer* addPeer(ENetPeer* peer);
|
||||||
void removePeer(ENetPeer* peer);
|
void removePeer(ENetPeer* peer);
|
||||||
|
|
||||||
ServerPlayer* addPlayer(ServerPeer* peer, std::string uuid);
|
ServerPlayer* createPlayer(ServerPeer *peer, std::string uuid);
|
||||||
public:
|
public:
|
||||||
std::vector<ServerPeer*> peers;
|
std::vector<ServerPeer*> peers;
|
||||||
std::vector<ServerPlayer*> players;
|
World* world;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
#include "../generic/blocks/BlockChunk.h"
|
#include "../generic/blocks/BlockChunk.h"
|
||||||
|
|
||||||
Server::Server() = default;
|
Server::Server() : connections(&world) {};
|
||||||
|
|
||||||
Server::Server(unsigned short port) {
|
Server::Server(unsigned short port) : connections(&world) {
|
||||||
this->port = port;
|
this->port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,12 +20,14 @@ void Server::init() {
|
|||||||
void Server::update() {
|
void Server::update() {
|
||||||
Timer loop("");
|
Timer loop("");
|
||||||
|
|
||||||
|
world.update();
|
||||||
|
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
while (handler.update(&event) && loop.elapsedNs() < 15L*1000000L) {
|
while (handler.update(&event) && loop.elapsedNs() < 15L*1000000L) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case ENET_EVENT_TYPE_CONNECT: {
|
case ENET_EVENT_TYPE_CONNECT: {
|
||||||
auto peer = connections.addPeer(event.peer);
|
auto peer = connections.addPeer(event.peer);
|
||||||
connections.addPlayer(peer, "Aurailus");
|
connections.createPlayer(peer, "Aurailus");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ENET_EVENT_TYPE_RECEIVE: {
|
case ENET_EVENT_TYPE_RECEIVE: {
|
||||||
@ -43,7 +45,7 @@ void Server::update() {
|
|||||||
Serializer::decodeFloat(&p.data[4]),
|
Serializer::decodeFloat(&p.data[4]),
|
||||||
Serializer::decodeFloat(&p.data[8])
|
Serializer::decodeFloat(&p.data[8])
|
||||||
);
|
);
|
||||||
player->pos = newPos;
|
player->setPos(newPos);
|
||||||
|
|
||||||
//Send All Clients the new positon
|
//Send All Clients the new positon
|
||||||
Packet r(Packet::ENTITY_INFO);
|
Packet r(Packet::ENTITY_INFO);
|
||||||
|
@ -29,6 +29,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool alive = true;
|
bool alive = true;
|
||||||
|
|
||||||
|
World world;
|
||||||
NetHandler handler;
|
NetHandler handler;
|
||||||
ConnectionList connections;
|
ConnectionList connections;
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#ifndef ZEUS_SERVERPEER_H
|
#ifndef ZEUS_SERVERPEER_H
|
||||||
#define ZEUS_SERVERPEER_H
|
#define ZEUS_SERVERPEER_H
|
||||||
|
|
||||||
|
|
||||||
#include <enet/enet.h>
|
#include <enet/enet.h>
|
||||||
|
|
||||||
class ServerPlayer;
|
class ServerPlayer;
|
||||||
|
@ -2,15 +2,13 @@
|
|||||||
// Created by aurailus on 11/01/19.
|
// Created by aurailus on 11/01/19.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include "ServerPlayer.h"
|
#include "ServerPlayer.h"
|
||||||
|
|
||||||
ServerPlayer::ServerPlayer(ServerPeer *peer) {
|
ServerPlayer::ServerPlayer(ServerPeer *peer) {
|
||||||
this->peer = peer;
|
this->peer = peer;
|
||||||
peer->player = this;
|
peer->player = this;
|
||||||
}
|
updateBounds();
|
||||||
|
|
||||||
ServerPlayer::~ServerPlayer() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet ServerPlayer::getInitPacket() {
|
Packet ServerPlayer::getInitPacket() {
|
||||||
@ -22,3 +20,38 @@ Packet ServerPlayer::getInitPacket() {
|
|||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 ServerPlayer::getPos() {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerPlayer::setPos(glm::vec3 pos) {
|
||||||
|
this->lastPos = this->pos;
|
||||||
|
this->pos = pos;
|
||||||
|
|
||||||
|
glm::vec3 chunkPos(std::floor(pos.x / 16), std::floor(pos.y / 16), std::floor(pos.z / 16));
|
||||||
|
glm::vec3 lastChunkPos(std::floor(lastPos.x / 16), std::floor(lastPos.y / 16), std::floor(lastPos.z / 16));
|
||||||
|
|
||||||
|
if (chunkPos != lastChunkPos) {
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<glm::vec3, glm::vec3> ServerPlayer::getBounds() {
|
||||||
|
return {minBounds, maxBounds};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerPlayer::updateBounds() {
|
||||||
|
glm::vec3 chunkPos(std::floor(pos.x / 16), std::floor(pos.y / 16), std::floor(pos.z / 16));
|
||||||
|
|
||||||
|
minBounds = glm::vec3(chunkPos.x - ACTIVE_RANGE, chunkPos.y - ACTIVE_RANGE, chunkPos.z - ACTIVE_RANGE);
|
||||||
|
maxBounds = glm::vec3(chunkPos.x + ACTIVE_RANGE, chunkPos.y + ACTIVE_RANGE, chunkPos.z + ACTIVE_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServerPlayer::isInBounds(glm::vec3 pos) {
|
||||||
|
return (pos.x >= minBounds.x && pos.x <= maxBounds.x
|
||||||
|
&& pos.y >= minBounds.y && pos.y <= maxBounds.y
|
||||||
|
&& pos.z >= minBounds.z && pos.z <= maxBounds.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerPlayer::~ServerPlayer() = default;
|
@ -12,14 +12,29 @@
|
|||||||
|
|
||||||
class ServerPlayer {
|
class ServerPlayer {
|
||||||
public:
|
public:
|
||||||
|
const static int ACTIVE_RANGE = 20;
|
||||||
|
|
||||||
explicit ServerPlayer(ServerPeer* peer);
|
explicit ServerPlayer(ServerPeer* peer);
|
||||||
|
|
||||||
Packet getInitPacket();
|
Packet getInitPacket();
|
||||||
|
|
||||||
ServerPeer* peer;
|
glm::vec3 getPos();
|
||||||
glm::vec3 pos = glm::vec3(0, 0, 0);
|
void setPos(glm::vec3 pos);
|
||||||
|
|
||||||
|
std::pair<glm::vec3, glm::vec3> getBounds();
|
||||||
|
bool isInBounds(glm::vec3 pos);
|
||||||
|
|
||||||
~ServerPlayer();
|
~ServerPlayer();
|
||||||
|
|
||||||
|
ServerPeer* peer;
|
||||||
|
private:
|
||||||
|
void updateBounds();
|
||||||
|
|
||||||
|
glm::vec3 pos = {0, 0, 0};
|
||||||
|
glm::vec3 lastPos = {0, 0, 0};
|
||||||
|
|
||||||
|
glm::vec3 minBounds = {0, 0, 0};
|
||||||
|
glm::vec3 maxBounds = {0, 0, 0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
75
src/server/world/World.cpp
Normal file
75
src/server/world/World.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// Created by aurailus on 05/03/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "World.h"
|
||||||
|
#include "../../generic/network/PacketChannel.h"
|
||||||
|
|
||||||
|
void World::addPlayer(ServerPlayer *player) {
|
||||||
|
this->players.push_back(player);
|
||||||
|
|
||||||
|
playerChangedChunks(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::playerChangedChunks(ServerPlayer *player) {
|
||||||
|
auto bounds = player->getBounds();
|
||||||
|
|
||||||
|
for (auto i = (int)bounds.first.x; i < (int)bounds.second.x; i++) {
|
||||||
|
for (auto j = (int)bounds.first.y; j < (int)bounds.second.y; j++) {
|
||||||
|
for (auto k = (int)bounds.first.z; k < (int)bounds.second.z; k++) {
|
||||||
|
generate(glm::vec3(i, j, k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::generate(glm::vec3 pos) {
|
||||||
|
if(!generateQueueMap.count(pos) && !chunkMap.count(pos)) {
|
||||||
|
|
||||||
|
generateQueueMap.insert(pos);
|
||||||
|
generateQueueList.push_back(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::update() {
|
||||||
|
while (!generateQueueList.empty()) {
|
||||||
|
auto it = generateQueueList.begin();
|
||||||
|
glm::vec3 pos = *it;
|
||||||
|
|
||||||
|
bool success = genStream.tryToQueue(pos);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
generateQueueList.erase(it);
|
||||||
|
generateQueueMap.erase(pos);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto finished = genStream.update();
|
||||||
|
for (auto chunk : finished) {
|
||||||
|
|
||||||
|
bool didCalcSerialized = false;
|
||||||
|
std::string serialized;
|
||||||
|
|
||||||
|
for (auto player : players) {
|
||||||
|
if (player->isInBounds(chunk->pos)) {
|
||||||
|
|
||||||
|
//Serialize the chunk
|
||||||
|
if (!didCalcSerialized) {
|
||||||
|
serialized = chunk->serialize();
|
||||||
|
didCalcSerialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send the Chunk to the player
|
||||||
|
Packet r(Packet::CHUNK_INFO);
|
||||||
|
|
||||||
|
Serializer::encodeInt(r.data, (int)chunk->pos.x);
|
||||||
|
Serializer::encodeInt(r.data, (int)chunk->pos.y);
|
||||||
|
Serializer::encodeInt(r.data, (int)chunk->pos.z);
|
||||||
|
Serializer::encodeString(r.data, serialized);
|
||||||
|
|
||||||
|
r.sendTo(player->peer->peer, PacketChannel::WORLD_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
src/server/world/World.h
Normal file
45
src/server/world/World.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// Created by aurailus on 05/03/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ZEUS_WORLD_H
|
||||||
|
#define ZEUS_WORLD_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include "../../generic/blocks/BlockChunk.h"
|
||||||
|
#include "../ServerPlayer.h"
|
||||||
|
#include "WorldGenStream.h"
|
||||||
|
|
||||||
|
class World {
|
||||||
|
public:
|
||||||
|
World() = default;
|
||||||
|
|
||||||
|
void addPlayer(ServerPlayer* player);
|
||||||
|
void update();
|
||||||
|
|
||||||
|
~World() = default;
|
||||||
|
private:
|
||||||
|
void playerChangedChunks(ServerPlayer* player);
|
||||||
|
void generate(glm::vec3 pos);
|
||||||
|
|
||||||
|
struct vec3cmp {
|
||||||
|
size_t operator()(const glm::vec3& k)const {
|
||||||
|
return std::hash<float>()(k.x) ^ std::hash<float>()(k.y) ^ std::hash<float>()(k.z);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WorldGenStream genStream;
|
||||||
|
|
||||||
|
std::vector<ServerPlayer*> players;
|
||||||
|
|
||||||
|
std::unordered_map<glm::vec3, BlockChunk*, vec3cmp> chunkMap;
|
||||||
|
std::vector<std::pair<glm::vec3, BlockChunk*>> chunkList;
|
||||||
|
|
||||||
|
std::unordered_set<glm::vec3, vec3cmp> generateQueueMap;
|
||||||
|
std::vector<glm::vec3> generateQueueList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ZEUS_WORLD_H
|
93
src/server/world/WorldGenStream.cpp
Normal file
93
src/server/world/WorldGenStream.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
//
|
||||||
|
// Created by aurailus on 06/03/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "WorldGenStream.h"
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
|
||||||
|
|
||||||
|
WorldGenStream::WorldGenStream() : gen(0) {
|
||||||
|
queuedTasks.reserve((unsigned long) TOTAL_QUEUE_SIZE);
|
||||||
|
|
||||||
|
threads.reserve(THREADS);
|
||||||
|
for (int i = 0; i < THREADS; i++) {
|
||||||
|
threads.emplace_back(&gen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldGenStream::tryToQueue(glm::vec3 pos) {
|
||||||
|
unsigned long sizeOfQueue = queuedTasks.size();
|
||||||
|
|
||||||
|
if (sizeOfQueue < TOTAL_QUEUE_SIZE && !queuedMap.count(pos)) {
|
||||||
|
queuedTasks.push_back(pos);
|
||||||
|
queuedMap.insert(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sizeOfQueue + 1 < TOTAL_QUEUE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BlockChunk*> WorldGenStream::update() {
|
||||||
|
std::vector<BlockChunk*> finishedChunks;
|
||||||
|
|
||||||
|
for (auto& t : threads) {
|
||||||
|
for (auto& u : t.tasks) {
|
||||||
|
if (!u.unlocked) continue;
|
||||||
|
|
||||||
|
if (u.chunk != nullptr) {
|
||||||
|
finishedChunks.push_back(u.chunk);
|
||||||
|
u.chunk = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queuedTasks.empty()) {
|
||||||
|
auto it = queuedTasks.begin();
|
||||||
|
glm::vec3 pos = *it;
|
||||||
|
queuedTasks.erase(it);
|
||||||
|
queuedMap.erase(pos);
|
||||||
|
|
||||||
|
u.pos = pos;
|
||||||
|
//Lock it in to allow the thread to edit it.
|
||||||
|
u.unlocked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finishedChunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldGenStream::Thread::Thread(MapGen *gen) {
|
||||||
|
this->gen = gen;
|
||||||
|
|
||||||
|
thread = std::thread(WorldGenStream::threadFunction, this);
|
||||||
|
thread.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldGenStream::threadFunction(WorldGenStream::Thread *thread) {
|
||||||
|
while (thread->keepAlive) {
|
||||||
|
|
||||||
|
bool empty = true;
|
||||||
|
for (Unit& u : thread->tasks) {
|
||||||
|
if (!u.unlocked) {
|
||||||
|
|
||||||
|
empty = false;
|
||||||
|
u.chunk = thread->gen->generate(u.pos);
|
||||||
|
u.unlocked = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldGenStream::~WorldGenStream() {
|
||||||
|
for (auto& t : threads) {
|
||||||
|
t.keepAlive = false;
|
||||||
|
t.thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic pop
|
69
src/server/world/WorldGenStream.h
Normal file
69
src/server/world/WorldGenStream.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
//
|
||||||
|
// Created by aurailus on 06/03/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
|
||||||
|
#ifndef ZEUS_WORLDGENSTREAM_H
|
||||||
|
#define ZEUS_WORLDGENSTREAM_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <vec3.hpp>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include "../../generic/blocks/BlockChunk.h"
|
||||||
|
#include "../../generic/gen/MapGen.h"
|
||||||
|
|
||||||
|
class WorldGenStream {
|
||||||
|
public:
|
||||||
|
static const int THREAD_QUEUE_SIZE = 32;
|
||||||
|
static const int THREADS = 8;
|
||||||
|
static const int TOTAL_QUEUE_SIZE = THREADS * THREAD_QUEUE_SIZE;
|
||||||
|
|
||||||
|
WorldGenStream();
|
||||||
|
~WorldGenStream();
|
||||||
|
|
||||||
|
//Attempt to add `pos` to the pre-thread queue.
|
||||||
|
//Will return a boolean stating if there is more space left in the queue.
|
||||||
|
bool tryToQueue(glm::vec3 pos);
|
||||||
|
|
||||||
|
//Will return a vector of BlockChunk pointers containing finished chunks.
|
||||||
|
//Frees up the threads and starts new tasks.
|
||||||
|
std::vector<BlockChunk*> update();
|
||||||
|
|
||||||
|
struct Unit {
|
||||||
|
glm::vec3 pos {0, 0, 0};
|
||||||
|
BlockChunk* chunk = nullptr;
|
||||||
|
|
||||||
|
bool unlocked = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Thread {
|
||||||
|
explicit Thread(MapGen* gen);
|
||||||
|
|
||||||
|
MapGen* gen;
|
||||||
|
|
||||||
|
std::thread thread;
|
||||||
|
bool keepAlive = true;
|
||||||
|
|
||||||
|
std::vector<Unit> tasks = std::vector<Unit>(THREAD_QUEUE_SIZE);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Thread> threads;
|
||||||
|
private:
|
||||||
|
static void threadFunction(Thread* thread);
|
||||||
|
|
||||||
|
struct vec3cmp {
|
||||||
|
size_t operator()(const glm::vec3& k)const {
|
||||||
|
return std::hash<float>()(k.x) ^ std::hash<float>()(k.y) ^ std::hash<float>()(k.z);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MapGen gen;
|
||||||
|
std::vector<glm::vec3> queuedTasks;
|
||||||
|
std::unordered_set<glm::vec3, vec3cmp> queuedMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ZEUS_WORLDGENSTREAM_H
|
||||||
|
#pragma clang diagnostic pop
|
@ -47,27 +47,27 @@ TEST_CASE("Blockchunks", "[networking]") {
|
|||||||
delete b2;
|
delete b2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SECTION("BlockChunk Packet Encoding") {
|
SECTION("BlockChunk Packet Encoding") {
|
||||||
// auto p = new Packet(Packet::CHUNKINFO);
|
auto p = Packet(Packet::CHUNK_INFO);
|
||||||
// p->addString(gzip);
|
Serializer::encodeString(p.data, gzip);
|
||||||
//
|
|
||||||
// auto byteArr = p->serialize();
|
auto enetP = p.toENetPacket();
|
||||||
//
|
|
||||||
// auto p2 = Packet::deserialize(byteArr);
|
auto p2 = Packet(enetP);
|
||||||
//
|
|
||||||
// int len = Packet::decodeInt(&p2->data[0]);
|
int len = Serializer::decodeInt(&p2.data[0]);
|
||||||
// std::string data(p->data.begin() + 4, p->data.begin() + 4 + len);
|
std::string data(p.data.begin() + 4, p.data.begin() + 4 + len);
|
||||||
//
|
|
||||||
// auto b2 = new BlockChunk();
|
auto b2 = new BlockChunk();
|
||||||
// REQUIRE(b2->deserialize(data));
|
REQUIRE(b2->deserialize(data));
|
||||||
//
|
|
||||||
// for (int j = 0; j < 4096; j++) {
|
for (int j = 0; j < 4096; j++) {
|
||||||
// REQUIRE(b2->getBlock(j) == b->getBlock(j));
|
REQUIRE(b2->getBlock(j) == b->getBlock(j));
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// delete b2;
|
delete b2;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
delete b;
|
delete b;
|
||||||
|
|
||||||
INFO("Iteration " << i << " passed.");
|
INFO("Iteration " << i << " passed.");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user