[WIP] Convert all chunk-related logic to the new system's semantics

Replaced all references to chunk->players and chunk->NPCs with
chunk->entities and all instances of the old NPCClass enum with
EntityType.

The server compiles but will not yet run properly.
This commit is contained in:
dongresource 2021-03-21 03:54:24 +01:00
parent 224ffe05e7
commit 0c8e209360
13 changed files with 119 additions and 107 deletions

View File

@ -240,59 +240,67 @@ bool Chunking::inPopulatedChunks(std::set<Chunk*>* chnks) {
void Chunking::createInstance(uint64_t instanceID) {
std::vector<ChunkPos> templateChunks = getChunksInMap(MAPNUM(instanceID)); // base instance chunks
if (getChunksInMap(instanceID).size() == 0) { // only instantiate if the instance doesn't exist already
std::cout << "Creating instance " << instanceID << std::endl;
for (ChunkPos &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
BaseNPC* baseNPC = NPCManager::NPCs[npcID];
if (baseNPC->npcClass == NPC_MOB) {
if (((Mob*)baseNPC)->groupLeader != 0 && ((Mob*)baseNPC)->groupLeader != npcID)
continue; // follower; don't copy individually
Mob* newMob = new Mob(baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ, baseNPC->appearanceData.iAngle,
instanceID, baseNPC->appearanceData.iNPCType, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], NPCManager::nextId++);
NPCManager::NPCs[newMob->appearanceData.iNPC_ID] = newMob;
MobAI::Mobs[newMob->appearanceData.iNPC_ID] = newMob;
// only instantiate if the instance doesn't exist already
if (getChunksInMap(instanceID).size() != 0) {
std::cout << "Instance " << instanceID << " already exists" << std::endl;
return;
}
// if in a group, copy over group members as well
if (((Mob*)baseNPC)->groupLeader != 0) {
newMob->groupLeader = newMob->appearanceData.iNPC_ID; // set leader ID for new leader
Mob* mobData = (Mob*)baseNPC;
for (int i = 0; i < 4; i++) {
if (mobData->groupMember[i] != 0) {
int followerID = NPCManager::nextId++; // id for follower
BaseNPC* baseFollower = NPCManager::NPCs[mobData->groupMember[i]]; // follower from template
// new follower instance
Mob* newMobFollower = new Mob(baseFollower->appearanceData.iX, baseFollower->appearanceData.iY, baseFollower->appearanceData.iZ, baseFollower->appearanceData.iAngle,
instanceID, baseFollower->appearanceData.iNPCType, NPCManager::NPCData[baseFollower->appearanceData.iNPCType], followerID);
// add follower to NPC maps
NPCManager::NPCs[followerID] = newMobFollower;
MobAI::Mobs[followerID] = newMobFollower;
// set follower-specific properties
newMobFollower->groupLeader = newMob->appearanceData.iNPC_ID;
newMobFollower->offsetX = ((Mob*)baseFollower)->offsetX;
newMobFollower->offsetY = ((Mob*)baseFollower)->offsetY;
// add follower copy to leader copy
newMob->groupMember[i] = followerID;
NPCManager::updateNPCPosition(followerID, baseFollower->appearanceData.iX, baseFollower->appearanceData.iY, baseFollower->appearanceData.iZ,
instanceID, baseFollower->appearanceData.iAngle);
}
std::cout << "Creating instance " << instanceID << std::endl;
for (ChunkPos &coords : templateChunks) {
for (const EntityRef& ref : chunks[coords]->entities) {
if (ref.type == EntityType::PLAYER)
continue;
int npcID = ref.id;
BaseNPC* baseNPC = (BaseNPC*)ref.getEntity();
// make a copy of each NPC in the template chunks and put them in the new instance
if (baseNPC->type == EntityType::MOB) {
if (((Mob*)baseNPC)->groupLeader != 0 && ((Mob*)baseNPC)->groupLeader != npcID)
continue; // follower; don't copy individually
Mob* newMob = new Mob(baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ, baseNPC->appearanceData.iAngle,
instanceID, baseNPC->appearanceData.iNPCType, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], NPCManager::nextId++);
NPCManager::NPCs[newMob->appearanceData.iNPC_ID] = newMob;
MobAI::Mobs[newMob->appearanceData.iNPC_ID] = newMob;
// if in a group, copy over group members as well
if (((Mob*)baseNPC)->groupLeader != 0) {
newMob->groupLeader = newMob->appearanceData.iNPC_ID; // set leader ID for new leader
Mob* mobData = (Mob*)baseNPC;
for (int i = 0; i < 4; i++) {
if (mobData->groupMember[i] != 0) {
int followerID = NPCManager::nextId++; // id for follower
BaseNPC* baseFollower = NPCManager::NPCs[mobData->groupMember[i]]; // follower from template
// new follower instance
Mob* newMobFollower = new Mob(baseFollower->appearanceData.iX, baseFollower->appearanceData.iY, baseFollower->appearanceData.iZ, baseFollower->appearanceData.iAngle,
instanceID, baseFollower->appearanceData.iNPCType, NPCManager::NPCData[baseFollower->appearanceData.iNPCType], followerID);
// add follower to NPC maps
NPCManager::NPCs[followerID] = newMobFollower;
MobAI::Mobs[followerID] = newMobFollower;
// set follower-specific properties
newMobFollower->groupLeader = newMob->appearanceData.iNPC_ID;
newMobFollower->offsetX = ((Mob*)baseFollower)->offsetX;
newMobFollower->offsetY = ((Mob*)baseFollower)->offsetY;
// add follower copy to leader copy
newMob->groupMember[i] = followerID;
NPCManager::updateNPCPosition(followerID, baseFollower->appearanceData.iX, baseFollower->appearanceData.iY, baseFollower->appearanceData.iZ,
instanceID, baseFollower->appearanceData.iAngle);
}
}
NPCManager::updateNPCPosition(newMob->appearanceData.iNPC_ID, baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ,
instanceID, baseNPC->appearanceData.iAngle);
} else {
BaseNPC* newNPC = new BaseNPC(baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ, baseNPC->appearanceData.iAngle,
instanceID, baseNPC->appearanceData.iNPCType, NPCManager::nextId++);
NPCManager::NPCs[newNPC->appearanceData.iNPC_ID] = newNPC;
NPCManager::updateNPCPosition(newNPC->appearanceData.iNPC_ID, baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ,
instanceID, baseNPC->appearanceData.iAngle);
}
NPCManager::updateNPCPosition(newMob->appearanceData.iNPC_ID, baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ,
instanceID, baseNPC->appearanceData.iAngle);
} else {
BaseNPC* newNPC = new BaseNPC(baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ, baseNPC->appearanceData.iAngle,
instanceID, baseNPC->appearanceData.iNPCType, NPCManager::nextId++);
NPCManager::NPCs[newNPC->appearanceData.iNPC_ID] = newNPC;
NPCManager::updateNPCPosition(newNPC->appearanceData.iNPC_ID, baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ,
instanceID, baseNPC->appearanceData.iAngle);
}
}
} else {
std::cout << "Instance " << instanceID << " already exists" << std::endl;
}
}

View File

@ -11,8 +11,8 @@
class Chunk {
public:
std::set<CNSocket*> players;
std::set<int32_t> NPCs;
//std::set<CNSocket*> players;
//std::set<int32_t> NPCs;
std::set<EntityRef> entities;
int nplayers = 0;
};
@ -41,18 +41,4 @@ namespace Chunking {
bool inPopulatedChunks(std::set<Chunk*>* chnks);
void createInstance(uint64_t);
void destroyInstanceIfEmpty(uint64_t);
// death row below this point
//void updatePlayerChunk(CNSocket* sock, ChunkPos from, ChunkPos to);
//void updateNPCChunk(int32_t id, ChunkPos from, ChunkPos to);
//void trackPlayer(ChunkPos chunkPos, CNSocket* sock);
//void trackNPC(ChunkPos chunkPos, int32_t id);
//void untrackPlayer(ChunkPos chunkPos, CNSocket* sock);
//void untrackNPC(ChunkPos chunkPos, int32_t id);
//void addPlayerToChunks(std::set<Chunk*> chnks, CNSocket* sock);
//void addNPCToChunks(std::set<Chunk*> chnks, int32_t id);
//void removePlayerFromChunks(std::set<Chunk*> chnks, CNSocket* sock);
//void removeNPCFromChunks(std::set<Chunk*> chnks, int32_t id);
}

View File

@ -662,7 +662,7 @@ static void whoisCommand(std::string full, std::vector<std::string>& args, CNSoc
Chat::sendServerMessage(sock, "[WHOIS] Type: " + std::to_string(npc->appearanceData.iNPCType));
Chat::sendServerMessage(sock, "[WHOIS] HP: " + std::to_string(npc->appearanceData.iHP));
Chat::sendServerMessage(sock, "[WHOIS] CBF: " + std::to_string(npc->appearanceData.iConditionBitFlag));
Chat::sendServerMessage(sock, "[WHOIS] Class: " + std::to_string(npc->npcClass));
Chat::sendServerMessage(sock, "[WHOIS] EntityType: " + std::to_string((int)npc->type));
Chat::sendServerMessage(sock, "[WHOIS] X: " + std::to_string(npc->appearanceData.iX));
Chat::sendServerMessage(sock, "[WHOIS] Y: " + std::to_string(npc->appearanceData.iY));
Chat::sendServerMessage(sock, "[WHOIS] Z: " + std::to_string(npc->appearanceData.iZ));
@ -682,7 +682,11 @@ static void lairUnlockCommand(std::string full, std::vector<std::string>& args,
int taskID = -1;
int missionID = -1;
int found = 0;
for (int32_t id : chnk->NPCs) {
for (const EntityRef& ref : chnk->entities) {
if (ref.type == EntityType::PLAYER)
continue;
int32_t id = ref.id;
if (NPCManager::NPCs.find(id) == NPCManager::NPCs.end())
continue;

View File

@ -9,6 +9,7 @@ enum class EntityType {
PLAYER,
SIMPLE_NPC,
COMBAT_NPC,
MOB,
EGG,
BUS
};
@ -68,34 +69,37 @@ struct EntityRef {
}
};
/*
* Subclasses
*/
class BaseNPC : public Entity {
public:
sNPCAppearanceData appearanceData;
NPCClass npcClass;
//NPCClass npcClass;
int playersInView;
BaseNPC() {};
BaseNPC(int x, int y, int z, int angle, uint64_t iID, int type, int id) { // XXX
BaseNPC(int x, int y, int z, int angle, uint64_t iID, int t, int id) { // XXX
appearanceData.iX = x;
appearanceData.iY = y;
appearanceData.iZ = z;
appearanceData.iNPCType = type;
appearanceData.iNPCType = t;
appearanceData.iHP = 400;
appearanceData.iAngle = angle;
appearanceData.iConditionBitFlag = 0;
appearanceData.iBarkerType = 0;
appearanceData.iNPC_ID = id;
npcClass = NPCClass::NPC_BASE;
type = EntityType::SIMPLE_NPC;
instanceID = iID;
chunkPos = std::make_tuple(0, 0, 0);
playersInView = 0;
};
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;
BaseNPC(int x, int y, int z, int angle, uint64_t iID, int t, int id, EntityType entityType) : BaseNPC(x, y, z, angle, iID, t, id) {
type = entityType;
}
// XXX: move to CombatNPC, probably
@ -111,10 +115,10 @@ struct Egg : public BaseNPC {
bool dead = false;
time_t deadUntil;
Egg(int x, int y, int z, uint64_t iID, int type, int32_t id, bool summon)
: BaseNPC(x, y, z, 0, iID, type, id) {
Egg(int x, int y, int z, uint64_t iID, int t, int32_t id, bool summon)
: BaseNPC(x, y, z, 0, iID, t, id) {
summoned = summon;
npcClass = NPCClass::NPC_EGG;
type = EntityType::EGG;
}
virtual bool isAlive() override { return !dead; }

View File

@ -121,7 +121,12 @@ bool MobAI::aggroCheck(Mob *mob, time_t currTime) {
for (auto it = mob->viewableChunks.begin(); it != mob->viewableChunks.end(); it++) {
Chunk* chunk = *it;
for (CNSocket *s : chunk->players) {
for (const EntityRef& ref : chunk->entities) {
// TODO: support targetting other CombatNPCs
if (ref.type != EntityType::PLAYER)
continue;
CNSocket *s = ref.sock;
Player *plr = PlayerManager::getPlayer(s);
if (plr->HP <= 0)
@ -298,7 +303,12 @@ static void useAbilities(Mob *mob, time_t currTime) {
// find the players within range of eruption
for (auto it = mob->viewableChunks.begin(); it != mob->viewableChunks.end(); it++) {
Chunk* chunk = *it;
for (CNSocket *s : chunk->players) {
for (const EntityRef& ref : chunk->entities) {
// TODO: see aggroCheck()
if (ref.type != EntityType::PLAYER)
continue;
CNSocket *s= ref.sock;
Player *plr = PlayerManager::getPlayer(s);
if (plr->HP <= 0)

View File

@ -53,8 +53,8 @@ struct Mob : public BaseNPC {
// temporary; until we're sure what's what
nlohmann::json data;
Mob(int x, int y, int z, int angle, uint64_t iID, int type, nlohmann::json d, int32_t id)
: BaseNPC(x, y, z, angle, iID, type, id),
Mob(int x, int y, int z, int angle, uint64_t iID, int t, nlohmann::json d, int32_t id)
: BaseNPC(x, y, z, angle, iID, t, id),
maxHealth(d["m_iHP"]),
sightRange(d["m_iSightRange"]) {
state = MobState::ROAMING;
@ -78,12 +78,12 @@ struct Mob : public BaseNPC {
// NOTE: there appear to be discrepancies in the dump
appearanceData.iHP = maxHealth;
npcClass = NPC_MOB;
type = EntityType::MOB;
}
// constructor for /summon
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, d, id) {
Mob(int x, int y, int z, uint64_t iID, int t, nlohmann::json d, int32_t id)
: Mob(x, y, z, 0, iID, t, d, id) {
summoned = true; // will be despawned and deallocated when killed
}

View File

@ -88,8 +88,9 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, uint64_t I,
void NPCManager::sendToViewable(BaseNPC *npc, void *buf, uint32_t type, size_t size) {
for (auto it = npc->viewableChunks.begin(); it != npc->viewableChunks.end(); it++) {
Chunk* chunk = *it;
for (CNSocket *s : chunk->players) {
s->sendPacket(buf, type, size);
for (const EntityRef& ref : chunk->entities) {
if (ref.type == EntityType::PLAYER)
ref.sock->sendPacket(buf, type, size);
}
}
}
@ -282,8 +283,11 @@ BaseNPC* NPCManager::getNearestNPC(std::set<Chunk*>* chunks, int X, int Y, int Z
int lastDist = INT_MAX;
for (auto c = chunks->begin(); c != chunks->end(); c++) { // haha get it
Chunk* chunk = *c;
for (auto _npc = chunk->NPCs.begin(); _npc != chunk->NPCs.end(); _npc++) {
BaseNPC* npcTemp = NPCs[*_npc];
for (auto ent = chunk->entities.begin(); ent != chunk->entities.end(); ent++) {
if (ent->type == EntityType::PLAYER)
continue;
BaseNPC* npcTemp = (BaseNPC*)ent->getEntity();
int distXY = std::hypot(X - npcTemp->appearanceData.iX, Y - npcTemp->appearanceData.iY);
int dist = std::hypot(distXY, Z - npcTemp->appearanceData.iZ);
if (dist < lastDist) {

View File

@ -93,6 +93,8 @@ struct Player : public Entity {
time_t lastShot;
std::vector<sItemBase> buyback;
Player() { type = EntityType::PLAYER; }
virtual void enterIntoViewOf(CNSocket *sock) override;
virtual void disappearFromViewOf(CNSocket *sock) override;
};

View File

@ -331,11 +331,11 @@ void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, siz
Player* plr = getPlayer(sock);
for (auto it = plr->viewableChunks.begin(); it != plr->viewableChunks.end(); it++) {
Chunk* chunk = *it;
for (CNSocket* otherSock : chunk->players) {
if (otherSock == sock)
for (const EntityRef& ref : chunk->entities) {
if (ref.type != EntityType::PLAYER || ref.sock == sock)
continue;
otherSock->sendPacket(buf, type, size);
ref.sock->sendPacket(buf, type, size);
}
}
}

View File

@ -40,11 +40,11 @@ namespace PlayerManager {
Player* plr = getPlayer(sock);
for (auto it = plr->viewableChunks.begin(); it != plr->viewableChunks.end(); it++) {
Chunk* chunk = *it;
for (CNSocket* otherSock : chunk->players) {
if (otherSock == sock)
for (const EntityRef& ref : chunk->entities) {
if (ref.type != EntityType::PLAYER || ref.sock == sock)
continue;
otherSock->sendPacket(pkt, type);
ref.sock->sendPacket(pkt, type);
}
}
}

View File

@ -139,7 +139,7 @@ static void loadPaths(int* nextId) {
if (passedDistance >= SLIDER_GAP_SIZE) { // space them out uniformaly
passedDistance -= SLIDER_GAP_SIZE; // step down
// spawn a slider
BaseNPC* slider = new BaseNPC(point.x, point.y, point.z, 0, INSTANCE_OVERWORLD, 1, (*nextId)++, NPC_BUS);
BaseNPC* slider = new BaseNPC(point.x, point.y, point.z, 0, INSTANCE_OVERWORLD, 1, (*nextId)++, EntityType::BUS);
NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider;
NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->appearanceData.iX, slider->appearanceData.iY, slider->appearanceData.iZ, INSTANCE_OVERWORLD, 0);
Transport::NPCQueues[slider->appearanceData.iNPC_ID] = route;
@ -965,7 +965,7 @@ void TableData::flush() {
continue;
int x, y, z;
if (npc->npcClass == NPC_MOB) {
if (npc->type == EntityType::MOB) {
Mob *m = (Mob*)npc;
x = m->spawnX;
y = m->spawnY;
@ -998,7 +998,7 @@ void TableData::flush() {
int x, y, z;
std::vector<Mob*> followers;
if (npc->npcClass == NPC_MOB) {
if (npc->type == EntityType::MOB) {
Mob* m = (Mob*)npc;
x = m->spawnX;
y = m->spawnY;

View File

@ -256,13 +256,13 @@ static void stepNPCPathing() {
}
// skip if not simulating mobs
if (npc->npcClass == NPC_MOB && !MobAI::simulateMobs) {
if (npc->type == EntityType::MOB && !MobAI::simulateMobs) {
it++;
continue;
}
// do not roam if not roaming
if (npc->npcClass == NPC_MOB && ((Mob*)npc)->state != MobState::ROAMING) {
if (npc->type == EntityType::MOB && ((Mob*)npc)->state != MobState::ROAMING) {
it++;
continue;
}
@ -277,9 +277,11 @@ static void stepNPCPathing() {
// update NPC location to update viewables
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z, npc->instanceID, npc->appearanceData.iAngle);
switch (npc->npcClass) {
case NPC_BUS:
// TODO: move walking logic into Entity stack
switch (npc->type) {
case EntityType::BUS:
INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove);
busMove.eTT = 3;
busMove.iT_ID = npc->appearanceData.iNPC_ID;
busMove.iMoveStyle = 0; // ???
@ -290,7 +292,7 @@ static void stepNPCPathing() {
NPCManager::sendToViewable(npc, &busMove, P_FE2CL_TRANSPORTATION_MOVE, sizeof(sP_FE2CL_TRANSPORTATION_MOVE));
break;
case NPC_MOB:
case EntityType::MOB:
MobAI::incNextMovement((Mob*)npc);
/* fallthrough */
default:
@ -310,7 +312,7 @@ static void stepNPCPathing() {
* Move processed point to the back to maintain cycle, unless this is a
* dynamically calculated mob route.
*/
if (!(npc->npcClass == NPC_MOB && !((Mob*)npc)->staticPath))
if (!(npc->type == EntityType::MOB && !((Mob*)npc)->staticPath))
queue->push(point);
it++; // go to next entry in map

View File

@ -24,14 +24,6 @@ enum eCN_GM_TeleportType {
eCN_GM_TeleportMapType__Unstick
};
// NPC classes
enum NPCClass {
NPC_BASE = 0,
NPC_MOB = 1,
NPC_BUS = 2,
NPC_EGG = 3
};
// nano powers
enum {
EST_NONE = 0,