diff --git a/src/ChunkManager.cpp b/src/ChunkManager.cpp index c9c85b7..d49cb6f 100644 --- a/src/ChunkManager.cpp +++ b/src/ChunkManager.cpp @@ -171,6 +171,21 @@ std::vector ChunkManager::getDeltaChunks(std::vector from, std:: return delta; } +/* + * inefficient algorithm to get all chunks from a specific instance + */ +std::vector> ChunkManager::getChunksInMap(uint64_t mapNum) { + std::vector> chnks; + + for (auto it = ChunkManager::chunks.begin(); it != ChunkManager::chunks.end(); it++) { + if (std::get<2>(it->first) == mapNum) { + chnks.push_back(it->first); + } + } + + return chnks; +} + bool ChunkManager::inPopulatedChunks(int posX, int posY, uint64_t instanceID) { auto chunk = ChunkManager::grabChunk(posX, posY, instanceID); auto nearbyChunks = ChunkManager::grabChunks(chunk); @@ -182,3 +197,33 @@ bool ChunkManager::inPopulatedChunks(int posX, int posY, uint64_t instanceID) { return false; } + +void ChunkManager::createInstance(uint64_t instanceID) { + + std::vector> templateChunks = ChunkManager::getChunksInMap(instanceID & 0xffffffff); // base instance chunks + if (ChunkManager::getChunksInMap(instanceID).size() == 0) { // only instantiate if the instance doesn't exist already + std::cout << "Creating instance " << instanceID << std::endl; + for (std::tuple &coords : templateChunks) { + for (int npcID : chunks[coords]->NPCs) { + // make a copy of each NPC in the template chunks and put them in the new instance + int newID = NPCManager::nextId++; + BaseNPC* newNPC = new BaseNPC(); + memcpy(newNPC, NPCManager::NPCs[npcID], sizeof(BaseNPC)); + newNPC->appearanceData.iNPC_ID = newID; + NPCManager::NPCs[newID] = newNPC; + NPCManager::updateNPCInstance(newID, instanceID); + } + } + } + else { + std::cout << "Instance " << instanceID << " already exists" << std::endl; + } +} + +void ChunkManager::destroyInstance(uint64_t instanceID) { + std::cout << "Deleting instance " << instanceID << std::endl; + std::vector> instanceChunks = ChunkManager::getChunksInMap(instanceID); + for (std::tuple& coords : instanceChunks) { + destroyChunk(coords); + } +} diff --git a/src/ChunkManager.hpp b/src/ChunkManager.hpp index 9ba935f..73d90bc 100644 --- a/src/ChunkManager.hpp +++ b/src/ChunkManager.hpp @@ -16,8 +16,8 @@ public: 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) + //INSTANCE_IZ, // all infected zones share an instance + //INSTANCE_UNIQUE // fusion lairs are generated as requested (+ uid) }; namespace ChunkManager { @@ -35,5 +35,9 @@ namespace ChunkManager { std::tuple grabChunk(int posX, int posY, uint64_t instanceID); std::vector grabChunks(std::tuple chunkPos); std::vector getDeltaChunks(std::vector from, std::vector to); + std::vector> getChunksInMap(uint64_t mapNum); bool inPopulatedChunks(int posX, int posY, uint64_t instanceID); + + void createInstance(uint64_t); + void destroyInstance(uint64_t); } diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index cbd1eaa..9c95035 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -3,6 +3,7 @@ #include "settings.hpp" #include "MobManager.hpp" #include "MissionManager.hpp" +#include "ChunkManager.hpp" #include #include @@ -608,8 +609,9 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) { if (Warps[warpId].isInstance) { uint64_t instanceID = Warps[warpId].instanceID; - if (false) { // TODO check if instance is unique and make a copy + if (Warps[warpId].limitTaskID != 0) { // if warp requires you to be on a mission, it's gotta be a unique instance instanceID += ((uint64_t)plrv.plr->iIDGroup << 32); // upper 32 bits are leader ID + ChunkManager::createInstance(instanceID); } PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID); diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index fe584ae..a99dfb2 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -361,7 +361,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) + plr.instanceID = INSTANCE_OVERWORLD; // the player should never be in an instance on enter sock->setEKey(CNSocketEncryption::createNewKey(response.uiSvrTime, response.iID + 1, response.PCLoadData2CL.iFusionMatter + 1)); sock->setFEKey(plr.FEKey); @@ -929,7 +929,7 @@ WarpLocation PlayerManager::getRespawnPoint(Player *plr) { for (auto targ : NPCManager::RespawnPoints) { curDist = sqrt(pow(plr->x - targ.x, 2) + pow(plr->y - targ.y, 2)); - if (curDist < bestDist) { + if (curDist < bestDist && targ.instanceID == (plr->instanceID & 0xffffffff)) { // only mapNum needs to match best = targ; bestDist = curDist; } diff --git a/src/TableData.cpp b/src/TableData.cpp index 09025db..2844a58 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -29,7 +29,7 @@ void TableData::init() { inFile >> npcData; for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { auto npc = _npc.value(); - uint64_t instanceID = npc.find("mapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["mapNum"]; + int instanceID = npc.find("mapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["mapNum"]; BaseNPC *tmp = new BaseNPC(npc["x"], npc["y"], npc["z"], npc["angle"], instanceID, npc["id"], nextId); NPCManager::NPCs[nextId] = tmp; @@ -37,7 +37,7 @@ void TableData::init() { nextId++; if (npc["id"] == 641 || npc["id"] == 642) - NPCManager::RespawnPoints.push_back({ npc["x"], npc["y"], ((int)npc["z"]) + RESURRECT_HEIGHT }); + NPCManager::RespawnPoints.push_back({ npc["x"], npc["y"], ((int)npc["z"]) + RESURRECT_HEIGHT, instanceID }); } } catch (const std::exception& err) {