New MapGen class for server-client map synchronization.

master
aurailus 2019-01-29 16:41:59 -08:00
parent 3fc3d84bb4
commit a89efe9dcb
18 changed files with 216 additions and 120 deletions

View File

@ -57,8 +57,8 @@ add_executable(zeus
zeus/generic/helpers/ArrayTrans3D.h
zeus/client/graphics/mesh/MeshChunk.cpp
zeus/client/graphics/mesh/MeshChunk.h
zeus/client/graphics/scene/GameScene.cpp
zeus/client/graphics/scene/GameScene.h
zeus/client/scene/GameScene.cpp
zeus/client/scene/GameScene.h
zeus/client/engine/graphics/Renderer.cpp
zeus/client/engine/graphics/Renderer.h
zeus/client/lua/LuaParser.cpp
@ -86,8 +86,8 @@ add_executable(zeus
zeus/client/engine/scene/SceneManager.h
zeus/client/engine/scene/Scene.h
zeus/client/ClientState.h
zeus/client/graphics/scene/MenuScene.cpp
zeus/client/graphics/scene/MenuScene.h
zeus/client/scene/MenuScene.cpp
zeus/client/scene/MenuScene.h
zeus/server/Server.cpp
zeus/server/Server.h
zeus/server/network/ServerClient.cpp
@ -101,6 +101,6 @@ add_executable(zeus
zeus/client/gameworld/WorldThreadDefs.cpp
zeus/client/gameworld/WorldThreadDefs.h
zeus/server/network/ConnMan.cpp
zeus/server/network/ConnMan.h)
zeus/server/network/ConnMan.h zeus/generic/gen/MapGen.cpp zeus/generic/gen/MapGen.h)
target_link_libraries(zeus ${OPENGL_gl_LIBRARY} glfw libGLEW.so pthread lua dl z)

View File

@ -9,8 +9,8 @@
#include "ClientState.h"
#include "engine/scene/SceneManager.h"
#include "graphics/scene/GameScene.h"
#include "graphics/scene/MenuScene.h"
#include "scene/GameScene.h"
#include "scene/MenuScene.h"
#include "engine/Timer.h"

View File

@ -9,9 +9,10 @@
World::World(BlockAtlas *atlas) {
blockAtlas = atlas;
mapGen = new MapGen(0);
for (int i = 0; i < GEN_THREADS; i++) {
genThreads.push_back(new ChunkThreadDef());
genThreads.push_back(new ChunkThreadDef(mapGen));
}
for (int i = 0; i < MESH_THREADS; i++) {
@ -25,9 +26,22 @@ void World::genNewChunk(glm::vec3 pos) {
}
}
void World::loadChunkPacket(Packet *p) {
auto b = new BlockChunk();
int len = Packet::decodeInt(&p->data[12]);
std::string data(p->data.begin() + 16, p->data.begin() + 16 + len);
b->deserialize(data);
commitChunk(glm::vec3(0, 0, 0), b);
}
void World::commitChunk(glm::vec3 pos, BlockChunk *c) {
blockChunks.insert(std::pair<glm::vec3, BlockChunk*>(pos, c));
attemptMeshChunk(pos);
if (!blockChunks.count(pos)) {
blockChunks.insert(std::pair<glm::vec3, BlockChunk *>(pos, c));
attemptMeshChunk(pos);
}
}
void World::remeshChunk(glm::vec3 pos) {
@ -183,7 +197,9 @@ void World::handleChunkGenQueue() {
Timer t("Chunk Initialization");
int genUpdates = 0;
for (auto iter = finishedGen.begin(); iter != finishedGen.end(); ) {
if (t.elapsedNs() > 4000000) break;
if (t.elapsedNs() > 4000000) {
break;
}
ChunkThreadData* threadData = *iter;
@ -201,9 +217,6 @@ void World::handleChunkGenQueue() {
//Takes a threadDef object which contains a vector of tasks to do, and infinitely loops, completing tasks and
//re-inserting them into the vector to be further manipulated by the main thread.
void World::chunkGenThread(ChunkThreadDef* threadDef) {
PerlinNoise p(9);
PerlinNoise p2(9);
//Infinite loop
while (true) {
std::unique_lock<std::mutex> lock(threadDef->lock, std::defer_lock);
@ -223,43 +236,7 @@ void World::chunkGenThread(ChunkThreadDef* threadDef) {
lock.unlock();
if (data != nullptr) {
auto *blocks = new std::vector<int>();
blocks->reserve(4096);
glm::vec3 innerPos, pos;
for (int ind = 0; ind < 4096; ind++) {
ArrayTrans3D::indAssignVec(ind, &innerPos);
pos.x = innerPos.x + data->pos.x * CHUNK_SIZE;
pos.y = innerPos.y + data->pos.y * CHUNK_SIZE;
pos.z = innerPos.z + data->pos.z * CHUNK_SIZE;
double val = p.noise(pos.x / (double) 32, pos.z / (double) 32, 0) * 16;
val *= p2.noise((pos.x + 16) / (double) 48, (pos.z + 16) / (double) 48, 0) * 8;
val /= 16;
val *= pow(p.noise(pos.x / (double) 64, pos.z / (double) 64, 0), 2) * 40 + 1;
val -= pos.y;
int block = 0;
if (val > 0) block = 6 + rand() % 4;
if (val > 1) block = 1;
if (val > 2) block = 2;
if (val > 3) block = 3;
blocks->push_back(block);
}
// (*blocks)[ArrayTrans3D::vecToInd(8, 8, 8)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(7, 8, 8)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(7, 8, 7)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(8, 8, 7)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(8, 7, 8)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(7, 7, 8)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(7, 7, 7)] = 4;
// (*blocks)[ArrayTrans3D::vecToInd(8, 7, 7)] = 4;
data->chunk = new BlockChunk(blocks);
data->chunk = threadDef->mapGen->generate(data->pos);
data->done = true;
lock.lock();
@ -331,7 +308,6 @@ void World::handleMeshGenQueue() {
//Function that runs on each MeshGenThread in the mesh generation threadpool.
//Processes tasks and returns meshes in the same vector to be handled by the main thread.
void World::meshGenThread(MeshThreadDef* threadDef) {
//Infinite loop
while (true) {
std::unique_lock<std::mutex> lock(threadDef->lock, std::defer_lock);
@ -365,4 +341,4 @@ void World::meshGenThread(MeshThreadDef* threadDef) {
std::unordered_map<glm::vec3, MeshChunk*, World::vec3cmp>* World::getMeshChunks() {
return &meshChunks;
}
}

View File

@ -18,6 +18,7 @@
#include "../../generic/helpers/ArrayTrans3D.h"
#include "../../generic/blocks/BlockAtlas.h"
#include "../../generic/blocks/BlockChunk.h"
#include "../../generic/gen/MapGen.h"
#include "../graphics/mesh/MeshChunk.h"
class World {
@ -39,6 +40,8 @@ public:
void commitChunk(glm::vec3 pos, BlockChunk *c);
void remeshChunk(glm::vec3 pos);
void loadChunkPacket(Packet* p);
void attemptMeshChunk(glm::vec3 pos);
//This function also updates the chunk that is being checked's adjacent data, so maybe a rename is in order.
bool getAdjacentExists(glm::vec3 pos, glm::vec3 myPos);
@ -94,7 +97,7 @@ private:
void handleMeshGenQueue();
const int GEN_THREADS = 8;
const int GEN_QUEUE_SIZE = 4;
const int GEN_QUEUE_SIZE = 8;
const int GEN_FINISHED_SIZE = GEN_THREADS * GEN_QUEUE_SIZE;
std::unordered_set<glm::vec3, vec3cmp> pendingGen;
@ -102,7 +105,7 @@ private:
std::vector<ChunkThreadData*> finishedGen;
const int MESH_THREADS = 4;
const int MESH_QUEUE_SIZE = 32;
const int MESH_QUEUE_SIZE = 64;
const int MESH_FINISHED_SIZE = GEN_THREADS * GEN_QUEUE_SIZE;
std::unordered_set<glm::vec3, vec3cmp> pendingMesh;
@ -110,6 +113,7 @@ private:
std::vector<MeshThreadData*> finishedMesh;
BlockAtlas* blockAtlas;
MapGen* mapGen;
};
#endif //GLPROJECT_WORLD_H

View File

@ -12,7 +12,9 @@ ChunkThreadData::ChunkThreadData(glm::vec3 pos, BlockAtlas *atlas) {
this->chunk = nullptr;
}
ChunkThreadDef::ChunkThreadDef() {
ChunkThreadDef::ChunkThreadDef(MapGen *mapGen) {
this->mapGen = mapGen;
thread = new std::thread(World::chunkGenThread, this);
sched_param sch_params{};

View File

@ -11,6 +11,7 @@
#include "../../generic/blocks/BlockChunk.h"
#include "../../generic/blocks/BlockAtlas.h"
#include "../../generic/gen/MapGen.h"
//Structs for storing the threads used in World, and passing data to and from them.
@ -51,12 +52,14 @@ struct ChunkThreadData {
};
struct ChunkThreadDef {
ChunkThreadDef();
explicit ChunkThreadDef(MapGen *mapGen);
std::thread* thread;
std::mutex lock;
std::vector<ChunkThreadData*> tasks;
MapGen* mapGen;
~ChunkThreadDef();
};

View File

@ -6,7 +6,7 @@
#define ZEUS_LUAAPI_H
#include "LuaParser.h"
#include "../graphics/scene/GameScene.h"
#include "../scene/GameScene.h"
class LuaApi {
public:

View File

@ -67,6 +67,9 @@ ServerConfig* ServerConnection::connect() {
.playerPos = glm::vec3(x, y, z)
};
}
else {
inPackets.push_back(packet);
}
}
}
if (!connected) {
@ -80,48 +83,50 @@ ServerConfig* ServerConnection::connect() {
}
void ServerConnection::update() {
Timer t("Loop time");
//Collect incoming packets
while (socket.available() > 0) {
size_t pendingSize = socket.available();
std::vector<Packet::PacketByte> recv_buf((unsigned long)pendingSize);
std::vector<Packet::PacketByte> recv_buf((unsigned long) pendingSize);
auto remote_endpoint = new asio::ip::udp::endpoint();
socket.receive_from(asio::buffer(recv_buf, pendingSize), *remote_endpoint);
auto packet = Packet::deserialize(recv_buf);
if (packet->length > 0) handlePacket(*packet, remote_endpoint);
if (packet->length > 0) inPackets.push_back(packet);
}
long sleep_for = 16L*1000000L - t.elapsedNs();
std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_for));
// handleInPackets();
}
void ServerConnection::handlePacket(Packet &packet, asio::ip::udp::endpoint* endpoint) {
bool ServerConnection::hasInPacket() {
return !inPackets.empty();
}
Packet *ServerConnection::getPacket() {
auto it = inPackets.begin();
inPackets.erase(it);
return *it;
}
//void ServerConnection::handleInPackets() {
// while (!inPackets.empty()) {
// auto it = inPackets.begin();
// inPackets.erase(it);
// Packet* packet = *it;
//
// handlePacket(packet);
//
// delete packet;
// }
//}
//
//void ServerConnection::handlePacket(Packet* packet) {
// std::cout << packet->type << std::endl;
//}
void ServerConnection::sendPacket(Packet &p, asio::ip::udp::endpoint &e) {
auto data = p.serialize();
socket.send_to(asio::buffer(data, data.size()), e);
}
void ServerConnection::reqChunks(glm::vec3 a, glm::vec3 b) {
Packet p(Packet::REQCHUNKS);
for (int i = (int)a.x; i < (int)b.x; i++) {
for (int j = (int)a.y; j < (int)b.y; j++) {
for (int k = (int)a.z; k < (int)b.z; k++) {
p.addInt(i);
p.addInt(j);
p.addInt(k);
}
}
}
sendPacket(p, remote_endpoint);
}
ServerConnection::~ServerConnection() = default;

View File

@ -25,13 +25,17 @@ public:
void sendPacket(Packet& p, asio::ip::udp::endpoint& e);
void update();
void handlePacket(Packet &packet, asio::ip::udp::endpoint* endpoint);
void reqChunks(glm::vec3 a, glm::vec3 b);
// void handleInPackets();
// void handlePacket(Packet* packet);
bool hasInPacket();
Packet* getPacket();
~ServerConnection();
private:
bool connected;
std::vector<Packet*> inPackets;
asio::io_context io_context;
asio::ip::udp::socket socket;

View File

@ -5,8 +5,8 @@
#include "GameScene.h"
//TODO: Fix this
#include "../../lua/l_register_block.h"
#include "../../lua/l_register_blockmodel.h"
#include "../lua/l_register_block.h"
#include "../lua/l_register_blockmodel.h"
GameScene::GameScene(ClientState* state) : Scene(state) {
server = new ServerConnection("127.0.0.1", 12345);
@ -29,7 +29,7 @@ GameScene::GameScene(ClientState* state) : Scene(state) {
int SIZE = 12;
for (int i = -SIZE; i < SIZE; i++) {
for (int j = -1; j < 12; j++) {
for (int j = -12; j < 12; j++) {
for (int k = -SIZE; k < SIZE; k++) {
world->genNewChunk(glm::vec3(i, j, k));
}
@ -73,12 +73,19 @@ GameScene::GameScene(ClientState* state) : Scene(state) {
crosshair->setScale(22);
guiEntities.push_back(crosshair);
server->reqChunks(glm::vec3(-4, -4, -4), glm::vec3(4, 4, 4));
}
void GameScene::update() {
server->update();
while (server->hasInPacket()) {
auto packet = server->getPacket();
if (packet->type == Packet::CHUNKINFO) world->loadChunkPacket(packet);
delete packet;
}
auto window = state->renderer->getWindow();
player->update(window->getKeysArray(), state->deltaTime, window->getDeltaX(), window->getDeltaY());

View File

@ -6,19 +6,19 @@
#define SRC_GAMEWORLD_H
#include "../../engine/scene/Scene.h"
#include "../../engine/graphics/Renderer.h"
#include "../gui/DebugGui.h"
#include "../engine/scene/Scene.h"
#include "../engine/graphics/Renderer.h"
#include "../graphics/gui/DebugGui.h"
#include "../../lua/LuaParser.h"
#include "../lua/LuaParser.h"
#include "../../gameworld/World.h"
#include "../../gameworld/Player.h"
#include "../gameworld/World.h"
#include "../gameworld/Player.h"
#include "../../network/ServerConnection.h"
#include "../network/ServerConnection.h"
#include "../../../generic/blocks/TextureAtlas.h"
#include "../../../generic/blocks/BlockAtlas.h"
#include "../../generic/blocks/TextureAtlas.h"
#include "../../generic/blocks/BlockAtlas.h"
class GameScene : public Scene {
public:

View File

@ -6,9 +6,9 @@
#define ZEUS_MENUSCENE_H
#include "../../ClientState.h"
#include "../../engine/scene/Scene.h"
#include "../../engine/graphics/HudText.h"
#include "../ClientState.h"
#include "../engine/scene/Scene.h"
#include "../engine/graphics/HudText.h"
class MenuScene : public Scene {
public:

View File

@ -0,0 +1,45 @@
//
// Created by aurailus on 28/01/19.
//
#include "MapGen.h"
void MapGen::init(unsigned int seed) {
}
BlockChunk* MapGen::generate(glm::vec3 pos) {
MapGenJob j(pos);
getElevation(j);
getBiome(j);
fillBlocks(j);
return new BlockChunk(j.blocks);
}
void MapGen::getElevation(MapGen::MapGenJob &j) {
glm::vec3* localPos;
glm::vec3 globalPos;
for (int i = 0; i < 4096; i++) {
localPos = ArrayTrans3D::indToVec(i);
globalPos = glm::vec3(j.pos.x * 16 + localPos->x, j.pos.y * 16 + localPos->y, j.pos.z * 16 + localPos->z);
int val = (int)floor(p.noise(globalPos.x / 16, 0, globalPos.z / 16) * 32) - (int)globalPos.y;
j.elevation[i] = val;
}
}
void MapGen::getBiome(MapGen::MapGenJob &j) {
//TODO: Biome Voronoi calculation
}
void MapGen::fillBlocks(MapGen::MapGenJob &j) {
glm::vec3* localPos;
glm::vec3 globalPos;
for (int i = 0; i < 4096; i++) {
int ev = j.elevation[i];
(*(j.blocks))[i] = ev < 0 ? 0 : ev < 1 ? 1 : ev < 2 ? 2 : 3;
}
}

47
zeus/generic/gen/MapGen.h Normal file
View File

@ -0,0 +1,47 @@
//
// Created by aurailus on 28/01/19.
//
#ifndef ZEUS_MAPGEN_H
#define ZEUS_MAPGEN_H
#include <vec3.hpp>
#include <vector>
#include "../blocks/BlockChunk.h"
#include "../helpers/PerlinNoise.h"
class MapGen {
public:
MapGen() : p(1) { init(1); }
explicit MapGen(unsigned int seed) : p(seed) { init(seed); }
BlockChunk* generate(glm::vec3 pos);
private:
struct MapGenJob {
std::vector<int>
elevation,
biome,
*blocks;
glm::vec3 pos;
explicit MapGenJob(glm::vec3 pos) {
this->pos = pos;
elevation.reserve(4096);
biome.reserve(4096);
blocks = new std::vector<int>(4096);
}
};
void getElevation(MapGenJob& j);
void getBiome(MapGenJob& j);
void fillBlocks(MapGenJob& j);
void init(unsigned int seed);
PerlinNoise p;
};
#endif //ZEUS_MAPGEN_H

View File

@ -15,12 +15,7 @@ Packet* Packet::deserialize(std::vector<PacketByte> data) {
//Seperate the packet header from the body,
//This can be changed to support more header values in the future.
//Determine Packet Type
int num = 0;
for (int i = 0; i < 4; i++) {
num <<= 8;
num |= data[i];
}
int num = decodeInt(&data[0]);
//Get body of the packet
std::vector<PacketByte> dataBody;

View File

@ -46,7 +46,7 @@ public:
const static PacketType HANDSHAKE = 1;
const static PacketType AUTHENTICATE = 2;
const static PacketType PLAYERINFO = 3;
const static PacketType REQCHUNKS = 4;
const static PacketType CHUNKINFO = 4;
};

View File

@ -3,6 +3,7 @@
//
#include "ConnMan.h"
#include "../../generic/blocks/BlockChunk.h"
ConnMan::ConnMan() = default;
@ -58,18 +59,7 @@ void ConnMan::handlePacket(Packet* packet, udp::endpoint* endpoint) {
}
else {
//TODO: Push to the packet vector
// if (packet->type == Packet::REQCHUNKS) {
// for (int i = 0; i < packet->length / 12; i++) {
// int offsetBase = i * 12;
// int x = Packet::decodeInt(&packet->data[0 + offsetBase]);
// int y = Packet::decodeInt(&packet->data[0 + offsetBase + 4]);
// int z = Packet::decodeInt(&packet->data[0 + offsetBase + 8]);
// printf("%i, %i, %i\n", x, y, z);
// }
// std::cout << packet->length << std::endl;
// }
}
}
ServerClient* ConnMan::addClient(std::string uuid, udp::endpoint* endpoint) {
@ -94,6 +84,24 @@ void ConnMan::addPlayer(ServerClient* client, std::string username) {
p.addFloat(player->pos.z);
send(&p, client);
p = Packet(Packet::CHUNKINFO);
p.addInt(0);
p.addInt(0);
p.addInt(0);
auto blocks = new std::vector<int>();
for (int i = 0; i < 4096; i++) {
blocks->push_back(i < 2048 ? 0 : 1);
}
auto originalChunk = new BlockChunk(blocks);
auto gzip = originalChunk->serialize();
p.addString(gzip);
send(&p, client);
}
//Create a IP + Port combo that can be used as a UUID for an endpoint.