diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 81bb019..236b62b 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -140,31 +140,36 @@ void NanoManager::addNano(CNSocket* sock, int16_t nanoId, int16_t slot) { Player *plr = PlayerManager::getPlayer(sock); + int level = nanoId < plr->level ? plr->level : nanoId; + // Send to client INITSTRUCT(sP_FE2CL_REP_PC_NANO_CREATE_SUCC, resp); resp.Nano.iID = nanoId; resp.Nano.iStamina = 150; resp.iQuestItemSlotNum = slot; - - sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_NANO_CREATE_SUCC, sizeof(sP_FE2CL_REP_PC_NANO_CREATE_SUCC)); + resp.iPC_Level = level; // Update player plr->Nanos[nanoId] = resp.Nano; + plr->level = level; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_NANO_CREATE_SUCC, sizeof(sP_FE2CL_REP_PC_NANO_CREATE_SUCC)); + + /* + * iPC_Level in NANO_CREATE_SUCC sets the player's level. + * Other players must be notified of the change as well. Both P_FE2CL_REP_PC_NANO_CREATE and + * P_FE2CL_REP_PC_CHANGE_LEVEL appear to play the same animation, but only the latter affects + * the other player's displayed level. + */ - // After a nano gets added, setting the level seems to be important so we are doing that - if (nanoId < plr->level) - nanoId = plr->level; - // Even if player level is unchanged, this packet still needs to be sent as using /nano always sets the player to 0 INITSTRUCT(sP_FE2CL_REP_PC_CHANGE_LEVEL, resp2); resp2.iPC_ID = plr->iID; - resp2.iPC_Level = nanoId; + resp2.iPC_Level = level; - sock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL)); + // Update other players' perception of the player's level for (CNSocket* s : PlayerManager::players[sock].viewable) s->sendPacket((void*)&resp2, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL)); - - plr->level = nanoId; } void NanoManager::summonNano(CNSocket *sock, int slot) { @@ -173,12 +178,10 @@ void NanoManager::summonNano(CNSocket *sock, int slot) { sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_ACTIVE_SUCC, sizeof(sP_FE2CL_REP_NANO_ACTIVE_SUCC)); Player *plr = PlayerManager::getPlayer(sock); - std::cout << "summon nano\n"; - - if (slot > 2 || slot < 0) // TODO: implement proper way to dismiss nano if slot = -1 + if (slot > 2 || slot < -1) return; // sanity check - int nanoId = plr->equippedNanos[slot]; + int nanoId = slot == -1 ? -1 : plr->equippedNanos[slot]; if (nanoId > 36 || nanoId < 0) return; // sanity check diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index b7eba9b..116b745 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -204,7 +204,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { response.PCLoadData2CL.iLevel = plr.level; response.PCLoadData2CL.iCandy = plr.money; response.PCLoadData2CL.iMentor = 5; // Computress - response.PCLoadData2CL.iMentorCount = 4; + response.PCLoadData2CL.iMentorCount = 1; // how many guides the player has had response.PCLoadData2CL.iMapNum = 0; response.PCLoadData2CL.iX = plr.x; response.PCLoadData2CL.iY = plr.y; @@ -233,9 +233,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { //response.PCLoadData2CL.aNanoSlots[1] = 2; //response.PCLoadData2CL.aNanoSlots[2] = 3; - response.PCLoadData2CL.aQuestFlag[0] = -1; - - // shut computress up + // shut Computress up response.PCLoadData2CL.iFirstUseFlag1 = UINT64_MAX; response.PCLoadData2CL.iFirstUseFlag2 = UINT64_MAX; @@ -533,6 +531,7 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) { sP_CL2FE_REQ_PC_GOTO* gotoData = (sP_CL2FE_REQ_PC_GOTO*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, response); + PlayerView& plrv = players[sock]; DEBUGLOG( std::cout << "P_CL2FE_REQ_PC_GOTO:" << std::endl; @@ -541,9 +540,13 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) { std::cout << "\tZ: " << gotoData->iToZ << std::endl; ) - response.iX = gotoData->iToX; - response.iY = gotoData->iToY; - response.iZ = gotoData->iToZ; + response.iX = plrv.plr->x = gotoData->iToX; + response.iY = plrv.plr->y = gotoData->iToY; + response.iZ = plrv.plr->z = gotoData->iToZ; + + // force player & NPC reload + plrv.viewable.clear(); + plrv.viewableNPCs.clear(); sock->sendPacket((void*)&response, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC)); } @@ -616,30 +619,22 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) { Player *plr = PlayerManager::getPlayer(sock); WarpLocation target = PlayerManager::getRespawnPoint(plr); - // players respawn at same spot they died at for now... sP_CL2FE_REQ_PC_REGEN* reviveData = (sP_CL2FE_REQ_PC_REGEN*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_REGEN_SUCC, response); + INITSTRUCT(sP_FE2CL_PC_REGEN, resp2); - /* - * Update player state - */ // Nanos for (int n = 0; n < 3; n++) { int nanoID = plr->equippedNanos[n]; - if (nanoID > 0 && nanoID < 37) { // sanity check - plr->Nanos[nanoID].iStamina = 75; // max is 150, so 75 is half - response.PCRegenData.Nanos[n] = plr->Nanos[nanoID]; - } + plr->Nanos[nanoID].iStamina = 75; // max is 150, so 75 is half + response.PCRegenData.Nanos[n] = plr->Nanos[nanoID]; } - plr->activeNano = -1; - // Position + // Update player plr->x = target.x; plr->y = target.y; plr->z = target.z; - // HP and FM plr->HP = 1000 * plr->level; - plr->fusionmatter = plr->fusionmatter; // TODO: does this actually change? // Response parameters response.PCRegenData.iActiveNanoSlotNum = plr->activeNano; @@ -652,6 +647,18 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) { response.PCRegenData.iMapNum = reviveData->iIndex; sock->sendPacket((void*)&response, P_FE2CL_REP_PC_REGEN_SUCC, sizeof(sP_FE2CL_REP_PC_REGEN_SUCC)); + + // Update other players + resp2.PCRegenDataForOtherPC.iPC_ID = plr->iID; + resp2.PCRegenDataForOtherPC.iX = plr->x; + resp2.PCRegenDataForOtherPC.iY = plr->y; + resp2.PCRegenDataForOtherPC.iZ = plr->z; + resp2.PCRegenDataForOtherPC.iHP = plr->HP; + resp2.PCRegenDataForOtherPC.iAngle = plr->angle; + resp2.PCRegenDataForOtherPC.Nano = plr->Nanos[plr->activeNano]; + + for (CNSocket *s : players[sock].viewable) + s->sendPacket((void*)&resp2, P_FE2CL_PC_REGEN, sizeof(sP_FE2CL_PC_REGEN)); } void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) { diff --git a/src/main.cpp b/src/main.cpp index 9f1549e..110acbb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,8 +28,8 @@ #endif #endif -CNShardServer *shardServer; -std::thread *shardThread; +CNShardServer *shardServer = nullptr; +std::thread *shardThread = nullptr; void startShard(CNShardServer* server) { server->start(); @@ -39,8 +39,11 @@ void startShard(CNShardServer* server) { // terminate gracefully on SIGINT (for gprof) void terminate(int arg) { std::cout << "OpenFusion: terminating." << std::endl; - shardServer->kill(); - shardThread->join(); + + if (shardServer != nullptr && shardThread != nullptr) { + shardServer->kill(); + shardThread->join(); + } #if defined(__SANITIZE_ADDRESS__) TableData::cleanup();