Bugfixes.

* Add newly created chunks to nearby players and NPCs. This fixes the
slider/static path mob pop-in problem.
* Update a player's chunks when resurrecting. This fixes a mob desync
problem.
* Use a private instance for the Time Lab
* Spawn a slider for every stop
* Fix mobs in private lairs using the template chunk mobs's current
health for their max health
* Don't call into the JSON lib in the loop in aggroCheck(). This is an
optimization found after using gprof.
* Don't print NPC deletions to console. This stops the spam when a
private instance is deleted.
* Changed default view distance to half the length of a map tile, so
chunks are aligned to map tiles
* Update tdata reference
This commit is contained in:
dongresource 2020-10-21 00:55:58 +02:00
parent 49d8ed2e36
commit c9f9b093f4
10 changed files with 46 additions and 29 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ build/
*.db
version.h
infer-out
gmon.out

View File

@ -21,7 +21,7 @@ port=8002
ip=127.0.0.1
# distance at which other players and NPCs become visible.
# this value is used for calculating chunk size
viewdistance=30000
viewdistance=25600
# time, in milliseconds, to wait before kicking a non-responsive client
# default is 1 minute
timeout=60000

View File

@ -8,15 +8,33 @@ std::map<std::tuple<int, int, uint64_t>, Chunk*> ChunkManager::chunks;
void ChunkManager::init() {} // stubbed
void ChunkManager::newChunk(std::tuple<int, int, uint64_t> pos) {
Chunk *chunk = new Chunk();
chunk->players = std::set<CNSocket*>();
chunk->NPCs = std::set<int32_t>();
// add the new chunk to every player and mob that's near it
for (Chunk *c : grabChunks(pos)) {
if (c == chunk)
continue;
for (CNSocket *s : c->players)
PlayerManager::players[s].currentChunks.push_back(chunk);
for (int32_t id : c->NPCs)
NPCManager::NPCs[id]->currentChunks.push_back(chunk);
}
chunks[pos] = chunk;
}
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()) {
chunks[pos] = new Chunk();
chunks[pos]->players = std::set<CNSocket*>();
chunks[pos]->NPCs = std::set<int32_t>();
}
if (chunks.find(pos) == chunks.end())
newChunk(pos);
Chunk* chunk = chunks[pos];
@ -27,11 +45,8 @@ void ChunkManager::addPlayer(int posX, int posY, uint64_t instanceID, CNSocket*
std::tuple<int, int, uint64_t> pos = grabChunk(posX, posY, instanceID);
// make chunk if it doesn't exist!
if (chunks.find(pos) == chunks.end()) {
chunks[pos] = new Chunk();
chunks[pos]->players = std::set<CNSocket*>();
chunks[pos]->NPCs = std::set<int32_t>();
}
if (chunks.find(pos) == chunks.end())
newChunk(pos);
Chunk* chunk = chunks[pos];
@ -212,7 +227,7 @@ void ChunkManager::createInstance(uint64_t instanceID) {
BaseNPC* baseNPC = NPCManager::NPCs[npcID];
if (baseNPC->npcClass == NPC_MOB) {
Mob* newMob = new Mob(baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ, baseNPC->appearanceData.iAngle,
instanceID, baseNPC->appearanceData.iNPCType, baseNPC->appearanceData.iHP, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], newID);
instanceID, baseNPC->appearanceData.iNPCType, ((Mob*)baseNPC)->maxHealth, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], newID);
NPCManager::NPCs[newID] = newMob;
MobManager::Mobs[newID] = newMob;
} else {

View File

@ -26,6 +26,7 @@ namespace ChunkManager {
extern std::map<std::tuple<int, int, uint64_t>, Chunk*> chunks;
void newChunk(std::tuple<int, int, uint64_t> pos);
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);

View File

@ -1046,7 +1046,7 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) {
if (plr->HP <= 0)
continue;
int mobRange = mob->data["m_iSightRange"];
int mobRange = mob->sightRange;
if (plr->iConditionBitFlag & CSB_BIT_UP_STEALTH)
mobRange /= 3;

View File

@ -35,6 +35,7 @@ struct Mob : public BaseNPC {
// roaming
int idleRange;
const int sightRange;
time_t nextMovement = 0;
bool staticPath = false;
@ -50,7 +51,9 @@ struct Mob : public BaseNPC {
nlohmann::json data;
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),
sightRange(d["m_iSightRange"]) {
state = MobState::ROAMING;
data = d;

View File

@ -107,7 +107,7 @@ void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
void NPCManager::destroyNPC(int32_t id) {
// sanity check
if (NPCs.find(id) == NPCs.end()) {
std::cout << "npc not found : " << id << std::endl;
std::cout << "npc not found: " << id << std::endl;
return;
}
@ -133,8 +133,6 @@ void NPCManager::destroyNPC(int32_t id) {
// finally, remove it from the map and free it
NPCs.erase(id);
delete entity;
std::cout << "npc removed!" << std::endl;
}
void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, int angle) {
@ -601,7 +599,9 @@ 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) {
uint64_t instanceID = Warps[warpId].instanceID;
if (Warps[warpId].limitTaskID != 0) { // if warp requires you to be on a mission, it's gotta be a unique instance
// if warp requires you to be on a mission, it's gotta be a unique instance
if (Warps[warpId].limitTaskID != 0 || instanceID == 14) { // 14 is a special case for the Time Lab
instanceID += ((uint64_t)plrv.plr->iIDGroup << 32); // upper 32 bits are leader ID
ChunkManager::createInstance(instanceID);
}

View File

@ -793,9 +793,7 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
NanoManager::nanoUnbuff(sock, CSB_BIT_PHOENIX, ECSB_PHOENIX, 0, false);
plr->HP = PC_MAXHEALTH(plr->level);
} else {
plr->x = target.x;
plr->y = target.y;
plr->z = target.z;
updatePlayerPosition(sock, target.x, target.y, target.z);
if (reviveData->iRegenType != 5)
plr->HP = PC_MAXHEALTH(plr->level);

View File

@ -264,14 +264,13 @@ void TableData::loadPaths(int* nextId) {
for (nlohmann::json::iterator _sliderPoint = pathDataSlider.begin(); _sliderPoint != pathDataSlider.end(); _sliderPoint++) {
auto sliderPoint = _sliderPoint.value();
if (sliderPoint["stop"]) { // check if this point in the circuit is a stop
if (stops % 2 == 0) { // on;y put a slider down every other stop
// spawn a slider
BaseNPC* slider = new BaseNPC(sliderPoint["iX"], sliderPoint["iY"], sliderPoint["iZ"], 0, INSTANCE_OVERWORLD, 1, (*nextId)++, NPC_BUS);
NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider;
NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->appearanceData.iX, slider->appearanceData.iY, slider->appearanceData.iZ);
// set slider path to a rotation of the circuit
constructPathSlider(pathDataSlider, pos, slider->appearanceData.iNPC_ID);
}
BaseNPC* slider = new BaseNPC(sliderPoint["iX"], sliderPoint["iY"], sliderPoint["iZ"], 0, INSTANCE_OVERWORLD, 1, (*nextId)++, NPC_BUS);
NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider;
NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->appearanceData.iX, slider->appearanceData.iY, slider->appearanceData.iZ);
// set slider path to a rotation of the circuit
constructPathSlider(pathDataSlider, pos, slider->appearanceData.iNPC_ID);
stops++;
}
pos++;

View File

@ -12,7 +12,7 @@ int settings::DBSAVEINTERVAL = 240;
int settings::SHARDPORT = 8002;
std::string settings::SHARDSERVERIP = "127.0.0.1";
time_t settings::TIMEOUT = 60000;
int settings::VIEWDISTANCE = 40000;
int settings::VIEWDISTANCE = 25600;
bool settings::SIMULATEMOBS = true;
// default spawn point is Sector V (future)