diff --git a/src/ChunkManager.cpp b/src/ChunkManager.cpp index a9fcec1..3c7e335 100644 --- a/src/ChunkManager.cpp +++ b/src/ChunkManager.cpp @@ -3,12 +3,12 @@ #include "NPCManager.hpp" #include "settings.hpp" -std::map, Chunk*> ChunkManager::chunks; +std::map, Chunk*> ChunkManager::chunks; void ChunkManager::init() {} // stubbed -void ChunkManager::addNPC(int posX, int posY, int32_t id) { - std::pair pos = grabChunk(posX, posY); +void ChunkManager::addNPC(int posX, int posY, int instanceID, int32_t id) { + std::tuple pos = grabChunk(posX, posY, instanceID); // make chunk if it doesn't exist! if (chunks.find(pos) == chunks.end()) { @@ -22,8 +22,8 @@ void ChunkManager::addNPC(int posX, int posY, int32_t id) { chunk->NPCs.insert(id); } -void ChunkManager::addPlayer(int posX, int posY, CNSocket* sock) { - std::pair pos = grabChunk(posX, posY); +void ChunkManager::addPlayer(int posX, int posY, int instanceID, CNSocket* sock) { + std::tuple pos = grabChunk(posX, posY, instanceID); // make chunk if it doesn't exist! if (chunks.find(pos) == chunks.end()) { @@ -37,7 +37,7 @@ void ChunkManager::addPlayer(int posX, int posY, CNSocket* sock) { chunk->players.insert(sock); } -void ChunkManager::removePlayer(std::pair chunkPos, CNSocket* sock) { +void ChunkManager::removePlayer(std::tuple chunkPos, CNSocket* sock) { if (!checkChunk(chunkPos)) return; // do nothing if chunk doesn't even exist @@ -48,7 +48,7 @@ void ChunkManager::removePlayer(std::pair chunkPos, CNSocket* sock) { // TODO: if players and NPCs are empty, free chunk and remove it from surrounding views } -void ChunkManager::removeNPC(std::pair chunkPos, int32_t id) { +void ChunkManager::removeNPC(std::tuple chunkPos, int32_t id) { if (!checkChunk(chunkPos)) return; // do nothing if chunk doesn't even exist @@ -59,22 +59,25 @@ void ChunkManager::removeNPC(std::pair chunkPos, int32_t id) { // TODO: if players and NPCs are empty, free chunk and remove it from surrounding views } -bool ChunkManager::checkChunk(std::pair chunk) { +bool ChunkManager::checkChunk(std::tuple chunk) { return chunks.find(chunk) != chunks.end(); } -std::pair ChunkManager::grabChunk(int posX, int posY) { - return std::make_pair(posX / (settings::CHUNKSIZE / 3), posY / (settings::CHUNKSIZE / 3)); +std::tuple ChunkManager::grabChunk(int posX, int posY, int instanceID) { + return std::make_tuple(posX / (settings::CHUNKSIZE / 3), posY / (settings::CHUNKSIZE / 3), instanceID); } -std::vector ChunkManager::grabChunks(std::pair chunk) { +std::vector ChunkManager::grabChunks(std::tuple chunk) { std::vector chnks; chnks.reserve(9); + int x, y, inst; + std::tie(x, y, inst) = chunk; + // grabs surrounding chunks if they exist for (int i = -1; i < 2; i++) { for (int z = -1; z < 2; z++) { - std::pair pos(chunk.first+i, chunk.second+z); + std::tuple pos = std::make_tuple(x+i, y+z, inst); // if chunk exists, add it to the vector if (checkChunk(pos)) @@ -108,8 +111,8 @@ std::vector ChunkManager::getDeltaChunks(std::vector from, std:: return delta; } -bool ChunkManager::inPopulatedChunks(int posX, int posY) { - auto chunk = ChunkManager::grabChunk(posX, posY); +bool ChunkManager::inPopulatedChunks(int posX, int posY, int instanceID) { + auto chunk = ChunkManager::grabChunk(posX, posY, instanceID); auto nearbyChunks = ChunkManager::grabChunks(chunk); for (Chunk *c: nearbyChunks) { diff --git a/src/ChunkManager.hpp b/src/ChunkManager.hpp index 97d061a..cdcdb5c 100644 --- a/src/ChunkManager.hpp +++ b/src/ChunkManager.hpp @@ -6,6 +6,7 @@ #include #include #include +#include class Chunk { public: @@ -13,19 +14,25 @@ public: std::set NPCs; }; +enum { + INSTANCE_OVERWORLD, // default instance every player starts in + INSTANCE_IZ, // all infected zones share an instance + INSTANCE_UNIQUE // fusion lairs are generated as requested (+ uid) +}; + namespace ChunkManager { void init(); void cleanup(); - extern std::map, Chunk*> chunks; + extern std::map, Chunk*> chunks; - void addNPC(int posX, int posY, int32_t id); - void addPlayer(int posX, int posY, CNSocket* sock); - void removePlayer(std::pair chunkPos, CNSocket* sock); - void removeNPC(std::pair chunkPos, int32_t id); - bool checkChunk(std::pair chunk); - std::pair grabChunk(int posX, int posY); - std::vector grabChunks(std::pair chunkPos); + void addNPC(int posX, int posY, int instanceID, int32_t id); + void addPlayer(int posX, int posY, int instanceID, CNSocket* sock); + void removePlayer(std::tuple chunkPos, CNSocket* sock); + void removeNPC(std::tuple chunkPos, int32_t id); + bool checkChunk(std::tuple chunk); + std::tuple grabChunk(int posX, int posY, int instanceID); + std::vector grabChunks(std::tuple chunkPos); std::vector getDeltaChunks(std::vector from, std::vector to); - bool inPopulatedChunks(int posX, int posY); + bool inPopulatedChunks(int posX, int posY, int instanceID); } diff --git a/src/MobManager.cpp b/src/MobManager.cpp index dd33502..402da94 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -457,7 +457,7 @@ void MobManager::step(CNServer *serv, time_t currTime) { int y = pair.second->appearanceData.iY; // skip chunks without players - if (!ChunkManager::inPopulatedChunks(x, y)) + if (!ChunkManager::inPopulatedChunks(x, y, pair.second->instanceID)) continue; // skip mob movement and combat if disabled diff --git a/src/MobManager.hpp b/src/MobManager.hpp index 879d273..234a090 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -42,8 +42,8 @@ struct Mob : public BaseNPC { // temporary; until we're sure what's what nlohmann::json data; - Mob(int x, int y, int z, int type, int hp, int angle, nlohmann::json d, int32_t id) - : BaseNPC(x, y, z, type, id), maxHealth(hp) { + Mob(int x, int y, int z, int iID, int type, int hp, int angle, nlohmann::json d, int32_t id) + : BaseNPC(x, y, z, iID, type, id), maxHealth(hp) { state = MobState::ROAMING; data = d; @@ -68,8 +68,8 @@ struct Mob : public BaseNPC { } // constructor for /summon - Mob(int x, int y, int z, int type, nlohmann::json d, int32_t id) - : Mob(x, y, z, type, 0, 0, d, id) { + Mob(int x, int y, int z, int iID, int type, nlohmann::json d, int32_t id) + : Mob(x, y, z, iID, type, 0, 0, d, id) { summoned = true; // will be despawned and deallocated when killed appearanceData.iHP = maxHealth = d["m_iHP"]; } diff --git a/src/NPC.hpp b/src/NPC.hpp index 3dffe27..c48b5c9 100644 --- a/src/NPC.hpp +++ b/src/NPC.hpp @@ -7,11 +7,12 @@ class BaseNPC { public: sNPCAppearanceData appearanceData; NPCClass npcClass; - std::pair chunkPos; + int instanceID; + std::tuple chunkPos; std::vector currentChunks; BaseNPC() {}; - BaseNPC(int x, int y, int z, int type, int id) { + BaseNPC(int x, int y, int z, int iID, int type, int id) { appearanceData.iX = x; appearanceData.iY = y; appearanceData.iZ = z; @@ -22,9 +23,11 @@ public: appearanceData.iBarkerType = 0; appearanceData.iNPC_ID = id; - chunkPos = std::pair(0, 0); + instanceID = iID; + + chunkPos = std::make_tuple(0, 0, instanceID); }; - BaseNPC(int x, int y, int z, int type, int id, NPCClass classType) : BaseNPC(x, y, z, type, id) { + BaseNPC(int x, int y, int z, int iID, int type, int id, NPCClass classType) : BaseNPC(x, y, z, iID, type, id) { npcClass = classType; } }; diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index b78ea49..4ac22c7 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -140,7 +140,7 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) { npc->appearanceData.iX = X; npc->appearanceData.iY = Y; npc->appearanceData.iZ = Z; - std::pair newPos = ChunkManager::grabChunk(X, Y); + std::tuple newPos = ChunkManager::grabChunk(X, Y, npc->instanceID); // nothing to be done (but we should also update currentChunks to add/remove stale chunks) if (newPos == npc->chunkPos) { @@ -158,7 +158,7 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) { // update chunks ChunkManager::removeNPC(npc->chunkPos, id); - ChunkManager::addNPC(X, Y, id); + ChunkManager::addNPC(X, Y, npc->instanceID, id); npc->chunkPos = newPos; npc->currentChunks = allChunks; @@ -544,10 +544,10 @@ void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) { resp.NPCAppearanceData.iZ = plr->z; if (team == 2) { - NPCs[resp.NPCAppearanceData.iNPC_ID] = new Mob(plr->x, plr->y, plr->z, req->iNPCType, NPCData[req->iNPCType], resp.NPCAppearanceData.iNPC_ID); + NPCs[resp.NPCAppearanceData.iNPC_ID] = new Mob(plr->x, plr->y, plr->z, plr->instanceID, req->iNPCType, NPCData[req->iNPCType], resp.NPCAppearanceData.iNPC_ID); MobManager::Mobs[resp.NPCAppearanceData.iNPC_ID] = (Mob*)NPCs[resp.NPCAppearanceData.iNPC_ID]; } else - NPCs[resp.NPCAppearanceData.iNPC_ID] = new BaseNPC(plr->x, plr->y, plr->z, req->iNPCType, resp.NPCAppearanceData.iNPC_ID); + NPCs[resp.NPCAppearanceData.iNPC_ID] = new BaseNPC(plr->x, plr->y, plr->z, plr->instanceID, req->iNPCType, resp.NPCAppearanceData.iNPC_ID); updateNPCPosition(resp.NPCAppearanceData.iNPC_ID, plr->x, plr->y, plr->z); } @@ -585,7 +585,7 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) { // force player & NPC reload PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock); plrv.currentChunks.clear(); - plrv.chunkPos = std::make_pair(0, 0); + plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC)); } diff --git a/src/Player.hpp b/src/Player.hpp index 26804df..51b21c8 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -37,7 +37,7 @@ struct Player { int32_t iConditionBitFlag; int8_t iSpecialState; - int x, y, z, angle; + int x, y, z, angle, instanceID; sItemBase Equip[AEQUIP_COUNT]; sItemBase Inven[AINVEN_COUNT]; sItemBase Bank[ABANK_COUNT]; diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 6fac1a1..6baf8bf 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -47,7 +47,7 @@ void PlayerManager::addPlayer(CNSocket* key, Player plr) { memcpy(p, &plr, sizeof(Player)); players[key] = PlayerView(); - players[key].chunkPos = std::make_pair(0, 0); + players[key].chunkPos = std::make_tuple(0, 0, p->instanceID); players[key].currentChunks = std::vector(); players[key].plr = p; players[key].lastHeartbeat = 0; @@ -191,7 +191,7 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) { void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y) { PlayerView& view = players[sock]; - std::pair newPos = ChunkManager::grabChunk(X, Y); + std::tuple newPos = ChunkManager::grabChunk(X, Y, view.plr->instanceID); // nothing to be done if (newPos == view.chunkPos) @@ -206,7 +206,7 @@ void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y) { // now, add all the new npcs & players! addPlayerToChunks(ChunkManager::getDeltaChunks(allChunks, view.currentChunks), sock); - ChunkManager::addPlayer(X, Y, sock); // takes care of adding the player to the chunk if it exists or not + ChunkManager::addPlayer(X, Y, view.plr->instanceID, sock); // takes care of adding the player to the chunk if it exists or not view.chunkPos = newPos; view.currentChunks = allChunks; } @@ -309,6 +309,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { response.PCLoadData2CL.iFirstUseFlag2 = UINT64_MAX; plr.SerialKey = enter->iEnterSerialKey; + plr.instanceID = INSTANCE_OVERWORLD; // TODO: load this from the database (as long as it's not a unique instance) motd.iType = 1; U8toU16(settings::MOTDSTRING, (char16_t*)motd.szSystemMsg); @@ -647,7 +648,7 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) { // force player & NPC reload PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock); plrv.currentChunks.clear(); - plrv.chunkPos = std::make_pair(0, 0); + plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID); sock->sendPacket((void*)&response, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC)); } diff --git a/src/PlayerManager.hpp b/src/PlayerManager.hpp index 44a5b24..f4fafb4 100644 --- a/src/PlayerManager.hpp +++ b/src/PlayerManager.hpp @@ -13,7 +13,7 @@ struct WarpLocation; struct PlayerView { - std::pair chunkPos; + std::tuple chunkPos; std::vector currentChunks; Player *plr; time_t lastHeartbeat; diff --git a/src/TableData.cpp b/src/TableData.cpp index b15b978..94c6bbc 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -25,7 +25,7 @@ void TableData::init() { for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { auto npc = _npc.value(); - BaseNPC *tmp = new BaseNPC(npc["x"], npc["y"], npc["z"], npc["id"], nextId); + BaseNPC *tmp = new BaseNPC(npc["x"], npc["y"], npc["z"], INSTANCE_OVERWORLD, npc["id"], nextId); NPCManager::NPCs[nextId] = tmp; NPCManager::updateNPCPosition(nextId, npc["x"], npc["y"], npc["z"]); @@ -179,7 +179,7 @@ void TableData::init() { for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { auto npc = _npc.value(); auto td = NPCManager::NPCData[(int)npc["iNPCType"]]; - Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iNPCType"], npc["iHP"], npc["iAngle"], td, nextId); + Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], INSTANCE_OVERWORLD, npc["iNPCType"], npc["iHP"], npc["iAngle"], td, nextId); NPCManager::NPCs[nextId] = tmp; MobManager::Mobs[nextId] = (Mob*)NPCManager::NPCs[nextId]; diff --git a/src/TransportManager.cpp b/src/TransportManager.cpp index 91c70f8..ab3fc9e 100644 --- a/src/TransportManager.cpp +++ b/src/TransportManager.cpp @@ -149,7 +149,7 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) */ PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock); plrv.currentChunks.clear(); - plrv.chunkPos = std::make_pair(0, 0); + plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID); break; case 2: // Monkey Skyway if (SkywayPaths.find(route.mssRouteNum) != SkywayPaths.end()) { // check if route exists @@ -268,7 +268,7 @@ void TransportManager::stepNPCPathing() { NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z); // get chunks in view - auto chunk = ChunkManager::grabChunk(npc->appearanceData.iX, npc->appearanceData.iY); + auto chunk = ChunkManager::grabChunk(npc->appearanceData.iX, npc->appearanceData.iY, npc->instanceID); auto chunks = ChunkManager::grabChunks(chunk); switch (npc->npcClass) {