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
if (args.size() < 2) {
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;
}

View File

@ -3,12 +3,12 @@
#include "NPCManager.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::addNPC(int posX, int posY, int instanceID, int32_t id) {
std::tuple<int, int, int> pos = grabChunk(posX, posY, instanceID);
void ChunkManager::addNPC(int posX, int posY, uint64_t instanceID, int32_t id) {
std::tuple<int, int, uint64_t> 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, int instanceID, int32_t id) {
chunk->NPCs.insert(id);
}
void ChunkManager::addPlayer(int posX, int posY, int instanceID, CNSocket* sock) {
std::tuple<int, int, int> pos = grabChunk(posX, posY, instanceID);
void ChunkManager::addPlayer(int posX, int posY, uint64_t instanceID, CNSocket* sock) {
std::tuple<int, int, uint64_t> 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, int instanceID, CNSocket* 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))
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;
}
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))
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;
}
void ChunkManager::destroyChunk(std::tuple<int, int, int> chunkPos) {
void ChunkManager::destroyChunk(std::tuple<int, int, uint64_t> chunkPos) {
if (!checkChunk(chunkPos))
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;
}
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();
}
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);
}
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;
chnks.reserve(9);
int x, y, inst;
int x, y;
uint64_t 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::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 (checkChunk(pos))
@ -170,7 +171,7 @@ std::vector<Chunk*> ChunkManager::getDeltaChunks(std::vector<Chunk*> from, std::
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 nearbyChunks = ChunkManager::grabChunks(chunk);

View File

@ -24,16 +24,16 @@ namespace ChunkManager {
void init();
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 addPlayer(int posX, int posY, int instanceID, CNSocket* sock);
bool removePlayer(std::tuple<int, int, int> chunkPos, CNSocket* sock);
bool removeNPC(std::tuple<int, int, int> chunkPos, int32_t id);
bool checkChunk(std::tuple<int, int, int> chunk);
void destroyChunk(std::tuple<int, int, int> chunkPos);
std::tuple<int, int, int> grabChunk(int posX, int posY, int instanceID);
std::vector<Chunk*> grabChunks(std::tuple<int, int, int> chunkPos);
void addNPC(int posX, int posY, uint64_t instanceID, int32_t id);
void addPlayer(int posX, int posY, uint64_t instanceID, CNSocket* sock);
bool removePlayer(std::tuple<int, int, uint64_t> chunkPos, CNSocket* sock);
bool removeNPC(std::tuple<int, int, uint64_t> chunkPos, int32_t id);
bool checkChunk(std::tuple<int, int, uint64_t> chunk);
void destroyChunk(std::tuple<int, int, uint64_t> chunkPos);
std::tuple<int, int, uint64_t> grabChunk(int posX, int posY, uint64_t instanceID);
std::vector<Chunk*> grabChunks(std::tuple<int, int, uint64_t> chunkPos);
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
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) {
state = MobState::ROAMING;
@ -71,7 +71,7 @@ struct Mob : public BaseNPC {
}
// 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) {
summoned = true; // will be despawned and deallocated when killed
appearanceData.iHP = maxHealth = d["m_iHP"];

View File

@ -7,12 +7,12 @@ class BaseNPC {
public:
sNPCAppearanceData appearanceData;
NPCClass npcClass;
int instanceID;
std::tuple<int, int, int> chunkPos;
uint64_t instanceID;
std::tuple<int, int, uint64_t> chunkPos;
std::vector<Chunk*> currentChunks;
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.iY = y;
appearanceData.iZ = z;
@ -27,7 +27,7 @@ public:
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;
}
};

View File

@ -146,7 +146,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::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)
if (newPos == npc->chunkPos) {
@ -177,7 +177,7 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) {
npc->currentChunks = allChunks;
}
void NPCManager::updateNPCInstance(int32_t npcID, int instanceID) {
void NPCManager::updateNPCInstance(int32_t npcID, uint64_t instanceID) {
BaseNPC* npc = NPCs[npcID];
npc->instanceID = instanceID;
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;
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
{
@ -603,7 +608,7 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
resp.eIL = 4; // do not take away any items
PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock);
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));
}
}

View File

@ -29,7 +29,7 @@ namespace NPCManager {
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);
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);

View File

@ -37,7 +37,8 @@ struct Player {
int32_t iConditionBitFlag;
int8_t iSpecialState;
int x, y, z, angle, instanceID;
int x, y, z, angle;
uint64_t instanceID;
sItemBase Equip[AEQUIP_COUNT];
sItemBase Inven[AINVEN_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);
}
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];
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
if (newPos == view.chunkPos)
@ -222,13 +222,13 @@ void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y,int mapNum) {
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];
Player* plr = plrv.plr;
plr->instanceID = I;
if (I != INSTANCE_OVERWORLD) {
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));
sendPlayerTo(sock, X, Y, Z);
} else {

View File

@ -13,7 +13,7 @@
struct WarpLocation;
struct PlayerView {
std::tuple<int, int, int> chunkPos;
std::tuple<int, int, uint64_t> chunkPos;
std::vector<Chunk*> currentChunks;
Player *plr;
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, 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 sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size);

View File

@ -29,7 +29,7 @@ void TableData::init() {
inFile >> npcData;
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
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);
NPCManager::NPCs[nextId] = tmp;
@ -181,7 +181,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"]];
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);
NPCManager::NPCs[nextId] = tmp;
@ -409,7 +409,7 @@ void TableData::loadGruntwork(int32_t *nextId) {
auto npcMap = gruntwork["instances"];
for (auto _map = npcMap.begin(); _map != npcMap.end(); _map++) {
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())
continue; // NPC not found
BaseNPC* npc = NPCManager::NPCs[npcID];
@ -423,7 +423,7 @@ void TableData::loadGruntwork(int32_t *nextId) {
for (auto _mob = mobs.begin(); _mob != mobs.end(); _mob++) {
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"],
NPCManager::NPCData[(int)mob["iNPCType"]], (*nextId)++);