2020-08-18 20:42:30 +00:00
|
|
|
#include "CNProtocol.hpp"
|
|
|
|
#include "PlayerManager.hpp"
|
2020-08-20 21:43:48 +00:00
|
|
|
#include "NPCManager.hpp"
|
2020-08-18 20:42:30 +00:00
|
|
|
#include "CNShardServer.hpp"
|
|
|
|
#include "CNShared.hpp"
|
2020-09-21 19:43:53 +00:00
|
|
|
#include "MissionManager.hpp"
|
2020-09-22 11:16:09 +00:00
|
|
|
#include "ItemManager.hpp"
|
2020-10-04 23:54:08 +00:00
|
|
|
#include "NanoManager.hpp"
|
|
|
|
#include "GroupManager.hpp"
|
2020-10-02 23:50:47 +00:00
|
|
|
#include "ChatManager.hpp"
|
2020-10-14 04:26:30 +00:00
|
|
|
#include "Database.hpp"
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
#include "settings.hpp"
|
|
|
|
|
2020-09-11 23:22:58 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
std::map<CNSocket*, PlayerView> PlayerManager::players;
|
|
|
|
|
|
|
|
void PlayerManager::init() {
|
|
|
|
// register packet types
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ENTER, PlayerManager::enterPlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LOADING_COMPLETE, PlayerManager::loadPlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVE, PlayerManager::movePlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_STOP, PlayerManager::stopPlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_JUMP, PlayerManager::jumpPlayer);
|
2020-08-20 16:26:26 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_JUMPPAD, PlayerManager::jumppadPlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LAUNCHER, PlayerManager::launchPlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ZIPLINE, PlayerManager::ziplinePlayer);
|
2020-08-18 20:42:30 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVEPLATFORM, PlayerManager::movePlatformPlayer);
|
2020-09-23 04:08:51 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVETRANSPORTATION, PlayerManager::moveSliderPlayer);
|
2020-08-20 16:26:26 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SLOPE, PlayerManager::moveSlopePlayer);
|
2020-08-18 20:42:30 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, PlayerManager::gotoPlayer);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, PlayerManager::setSpecialPlayer);
|
2020-08-19 01:34:39 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, PlayerManager::heartbeatPlayer);
|
2020-08-24 21:04:56 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, PlayerManager::revivePlayer);
|
2020-08-19 17:22:54 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, PlayerManager::exitGame);
|
2020-08-24 21:04:56 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setSpecialSwitchPlayer);
|
2020-09-22 15:30:49 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setGMSpecialSwitchPlayer);
|
2020-08-24 21:04:56 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, PlayerManager::enterPlayerVehicle);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, PlayerManager::exitPlayerVehicle);
|
2020-10-05 00:03:13 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, PlayerManager::changePlayerGuide);
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::addPlayer(CNSocket* key, Player plr) {
|
2020-08-24 22:02:07 +00:00
|
|
|
Player *p = new Player();
|
|
|
|
|
|
|
|
memcpy(p, &plr, sizeof(Player));
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
players[key] = PlayerView();
|
2020-10-02 20:17:24 +00:00
|
|
|
players[key].chunkPos = std::make_tuple(0, 0, 0);
|
2020-09-17 22:45:43 +00:00
|
|
|
players[key].currentChunks = std::vector<Chunk*>();
|
2020-08-24 22:02:07 +00:00
|
|
|
players[key].plr = p;
|
2020-08-19 01:34:39 +00:00
|
|
|
players[key].lastHeartbeat = 0;
|
2020-08-19 00:11:31 +00:00
|
|
|
|
2020-09-11 23:22:58 +00:00
|
|
|
key->plr = p;
|
|
|
|
|
2020-08-21 17:38:45 +00:00
|
|
|
std::cout << U16toU8(plr.PCStyle.szFirstName) << " " << U16toU8(plr.PCStyle.szLastName) << " has joined!" << std::endl;
|
2020-08-19 00:11:31 +00:00
|
|
|
std::cout << players.size() << " players" << std::endl;
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::removePlayer(CNSocket* key) {
|
2020-09-17 22:45:43 +00:00
|
|
|
PlayerView& view = players[key];
|
2020-10-19 02:30:12 +00:00
|
|
|
uint64_t fromInstance = view.plr->instanceID;
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
GroupManager::groupKickPlayer(view.plr);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-10-14 04:26:30 +00:00
|
|
|
// save player to DB
|
|
|
|
Database::updatePlayer(view.plr);
|
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// remove players from all chunks
|
|
|
|
removePlayerFromChunks(view.currentChunks, key);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// remove from chunk
|
|
|
|
if (ChunkManager::chunks.find(view.chunkPos) != ChunkManager::chunks.end())
|
|
|
|
ChunkManager::chunks[view.chunkPos]->players.erase(key);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
std::cout << U16toU8(view.plr->PCStyle.szFirstName) << " " << U16toU8(view.plr->PCStyle.szLastName) << " (PlayerId = " << view.plr->iID << ") has left!" << std::endl;
|
2020-08-25 22:09:31 +00:00
|
|
|
|
2020-09-11 23:22:58 +00:00
|
|
|
key->plr = nullptr;
|
2020-09-17 22:45:43 +00:00
|
|
|
delete view.plr;
|
2020-08-25 22:09:31 +00:00
|
|
|
players.erase(key);
|
2020-09-17 19:22:31 +00:00
|
|
|
|
2020-10-19 02:30:12 +00:00
|
|
|
// if the player was in a lair, clean it up
|
|
|
|
ChunkManager::destroyInstanceIfEmpty(fromInstance);
|
|
|
|
|
2020-09-17 19:22:31 +00:00
|
|
|
std::cout << players.size() << " players" << std::endl;
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 02:36:38 +00:00
|
|
|
bool PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
|
2020-09-17 22:45:43 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_EXIT, exitPlayer);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// for chunks that need the player to be removed from
|
|
|
|
for (Chunk* chunk : chunks) {
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// remove NPCs
|
|
|
|
for (int32_t id : chunk->NPCs) {
|
2020-09-23 04:08:51 +00:00
|
|
|
BaseNPC* npc = NPCManager::NPCs[id];
|
|
|
|
switch (npc->npcClass) {
|
|
|
|
case NPC_BUS:
|
|
|
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, exitBusData);
|
|
|
|
exitBusData.eTT = 3;
|
|
|
|
exitBusData.iT_ID = id;
|
|
|
|
sock->sendPacket((void*)&exitBusData, P_FE2CL_TRANSPORTATION_EXIT, sizeof(sP_FE2CL_TRANSPORTATION_EXIT));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
|
|
|
|
exitData.iNPC_ID = id;
|
|
|
|
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
|
|
|
|
break;
|
|
|
|
}
|
2020-08-22 18:02:08 +00:00
|
|
|
}
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// remove players from eachother
|
|
|
|
for (CNSocket* otherSock : chunk->players) {
|
|
|
|
exitPlayer.iID = players[sock].plr->iID;
|
|
|
|
otherSock->sendPacket((void*)&exitPlayer, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
|
|
|
|
exitPlayer.iID = players[otherSock].plr->iID;
|
|
|
|
sock->sendPacket((void*)&exitPlayer, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
2020-08-20 21:59:32 +00:00
|
|
|
}
|
2020-09-18 03:44:37 +00:00
|
|
|
|
2020-09-21 19:55:34 +00:00
|
|
|
// remove us from that old stinky chunk
|
2020-10-15 02:36:38 +00:00
|
|
|
return ChunkManager::removePlayer(players[sock].chunkPos, sock);
|
2020-09-17 22:45:43 +00:00
|
|
|
}
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
for (Chunk* chunk : chunks) {
|
|
|
|
// add npcs
|
|
|
|
for (int32_t id : chunk->NPCs) {
|
2020-09-23 04:08:51 +00:00
|
|
|
BaseNPC* npc = NPCManager::NPCs[id];
|
|
|
|
switch (npc->npcClass) {
|
|
|
|
case NPC_BUS:
|
|
|
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_ENTER, enterBusData);
|
|
|
|
enterBusData.AppearanceData = { 3, npc->appearanceData.iNPC_ID, npc->appearanceData.iNPCType, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ };
|
|
|
|
sock->sendPacket((void*)&enterBusData, P_FE2CL_TRANSPORTATION_ENTER, sizeof(sP_FE2CL_TRANSPORTATION_ENTER));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
|
|
|
|
enterData.NPCAppearanceData = NPCManager::NPCs[id]->appearanceData;
|
|
|
|
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
|
|
|
|
break;
|
|
|
|
}
|
2020-09-17 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add players
|
|
|
|
for (CNSocket* otherSock : chunk->players) {
|
2020-08-24 22:02:07 +00:00
|
|
|
Player *otherPlr = players[otherSock].plr;
|
|
|
|
Player *plr = players[sock].plr;
|
|
|
|
|
|
|
|
newPlayer.PCAppearanceData.iID = plr->iID;
|
|
|
|
newPlayer.PCAppearanceData.iHP = plr->HP;
|
|
|
|
newPlayer.PCAppearanceData.iLv = plr->level;
|
|
|
|
newPlayer.PCAppearanceData.iX = plr->x;
|
|
|
|
newPlayer.PCAppearanceData.iY = plr->y;
|
|
|
|
newPlayer.PCAppearanceData.iZ = plr->z;
|
|
|
|
newPlayer.PCAppearanceData.iAngle = plr->angle;
|
|
|
|
newPlayer.PCAppearanceData.PCStyle = plr->PCStyle;
|
|
|
|
newPlayer.PCAppearanceData.Nano = plr->Nanos[plr->activeNano];
|
|
|
|
newPlayer.PCAppearanceData.iPCState = plr->iPCState;
|
2020-09-22 15:30:49 +00:00
|
|
|
newPlayer.PCAppearanceData.iSpecialState = plr->iSpecialState;
|
2020-08-24 22:02:07 +00:00
|
|
|
memcpy(newPlayer.PCAppearanceData.ItemEquip, plr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
2020-08-22 23:31:09 +00:00
|
|
|
|
|
|
|
otherSock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
|
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
newPlayer.PCAppearanceData.iID = otherPlr->iID;
|
|
|
|
newPlayer.PCAppearanceData.iHP = otherPlr->HP;
|
|
|
|
newPlayer.PCAppearanceData.iLv = otherPlr->level;
|
|
|
|
newPlayer.PCAppearanceData.iX = otherPlr->x;
|
|
|
|
newPlayer.PCAppearanceData.iY = otherPlr->y;
|
|
|
|
newPlayer.PCAppearanceData.iZ = otherPlr->z;
|
|
|
|
newPlayer.PCAppearanceData.iAngle = otherPlr->angle;
|
|
|
|
newPlayer.PCAppearanceData.PCStyle = otherPlr->PCStyle;
|
|
|
|
newPlayer.PCAppearanceData.Nano = otherPlr->Nanos[otherPlr->activeNano];
|
|
|
|
newPlayer.PCAppearanceData.iPCState = otherPlr->iPCState;
|
2020-09-22 15:30:49 +00:00
|
|
|
newPlayer.PCAppearanceData.iSpecialState = otherPlr->iSpecialState;
|
2020-08-24 22:02:07 +00:00
|
|
|
memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
2020-08-22 23:31:09 +00:00
|
|
|
|
|
|
|
sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-17 22:45:43 +00:00
|
|
|
}
|
2020-08-20 21:43:48 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle) {
|
|
|
|
players[sock].plr->angle = angle;
|
|
|
|
updatePlayerPosition(sock, X, Y, Z);
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
|
|
|
|
PlayerView& view = players[sock];
|
|
|
|
view.plr->x = X;
|
|
|
|
view.plr->y = Y;
|
|
|
|
view.plr->z = Z;
|
2020-10-02 20:17:24 +00:00
|
|
|
updatePlayerChunk(sock, X, Y, view.plr->instanceID);
|
2020-09-24 22:43:58 +00:00
|
|
|
}
|
2020-09-17 22:45:43 +00:00
|
|
|
|
2020-10-12 16:55:41 +00:00
|
|
|
void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y, uint64_t instanceID) {
|
2020-09-24 22:43:58 +00:00
|
|
|
PlayerView& view = players[sock];
|
2020-10-12 16:55:41 +00:00
|
|
|
std::tuple<int, int, uint64_t> newPos = ChunkManager::grabChunk(X, Y, view.plr->instanceID);
|
2020-09-02 22:22:00 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// nothing to be done
|
2020-09-24 22:43:58 +00:00
|
|
|
if (newPos == view.chunkPos)
|
2020-09-17 22:45:43 +00:00
|
|
|
return;
|
2020-08-23 15:42:37 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// add player to chunk
|
2020-09-21 19:55:34 +00:00
|
|
|
std::vector<Chunk*> allChunks = ChunkManager::grabChunks(newPos);
|
2020-08-23 15:42:37 +00:00
|
|
|
|
2020-10-15 02:36:38 +00:00
|
|
|
Chunk *chunk = nullptr;
|
|
|
|
if (ChunkManager::checkChunk(view.chunkPos))
|
|
|
|
chunk = ChunkManager::chunks[view.chunkPos];
|
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
// first, remove all the old npcs & players from the old chunks
|
2020-10-15 02:36:38 +00:00
|
|
|
if (removePlayerFromChunks(ChunkManager::getDeltaChunks(view.currentChunks, allChunks), sock)) {
|
|
|
|
allChunks.erase(std::remove(allChunks.begin(), allChunks.end(), chunk), allChunks.end());
|
|
|
|
}
|
2020-09-24 22:43:58 +00:00
|
|
|
|
2020-09-17 23:03:23 +00:00
|
|
|
// now, add all the new npcs & players!
|
|
|
|
addPlayerToChunks(ChunkManager::getDeltaChunks(allChunks, view.currentChunks), sock);
|
2020-09-24 22:43:58 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
view.chunkPos = newPos;
|
|
|
|
view.currentChunks = allChunks;
|
2020-10-23 18:47:30 +00:00
|
|
|
ChunkManager::addPlayer(X, Y, view.plr->instanceID, sock); // takes care of adding the player to the chunk if it exists or not
|
2020-08-23 15:42:37 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 16:55:41 +00:00
|
|
|
void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I) {
|
2020-10-02 20:17:24 +00:00
|
|
|
PlayerView& plrv = PlayerManager::players[sock];
|
|
|
|
Player* plr = plrv.plr;
|
2020-10-19 02:30:12 +00:00
|
|
|
|
2020-10-22 17:14:24 +00:00
|
|
|
if (plrv.plr->instanceID == 0) {
|
|
|
|
// save last uninstanced coords
|
|
|
|
plrv.plr->lastX = plrv.plr->x;
|
|
|
|
plrv.plr->lastY = plrv.plr->y;
|
|
|
|
plrv.plr->lastZ = plrv.plr->z;
|
|
|
|
plrv.plr->lastAngle = plrv.plr->angle;
|
|
|
|
}
|
|
|
|
|
|
|
|
MissionManager::failInstancedMissions(sock); // fail any instanced missions
|
|
|
|
|
2020-10-25 22:14:35 +00:00
|
|
|
uint64_t fromInstance = plrv.plr->instanceID; // pre-warp instance, saved for post-warp
|
2020-10-19 02:30:12 +00:00
|
|
|
|
2020-10-02 20:17:24 +00:00
|
|
|
plr->instanceID = I;
|
|
|
|
if (I != INSTANCE_OVERWORLD) {
|
|
|
|
INITSTRUCT(sP_FE2CL_INSTANCE_MAP_INFO, pkt);
|
2020-10-18 20:43:22 +00:00
|
|
|
pkt.iEP_ID = PLAYERID(I) == 0; // iEP_ID has to be positive for the map to be enabled
|
|
|
|
pkt.iInstanceMapNum = (int32_t)MAPNUM(I); // lower 32 bits are mapnum
|
2020-10-02 20:17:24 +00:00
|
|
|
sock->sendPacket((void*)&pkt, P_FE2CL_INSTANCE_MAP_INFO, sizeof(sP_FE2CL_INSTANCE_MAP_INFO));
|
|
|
|
sendPlayerTo(sock, X, Y, Z);
|
|
|
|
} else {
|
|
|
|
// annoying but necessary to set the flag back
|
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp);
|
|
|
|
resp.iX = X;
|
|
|
|
resp.iY = Y;
|
|
|
|
resp.iZ = Z;
|
|
|
|
resp.iCandy = plrv.plr->money;
|
|
|
|
resp.eIL = 4; // do not take away any items
|
|
|
|
PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock);
|
|
|
|
plrv.currentChunks.clear();
|
|
|
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC));
|
2020-10-17 04:58:51 +00:00
|
|
|
updatePlayerPosition(sock, X, Y, Z);
|
2020-10-02 20:17:24 +00:00
|
|
|
}
|
2020-10-19 02:30:12 +00:00
|
|
|
|
2020-10-25 22:14:35 +00:00
|
|
|
// post-warp: check if the source instance has no more players in it and delete it if so
|
2020-10-19 02:30:12 +00:00
|
|
|
ChunkManager::destroyInstanceIfEmpty(fromInstance);
|
2020-10-03 15:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) {
|
|
|
|
PlayerManager::updatePlayerPosition(sock, X, Y, Z);
|
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, pkt);
|
|
|
|
pkt.iX = X;
|
|
|
|
pkt.iY = Y;
|
|
|
|
pkt.iZ = Z;
|
|
|
|
|
|
|
|
// force player & NPC reload
|
|
|
|
PlayerView& plrv = players[sock];
|
|
|
|
PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock);
|
|
|
|
plrv.currentChunks.clear();
|
|
|
|
plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID);
|
|
|
|
sock->sendPacket((void*)&pkt, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC));
|
|
|
|
}
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_ENTER))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_ENTER* enter = (sP_CL2FE_REQ_PC_ENTER*)data->buf;
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_ENTER_SUCC, response);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
// TODO: check if serialkey exists, if it doesn't send sP_FE2CL_REP_PC_ENTER_FAIL
|
|
|
|
Player plr = CNSharedData::getPlayer(enter->iEnterSerialKey);
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
plr.groupCnt = 1;
|
|
|
|
plr.iIDGroup = plr.groupIDs[0] = plr.iID;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
DEBUGLOG(
|
|
|
|
std::cout << "P_CL2FE_REQ_PC_ENTER:" << std::endl;
|
2020-08-24 23:08:02 +00:00
|
|
|
std::cout << "\tID: " << U16toU8(enter->szID) << std::endl;
|
|
|
|
std::cout << "\tSerial: " << enter->iEnterSerialKey << std::endl;
|
|
|
|
std::cout << "\tTemp: " << enter->iTempValue << std::endl;
|
|
|
|
std::cout << "\tPC_UID: " << plr.PCStyle.iPC_UID << std::endl;
|
2020-09-14 13:20:55 +00:00
|
|
|
)
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-27 05:12:26 +00:00
|
|
|
// check if account is already in use
|
|
|
|
if (isAccountInUse(plr.accountId)) {
|
|
|
|
// kick the other player
|
|
|
|
exitDuplicate(plr.accountId);
|
|
|
|
}
|
|
|
|
|
2020-09-02 22:22:00 +00:00
|
|
|
response.iID = plr.iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
response.uiSvrTime = getTime();
|
2020-09-22 02:26:12 +00:00
|
|
|
response.PCLoadData2CL.iUserLevel = plr.accountLevel;
|
2020-09-02 22:22:00 +00:00
|
|
|
response.PCLoadData2CL.iHP = plr.HP;
|
2020-08-22 23:31:09 +00:00
|
|
|
response.PCLoadData2CL.iLevel = plr.level;
|
2020-08-26 17:40:10 +00:00
|
|
|
response.PCLoadData2CL.iCandy = plr.money;
|
2020-09-19 03:26:20 +00:00
|
|
|
response.PCLoadData2CL.iFusionMatter = plr.fusionmatter;
|
2020-09-21 19:43:53 +00:00
|
|
|
response.PCLoadData2CL.iMentor = plr.mentor;
|
2020-09-12 20:43:04 +00:00
|
|
|
response.PCLoadData2CL.iMentorCount = 1; // how many guides the player has had
|
2020-08-22 23:31:09 +00:00
|
|
|
response.PCLoadData2CL.iX = plr.x;
|
|
|
|
response.PCLoadData2CL.iY = plr.y;
|
|
|
|
response.PCLoadData2CL.iZ = plr.z;
|
2020-09-02 22:22:00 +00:00
|
|
|
response.PCLoadData2CL.iAngle = plr.angle;
|
2020-09-21 19:43:53 +00:00
|
|
|
response.PCLoadData2CL.iBatteryN = plr.batteryN;
|
|
|
|
response.PCLoadData2CL.iBatteryW = plr.batteryW;
|
2020-10-19 17:26:14 +00:00
|
|
|
response.PCLoadData2CL.iBuddyWarpTime = 60; // sets 60s warp cooldown on login
|
2020-09-07 00:16:44 +00:00
|
|
|
|
2020-09-22 03:54:07 +00:00
|
|
|
response.PCLoadData2CL.iWarpLocationFlag = plr.iWarpLocationFlag;
|
|
|
|
response.PCLoadData2CL.aWyvernLocationFlag[0] = plr.aSkywayLocationFlag[0];
|
|
|
|
response.PCLoadData2CL.aWyvernLocationFlag[1] = plr.aSkywayLocationFlag[1];
|
|
|
|
|
2020-09-07 00:16:44 +00:00
|
|
|
response.PCLoadData2CL.iActiveNanoSlotNum = -1;
|
2020-08-22 23:31:09 +00:00
|
|
|
response.PCLoadData2CL.iFatigue = 50;
|
|
|
|
response.PCLoadData2CL.PCStyle = plr.PCStyle;
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-10-19 17:26:14 +00:00
|
|
|
// client doesnt read this, it gets it from charinfo
|
|
|
|
// response.PCLoadData2CL.PCStyle2 = plr.PCStyle2;
|
2020-09-14 14:03:30 +00:00
|
|
|
// inventory
|
2020-08-18 20:42:30 +00:00
|
|
|
for (int i = 0; i < AEQUIP_COUNT; i++)
|
2020-08-22 23:31:09 +00:00
|
|
|
response.PCLoadData2CL.aEquip[i] = plr.Equip[i];
|
2020-08-24 21:04:56 +00:00
|
|
|
for (int i = 0; i < AINVEN_COUNT; i++)
|
2020-08-22 23:31:09 +00:00
|
|
|
response.PCLoadData2CL.aInven[i] = plr.Inven[i];
|
2020-09-21 19:43:53 +00:00
|
|
|
// quest inventory
|
|
|
|
for (int i = 0; i < AQINVEN_COUNT; i++)
|
|
|
|
response.PCLoadData2CL.aQInven[i] = plr.QInven[i];
|
2020-09-14 14:03:30 +00:00
|
|
|
// nanos
|
2020-09-07 00:16:44 +00:00
|
|
|
for (int i = 1; i < SIZEOF_NANO_BANK_SLOT; i++) {
|
2020-09-02 22:22:00 +00:00
|
|
|
response.PCLoadData2CL.aNanoBank[i] = plr.Nanos[i];
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
2020-09-07 00:16:44 +00:00
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
response.PCLoadData2CL.aNanoSlots[i] = plr.equippedNanos[i];
|
|
|
|
}
|
2020-10-19 17:26:14 +00:00
|
|
|
// missions in progress
|
2020-09-21 19:43:53 +00:00
|
|
|
for (int i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
|
|
|
if (plr.tasks[i] == 0)
|
|
|
|
break;
|
|
|
|
response.PCLoadData2CL.aRunningQuest[i].m_aCurrTaskID = plr.tasks[i];
|
|
|
|
TaskData &task = *MissionManager::Tasks[plr.tasks[i]];
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
response.PCLoadData2CL.aRunningQuest[i].m_aKillNPCID[j] = (int)task["m_iCSUEnemyID"][j];
|
|
|
|
response.PCLoadData2CL.aRunningQuest[i].m_aKillNPCCount[j] = plr.RemainingNPCCount[i][j];
|
|
|
|
/*
|
|
|
|
* client doesn't care about NeededItem ID and Count,
|
|
|
|
* it gets Count from Quest Inventory
|
2020-10-05 00:03:13 +00:00
|
|
|
*
|
2020-09-21 19:43:53 +00:00
|
|
|
* KillNPCCount sets RemainEnemyNum in the client
|
2020-09-21 21:30:05 +00:00
|
|
|
* Yes, this is extraordinary stupid.
|
2020-09-21 19:43:53 +00:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
response.PCLoadData2CL.iCurrentMissionID = plr.CurrentMissionID;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-21 19:43:53 +00:00
|
|
|
// completed missions
|
|
|
|
// the packet requires 32 items, but the client only checks the first 16 (shrug)
|
2020-09-13 18:45:51 +00:00
|
|
|
for (int i = 0; i < 16; i++) {
|
|
|
|
response.PCLoadData2CL.aQuestFlag[i] = plr.aQuestFlag[i];
|
|
|
|
}
|
|
|
|
|
2020-09-12 20:43:04 +00:00
|
|
|
// shut Computress up
|
2020-08-25 01:42:52 +00:00
|
|
|
response.PCLoadData2CL.iFirstUseFlag1 = UINT64_MAX;
|
|
|
|
response.PCLoadData2CL.iFirstUseFlag2 = UINT64_MAX;
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
plr.SerialKey = enter->iEnterSerialKey;
|
2020-10-13 03:42:47 +00:00
|
|
|
plr.instanceID = INSTANCE_OVERWORLD; // the player should never be in an instance on enter
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
sock->setEKey(CNSocketEncryption::createNewKey(response.uiSvrTime, response.iID + 1, response.PCLoadData2CL.iFusionMatter + 1));
|
2020-08-18 20:42:30 +00:00
|
|
|
sock->setFEKey(plr.FEKey);
|
2020-08-22 23:31:09 +00:00
|
|
|
sock->setActiveKey(SOCKETKEY_FE); // send all packets using the FE key from now on
|
|
|
|
|
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_ENTER_SUCC, sizeof(sP_FE2CL_REP_PC_ENTER_SUCC));
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-21 17:38:45 +00:00
|
|
|
// transmit MOTD after entering the game, so the client hopefully changes modes on time
|
2020-10-02 23:50:47 +00:00
|
|
|
ChatManager::sendServerMessage(sock, settings::MOTDSTRING);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
addPlayer(sock, plr);
|
2020-10-19 17:26:14 +00:00
|
|
|
// check if there is an expiring vehicle
|
2020-09-22 11:16:09 +00:00
|
|
|
ItemManager::checkItemExpire(sock, getPlayer(sock));
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-10-19 17:26:14 +00:00
|
|
|
// set player equip stats
|
2020-09-27 01:53:03 +00:00
|
|
|
ItemManager::setItemStats(getPlayer(sock));
|
2020-10-14 18:36:38 +00:00
|
|
|
|
|
|
|
MissionManager::failInstancedMissions(sock);
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {
|
|
|
|
for (Chunk* chunk : players[sock].currentChunks) {
|
|
|
|
for (CNSocket* otherSock : chunk->players) {
|
|
|
|
if (otherSock == sock)
|
|
|
|
continue;
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
otherSock->sendPacket(buf, type, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_LOADING_COMPLETE))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_LOADING_COMPLETE* complete = (sP_CL2FE_REQ_PC_LOADING_COMPLETE*)data->buf;
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, response);
|
2020-08-25 18:42:52 +00:00
|
|
|
Player *plr = getPlayer(sock);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
DEBUGLOG(
|
|
|
|
std::cout << "P_CL2FE_REQ_PC_LOADING_COMPLETE:" << std::endl;
|
2020-08-24 23:08:02 +00:00
|
|
|
std::cout << "\tPC_ID: " << complete->iPC_ID << std::endl;
|
2020-08-18 20:42:30 +00:00
|
|
|
)
|
|
|
|
|
2020-08-24 23:08:02 +00:00
|
|
|
response.iPC_ID = complete->iPC_ID;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-25 18:42:52 +00:00
|
|
|
// reload players & NPCs
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, plr->x, plr->y, plr->z, plr->angle);
|
2020-08-25 18:42:52 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, sizeof(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::movePlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_MOVE))
|
|
|
|
return; // ignore the malformed packet
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_MOVE* moveData = (sP_CL2FE_REQ_PC_MOVE*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, moveData->iX, moveData->iY, moveData->iZ, moveData->iAngle);
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
players[sock].plr->angle = moveData->iAngle;
|
2020-08-18 20:42:30 +00:00
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_MOVE, moveResponse);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
moveResponse.iID = players[sock].plr->iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
moveResponse.cKeyValue = moveData->cKeyValue;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
moveResponse.iX = moveData->iX;
|
|
|
|
moveResponse.iY = moveData->iY;
|
|
|
|
moveResponse.iZ = moveData->iZ;
|
|
|
|
moveResponse.iAngle = moveData->iAngle;
|
|
|
|
moveResponse.fVX = moveData->fVX;
|
|
|
|
moveResponse.fVY = moveData->fVY;
|
|
|
|
moveResponse.fVZ = moveData->fVZ;
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
moveResponse.iSpeed = moveData->iSpeed;
|
|
|
|
moveResponse.iCliTime = moveData->iCliTime; // maybe don't send this??? seems unneeded...
|
|
|
|
moveResponse.iSvrTime = tm;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&moveResponse, P_FE2CL_PC_MOVE, sizeof(sP_FE2CL_PC_MOVE));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::stopPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_STOP))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_STOP* stopData = (sP_CL2FE_REQ_PC_STOP*)data->buf;
|
|
|
|
updatePlayerPosition(sock, stopData->iX, stopData->iY, stopData->iZ);
|
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_STOP, stopResponse);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
stopResponse.iID = players[sock].plr->iID;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
stopResponse.iX = stopData->iX;
|
|
|
|
stopResponse.iY = stopData->iY;
|
|
|
|
stopResponse.iZ = stopData->iZ;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
stopResponse.iCliTime = stopData->iCliTime; // maybe don't send this??? seems unneeded...
|
|
|
|
stopResponse.iSvrTime = tm;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&stopResponse, P_FE2CL_PC_STOP, sizeof(sP_FE2CL_PC_STOP));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::jumpPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_JUMP))
|
|
|
|
return; // ignore the malformed packet
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_JUMP* jumpData = (sP_CL2FE_REQ_PC_JUMP*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, jumpData->iX, jumpData->iY, jumpData->iZ, jumpData->iAngle);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_JUMP, jumpResponse);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
jumpResponse.iID = players[sock].plr->iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
jumpResponse.cKeyValue = jumpData->cKeyValue;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
jumpResponse.iX = jumpData->iX;
|
|
|
|
jumpResponse.iY = jumpData->iY;
|
|
|
|
jumpResponse.iZ = jumpData->iZ;
|
|
|
|
jumpResponse.iAngle = jumpData->iAngle;
|
|
|
|
jumpResponse.iVX = jumpData->iVX;
|
|
|
|
jumpResponse.iVY = jumpData->iVY;
|
|
|
|
jumpResponse.iVZ = jumpData->iVZ;
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
jumpResponse.iSpeed = jumpData->iSpeed;
|
|
|
|
jumpResponse.iCliTime = jumpData->iCliTime; // maybe don't send this??? seems unneeded...
|
|
|
|
jumpResponse.iSvrTime = tm;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&jumpResponse, P_FE2CL_PC_JUMP, sizeof(sP_FE2CL_PC_JUMP));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-08-20 16:26:26 +00:00
|
|
|
void PlayerManager::jumppadPlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_JUMPPAD))
|
|
|
|
return; // ignore the malformed packet
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-20 16:26:26 +00:00
|
|
|
sP_CL2FE_REQ_PC_JUMPPAD* jumppadData = (sP_CL2FE_REQ_PC_JUMPPAD*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, jumppadData->iX, jumppadData->iY, jumppadData->iZ, jumppadData->iAngle);
|
2020-08-20 16:26:26 +00:00
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_JUMPPAD, jumppadResponse);
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
jumppadResponse.iPC_ID = players[sock].plr->iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
jumppadResponse.cKeyValue = jumppadData->cKeyValue;
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
jumppadResponse.iX = jumppadData->iX;
|
|
|
|
jumppadResponse.iY = jumppadData->iY;
|
|
|
|
jumppadResponse.iZ = jumppadData->iZ;
|
|
|
|
jumppadResponse.iVX = jumppadData->iVX;
|
|
|
|
jumppadResponse.iVY = jumppadData->iVY;
|
|
|
|
jumppadResponse.iVZ = jumppadData->iVZ;
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
jumppadResponse.iCliTime = jumppadData->iCliTime;
|
|
|
|
jumppadResponse.iSvrTime = tm;
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&jumppadResponse, P_FE2CL_PC_JUMPPAD, sizeof(sP_FE2CL_PC_JUMPPAD));
|
2020-08-20 16:26:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::launchPlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_LAUNCHER))
|
|
|
|
return; // ignore the malformed packet
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-20 16:26:26 +00:00
|
|
|
sP_CL2FE_REQ_PC_LAUNCHER* launchData = (sP_CL2FE_REQ_PC_LAUNCHER*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, launchData->iX, launchData->iY, launchData->iZ, launchData->iAngle);
|
2020-08-20 16:26:26 +00:00
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_LAUNCHER, launchResponse);
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
launchResponse.iPC_ID = players[sock].plr->iID;
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
launchResponse.iX = launchData->iX;
|
|
|
|
launchResponse.iY = launchData->iY;
|
|
|
|
launchResponse.iZ = launchData->iZ;
|
|
|
|
launchResponse.iVX = launchData->iVX;
|
|
|
|
launchResponse.iVY = launchData->iVY;
|
|
|
|
launchResponse.iVZ = launchData->iVZ;
|
|
|
|
launchResponse.iSpeed = launchData->iSpeed;
|
|
|
|
launchResponse.iAngle = launchData->iAngle;
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
launchResponse.iCliTime = launchData->iCliTime;
|
|
|
|
launchResponse.iSvrTime = tm;
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&launchResponse, P_FE2CL_PC_LAUNCHER, sizeof(sP_FE2CL_PC_LAUNCHER));
|
2020-08-20 16:26:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::ziplinePlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_ZIPLINE))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
|
|
|
sP_CL2FE_REQ_PC_ZIPLINE* ziplineData = (sP_CL2FE_REQ_PC_ZIPLINE*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, ziplineData->iX, ziplineData->iY, ziplineData->iZ, ziplineData->iAngle);
|
2020-08-20 16:26:26 +00:00
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_ZIPLINE, ziplineResponse);
|
2020-08-22 23:31:09 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
ziplineResponse.iPC_ID = players[sock].plr->iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
ziplineResponse.iCliTime = ziplineData->iCliTime;
|
|
|
|
ziplineResponse.iSvrTime = tm;
|
|
|
|
ziplineResponse.iX = ziplineData->iX;
|
|
|
|
ziplineResponse.iY = ziplineData->iY;
|
|
|
|
ziplineResponse.iZ = ziplineData->iZ;
|
|
|
|
ziplineResponse.fVX = ziplineData->fVX;
|
|
|
|
ziplineResponse.fVY = ziplineData->fVY;
|
|
|
|
ziplineResponse.fVZ = ziplineData->fVZ;
|
|
|
|
ziplineResponse.fMovDistance = ziplineData->fMovDistance;
|
|
|
|
ziplineResponse.fMaxDistance = ziplineData->fMaxDistance;
|
2020-09-14 14:03:30 +00:00
|
|
|
ziplineResponse.fDummy = ziplineData->fDummy; // wtf is this for?
|
2020-08-22 23:31:09 +00:00
|
|
|
ziplineResponse.iStX = ziplineData->iStX;
|
|
|
|
ziplineResponse.iStY = ziplineData->iStY;
|
|
|
|
ziplineResponse.iStZ = ziplineData->iStZ;
|
|
|
|
ziplineResponse.bDown = ziplineData->bDown;
|
|
|
|
ziplineResponse.iSpeed = ziplineData->iSpeed;
|
|
|
|
ziplineResponse.iAngle = ziplineData->iAngle;
|
|
|
|
ziplineResponse.iRollMax = ziplineData->iRollMax;
|
|
|
|
ziplineResponse.iRoll = ziplineData->iRoll;
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&ziplineResponse, P_FE2CL_PC_ZIPLINE, sizeof(sP_FE2CL_PC_ZIPLINE));
|
2020-08-20 16:26:26 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_MOVEPLATFORM))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_MOVEPLATFORM* platformData = (sP_CL2FE_REQ_PC_MOVEPLATFORM*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, platformData->iX, platformData->iY, platformData->iZ, platformData->iAngle);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_MOVEPLATFORM, platResponse);
|
2020-08-22 23:31:09 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
platResponse.iPC_ID = players[sock].plr->iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
platResponse.iCliTime = platformData->iCliTime;
|
|
|
|
platResponse.iSvrTime = tm;
|
|
|
|
platResponse.iX = platformData->iX;
|
|
|
|
platResponse.iY = platformData->iY;
|
|
|
|
platResponse.iZ = platformData->iZ;
|
|
|
|
platResponse.iAngle = platformData->iAngle;
|
|
|
|
platResponse.fVX = platformData->fVX;
|
|
|
|
platResponse.fVY = platformData->fVY;
|
|
|
|
platResponse.fVZ = platformData->fVZ;
|
|
|
|
platResponse.iLcX = platformData->iLcX;
|
|
|
|
platResponse.iLcY = platformData->iLcY;
|
|
|
|
platResponse.iLcZ = platformData->iLcZ;
|
|
|
|
platResponse.iSpeed = platformData->iSpeed;
|
|
|
|
platResponse.bDown = platformData->bDown;
|
|
|
|
platResponse.cKeyValue = platformData->cKeyValue;
|
|
|
|
platResponse.iPlatformID = platformData->iPlatformID;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM));
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-23 04:08:51 +00:00
|
|
|
void PlayerManager::moveSliderPlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_MOVETRANSPORTATION))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
|
|
|
sP_CL2FE_REQ_PC_MOVETRANSPORTATION* sliderData = (sP_CL2FE_REQ_PC_MOVETRANSPORTATION*)data->buf;
|
|
|
|
updatePlayerPosition(sock, sliderData->iX, sliderData->iY, sliderData->iZ, sliderData->iAngle);
|
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
|
|
|
INITSTRUCT(sP_FE2CL_PC_MOVETRANSPORTATION, sliderResponse);
|
|
|
|
|
|
|
|
sliderResponse.iPC_ID = players[sock].plr->iID;
|
|
|
|
sliderResponse.iCliTime = sliderData->iCliTime;
|
|
|
|
sliderResponse.iSvrTime = tm;
|
|
|
|
sliderResponse.iX = sliderData->iX;
|
|
|
|
sliderResponse.iY = sliderData->iY;
|
|
|
|
sliderResponse.iZ = sliderData->iZ;
|
|
|
|
sliderResponse.iAngle = sliderData->iAngle;
|
|
|
|
sliderResponse.fVX = sliderData->fVX;
|
|
|
|
sliderResponse.fVY = sliderData->fVY;
|
|
|
|
sliderResponse.fVZ = sliderData->fVZ;
|
|
|
|
sliderResponse.iLcX = sliderData->iLcX;
|
|
|
|
sliderResponse.iLcY = sliderData->iLcY;
|
|
|
|
sliderResponse.iLcZ = sliderData->iLcZ;
|
|
|
|
sliderResponse.iSpeed = sliderData->iSpeed;
|
|
|
|
sliderResponse.cKeyValue = sliderData->cKeyValue;
|
|
|
|
sliderResponse.iT_ID = sliderData->iT_ID;
|
|
|
|
|
|
|
|
sendToViewable(sock, (void*)&sliderResponse, P_FE2CL_PC_MOVETRANSPORTATION, sizeof(sP_FE2CL_PC_MOVETRANSPORTATION));
|
|
|
|
}
|
|
|
|
|
2020-08-20 16:26:26 +00:00
|
|
|
void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_SLOPE))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
|
|
|
sP_CL2FE_REQ_PC_SLOPE* slopeData = (sP_CL2FE_REQ_PC_SLOPE*)data->buf;
|
2020-09-02 22:22:00 +00:00
|
|
|
updatePlayerPosition(sock, slopeData->iX, slopeData->iY, slopeData->iZ,slopeData->iAngle);
|
2020-08-20 16:26:26 +00:00
|
|
|
|
|
|
|
uint64_t tm = getTime();
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_SLOPE, slopeResponse);
|
2020-08-22 23:31:09 +00:00
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
slopeResponse.iPC_ID = players[sock].plr->iID;
|
2020-08-22 23:31:09 +00:00
|
|
|
slopeResponse.iCliTime = slopeData->iCliTime;
|
|
|
|
slopeResponse.iSvrTime = tm;
|
|
|
|
slopeResponse.iX = slopeData->iX;
|
|
|
|
slopeResponse.iY = slopeData->iY;
|
|
|
|
slopeResponse.iZ = slopeData->iZ;
|
|
|
|
slopeResponse.iAngle = slopeData->iAngle;
|
|
|
|
slopeResponse.fVX = slopeData->fVX;
|
|
|
|
slopeResponse.fVY = slopeData->fVY;
|
|
|
|
slopeResponse.fVZ = slopeData->fVZ;
|
|
|
|
slopeResponse.iSpeed = slopeData->iSpeed;
|
|
|
|
slopeResponse.cKeyValue = slopeData->cKeyValue;
|
|
|
|
slopeResponse.iSlopeID = slopeData->iSlopeID;
|
2020-08-20 16:26:26 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&slopeResponse, P_FE2CL_PC_SLOPE, sizeof(sP_FE2CL_PC_SLOPE));
|
2020-08-20 16:26:26 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_GOTO))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_REQ_PC_GOTO* gotoData = (sP_CL2FE_REQ_PC_GOTO*)data->buf;
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, response);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
DEBUGLOG(
|
|
|
|
std::cout << "P_CL2FE_REQ_PC_GOTO:" << std::endl;
|
2020-08-24 23:08:02 +00:00
|
|
|
std::cout << "\tX: " << gotoData->iToX << std::endl;
|
|
|
|
std::cout << "\tY: " << gotoData->iToY << std::endl;
|
|
|
|
std::cout << "\tZ: " << gotoData->iToZ << std::endl;
|
2020-10-14 18:36:38 +00:00
|
|
|
)
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-10-14 18:29:02 +00:00
|
|
|
sendPlayerTo(sock, gotoData->iToX, gotoData->iToY, gotoData->iToZ, 0);
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-08-19 00:11:31 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SET_VALUE))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
sP_CL2FE_GM_REQ_PC_SET_VALUE* setData = (sP_CL2FE_GM_REQ_PC_SET_VALUE*)data->buf;
|
2020-09-09 01:15:25 +00:00
|
|
|
Player *plr = PlayerManager::getPlayer(sock);
|
|
|
|
|
2020-09-28 18:11:13 +00:00
|
|
|
if (plr == nullptr)
|
|
|
|
return;
|
|
|
|
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_GM_REP_PC_SET_VALUE, response);
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
DEBUGLOG(
|
|
|
|
std::cout << "P_CL2FE_GM_REQ_PC_SET_VALUE:" << std::endl;
|
2020-08-24 23:08:02 +00:00
|
|
|
std::cout << "\tPC_ID: " << setData->iPC_ID << std::endl;
|
|
|
|
std::cout << "\tSetValueType: " << setData->iSetValueType << std::endl;
|
|
|
|
std::cout << "\tSetValue: " << setData->iSetValue << std::endl;
|
2020-08-18 20:42:30 +00:00
|
|
|
)
|
|
|
|
|
2020-09-09 01:15:25 +00:00
|
|
|
// Handle serverside value-changes
|
|
|
|
switch (setData->iSetValueType) {
|
|
|
|
case 1:
|
|
|
|
plr->HP = setData->iSetValue;
|
|
|
|
break;
|
|
|
|
case 2:
|
2020-09-28 16:53:16 +00:00
|
|
|
plr->batteryW = setData->iSetValue;
|
2020-09-09 01:15:25 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-09-28 16:53:16 +00:00
|
|
|
plr->batteryN = setData->iSetValue;
|
2020-09-09 01:15:25 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
plr->fusionmatter = setData->iSetValue;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
plr->money = setData->iSetValue;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-08-24 23:08:02 +00:00
|
|
|
response.iPC_ID = setData->iPC_ID;
|
2020-08-22 23:31:09 +00:00
|
|
|
response.iSetValue = setData->iSetValue;
|
|
|
|
response.iSetValueType = setData->iSetValueType;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_GM_REP_PC_SET_VALUE, sizeof(sP_FE2CL_GM_REP_PC_SET_VALUE));
|
2020-08-19 01:34:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
players[sock].lastHeartbeat = getTime();
|
2020-08-19 17:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) {
|
2020-08-22 18:08:37 +00:00
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_EXIT))
|
|
|
|
return;
|
2020-08-24 21:04:56 +00:00
|
|
|
|
2020-08-19 17:22:54 +00:00
|
|
|
sP_CL2FE_REQ_PC_EXIT* exitData = (sP_CL2FE_REQ_PC_EXIT*)data->buf;
|
2020-08-23 00:26:18 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, response);
|
2020-08-19 17:22:54 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
response.iID = exitData->iID;
|
|
|
|
response.iExitCode = 1;
|
2020-08-19 17:22:54 +00:00
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC));
|
2020-08-19 17:22:54 +00:00
|
|
|
}
|
2020-08-22 18:02:08 +00:00
|
|
|
|
2020-08-24 21:04:56 +00:00
|
|
|
void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_REGEN))
|
|
|
|
return;
|
|
|
|
|
2020-08-24 22:02:07 +00:00
|
|
|
Player *plr = PlayerManager::getPlayer(sock);
|
2020-09-28 18:11:13 +00:00
|
|
|
|
|
|
|
if (plr == nullptr)
|
|
|
|
return;
|
|
|
|
|
2020-08-25 01:34:53 +00:00
|
|
|
WarpLocation target = PlayerManager::getRespawnPoint(plr);
|
2020-08-24 21:04:56 +00:00
|
|
|
|
|
|
|
sP_CL2FE_REQ_PC_REGEN* reviveData = (sP_CL2FE_REQ_PC_REGEN*)data->buf;
|
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_REGEN_SUCC, response);
|
2020-09-12 20:43:04 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_REGEN, resp2);
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-09-25 14:57:32 +00:00
|
|
|
int activeSlot = -1;
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
if (reviveData->iRegenType == 3 && plr->iConditionBitFlag & CSB_BIT_PHOENIX) {
|
|
|
|
// nano revive
|
|
|
|
plr->Nanos[plr->activeNano].iStamina = 0;
|
|
|
|
NanoManager::nanoUnbuff(sock, CSB_BIT_PHOENIX, ECSB_PHOENIX, 0, false);
|
|
|
|
plr->HP = PC_MAXHEALTH(plr->level);
|
|
|
|
} else {
|
2020-10-20 22:55:58 +00:00
|
|
|
updatePlayerPosition(sock, target.x, target.y, target.z);
|
2020-10-04 23:54:08 +00:00
|
|
|
|
|
|
|
if (reviveData->iRegenType != 5)
|
|
|
|
plr->HP = PC_MAXHEALTH(plr->level);
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
int nanoID = plr->equippedNanos[i];
|
|
|
|
|
|
|
|
// halve nano health if respawning
|
2020-10-09 00:01:35 +00:00
|
|
|
if (reviveData->iRegenType != 5)
|
2020-10-04 23:54:08 +00:00
|
|
|
plr->Nanos[nanoID].iStamina = 75; // max is 150, so 75 is half
|
2020-10-09 00:01:35 +00:00
|
|
|
response.PCRegenData.Nanos[i] = plr->Nanos[nanoID];
|
2020-10-04 23:54:08 +00:00
|
|
|
if (plr->activeNano == nanoID)
|
|
|
|
activeSlot = i;
|
2020-09-25 14:57:32 +00:00
|
|
|
}
|
2020-09-12 18:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Response parameters
|
2020-09-25 14:57:32 +00:00
|
|
|
response.PCRegenData.iActiveNanoSlotNum = activeSlot;
|
2020-09-12 18:21:36 +00:00
|
|
|
response.PCRegenData.iX = plr->x;
|
|
|
|
response.PCRegenData.iY = plr->y;
|
|
|
|
response.PCRegenData.iZ = plr->z;
|
|
|
|
response.PCRegenData.iHP = plr->HP;
|
|
|
|
response.iFusionMatter = plr->fusionmatter;
|
2020-10-04 23:54:08 +00:00
|
|
|
response.bMoveLocation = 0;
|
|
|
|
response.PCRegenData.iMapNum = 0;
|
2020-08-24 21:04:56 +00:00
|
|
|
|
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_REGEN_SUCC, sizeof(sP_FE2CL_REP_PC_REGEN_SUCC));
|
2020-09-12 20:43:04 +00:00
|
|
|
|
|
|
|
// 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;
|
2020-10-04 23:54:08 +00:00
|
|
|
resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag;
|
|
|
|
resp2.PCRegenDataForOtherPC.iPCState = plr->iPCState;
|
|
|
|
resp2.PCRegenDataForOtherPC.iSpecialState = plr->iSpecialState;
|
2020-09-12 20:43:04 +00:00
|
|
|
resp2.PCRegenDataForOtherPC.Nano = plr->Nanos[plr->activeNano];
|
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
sendToViewable(sock, (void*)&resp2, P_FE2CL_PC_REGEN, sizeof(sP_FE2CL_PC_REGEN));
|
2020-08-24 21:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
2020-08-27 02:35:13 +00:00
|
|
|
PlayerView& plr = PlayerManager::players[sock];
|
2020-09-14 13:53:48 +00:00
|
|
|
|
2020-09-23 09:05:18 +00:00
|
|
|
if (plr.plr->Equip[8].iID > 0 && plr.plr->Equip[8].iTimeLimit>getTimestamp()) {
|
2020-08-27 02:35:13 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response);
|
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
|
2020-09-14 13:53:48 +00:00
|
|
|
|
2020-09-14 14:03:30 +00:00
|
|
|
// send to other players
|
2020-10-28 21:05:01 +00:00
|
|
|
plr.plr->iPCState |= 8;
|
2020-08-27 02:35:13 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
|
|
|
response2.iPC_ID = plr.plr->iID;
|
2020-10-28 21:05:01 +00:00
|
|
|
response2.iState = plr.plr->iPCState;
|
2020-09-14 13:53:48 +00:00
|
|
|
|
2020-09-17 22:45:43 +00:00
|
|
|
for (Chunk* chunk : players[sock].currentChunks) {
|
|
|
|
for (CNSocket* otherSock : chunk->players) {
|
|
|
|
otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
|
|
|
|
}
|
2020-08-27 02:35:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_FAIL, response);
|
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_FAIL, sizeof(sP_FE2CL_PC_VEHICLE_ON_FAIL));
|
2020-09-23 08:20:47 +00:00
|
|
|
|
2020-09-23 09:21:32 +00:00
|
|
|
// check if vehicle didn't expire
|
2020-10-19 17:26:14 +00:00
|
|
|
if (plr.plr->Equip[8].iTimeLimit < getTimestamp()) {
|
2020-09-23 08:20:47 +00:00
|
|
|
plr.plr->toRemoveVehicle.eIL = 0;
|
|
|
|
plr.plr->toRemoveVehicle.iSlotNum = 8;
|
|
|
|
ItemManager::checkItemExpire(sock, plr.plr);
|
|
|
|
}
|
2020-08-24 21:04:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
2020-08-27 02:35:13 +00:00
|
|
|
PlayerView plr = PlayerManager::players[sock];
|
2020-08-24 21:04:56 +00:00
|
|
|
|
2020-10-28 21:05:01 +00:00
|
|
|
if (plr.plr->iPCState & 8) {
|
|
|
|
INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response);
|
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC));
|
2020-09-14 13:53:48 +00:00
|
|
|
|
2020-10-28 21:05:01 +00:00
|
|
|
// send to other players
|
|
|
|
plr.plr->iPCState &= ~8;
|
|
|
|
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
|
|
|
response2.iPC_ID = plr.plr->iID;
|
|
|
|
response2.iState = plr.plr->iPCState;
|
|
|
|
|
|
|
|
sendToViewable(sock, (void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
|
|
|
|
}
|
2020-08-24 21:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
2020-09-22 15:30:49 +00:00
|
|
|
setSpecialState(sock, data);
|
|
|
|
}
|
2020-08-24 21:04:56 +00:00
|
|
|
|
2020-09-22 15:30:49 +00:00
|
|
|
void PlayerManager::setGMSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
|
|
|
|
|
|
|
if (getPlayer(sock)->accountLevel > 30)
|
|
|
|
return;
|
|
|
|
|
|
|
|
setSpecialState(sock, data);
|
2020-08-24 21:04:56 +00:00
|
|
|
}
|
|
|
|
|
2020-08-28 19:42:00 +00:00
|
|
|
void PlayerManager::changePlayerGuide(CNSocket *sock, CNPacketData *data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_CHANGE_MENTOR))
|
|
|
|
return;
|
|
|
|
|
|
|
|
sP_CL2FE_REQ_PC_CHANGE_MENTOR *pkt = (sP_CL2FE_REQ_PC_CHANGE_MENTOR*)data->buf;
|
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_CHANGE_MENTOR_SUCC, resp);
|
|
|
|
Player *plr = getPlayer(sock);
|
|
|
|
|
|
|
|
resp.iMentor = pkt->iMentor;
|
|
|
|
resp.iMentorCnt = 1;
|
|
|
|
resp.iFusionMatter = plr->fusionmatter; // no cost
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-08-28 19:42:00 +00:00
|
|
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_CHANGE_MENTOR_SUCC, sizeof(sP_FE2CL_REP_PC_CHANGE_MENTOR_SUCC));
|
2020-09-25 05:35:27 +00:00
|
|
|
// if it's changed from computress
|
|
|
|
if (plr->mentor == 5) {
|
|
|
|
// we're warping to the past
|
|
|
|
plr->PCStyle2.iPayzoneFlag = 1;
|
|
|
|
// remove all active missions
|
|
|
|
for (int i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
|
|
|
if (plr->tasks[i] != 0)
|
2020-10-14 18:36:38 +00:00
|
|
|
MissionManager::quitTask(sock, plr->tasks[i], true);
|
2020-09-25 05:35:27 +00:00
|
|
|
}
|
2020-09-26 01:48:45 +00:00
|
|
|
|
|
|
|
// start Blossom nano mission if applicable
|
|
|
|
MissionManager::updateFusionMatter(sock, 0);
|
2020-09-25 05:35:27 +00:00
|
|
|
}
|
|
|
|
// save it on player
|
2020-09-21 19:43:53 +00:00
|
|
|
plr->mentor = pkt->iMentor;
|
2020-08-28 19:42:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-24 21:04:56 +00:00
|
|
|
#pragma region Helper methods
|
2020-08-24 22:02:07 +00:00
|
|
|
Player *PlayerManager::getPlayer(CNSocket* key) {
|
2020-09-28 18:11:13 +00:00
|
|
|
if (players.find(key) != players.end())
|
|
|
|
return players[key].plr;
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-09-28 18:11:13 +00:00
|
|
|
return nullptr;
|
2020-08-24 21:04:56 +00:00
|
|
|
}
|
2020-08-25 01:34:53 +00:00
|
|
|
|
|
|
|
WarpLocation PlayerManager::getRespawnPoint(Player *plr) {
|
|
|
|
WarpLocation best;
|
|
|
|
uint32_t curDist, bestDist = UINT32_MAX;
|
|
|
|
|
|
|
|
for (auto targ : NPCManager::RespawnPoints) {
|
|
|
|
curDist = sqrt(pow(plr->x - targ.x, 2) + pow(plr->y - targ.y, 2));
|
2020-10-18 20:43:22 +00:00
|
|
|
if (curDist < bestDist && targ.instanceID == MAPNUM(plr->instanceID)) { // only mapNum needs to match
|
2020-08-25 01:34:53 +00:00
|
|
|
best = targ;
|
|
|
|
bestDist = curDist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best;
|
|
|
|
}
|
2020-10-01 23:37:50 +00:00
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
bool PlayerManager::isAccountInUse(int accountId) {
|
|
|
|
std::map<CNSocket*, PlayerView>::iterator it;
|
2020-10-19 17:26:14 +00:00
|
|
|
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++) {
|
2020-09-01 22:37:09 +00:00
|
|
|
if (it->second.plr->accountId == accountId)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerManager::exitDuplicate(int accountId) {
|
|
|
|
std::map<CNSocket*, PlayerView>::iterator it;
|
2020-10-01 23:37:50 +00:00
|
|
|
|
|
|
|
// disconnect any duplicate players
|
|
|
|
for (it = players.begin(); it != players.end(); it++) {
|
|
|
|
if (it->second.plr->accountId == accountId) {
|
2020-09-01 22:37:09 +00:00
|
|
|
CNSocket* sock = it->first;
|
2020-10-01 23:37:50 +00:00
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_DUPLICATE, resp);
|
|
|
|
resp.iErrorCode = 0;
|
|
|
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_EXIT_DUPLICATE, sizeof(sP_FE2CL_REP_PC_EXIT_DUPLICATE));
|
2020-10-01 23:37:50 +00:00
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
sock->kill();
|
2020-10-01 23:37:50 +00:00
|
|
|
CNShardServer::_killConnection(sock);
|
2020-09-01 22:37:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-22 15:30:49 +00:00
|
|
|
|
|
|
|
void PlayerManager::setSpecialState(CNSocket* sock, CNPacketData* data) {
|
|
|
|
if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH))
|
|
|
|
return; // ignore the malformed packet
|
|
|
|
|
|
|
|
Player *plr = getPlayer(sock);
|
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
if (plr == nullptr)
|
|
|
|
return;
|
|
|
|
|
2020-09-22 15:30:49 +00:00
|
|
|
sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH* setData = (sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf;
|
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
// HACK: work around the invisible weapon bug
|
|
|
|
if (setData->iSpecialStateFlag == CN_SPECIAL_STATE_FLAG__FULL_UI)
|
|
|
|
ItemManager::updateEquips(sock, plr);
|
|
|
|
|
2020-09-22 15:30:49 +00:00
|
|
|
INITSTRUCT(sP_FE2CL_PC_SPECIAL_STATE_CHANGE, response);
|
|
|
|
|
|
|
|
plr->iSpecialState ^= setData->iSpecialStateFlag;
|
|
|
|
|
|
|
|
response.iPC_ID = setData->iPC_ID;
|
|
|
|
response.iReqSpecialStateFlag = setData->iSpecialStateFlag;
|
|
|
|
response.iSpecialState = plr->iSpecialState;
|
|
|
|
|
|
|
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC));
|
|
|
|
sendToViewable(sock, (void*)&response, P_FE2CL_PC_SPECIAL_STATE_CHANGE, sizeof(sP_FE2CL_PC_SPECIAL_STATE_CHANGE));
|
|
|
|
}
|
2020-10-02 21:00:36 +00:00
|
|
|
|
2020-10-04 23:54:08 +00:00
|
|
|
Player *PlayerManager::getPlayerFromID(int32_t iID) {
|
|
|
|
for (auto& pair : PlayerManager::players)
|
|
|
|
if (pair.second.plr->iID == iID)
|
|
|
|
return pair.second.plr;
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CNSocket *PlayerManager::getSockFromID(int32_t iID) {
|
2020-10-02 21:00:36 +00:00
|
|
|
for (auto& pair : PlayerManager::players)
|
|
|
|
if (pair.second.plr->iID == iID)
|
|
|
|
return pair.first;
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-08-24 22:02:07 +00:00
|
|
|
#pragma endregion
|