Summoned mobs are now actually treated as mobs.

Unfortunetly, this necessitated keeping around yet more JSON objects for
the duration of the server's runtime.
It also involved unifying the way NPC IDs are handled, such that they
may be allocated and deallocated out of order.

If any NPCID-related bugs occour, this commit should be regarded as
the prime suspect.
This commit is contained in:
dongresource 2020-09-25 00:36:25 +02:00
parent cfb3d25bc5
commit 72d625fd8d
8 changed files with 65 additions and 33 deletions

View File

@ -215,6 +215,13 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
s->sendPacket(&pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
}
}
// if it was summoned, remove it permanently
if (mob->summoned) {
std::cout << "[INFO] Deallocating killed summoned mob" << std::endl;
NPCManager::removeNPC(mob->appearanceData.iNPC_ID);
return;
}
}
if (mob->killedTime != 0 && currTime - mob->killedTime < mob->regenTime * 100)

View File

@ -20,7 +20,7 @@ enum class MobState {
struct Mob : public BaseNPC {
// general
MobState state;
const int maxHealth;
int maxHealth;
int spawnX;
int spawnY;
int spawnZ;
@ -28,6 +28,7 @@ struct Mob : public BaseNPC {
// dead
time_t killedTime = 0;
time_t regenTime;
bool summoned = false;
bool despawned = false; // for the sake of death animations
// roaming
@ -41,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)
: BaseNPC(x, y, z, type), maxHealth(hp) {
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) {
state = MobState::ROAMING;
data = d;
@ -58,7 +59,17 @@ struct Mob : public BaseNPC {
// NOTE: there appear to be discrepancies in the dump
appearanceData.iHP = maxHealth;
npcClass = NPC_MOB;
}
// 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) {
summoned = true; // will be despawned and deallocated when killed
appearanceData.iHP = maxHealth = d["m_iHP"];
}
~Mob() {}
auto operator[](std::string s) {

View File

@ -8,7 +8,7 @@ public:
NPCClass npcClass;
BaseNPC() {};
BaseNPC(int x, int y, int z, int type) {
BaseNPC(int x, int y, int z, int type, int id) {
appearanceData.iX = x;
appearanceData.iY = y;
appearanceData.iZ = z;
@ -17,11 +17,9 @@ public:
appearanceData.iAngle = 0;
appearanceData.iConditionBitFlag = 0;
appearanceData.iBarkerType = 0;
// hopefully no collisions happen :eyes:
appearanceData.iNPC_ID = (int32_t)rand();
appearanceData.iNPC_ID = id;
};
BaseNPC(int x, int y, int z, int type, NPCClass classType) : BaseNPC(x, y, z, type) {
BaseNPC(int x, int y, int z, int type, int id, NPCClass classType) : BaseNPC(x, y, z, type, id) {
npcClass = classType;
}
};

View File

@ -8,13 +8,21 @@
#include <list>
#include <fstream>
#include <vector>
#include <assert.h>
#include "contrib/JSON.hpp"
std::map<int32_t, BaseNPC*> NPCManager::NPCs;
std::map<int32_t, WarpLocation> NPCManager::Warps;
std::vector<WarpLocation> NPCManager::RespawnPoints;
nlohmann::json NPCManager::NPCData;
/*
* Initialized at the end of TableData::init().
* This allows us to summon and kill mobs in arbitrary order without
* NPC ID collisions.
*/
int32_t NPCManager::nextId;
void NPCManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_NPC, npcWarpHandler);
@ -481,15 +489,21 @@ void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) {
if (plr->accountLevel > 30 || req->iNPCType >= 3314)
return;
resp.NPCAppearanceData.iNPC_ID = NPCs.size()+1;
int team = NPCData[req->iNPCType]["m_iTeam"];
assert(nextId < INT32_MAX);
resp.NPCAppearanceData.iNPC_ID = nextId++;
resp.NPCAppearanceData.iNPCType = req->iNPCType;
resp.NPCAppearanceData.iHP = 1000; // TODO: placeholder
resp.NPCAppearanceData.iHP = 1000;
resp.NPCAppearanceData.iX = plr->x;
resp.NPCAppearanceData.iY = plr->y;
resp.NPCAppearanceData.iZ = plr->z;
NPCs[resp.NPCAppearanceData.iNPC_ID] = new BaseNPC(plr->x, plr->y, plr->z, req->iNPCType);
NPCs[resp.NPCAppearanceData.iNPC_ID]->appearanceData.iNPC_ID = resp.NPCAppearanceData.iNPC_ID;
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);
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);
ChunkManager::addNPC(plr->x, plr->y, resp.NPCAppearanceData.iNPC_ID);
}

View File

