diff --git a/SQCSim-common/netprotocol.cpp b/SQCSim-common/netprotocol.cpp index 2ba7889..e087313 100644 --- a/SQCSim-common/netprotocol.cpp +++ b/SQCSim-common/netprotocol.cpp @@ -430,6 +430,77 @@ void netprot::Serialize(ChunkMod* chmod, char* buf[], uint32_t* buflen) { *buflen = sizeof(uint32_t) * 3 + 3; } +void netprot::Serialize(BulletAdd* bull, char* buf[], uint32_t* buflen) { + *buf[0] = (char)netprot::PACKET_TYPE::BULLET; + + uint64_t tstamp = bull->tstamp; + uint8_t ts8[sizeof(uint64_t)] = { + (uint8_t)((tstamp >> 56) & 0xFF), + (uint8_t)((tstamp >> 48) & 0xFF), + (uint8_t)((tstamp >> 40) & 0xFF), + (uint8_t)((tstamp >> 32) & 0xFF), + (uint8_t)((tstamp >> 24) & 0xFF), + (uint8_t)((tstamp >> 16) & 0xFF), + (uint8_t)((tstamp >> 8) & 0xFF), + (uint8_t)(tstamp & 0xFF) + }; + + memcpy(*buf + 1, ts8, sizeof(uint64_t)); + + uint64_t tid = bull->tid; + uint8_t tid8[sizeof(uint64_t)] = { + (uint8_t)((tid >> 56) & 0xFF), + (uint8_t)((tid >> 48) & 0xFF), + (uint8_t)((tid >> 40) & 0xFF), + (uint8_t)((tid >> 32) & 0xFF), + (uint8_t)((tid >> 24) & 0xFF), + (uint8_t)((tid >> 16) & 0xFF), + (uint8_t)((tid >> 8) & 0xFF), + (uint8_t)(tid & 0xFF) + }; + + memcpy(*buf + 1 + sizeof(uint64_t), tid8, sizeof(uint64_t)); + + uint32_t vec[3]; + memcpy(vec, &bull->pos, sizeof(Vector3f)); // Pour d�naturer les floats. + + uint8_t vec8[3 * sizeof(uint32_t)] = { + (uint8_t)((vec[0] >> 24) & 0xFF), + (uint8_t)((vec[0] >> 16) & 0xFF), + (uint8_t)((vec[0] >> 8) & 0xFF), + (uint8_t)(vec[0] & 0xFF), + (uint8_t)((vec[1] >> 24) & 0xFF), + (uint8_t)((vec[1] >> 16) & 0xFF), + (uint8_t)((vec[1] >> 8) & 0xFF), + (uint8_t)(vec[1] & 0xFF), + (uint8_t)((vec[2] >> 24) & 0xFF), + (uint8_t)((vec[2] >> 16) & 0xFF), + (uint8_t)((vec[2] >> 8) & 0xFF), + (uint8_t)(vec[2] & 0xFF) }; + + memcpy(*buf + 1 + sizeof(uint64_t) * 2, vec8, sizeof(uint32_t) * 3); + + memcpy(vec, &bull->dir, sizeof(Vector3f)); // Pour d�naturer les floats. + + uint8_t dir8[3 * sizeof(uint32_t)] = { + (uint8_t)((vec[0] >> 24) & 0xFF), + (uint8_t)((vec[0] >> 16) & 0xFF), + (uint8_t)((vec[0] >> 8) & 0xFF), + (uint8_t)(vec[0] & 0xFF), + (uint8_t)((vec[1] >> 24) & 0xFF), + (uint8_t)((vec[1] >> 16) & 0xFF), + (uint8_t)((vec[1] >> 8) & 0xFF), + (uint8_t)(vec[1] & 0xFF), + (uint8_t)((vec[2] >> 24) & 0xFF), + (uint8_t)((vec[2] >> 16) & 0xFF), + (uint8_t)((vec[2] >> 8) & 0xFF), + (uint8_t)(vec[2] & 0xFF) }; + + memcpy(*buf + 1 + sizeof(uint64_t) * 2 + sizeof(uint32_t) * 3, dir8, sizeof(uint32_t) * 3); + + *buflen = 1 + sizeof(uint64_t) * 2 + sizeof(uint32_t) * 6; +} + void netprot::Serialize(ErrorLog* errlog, char* buf[], uint32_t* buflen) { *buf[0] = (char)netprot::PACKET_TYPE::ERRLOG; @@ -876,6 +947,74 @@ bool netprot::Deserialize(ChunkMod* chmod, char* buf, uint32_t* buflen) { return true; } +bool netprot::Deserialize(BulletAdd* bull, char* buf, uint32_t* buflen) { + if (*buflen <= sizeof(BulletAdd)) + return false; + + uint8_t tst[sizeof(uint64_t)] = { 0,0,0,0,0,0,0,0 }; + memcpy(tst, &buf[1], sizeof(uint64_t)); + bull->tstamp = + (uint64_t)tst[0] << 56 | + (uint64_t)tst[1] << 48 | + (uint64_t)tst[2] << 40 | + (uint64_t)tst[3] << 32 | + (uint64_t)tst[4] << 24 | + (uint64_t)tst[5] << 16 | + (uint64_t)tst[6] << 8 | + (uint64_t)tst[7]; + + memcpy(tst, &buf[1 + sizeof(uint64_t)], sizeof(uint64_t)); + bull->tid = + (uint64_t)tst[0] << 56 | + (uint64_t)tst[1] << 48 | + (uint64_t)tst[2] << 40 | + (uint64_t)tst[3] << 32 | + (uint64_t)tst[4] << 24 | + (uint64_t)tst[5] << 16 | + (uint64_t)tst[6] << 8 | + (uint64_t)tst[7]; + + uint8_t subvec[3 * sizeof(uint32_t)] = { 0,0,0,0,0,0,0,0,0,0,0,0 }; + memcpy(subvec, &buf[1 + sizeof(uint64_t) * 2], sizeof(uint8_t) * 12); + uint32_t vec[3] = { + (uint32_t)subvec[0] << 24 | + (uint32_t)subvec[1] << 16 | + (uint32_t)subvec[2] << 8 | + (uint32_t)subvec[3], + (uint32_t)subvec[4] << 24 | + (uint32_t)subvec[5] << 16 | + (uint32_t)subvec[6] << 8 | + (uint32_t)subvec[7], + (uint32_t)subvec[8] << 24 | + (uint32_t)subvec[9] << 16 | + (uint32_t)subvec[10] << 8 | + (uint32_t)subvec[11] }; + + memcpy(&bull->pos, vec, sizeof(uint32_t) * 3); + + memcpy(subvec, &buf[1 + sizeof(uint64_t) * 2 + sizeof(uint8_t) * 12], sizeof(uint8_t) * 12); + + uint32_t dir[3] = { + (uint32_t)subvec[0] << 24 | + (uint32_t)subvec[1] << 16 | + (uint32_t)subvec[2] << 8 | + (uint32_t)subvec[3], + (uint32_t)subvec[4] << 24 | + (uint32_t)subvec[5] << 16 | + (uint32_t)subvec[6] << 8 | + (uint32_t)subvec[7], + (uint32_t)subvec[8] << 24 | + (uint32_t)subvec[9] << 16 | + (uint32_t)subvec[10] << 8 | + (uint32_t)subvec[11] }; + + memcpy(&bull->dir, dir, sizeof(uint32_t) * 3); + + *buflen = 1 + sizeof(uint64_t) * 2 + sizeof(uint8_t) * 24; + + return true; +} + bool netprot::Deserialize(ErrorLog* errlog, char* buf, uint32_t *buflen) { if (*buflen <= sizeof(ErrorLog)) return false; @@ -969,9 +1108,7 @@ netprot::Packet netprot::getPack(char* buf, uint32_t *buflen) { return pck; } -netprot::Packet netprot::getPack(netprot::Buffer* buf) { - return netprot::getPack(buf->ptr, &buf->len); -} +netprot::Packet netprot::getPack(netprot::Buffer* buf) { return netprot::getPack(buf->ptr, &buf->len); } bool netprot::emptyPack(netprot::Packet pck) { switch (pck.type) { diff --git a/SQCSim-common/netprotocol.h b/SQCSim-common/netprotocol.h index 27e7f56..dad658c 100644 --- a/SQCSim-common/netprotocol.h +++ b/SQCSim-common/netprotocol.h @@ -12,8 +12,8 @@ namespace netprot { ERR, INPUT, OUTPUT, SYNC, TEAMINF, SELFINF, PLAYINF, LOGINF, CHUNKMOD, PLAYERMOD, PICKUPMOD, - GAMEINFO, ENDINFO , CHAT, ERRLOG, - LAST_PACK + GAMEINFO, ENDINFO , BULLET, + CHAT, ERRLOG, LAST_PACK }; /* Structures */ @@ -135,6 +135,12 @@ namespace netprot { BlockType b_type, old_b_type; }; + struct BulletAdd { + Timestamp tstamp; + Vector3f pos, dir; + uint64_t id; + }; + struct ErrorLog { // srv -> cli TCP event char mess[140]; bool is_fatal; @@ -153,6 +159,7 @@ namespace netprot { void Serialize(GameInfo* ginfo, char* buf[], uint32_t* buflen); // cli/srv void Serialize(Chat* chat, char* buf[], uint32_t* buflen); // cli/srv void Serialize(ChunkMod* chmod, char* buf[], uint32_t* buflen); // srv + void Serialize(BulletAdd* bull, char* buf[], uint32_t* buflen); // srv void Serialize(ErrorLog* errlog, char* buf[], uint32_t* buflen); // srv bool Deserialize(Input* in, char* buf, uint32_t* buflen); // srv @@ -164,6 +171,7 @@ namespace netprot { bool Deserialize(GameInfo* ginfo, char* buf, uint32_t* buflen); // cli bool Deserialize(Chat* chat, char* buf, uint32_t* buflen); // srv/cli bool Deserialize(ChunkMod* chmod, char* buf, uint32_t* buflen); // cli + bool Deserialize(BulletAdd* bull, char* buf, uint32_t* buflen); // cli bool Deserialize(ErrorLog* errlog, char* buf, uint32_t* buflen); // srv PACKET_TYPE getType(char* buf, uint32_t buflen); diff --git a/SQCSim-srv/connection.cpp b/SQCSim-srv/connection.cpp index 39fed03..1e3ab99 100644 --- a/SQCSim-srv/connection.cpp +++ b/SQCSim-srv/connection.cpp @@ -95,7 +95,7 @@ void Connection::sendPacks(SOCKET sock, std::unordered_map= 1000) { outs -= 1000; Sync sync; - sync.hp = player.get()->GetHP(); + sync.hp = player->GetHP(); sync.timestamp = out.timestamp; sync.position = out.position; sync.sid = m_loginfo.sid; @@ -109,13 +109,14 @@ void Connection::sendPacks(SOCKET sock, std::unordered_mapSetDirection(in.direction); - player.get()->ApplyPhysics(player.get()->GetInput(in.keys.forward, - in.keys.backward, - in.keys.left, - in.keys.right, - in.keys.jump, false, el), world, el); + player->SetDirection(in.direction); + player->ApplyPhysics(player->GetInput(in.keys.forward, + in.keys.backward, + in.keys.left, + in.keys.right, + in.keys.jump, false, el), world, el); - //if (in.keys.block) - // ChunkDiffs.push_back() + if (in.keys.block) { + bool block = false; + ChunkMod* cmod = world->ChangeBlockAtCursor(BLOCK_TYPE::BTYPE_METAL, + player->GetPosition(), + player->GetDirection(), + block, true); + if (cmod) + ChunkDiffs.emplace_back(cmod); + } if (in.keys.shoot && m_shoot_acc <= 0.) - Bullets.push_back(Bullet(player.get()->GetPOV() + player.get()->GetDirection(), player.get()->GetDirection())); + Bullets.push_back(Bullet(player->GetPOV() + player->GetDirection(), player->GetDirection())); - - out.position = player.get()->GetPositionAbs(); + out.position = player->GetPositionAbs(); out.direction = in.direction; out.timestamp = in.timestamp; out.id = m_playinfo.id; m_output_manifest[out.timestamp] = out; m_output_vector.push_back(out); + tstamp = out.timestamp; ++m_last_in; } + + return tstamp; } void Connection::CleanInputManifest(Timestamp time) { @@ -161,3 +171,5 @@ void Connection::CleanInputManifest(Timestamp time) { // while (wat != m_input_manifest.begin()) // m_input_manifest.erase(wat--); } + +Timestamp Connection::GetTStamp() const { return m_tstamp; } diff --git a/SQCSim-srv/connection.h b/SQCSim-srv/connection.h index 7554f5a..091e7f4 100644 --- a/SQCSim-srv/connection.h +++ b/SQCSim-srv/connection.h @@ -20,7 +20,7 @@ public: PlayerInfo play); ~Connection(); - std::unique_ptr player = nullptr; + Player* player = nullptr; uint64_t GetHash(bool self = true) const; uint64_t GetTeamHash() const; @@ -36,7 +36,7 @@ public: void getPacks(SOCKET sock); void sendPacks(SOCKET sock, std::unordered_map conns, const uint32_t timer); - void Run(World* world); + Timestamp Run(World* world); void CleanInputManifest(Timestamp time); @@ -45,6 +45,8 @@ public: std::vector Bullets; std::vector ChunkDiffs; + Timestamp GetTStamp() const; + private: std::unordered_map m_input_manifest; std::vector m_input_vector; @@ -53,6 +55,7 @@ private: std::unordered_map m_chatlog; float m_shoot_acc = 0; + Timestamp m_tstamp = 0; SOCKET m_sock; sockaddr_in m_addr; diff --git a/SQCSim-srv/server.cpp b/SQCSim-srv/server.cpp index c4af364..aeba450 100644 --- a/SQCSim-srv/server.cpp +++ b/SQCSim-srv/server.cpp @@ -18,9 +18,9 @@ Server::~Server() { closesocket(m_sock_udp); if (m_sock_tcp) closesocket(m_sock_tcp); - for (const auto& [key, player] : m_players) + for (const auto& [key, player] : m_conns) closesocket(player->getSock()); - m_players.clear(); + m_conns.clear(); delete m_world; #ifdef _WIN32 WSACleanup(); @@ -165,7 +165,7 @@ int Server::Ready() { std::cout << m_game.seed << std::endl; Connection* conn = new Connection(sock, sockad, *log, play); - m_players[log->sid] = conn; + m_conns[log->sid] = conn; delete log; @@ -174,8 +174,8 @@ int Server::Ready() { } } } - for (auto& [keyin, playin] : m_players) // Not pretty, but it works. - for (auto& [keyout, playout] : m_players) { + for (auto& [keyin, playin] : m_conns) // Not pretty, but it works. + for (auto& [keyout, playout] : m_conns) { if (keyin == keyout) continue; sendPackTo(m_sock_udp, playout->getInfo(), &m_buf, playin->getAddr()); // et envoyer les infos des joueurs distants au nouveau joueur. @@ -192,17 +192,18 @@ void Server::Run() { Log("Debut de la partie...", false, false); - int players = m_players.size(); + int players = m_conns.size(); m_world = new World(); m_world->SetSeed(m_game.seed); m_world->GetChunks().Reset(nullptr); m_world->BuildWorld(); - for (auto& [key, conn] : m_players) { // Creation des instances de joueurs et premier sync. + for (auto& [key, conn] : m_conns) { // Creation des instances de joueurs et premier sync. int x = (rand() % (CHUNK_SIZE_X * WORLD_SIZE_X - 1)) - (CHUNK_SIZE_X * WORLD_SIZE_X / 2), y = (rand() % (CHUNK_SIZE_Y * WORLD_SIZE_Y - 1)) - (CHUNK_SIZE_Y * WORLD_SIZE_Y / 2); - conn->player = std::make_unique(Vector3f(x + .5f, CHUNK_SIZE_Y + 1.8f, y + .5f)); + conn->player = new Player(Vector3f(x + .5f, CHUNK_SIZE_Y + 1.8f, y + .5f)); + m_players[key] = conn->player; Sync sync; sync.position = conn->player->GetPositionAbs(); sync.hp = conn->player->GetHP(); @@ -212,11 +213,14 @@ void Server::Run() { sync.timer = m_game.countdown; sendPackTo(m_sock_udp, &sync, &m_buf, conn->getAddr()); } - + int timer = m_game.countdown, sync_acc = 0; std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); Timestamp last = 0; std::vector chatlog; + std::vector chunkdiffs; + std::vector bullets, outbox_bullets; + std::vector netbull; while (!endgame) { using namespace std::chrono; @@ -230,13 +234,14 @@ void Server::Run() { --timer; } - for (auto& [key, conn] : m_players) { + for (auto& [key, conn] : m_conns) { /* In */ int deadplayers = 0; std::vector lsPck; Input in; Chat chat; Sync sync; + lsPck = recvPacks(m_sock_udp, &m_buf); for (auto& pck : lsPck) { uint32_t bsize = m_buf.len - (pck - m_buf.ptr); @@ -244,7 +249,7 @@ void Server::Run() { using enum netprot::PACKET_TYPE; case INPUT: if (Deserialize(&in, pck, &bsize)) - m_players[in.sid]->AddInput(in); + m_conns[in.sid]->AddInput(in); break; case SYNC: if (Deserialize(&sync, pck, &bsize)) {} @@ -264,25 +269,80 @@ void Server::Run() { if (conn->player->AmIDead()) { ++deadplayers; conn->m_nsync == false; - continue; } - conn->Run(m_world); + else { + Timestamp tstamp = conn->Run(m_world); + + for (auto& chmo : conn->ChunkDiffs) + chunkdiffs.emplace_back(chmo); + conn->ChunkDiffs.clear(); + + for (auto& bull : conn->Bullets) { + bullets.emplace_back(bull); + BulletAdd* nbul = new BulletAdd(); + nbul->pos = conn->player->GetPosition(); + nbul->dir = conn->player->GetDirection(); + nbul->id = key; + nbul->tstamp = tstamp; + + netbull.emplace_back(nbul); + } + conn->Bullets.clear(); + } /* Out */ - conn->sendPacks(m_sock_udp, m_players, timer); + conn->sendPacks(m_sock_udp, m_conns, timer); } - if (deadplayers == players - 1 || timer <= 0) endgame = true; } + for (auto& bull : netbull) { + for (auto& [key, conn] : m_conns) + sendPackTo(m_sock_udp, bull, &m_buf, conn->getAddr()); + } + + for (auto& bull : bullets) { + ChunkMod* cmod = nullptr; + if (bull->Update(m_world, (1. / 60.), 20, m_players, &cmod)) { + if (cmod) + chunkdiffs.emplace_back(cmod); + outbox_bullets.emplace_back(std::move(bull)); + } + } + for (auto& chat : chatlog) - for (auto& [key, conn] : m_players) + for (auto& [key, conn] : m_conns) sendPackTo(m_sock_udp, &chat, &m_buf, conn->getAddr()); + + for (auto& chmo : chunkdiffs) { + for (auto& [key, conn] : m_conns) + sendPackTo(m_sock_udp, chmo, &m_buf, conn->getAddr()); + delete chmo; + } + + for (auto& bull : outbox_bullets) + delete bull; + + for (auto& bull : netbull) + delete bull; + + outbox_bullets.clear(); + netbull.clear(); + chunkdiffs.clear(); chatlog.clear(); } + Chat end; + end.src_id = 0; + char endmess[] = "Game over, motherfuckers."; + + strcpy(end.mess, endmess); + + for (auto& [key, conn] : m_conns) + sendPackTo(m_sock_udp, &end, &m_buf, conn->getAddr()); + // TODO: Gérer les 2-3 secondes post-game avant le billboard pour pas avoir un whiplash à la fin de la game. } @@ -325,11 +385,11 @@ void Server::Log(std::string str, bool is_error = false, bool is_fatal = false) closesocket(m_sock_udp); if (m_sock_tcp) closesocket(m_sock_tcp); - for (const auto& [key, player] : m_players) { + for (const auto& [key, player] : m_conns) { closesocket(player->getSock()); } delete m_world; - m_players.clear(); + m_conns.clear(); #ifdef _WIN32 WSACleanup(); #endif diff --git a/SQCSim-srv/server.h b/SQCSim-srv/server.h index dd5a397..33e78df 100644 --- a/SQCSim-srv/server.h +++ b/SQCSim-srv/server.h @@ -36,7 +36,8 @@ private: Buffer m_buf; - std::unordered_map m_players; + std::unordered_map m_players; + std::unordered_map m_conns; std::unordered_map m_chatlog; std::vector m_ids; GameInfo m_game; diff --git a/SQCSim2021/engine.cpp b/SQCSim2021/engine.cpp index 1a5bbd6..c188e97 100644 --- a/SQCSim2021/engine.cpp +++ b/SQCSim2021/engine.cpp @@ -1362,7 +1362,7 @@ void Engine::Render(float elapsedTime) { Sync sync; uint64_t id = m_conn.getId(); static std::vector lsPck; - static int sync_acc = 0; + static int sync_acc = 0, cmod_acc = 0; if (cmod) m_chunkmod_manifest.emplace_back(cmod); @@ -1371,6 +1371,7 @@ void Engine::Render(float elapsedTime) { last = tstamp; sync_acc += tstamp - last; + cmod_acc += tstamp - last; if (sync_acc >= 1000) { sync_acc -= 1000; @@ -1385,6 +1386,16 @@ void Engine::Render(float elapsedTime) { m_syncs[sync.timestamp] = sync; } + if (cmod_acc >= 1000) { + cmod_acc -= 1000; + if (!m_chunkmod_manifest.empty()) { + ChunkMod* cmod = m_chunkmod_manifest.front(); + m_chunkmod_manifest.pop_front(); + m_world.ChangeBlockAtPosition(cmod->old_b_type, cmod->pos); + delete cmod; + } + } + input.sid = id; input.direction = m_player.GetDirection(); input.timestamp = tstamp; @@ -1401,8 +1412,7 @@ void Engine::Render(float elapsedTime) { lsPck = recvPacks(m_conn.m_sock_udp, &m_buf); char* prevptr = nullptr; for (auto& pck : lsPck) { // We could make a few threads out of this. - Sync sync; - Output out; + Sync sync; Output out; ChunkMod cmod; BulletAdd bull; if (!prevptr) prevptr = m_buf.ptr; uint32_t bsize = m_buf.len - (pck - prevptr); @@ -1447,6 +1457,33 @@ void Engine::Render(float elapsedTime) { rt->Feed(out); } break; + case CHUNKMOD: + if (Deserialize(&cmod, pck, &bsize)) { + if (!std::erase_if(m_chunkmod_manifest, // Efface le chunkmod du manifeste s'il est dedans et reset le countdown, sinon fait la modification. + [cmod](ChunkMod* c) { + return cmod.pos == c->pos && + cmod.b_type == c->b_type && + cmod.old_b_type == c->old_b_type; + })) + m_world.ChangeBlockAtPosition(cmod.b_type, cmod.pos); + else cmod_acc = 0; + } + break; + case BULLET: + if (Deserialize(&bull, pck, &bsize)) { + Bullet* bult = new Bullet(bull.pos, bull.dir, bull.id); + for (int x = 0; x < MAX_BULLETS; ++x) // Ajouter une balle dans l'array (aussi connu sous le nom de "faire pow pow"). + if (!m_bullets[x]) { + m_bullets[x] = bult; + break; + } + else if (x == MAX_BULLETS - 1) { // S'il y a pas d'espace dans l'array, prendre la place de la première balle de l'array. + m_bullets[0]->~Bullet(); + m_bullets[0] = bult; + } + m_audio.Create3DAudioObj(m_powpow, AUDIO_PATH "pow.wav", bull.pos, bull.dir * 10, false, .5f); + } + break; default: std::cout << "packet be no good."; break; diff --git a/SQCSim2021/engine.h b/SQCSim2021/engine.h index 6f23719..e9f4709 100644 --- a/SQCSim2021/engine.h +++ b/SQCSim2021/engine.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "../SQCSim-common/array2d.h" #include "../SQCSim-common/blockinfo.h" #include "../SQCSim-common/boostinfo.h" @@ -87,8 +88,6 @@ private: Bullet* m_bullets[MAX_BULLETS]; //Menu - enum class GameState: uint8_t { MAIN_MENU, OPTIONS, QUIT, NEWG, PLAY, PAUSE, SINGLEMULTI }; - Vector3f m_otherplayerpos = Vector3f(999, 999, 999); World m_world = World(); @@ -172,7 +171,7 @@ private: bool m_selectedOptAudioMainBar = false; bool m_selectedOptAudioMusicBar = false; - bool m_selectedOptAudioSfxBar = false; + bool m_selectedOptAudioSfxBar = false; bool m_selectedGameplaySensitivityBar = false; bool m_damage = false; @@ -214,7 +213,7 @@ private: bool m_networkgame = false; Connector m_conn; - std::vector m_chunkmod_manifest; + std::deque m_chunkmod_manifest; std::chrono::high_resolution_clock::time_point m_startTime; std::unordered_map m_players; netprot::Buffer m_buf, m_bufout;