Add support for unique instances

This commit is contained in:
Gent 2020-10-12 12:55:41 -04:00
parent c1fd51b721
commit d4aed0abf4
11 changed files with 55 additions and 47 deletions

View File

@ -329,6 +329,7 @@ void instanceCommand(std::string full, std::vector<std::string>& args, CNSocket*
// no additional arguments: report current instance ID // no additional arguments: report current instance ID
if (args.size() < 2) { if (args.size() < 2) {
ChatManager::sendServerMessage(sock, "[INST] Current instance ID: " + std::to_string(plr->instanceID)); ChatManager::sendServerMessage(sock, "[INST] Current instance ID: " + std::to_string(plr->instanceID));
ChatManager::sendServerMessage(sock, "[INST] (Map " + std::to_string(plr->instanceID & 0xffffffff) + ", instance " + std::to_string(plr->instanceID >> 32) + ")");
return; return;
} }

View File

@ -3,12 +3,12 @@
#include "NPCManager.hpp" #include "NPCManager.hpp"
#include "settings.hpp" #include "settings.hpp"
std::map<std::tuple<int, int, int>, Chunk*> ChunkManager::chunks; std::map<std::tuple<int, int, uint64_t>, Chunk*> ChunkManager::chunks;
void ChunkManager::init() {} // stubbed void ChunkManager::init() {} // stubbed
void ChunkManager::addNPC(int posX, int posY, int instanceID, int32_t id) { void ChunkManager::addNPC(int posX, int posY, uint64_t instanceID, int32_t id) {
std::tuple<int, int, int> pos = grabChunk(posX, posY, instanceID); std::tuple<int, int, uint64_t> pos = grabChunk(posX, posY, instanceID);
// make chunk if it doesn't exist! // make chunk if it doesn't exist!
if (chunks.find(pos) == chunks.end()) { if (chunks.find(pos) == chunks.end()) {
@ -22,8 +22,8 @@ void ChunkManager::addNPC(int posX, int posY, int instanceID, int32_t id) {
chunk->NPCs.insert(id); chunk->NPCs.insert(id);
} }
void ChunkManager::addPlayer(int posX, int posY, int instanceID, CNSocket* sock) { void ChunkManager::addPlayer(int posX, int posY, uint64_t instanceID, CNSocket* sock) {
std::tuple<int, int, int> pos = grabChunk(posX, posY, instanceID); std::tuple<int, int, uint64_t> pos = grabChunk(posX, posY, instanceID);
// make chunk if it doesn't exist! // make chunk if it doesn't exist!
if (chunks.find(pos) == chunks.end()) { if (chunks.find(pos) == chunks.end()) {
@ -37,7 +37,7 @@ void ChunkManager::addPlayer(int posX, int posY, int instanceID, CNSocket* sock)
chunk->players.insert(sock); chunk->players.insert(sock);
} }
bool ChunkManager::removePlayer(std::tuple<int, int, int> chunkPos, CNSocket* sock) { bool ChunkManager::removePlayer(std::tuple<int, int, uint64_t> chunkPos, CNSocket* sock) {
if (!checkChunk(chunkPos)) if (!checkChunk(chunkPos))
return false; // do nothing if chunk doesn't even exist return false; // do nothing if chunk doesn't even exist
@ -57,7 +57,7 @@ bool ChunkManager::removePlayer(std::tuple<int, int, int> chunkPos, CNSocket* so
return false; return false;
} }
bool ChunkManager::removeNPC(std::tuple<int, int, int> chunkPos, int32_t id) { bool ChunkManager::removeNPC(std::tuple<int, int, uint64_t> chunkPos, int32_t id) {
if (!checkChunk(chunkPos)) if (!checkChunk(chunkPos))
return false; // do nothing if chunk doesn't even exist return false; // do nothing if chunk doesn't even exist
@ -77,7 +77,7 @@ bool ChunkManager::removeNPC(std::tuple<int, int, int> chunkPos, int32_t id) {
return false; return false;
} }
void ChunkManager::destroyChunk(std::tuple<int, int, int> chunkPos) { void ChunkManager::destroyChunk(std::tuple<int, int, uint64_t> chunkPos) {
if (!checkChunk(chunkPos)) if (!checkChunk(chunkPos))
return; // chunk doesn't exist, we don't need to do anything return; // chunk doesn't exist, we don't need to do anything
@ -118,25 +118,26 @@ void ChunkManager::destroyChunk(std::tuple<int, int, int> chunkPos) {
delete chunk; delete chunk;
} }
bool ChunkManager::checkChunk(std::tuple<int, int, int> chunk) { bool ChunkManager::checkChunk(std::tuple<int, int, uint64_t> chunk) {
return chunks.find(chunk) != chunks.end(); return chunks.find(chunk) != chunks.end();
} }
std::tuple<int, int, int> ChunkManager::grabChunk(int posX, int posY, int instanceID) { std::tuple<int, int, uint64_t> ChunkManager::grabChunk(int posX, int posY, uint64_t instanceID) {
return std::make_tuple(posX / (settings::VIEWDISTANCE / 3), posY / (settings::VIEWDISTANCE / 3), instanceID); return std::make_tuple(posX / (settings::VIEWDISTANCE / 3), posY / (settings::VIEWDISTANCE / 3), instanceID);
} }
std::vector<Chunk*> ChunkManager::grabChunks(std::tuple<int, int, int> chunk) { std::vector<Chunk*> ChunkManager::grabChunks(std::tuple<int, int, uint64_t> chunk) {
std::vector<Chunk*> chnks; std::vector<Chunk*> chnks;
chnks.reserve(9); chnks.reserve(9);
int x, y, inst; int x, y;
uint64_t inst;
std::tie(x, y, inst) = chunk; std::tie(x, y, inst) = chunk;
// grabs surrounding chunks if they exist // grabs surrounding chunks if they exist
for (int i = -1; i < 2; i++) { for (int i = -1; i < 2; i++) {
for (int z = -1; z < 2; z++) { for (int z = -1; z < 2; z++) {
std::tuple<int, int, int> pos = std::make_tuple(x+i, y+z, inst); std::tuple<int, int, uint64_t> pos = std::make_tuple(x+i, y+z, inst);
// if chunk exists, add it to the vector // if chunk exists, add it to the vector
if (checkChunk(pos)) if (checkChunk(pos))
@ -170,7 +171,7 @@ std::vector<Chunk*> ChunkManager::getDeltaChunks(std::vector<Chunk*> from, std::
return delta; return delta;
} }
bool ChunkManager::inPopulatedChunks(int posX, int posY, int instanceID) { bool ChunkManager::inPopulatedChunks(int posX, int posY, uint64_t instanceID) {
auto chunk = ChunkManager::grabChunk(posX, posY, instanceID); auto chunk = ChunkManager::grabChunk(posX, posY, instanceID);
auto nearbyChunks = ChunkManager::grabChunks(chunk); auto nearbyChunks = ChunkManager::grabChunks(chunk);

View File

@ -24,16 +24,16 @@ namespace ChunkManager {
void init(); void init();
void cleanup(); void cleanup();
extern std::map<std::tuple<int, int, int>, Chunk*> chunks; extern std::map<std::tuple<int, int, uint64_t>, Chunk*> chunks;
void addNPC(int posX, int posY, int instanceID, int32_t id); void addNPC(int posX, int posY, uint64_t instanceID, int32_t id);
void addPlayer(int posX, int posY, int instanceID, CNSocket* sock); void addPlayer(int posX, int posY, uint64_t instanceID, CNSocket* sock);
bool removePlayer(std::tuple<int, int, int> chunkPos, CNSocket* sock); bool removePlayer(std::tuple<int, int, uint64_t> chunkPos, CNSocket* sock);
bool removeNPC(std::tuple<int, int, int> chunkPos, int32_t id); bool removeNPC(std::tuple<int, int, uint64_t> chunkPos, int32_t id);
bool checkChunk(std::tuple<int, int, int> chunk); bool checkChunk(std::tuple<int, int, uint64_t> chunk);
void destroyChunk(std::tuple<int, int, int> chunkPos); void destroyChunk(std::tuple<int, int, uint64_t> chunkPos);
std::tuple<int, int, int> grabChunk(int posX, int posY, int instanceID); std::tuple<int, int, uint64_t> grabChunk(int posX, int posY, uint64_t instanceID);
std::vector<Chunk*> grabChunks(std::tuple<int, int, int> chunkPos); std::vector<Chunk*> grabChunks(std::tuple<int, int, uint64_t> chunkPos);
std::vector<Chunk*> getDeltaChunks(std::vector<Chunk*> from, std::vector<Chunk*> to); std::vector<Chunk*> getDeltaChunks(std::vector<Chunk*> from, std::vector<Chunk*> to);
bool inPopulatedChunks(int posX, int posY, int instanceID); bool inPopulatedChunks(int posX, int posY, uint64_t instanceID);
} }

View File

@ -45,7 +45,7 @@ struct Mob : public BaseNPC {
// temporary; until we're sure what's what // temporary; until we're sure what's what
nlohmann::json data; nlohmann::json data;
Mob(int x, int y, int z, int angle, int iID, int type, int hp, nlohmann::json d, int32_t id) Mob(int x, int y, int z, int angle, uint64_t iID, int type, int hp, nlohmann::json d, int32_t id)
: BaseNPC(x, y, z, angle, iID, type, id), maxHealth(hp) { : BaseNPC(x, y, z, angle, iID, type, id), maxHealth(hp) {
state = MobState::ROAMING; state = MobState::ROAMING;
@ -71,7 +71,7 @@ struct Mob : public BaseNPC {
} }
// constructor for /summon // constructor for /summon
Mob(int x, int y, int z, int iID, int type, nlohmann::json d, int32_t id) Mob(int x, int y, int z, uint64_t iID, int type, nlohmann::json d, int32_t id)
: Mob(x, y, z, 0, iID, type, 0, d, id) { : Mob(x, y, z, 0, iID, type, 0, d, id) {
summoned = true; // will be despawned and deallocated when killed summoned = true; // will be despawned and deallocated when killed
appearanceData.iHP = maxHealth = d["m_iHP"]; appearanceData.iHP = maxHealth = d["m_iHP"];

View File

@ -7,12 +7,12 @@ class BaseNPC {
public: public:
sNPCAppearanceData appearanceData; sNPCAppearanceData appearanceData;
NPCClass npcClass; NPCClass npcClass;
int instanceID; uint64_t instanceID;
std::tuple<int, int, int> chunkPos; std::tuple<int, int, uint64_t> chunkPos;
std::vector<Chunk*> currentChunks; std::vector<Chunk*> currentChunks;
BaseNPC() {}; BaseNPC() {};
BaseNPC(int x, int y, int z, int angle, int iID, int type, int id) { BaseNPC(int x, int y, int z, int angle, uint64_t iID, int type, int id) {
appearanceData.iX = x; appearanceData.iX = x;
appearanceData.iY = y; appearanceData.iY = y;
appearanceData.iZ = z; appearanceData.iZ = z;
@ -27,7 +27,7 @@ public:
chunkPos = std::make_tuple(0, 0, instanceID); chunkPos = std::make_tuple(0, 0, instanceID);
}; };
BaseNPC(int x, int y, int z, int angle, int iID, int type, int id, NPCClass classType) : BaseNPC(x, y, z, angle, iID, type, id) { BaseNPC(int x, int y, int z, int angle, uint64_t iID, int type, int id, NPCClass classType) : BaseNPC(x, y, z, angle, iID, type, id) {
npcClass = classType; npcClass = classType;
} }
}; };

View File

@ -146,7 +146,7 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) {
npc->appearanceData.iX = X; npc->appearanceData.iX = X;
npc->appearanceData.iY = Y; npc->appearanceData.iY = Y;
npc->appearanceData.iZ = Z; npc->appearanceData.iZ = Z;
std::tuple<int, int, int> newPos = ChunkManager::grabChunk(X, Y, npc->instanceID); std::tuple<int, int, uint64_t> newPos = ChunkManager::grabChunk(X, Y, npc->instanceID);
// nothing to be done (but we should also update currentChunks to add/remove stale chunks) // nothing to be done (but we should also update currentChunks to add/remove stale chunks)
if (newPos == npc->chunkPos) { if (newPos == npc->chunkPos) {
@ -177,7 +177,7 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) {
npc->currentChunks = allChunks; npc->currentChunks = allChunks;
} }
void NPCManager::updateNPCInstance(int32_t npcID, int instanceID) { void NPCManager::updateNPCInstance(int32_t npcID, uint64_t instanceID) {
BaseNPC* npc = NPCs[npcID]; BaseNPC* npc = NPCs[npcID];
npc->instanceID = instanceID; npc->instanceID = instanceID;
updateNPCPosition(npcID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ); updateNPCPosition(npcID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ);
@ -591,7 +591,12 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
// std::cerr << "Warped to Map Num:" << Warps[warpId].instanceID << " NPC ID " << Warps[warpId].npcID << std::endl; // std::cerr << "Warped to Map Num:" << Warps[warpId].instanceID << " NPC ID " << Warps[warpId].npcID << std::endl;
if (Warps[warpId].isInstance) if (Warps[warpId].isInstance)
{ {
PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, Warps[warpId].instanceID); uint64_t instanceID = Warps[warpId].instanceID;
if (false) { // TODO check if instance is unique and make a copy
instanceID += ((uint64_t)plrv.plr->iIDGroup << 32); // upper 32 bits are leader ID
}
PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID);
} }
else else
{ {
@ -603,7 +608,7 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
resp.eIL = 4; // do not take away any items resp.eIL = 4; // do not take away any items
PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock); PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock);
plrv.currentChunks.clear(); plrv.currentChunks.clear();
plrv.plr->instanceID = 0; plrv.plr->instanceID = INSTANCE_OVERWORLD;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC));
} }
} }

View File

@ -29,7 +29,7 @@ namespace NPCManager {
void destroyNPC(int32_t); void destroyNPC(int32_t);
void updateNPCPosition(int32_t, int X, int Y, int Z, int angle); void updateNPCPosition(int32_t, int X, int Y, int Z, int angle);
void updateNPCPosition(int32_t, int X, int Y, int Z); void updateNPCPosition(int32_t, int X, int Y, int Z);
void updateNPCInstance(int32_t, int instanceID); void updateNPCInstance(int32_t, uint64_t instanceID);
void sendToViewable(BaseNPC* npc, void* buf, uint32_t type, size_t size); void sendToViewable(BaseNPC* npc, void* buf, uint32_t type, size_t size);

View File

@ -37,7 +37,8 @@ struct Player {
int32_t iConditionBitFlag; int32_t iConditionBitFlag;
int8_t iSpecialState; int8_t iSpecialState;
int x, y, z, angle, instanceID; int x, y, z, angle;
uint64_t instanceID;
sItemBase Equip[AEQUIP_COUNT]; sItemBase Equip[AEQUIP_COUNT];
sItemBase Inven[AINVEN_COUNT]; sItemBase Inven[AINVEN_COUNT];
sItemBase Bank[ABANK_COUNT]; sItemBase Bank[ABANK_COUNT];

View File

@ -194,9 +194,9 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
updatePlayerChunk(sock, X, Y, view.plr->instanceID); updatePlayerChunk(sock, X, Y, view.plr->instanceID);
} }
void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y,int mapNum) { void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y, uint64_t instanceID) {
PlayerView& view = players[sock]; PlayerView& view = players[sock];
std::tuple<int, int, int> newPos = ChunkManager::grabChunk(X, Y, view.plr->instanceID); std::tuple<int, int, uint64_t> newPos = ChunkManager::grabChunk(X, Y, view.plr->instanceID);
// nothing to be done // nothing to be done
if (newPos == view.chunkPos) if (newPos == view.chunkPos)
@ -222,13 +222,13 @@ void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y,int mapNum) {
view.currentChunks = allChunks; view.currentChunks = allChunks;
} }
void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, int I) { void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I) {
PlayerView& plrv = PlayerManager::players[sock]; PlayerView& plrv = PlayerManager::players[sock];
Player* plr = plrv.plr; Player* plr = plrv.plr;
plr->instanceID = I; plr->instanceID = I;
if (I != INSTANCE_OVERWORLD) { if (I != INSTANCE_OVERWORLD) {
INITSTRUCT(sP_FE2CL_INSTANCE_MAP_INFO, pkt); INITSTRUCT(sP_FE2CL_INSTANCE_MAP_INFO, pkt);
pkt.iInstanceMapNum = I; pkt.iInstanceMapNum = (int32_t)(I & 0xffffffff); // lower 32 bits are mapnum
sock->sendPacket((void*)&pkt, P_FE2CL_INSTANCE_MAP_INFO, sizeof(sP_FE2CL_INSTANCE_MAP_INFO)); sock->sendPacket((void*)&pkt, P_FE2CL_INSTANCE_MAP_INFO, sizeof(sP_FE2CL_INSTANCE_MAP_INFO));
sendPlayerTo(sock, X, Y, Z); sendPlayerTo(sock, X, Y, Z);
} else { } else {

View File

@ -13,7 +13,7 @@
struct WarpLocation; struct WarpLocation;
struct PlayerView { struct PlayerView {
std::tuple<int, int, int> chunkPos; std::tuple<int, int, uint64_t> chunkPos;
std::vector<Chunk*> currentChunks; std::vector<Chunk*> currentChunks;
Player *plr; Player *plr;
time_t lastHeartbeat; time_t lastHeartbeat;
@ -32,9 +32,9 @@ namespace PlayerManager {
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z); void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z);
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle); void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle);
void updatePlayerChunk(CNSocket* sock, int X, int Y, int instanceID); void updatePlayerChunk(CNSocket* sock, int X, int Y, uint64_t instanceID);
void sendPlayerTo(CNSocket* sock, int X, int Y, int Z, int I); void sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I);
void sendPlayerTo(CNSocket* sock, int X, int Y, int Z); void sendPlayerTo(CNSocket* sock, int X, int Y, int Z);
void sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size); void sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size);

View File

@ -29,7 +29,7 @@ void TableData::init() {
inFile >> npcData; inFile >> npcData;
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
auto npc = _npc.value(); auto npc = _npc.value();
int instanceID = npc.find("mapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["mapNum"]; uint64_t 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); BaseNPC *tmp = new BaseNPC(npc["x"], npc["y"], npc["z"], npc["angle"], instanceID, npc["id"], nextId);
NPCManager::NPCs[nextId] = tmp; NPCManager::NPCs[nextId] = tmp;
@ -181,7 +181,7 @@ void TableData::init() {
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
auto npc = _npc.value(); auto npc = _npc.value();
auto td = NPCManager::NPCData[(int)npc["iNPCType"]]; auto td = NPCManager::NPCData[(int)npc["iNPCType"]];
int instanceID = npc.find("iMapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["iMapNum"]; uint64_t instanceID = npc.find("iMapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["iMapNum"];
Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iAngle"], instanceID, npc["iNPCType"], npc["iHP"], td, nextId); Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iAngle"], instanceID, npc["iNPCType"], npc["iHP"], td, nextId);
NPCManager::NPCs[nextId] = tmp; NPCManager::NPCs[nextId] = tmp;
@ -409,7 +409,7 @@ void TableData::loadGruntwork(int32_t *nextId) {
auto npcMap = gruntwork["instances"]; auto npcMap = gruntwork["instances"];
for (auto _map = npcMap.begin(); _map != npcMap.end(); _map++) { for (auto _map = npcMap.begin(); _map != npcMap.end(); _map++) {
int32_t npcID = _map.value()["iNPCID"]; int32_t npcID = _map.value()["iNPCID"];
int instanceID = _map.value()["iMapNum"]; uint64_t instanceID = _map.value()["iMapNum"];
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end()) if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
continue; // NPC not found continue; // NPC not found
BaseNPC* npc = NPCManager::NPCs[npcID]; BaseNPC* npc = NPCManager::NPCs[npcID];
@ -423,7 +423,7 @@ void TableData::loadGruntwork(int32_t *nextId) {
for (auto _mob = mobs.begin(); _mob != mobs.end(); _mob++) { for (auto _mob = mobs.begin(); _mob != mobs.end(); _mob++) {
auto mob = _mob.value(); auto mob = _mob.value();
int instanceID = mob.find("iMapNum") == mob.end() ? INSTANCE_OVERWORLD : (int)mob["iMapNum"]; uint64_t instanceID = mob.find("iMapNum") == mob.end() ? INSTANCE_OVERWORLD : (int)mob["iMapNum"];
Mob *npc = new Mob(mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iNPCType"], Mob *npc = new Mob(mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iNPCType"],
NPCManager::NPCData[(int)mob["iNPCType"]], (*nextId)++); NPCManager::NPCData[(int)mob["iNPCType"]], (*nextId)++);