@ -4,6 +4,8 @@
#include "PlayerManager.hpp"
#include "NPC.hpp"
#include "contrib/JSON.hpp"
#include <map>
#include <vector>
@ -18,6 +20,8 @@ namespace NPCManager {
extern std::map<int32_t, BaseNPC*> NPCs;
extern std::map<int32_t, WarpLocation> Warps;
extern std::vector<WarpLocation> RespawnPoints;
extern nlohmann::json NPCData;
extern int32_t nextId;
void init();
void addNPC(std::vector<Chunk*> viewableChunks, int32_t);

View File

@ -12,7 +12,7 @@
#include <fstream>
void TableData::init() {
int i = 0;
int32_t nextId = 0;
// load NPCs from NPC.json
try {
@ -24,14 +24,11 @@ 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"]);
BaseNPC *tmp = new BaseNPC(npc["x"], npc["y"], npc["z"], npc["id"], nextId);
// Temporary fix, IDs will be pulled from json later
tmp->appearanceData.iNPC_ID = i;
NPCManager::NPCs[i] = tmp;
ChunkManager::addNPC(npc["x"], npc["y"], i);
i++;
NPCManager::NPCs[nextId] = tmp;
ChunkManager::addNPC(npc["x"], npc["y"], nextId);
nextId++;
if (npc["id"] == 641 || npc["id"] == 642)
NPCManager::RespawnPoints.push_back({ npc["x"], npc["y"], ((int)npc["z"]) + RESURRECT_HEIGHT });
@ -52,6 +49,9 @@ void TableData::init() {
// read file into json
infile >> xdtData;
// data we'll need for summoned mobs
NPCManager::NPCData = xdtData["m_pNpcTable"]["m_pNpcData"];
try {
// load warps
nlohmann::json warpData = xdtData["m_pInstanceTable"]["m_pWarpData"];
@ -74,7 +74,7 @@ void TableData::init() {
TransportLocation transLoc = { tLoc["m_iNPCID"], tLoc["m_iXpos"], tLoc["m_iYpos"], tLoc["m_iZpos"] };
TransportManager::Locations[tLoc["m_iLocationID"]] = transLoc;
}
std::cout << "[INFO] Loaded " << TransportManager::Locations.size() << " S.C.A.M.P.E.R. locations" << std::endl; // TODO: Skyway operates differently
std::cout << "[INFO] Loaded " << TransportManager::Locations.size() << " S.C.A.M.P.E.R. locations" << std::endl;
for (nlohmann::json::iterator _tRoute = transRouteData.begin(); _tRoute != transRouteData.end(); _tRoute++) {
auto tRoute = _tRoute.value();
@ -165,21 +165,16 @@ void TableData::init() {
// read file into json
inFile >> npcData;
nlohmann::json npcTableData = xdtData["m_pNpcTable"]["m_pNpcData"];
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
auto npc = _npc.value();
auto td = npcTableData[(int)npc["iNPCType"]];
Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iNPCType"], npc["iHP"], npc["iAngle"], td);
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);
// Temporary fix, IDs will be pulled from json later
tmp->appearanceData.iNPC_ID = i;
NPCManager::NPCs[nextId] = tmp;
MobManager::Mobs[nextId] = (Mob*)NPCManager::NPCs[nextId];
ChunkManager::addNPC(npc["iX"], npc["iY"], nextId);
NPCManager::NPCs[i] = tmp;
MobManager::Mobs[i] = (Mob*)NPCManager::NPCs[i];
ChunkManager::addNPC(npc["iX"], npc["iY"], i);
i++;
nextId++;
}
std::cout << "[INFO] Populated " << NPCManager::NPCs.size() << " NPCs" << std::endl;
@ -187,6 +182,8 @@ void TableData::init() {
catch (const std::exception& err) {
std::cerr << "[WARN] Malformed mobs.json file! Reason:" << err.what() << std::endl;
}
NPCManager::nextId = nextId;
}
/*

View File

@ -18,7 +18,7 @@ void TransportManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler);
BaseNPC* bus = new BaseNPC(220447, 162431, -3650, 1, NPC_BUS);
BaseNPC* bus = new BaseNPC(220447, 162431, -3650, 1, NPCManager::nextId++, NPC_BUS);
NPCManager::NPCs[bus->appearanceData.iNPC_ID] = bus;
ChunkManager::addNPC(bus->appearanceData.iX, bus->appearanceData.iY, bus->appearanceData.iNPC_ID);
std::queue<WarpLocation> busPoints;

View File

@ -1,4 +1,5 @@
leak:TableData::init
leak:ChunkManager::addPlayer
leak:ChunkManager::addNPC
leak:NPCManager::npcSummonHandler
leak:nlohmann::basic_json