huge refactoring, chunking added

This commit is contained in:
CPunch 2020-09-17 17:45:43 -05:00
parent 001564a257
commit f4db0830ba
14 changed files with 282 additions and 214 deletions

View File

@ -46,6 +46,7 @@ CXXSRC=\
src/settings.cpp\ src/settings.cpp\
src/TransportManager.cpp\ src/TransportManager.cpp\
src/TableData.cpp\ src/TableData.cpp\
src/ChunkManager.cpp\
# headers (for timestamp purposes) # headers (for timestamp purposes)
CHDR=\ CHDR=\
@ -81,6 +82,7 @@ CXXHDR=\
src/settings.hpp\ src/settings.hpp\
src/TransportManager.hpp\ src/TransportManager.hpp\
src/TableData.hpp\ src/TableData.hpp\
src/ChunkManager.hpp\
COBJ=$(CSRC:.c=.o) COBJ=$(CSRC:.c=.o)
CXXOBJ=$(CXXSRC:.cpp=.o) CXXOBJ=$(CXXSRC:.cpp=.o)

View File

@ -23,16 +23,13 @@ void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
// send to visible players // send to visible players
for (CNSocket* otherSock : plr.viewable) { PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
}
} }
void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) { void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE)) if (data->size != sizeof(sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE))
return; // malformed packet return; // malformed packet
sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE*)data->buf; sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE*)data->buf;
PlayerView& plr = PlayerManager::players[sock];
// send to client // send to client
INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp); INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp);
@ -42,9 +39,7 @@ void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
// send to visible players // send to visible players
for (CNSocket* otherSock : plr.viewable) { PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
}
} }
void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) { void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) {
@ -63,7 +58,5 @@ void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT)); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
// send to visible players (players within render distance) // send to visible players (players within render distance)
for (CNSocket* otherSock : plr.viewable) { PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
}
} }

93
src/ChunkManager.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "ChunkManager.hpp"
#include "PlayerManager.hpp"
#include "NPCManager.hpp"
#include "settings.hpp"
std::map<std::pair<int, int>, Chunk*> ChunkManager::chunks;
void ChunkManager::init() {} // stubbed
void ChunkManager::cleanup() {
// cleans up all the allocated chunks
for (auto& pair : chunks) {
delete pair.second;
}
}
void ChunkManager::addNPC(int posX, int posY, int32_t id) {
std::pair<int, int> pos = grabChunk(posX, posY);
// 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>();
}
Chunk* chunk = chunks[pos];
chunk->NPCs.insert(id);
NPCManager::addNPC(grabChunks(pos.first, pos.second), id);
}
void ChunkManager::addPlayer(int posX, int posY, CNSocket* sock) {
std::pair<int, int> pos = grabChunk(posX, posY);
// 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>();
}
Chunk* chunk = chunks[pos];
chunk->players.insert(sock);
// TODO: update view for all players in surrounding chunks
}
std::pair<int, int> ChunkManager::grabChunk(int posX, int posY) {
return std::make_pair<int, int>(posX / (settings::PLAYERDISTANCE / 3), posY / (settings::PLAYERDISTANCE / 3));
}
std::vector<Chunk*> ChunkManager::grabChunks(int chunkX, int chunkY) {
std::vector<Chunk*> delta;
delta.reserve(9);
for (int i = -1; i < 2; i++) {
for (int z = -1; z < 2; z++) {
std::pair<int, int> pos(chunkX+i, chunkY+z);
// if chunk exists, add it to the delta
if (chunks.find(pos) != chunks.end()) {
delta.push_back(chunks[pos]);
}
}
}
return delta;
}
// returns the chunks that aren't shared (only from from)
std::vector<Chunk*> ChunkManager::getDeltaChunks(std::vector<Chunk*> from, std::vector<Chunk*> to) {
std::vector<Chunk*> delta;
for (Chunk* i : from) {
bool found = false;
// search for it in the other array
for (Chunk* z : to) {
if (i == z) {
found = true;
break;
}
}
// add it to the vector if we didn't find it!
if (!found)
delta.push_back(i);
}
return delta;
}

27
src/ChunkManager.hpp Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "CNProtocol.hpp"
#include <utility>
#include <vector>
#include <set>
#include <map>
class Chunk {
public:
std::set<CNSocket*> players;
std::set<int32_t> NPCs;
};
namespace ChunkManager {
void init();
void cleanup();
extern std::map<std::pair<int, int>, Chunk*> chunks;
void addNPC(int posX, int posY, int32_t id);
void addPlayer(int posX, int posY, CNSocket* sock);
std::pair<int, int> grabChunk(int posX, int posY);
std::vector<Chunk*> grabChunks(int chunkX, int chunkY);
std::vector<Chunk*> getDeltaChunks(std::vector<Chunk*> from, std::vector<Chunk*> to);
}

View File

@ -112,9 +112,7 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
plr.plr->iPCState = 0; plr.plr->iPCState = 0;
// send equip event to other players // send equip event to other players
for (CNSocket* otherSock : plr.viewable) { PlayerManager::sendToViewable(sock, (void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
otherSock->sendPacket((void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
}
} }
// send response // send response

View File

@ -77,8 +77,7 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
resp1->iPC_ID = plr->iID; resp1->iPC_ID = plr->iID;
// send to other players // send to other players
for (CNSocket *s : PlayerManager::players[sock].viewable) PlayerManager::sendToViewable(sock, (void*)respbuf, P_FE2CL_PC_ATTACK_NPCs, resplen);
s->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs, resplen);
} }
void MobManager::combatBegin(CNSocket *sock, CNPacketData *data) {} // stub void MobManager::combatBegin(CNSocket *sock, CNPacketData *data) {} // stub
@ -138,15 +137,12 @@ void MobManager::killMob(CNSocket *sock, Mob *mob) {
giveReward(sock); giveReward(sock);
MissionManager::mobKilled(sock, mob->appearanceData.iNPCType); MissionManager::mobKilled(sock, mob->appearanceData.iNPCType);
PlayerView& plrv = PlayerManager::players[sock];
INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt); INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt);
pkt.iNPC_ID = mob->appearanceData.iNPC_ID; pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
sock->sendPacket(&pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT)); sock->sendPacket(&pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
for (CNSocket *s : plrv.viewable) PlayerManager::sendToViewable(sock, (void*)&pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
s->sendPacket(&pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
} }
void MobManager::deadStep(Mob *mob, time_t currTime) { void MobManager::deadStep(Mob *mob, time_t currTime) {

View File

@ -27,6 +27,34 @@ void NPCManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VENDOR_BATTERY_BUY, npcVendorBuyBattery); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VENDOR_BATTERY_BUY, npcVendorBuyBattery);
} }
void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
BaseNPC* npc = NPCs[id];
// create struct
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
enterData.NPCAppearanceData = npc->appearanceData;
for (Chunk* chunk : viewableChunks) {
for (CNSocket* sock : chunk->players) {
// send to socket
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
}
}
}
void NPCManager::removeNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
// create struct
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
exitData.iNPC_ID = id;
for (Chunk* chunk : viewableChunks) {
for (CNSocket* sock : chunk->players) {
// send to socket
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
}
}
}
void NPCManager::npcVendorBuy(CNSocket* sock, CNPacketData* data) { void NPCManager::npcVendorBuy(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY)) if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY))
return; // malformed packet return; // malformed packet
@ -251,64 +279,6 @@ void NPCManager::npcVendorBuyBattery(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC));
} }
void NPCManager::updatePlayerNPCS(CNSocket* sock, PlayerView& view) {
std::list<int32_t> yesView;
std::list<int32_t> noView;
for (auto& pair : NPCs) {
int diffX = abs(view.plr->x - pair.second->appearanceData.iX);
int diffY = abs(view.plr->y - pair.second->appearanceData.iY);
if (diffX < settings::NPCDISTANCE && diffY < settings::NPCDISTANCE) {
// if it's a mob and it's dead (or otherwise not there), skip it.
if (MobManager::Mobs.find(pair.first) != MobManager::Mobs.end()) {
Mob *mob = (Mob*) pair.second;
if (mob->state == MobState::DEAD || mob->state == MobState::INACTIVE)
continue;
}
yesView.push_back(pair.first);
}
else {
noView.push_back(pair.first);
}
}
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
std::list<int32_t>::iterator i = view.viewableNPCs.begin();
while (i != view.viewableNPCs.end()) {
int32_t id = *i;
if (std::find(noView.begin(), noView.end(), id) != noView.end()) {
// it shouldn't be visible, send NPC_EXIT
exitData.iNPC_ID = id;
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
// remove from view
view.viewableNPCs.erase(i++);
}
else {
i++;
}
}
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
for (int32_t id : yesView) {
if (std::find(view.viewableNPCs.begin(), view.viewableNPCs.end(), id) == view.viewableNPCs.end()) {
// needs to be added to viewableNPCs! send NPC_ENTER
enterData.NPCAppearanceData = NPCs[id]->appearanceData;
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
// add to viewable
view.viewableNPCs.push_back(id);
}
}
PlayerManager::players[sock].viewableNPCs = view.viewableNPCs;
}
void NPCManager::npcBarkHandler(CNSocket* sock, CNPacketData* data) {} // stubbed for now void NPCManager::npcBarkHandler(CNSocket* sock, CNPacketData* data) {} // stubbed for now
void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) { void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) {
@ -330,9 +300,7 @@ void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) {
resp.NPCAppearanceData.iY = plr->y; resp.NPCAppearanceData.iY = plr->y;
resp.NPCAppearanceData.iZ = plr->z; resp.NPCAppearanceData.iZ = plr->z;
sock->sendPacket((void*)&resp, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER)); ChunkManager::addNPC(plr->x, plr->y, resp.NPCAppearanceData.iNPC_ID);
for (CNSocket *s : PlayerManager::players[sock].viewable)
s->sendPacket((void*)&resp, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
} }
void NPCManager::npcWarpHandler(CNSocket* sock, CNPacketData* data) { void NPCManager::npcWarpHandler(CNSocket* sock, CNPacketData* data) {
@ -353,8 +321,8 @@ void NPCManager::npcWarpHandler(CNSocket* sock, CNPacketData* data) {
resp.iZ = Warps[warpNpc->iWarpID].z; resp.iZ = Warps[warpNpc->iWarpID].z;
// force player & NPC reload // force player & NPC reload
plrv.viewable.clear(); plrv.currentChunks.clear();
plrv.viewableNPCs.clear(); plrv.chunkPos = std::make_pair<int, int>(0, 0);
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC));
} }

View File

@ -20,6 +20,9 @@ namespace NPCManager {
extern std::vector<WarpLocation> RespawnPoints; extern std::vector<WarpLocation> RespawnPoints;
void init(); void init();
void addNPC(std::vector<Chunk*> viewableChunks, int32_t);
void removeNPC(std::vector<Chunk*> viewableChunks, int32_t);
void npcBarkHandler(CNSocket* sock, CNPacketData* data); void npcBarkHandler(CNSocket* sock, CNPacketData* data);
void npcSummonHandler(CNSocket* sock, CNPacketData* data); void npcSummonHandler(CNSocket* sock, CNPacketData* data);
void npcWarpHandler(CNSocket* sock, CNPacketData* data); void npcWarpHandler(CNSocket* sock, CNPacketData* data);
@ -30,6 +33,4 @@ namespace NPCManager {
void npcVendorSell(CNSocket* sock, CNPacketData* data); void npcVendorSell(CNSocket* sock, CNPacketData* data);
void npcVendorBuyback(CNSocket* sock, CNPacketData* data); void npcVendorBuyback(CNSocket* sock, CNPacketData* data);
void npcVendorBuyBattery(CNSocket* sock, CNPacketData* data); void npcVendorBuyBattery(CNSocket* sock, CNPacketData* data);
void updatePlayerNPCS(CNSocket* sock, PlayerView& plr);
} }

View File

@ -169,8 +169,7 @@ void NanoManager::addNano(CNSocket* sock, int16_t nanoId, int16_t slot) {
resp2.iPC_Level = level; resp2.iPC_Level = level;
// Update other players' perception of the player's level // Update other players' perception of the player's level
for (CNSocket* s : PlayerManager::players[sock].viewable) PlayerManager::sendToViewable(sock, (void*)&resp2, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL));
s->sendPacket((void*)&resp2, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL));
} }
void NanoManager::summonNano(CNSocket *sock, int slot) { void NanoManager::summonNano(CNSocket *sock, int slot) {
@ -196,8 +195,7 @@ void NanoManager::summonNano(CNSocket *sock, int slot) {
else else
pkt1.Nano = plr->Nanos[nanoId]; pkt1.Nano = plr->Nanos[nanoId];
for (CNSocket* s : PlayerManager::players[sock].viewable) PlayerManager::sendToViewable(sock, (void*)&pkt1, P_FE2CL_NANO_ACTIVE, sizeof(sP_FE2CL_NANO_ACTIVE));
s->sendPacket((void*)&pkt1, P_FE2CL_NANO_ACTIVE, sizeof(sP_FE2CL_NANO_ACTIVE));
// update player // update player
plr->activeNano = nanoId; plr->activeNano = nanoId;

View File

@ -43,7 +43,8 @@ void PlayerManager::addPlayer(CNSocket* key, Player plr) {
memcpy(p, &plr, sizeof(Player)); memcpy(p, &plr, sizeof(Player));
players[key] = PlayerView(); players[key] = PlayerView();
players[key].viewable = std::list<CNSocket*>(); players[key].chunkPos = std::make_pair<int, int>(0, 0);
players[key].currentChunks = std::vector<Chunk*>();
players[key].plr = p; players[key].plr = p;
players[key].lastHeartbeat = 0; players[key].lastHeartbeat = 0;
@ -54,88 +55,63 @@ void PlayerManager::addPlayer(CNSocket* key, Player plr) {
} }
void PlayerManager::removePlayer(CNSocket* key) { void PlayerManager::removePlayer(CNSocket* key) {
PlayerView cachedView = players[key]; PlayerView& view = players[key];
// if players have them in their viewable lists, remove it
for (auto& pair : players) {
if (pair.first == key)
continue;
PlayerView& otherPlayer = pair.second;
otherPlayer.viewable.remove(key); // gone
std::cout << "PlayerId = " << otherPlayer.plr->iID << " removed from " << otherPlayer.plr->iID << "'s viewable list" << std::endl;
// now send PC_EXIT packet
INITSTRUCT(sP_FE2CL_PC_EXIT, exitPacket); INITSTRUCT(sP_FE2CL_PC_EXIT, exitPacket);
exitPacket.iID = players[key].plr->iID; exitPacket.iID = players[key].plr->iID;
pair.first->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT)); // remove players from all chunks
} removePlayerFromChunks(view.currentChunks, key);
std::cout << U16toU8(cachedView.plr->PCStyle.szFirstName) << " " << U16toU8(cachedView.plr->PCStyle.szLastName) << " (PlayerId = " << key->plr->iID << ") has left!" << std::endl; // remove from chunk
if (ChunkManager::chunks.find(view.chunkPos) != ChunkManager::chunks.end())
ChunkManager::chunks[view.chunkPos]->players.erase(key);
std::cout << U16toU8(view.plr->PCStyle.szFirstName) << " " << U16toU8(view.plr->PCStyle.szLastName) << " (PlayerId = " << view.plr->iID << ") has left!" << std::endl;
key->plr = nullptr; key->plr = nullptr;
delete cachedView.plr; delete view.plr;
players.erase(key); players.erase(key);
std::cout << players.size() << " players" << std::endl; std::cout << players.size() << " players" << std::endl;
} }
void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle) { void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
players[sock].plr->angle = angle; INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
updatePlayerPosition(sock, X, Y, Z); INITSTRUCT(sP_FE2CL_PC_EXIT, exitPlayer);
// for chunks that need the player to be removed from
for (Chunk* chunk : chunks) {
// remove NPCs
for (int32_t id : chunk->NPCs) {
exitData.iNPC_ID = id;
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
}
// 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));
}
}
} }
void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
players[sock].plr->x = X;
players[sock].plr->y = Y;
players[sock].plr->z = Z;
std::vector<CNSocket*> noView;
std::vector<CNSocket*> yesView;
// TODO: oh god this is sooooo perfomance heavy the more players you have
for (auto pair : players) {
if (pair.first == sock)
continue; // ignore our own connection
int diffX = abs(pair.second.plr->x - X); // the map is like a grid, X and Y are your position on the map, Z is the height. very different from other games...
int diffY = abs(pair.second.plr->y - Y);
if (diffX < settings::PLAYERDISTANCE && diffY < settings::PLAYERDISTANCE) {
yesView.push_back(pair.first);
}
else {
noView.push_back(pair.first);
}
}
INITSTRUCT(sP_FE2CL_PC_EXIT, exitPacket);
std::list<CNSocket*>::iterator i = players[sock].viewable.begin();
while (i != players[sock].viewable.end()) {
CNSocket* otherSock = *i;
if (std::find(noView.begin(), noView.end(), otherSock) != noView.end()) {
// sock shouldn't be visible, send PC_EXIT packet
exitPacket.iID = players[sock].plr->iID;
otherSock->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
exitPacket.iID = players[otherSock].plr->iID;
sock->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
// remove them from the viewable list
players[sock].viewable.erase(i++);
players[otherSock].viewable.remove(sock);
continue;
}
++i;
}
void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer); INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer);
for (CNSocket* otherSock : yesView) {
if (std::find(players[sock].viewable.begin(), players[sock].viewable.end(), otherSock) == players[sock].viewable.end()) {
// this needs to be added to the viewable players, send PC_ENTER
for (Chunk* chunk : chunks) {
// add npcs
for (int32_t id : chunk->NPCs) {
enterData.NPCAppearanceData = NPCManager::NPCs[id]->appearanceData;
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
}
// add players
for (CNSocket* otherSock : chunk->players) {
Player *otherPlr = players[otherSock].plr; Player *otherPlr = players[otherSock].plr;
Player *plr = players[sock].plr; Player *plr = players[sock].plr;
@ -166,28 +142,43 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr->Equip, sizeof(sItemBase) * AEQUIP_COUNT); memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW)); sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
players[sock].viewable.push_back(otherSock);
players[otherSock].viewable.push_back(sock);
} }
} }
NPCManager::updatePlayerNPCS(sock, players[sock]);
} }
void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle) {
players[sock].plr->angle = angle;
updatePlayerPosition(sock, X, Y, Z);
}
std::list<CNSocket*> PlayerManager::getNearbyPlayers(int x, int y, int dist) { void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
std::list<CNSocket*> plrs; PlayerView& view = players[sock];
view.plr->x = X;
view.plr->y = Y;
view.plr->z = Z;
for (auto pair : players) { std::pair<int, int> newPos = ChunkManager::grabChunk(X, Y);
int diffX = abs(pair.second.plr->x - x);
int diffY = abs(pair.second.plr->x - x);
if (diffX < dist && diffY < dist) // nothing to be done
plrs.push_back(pair.first); if (newPos == view.chunkPos)
} return;
return plrs; // add player to chunk
std::vector<Chunk*> allChunks = ChunkManager::grabChunks(newPos.first, newPos.second);
// first, remove all the old npcs & players from the old chunks
removePlayerFromChunks(ChunkManager::getDeltaChunks(view.currentChunks, allChunks), sock);
// now, add all the new npcs & players!
addPlayerToChunks(ChunkManager::getDeltaChunks(allChunks, view.currentChunks), sock);
// remove us from that old stinky chunk (+ a sanity check)
if (ChunkManager::chunks.find(view.chunkPos) != ChunkManager::chunks.end())
ChunkManager::chunks[view.chunkPos]->players.erase(sock);
ChunkManager::addPlayer(X, Y, sock); // takes care of adding the player to the chunk if it exists or not
view.chunkPos = newPos;
view.currentChunks = allChunks;
} }
void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
@ -267,6 +258,17 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
addPlayer(sock, plr); addPlayer(sock, plr);
} }
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;
otherSock->sendPacket(buf, type, size);
}
}
}
void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_LOADING_COMPLETE)) if (data->size != sizeof(sP_CL2FE_REQ_PC_LOADING_COMPLETE))
return; // ignore the malformed packet return; // ignore the malformed packet
@ -315,9 +317,7 @@ void PlayerManager::movePlayer(CNSocket* sock, CNPacketData* data) {
moveResponse.iCliTime = moveData->iCliTime; // maybe don't send this??? seems unneeded... moveResponse.iCliTime = moveData->iCliTime; // maybe don't send this??? seems unneeded...
moveResponse.iSvrTime = tm; moveResponse.iSvrTime = tm;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&moveResponse, P_FE2CL_PC_MOVE, sizeof(sP_FE2CL_PC_MOVE));
otherSock->sendPacket((void*)&moveResponse, P_FE2CL_PC_MOVE, sizeof(sP_FE2CL_PC_MOVE));
}
} }
void PlayerManager::stopPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::stopPlayer(CNSocket* sock, CNPacketData* data) {
@ -340,9 +340,7 @@ void PlayerManager::stopPlayer(CNSocket* sock, CNPacketData* data) {
stopResponse.iCliTime = stopData->iCliTime; // maybe don't send this??? seems unneeded... stopResponse.iCliTime = stopData->iCliTime; // maybe don't send this??? seems unneeded...
stopResponse.iSvrTime = tm; stopResponse.iSvrTime = tm;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&stopResponse, P_FE2CL_PC_STOP, sizeof(sP_FE2CL_PC_STOP));
otherSock->sendPacket((void*)&stopResponse, P_FE2CL_PC_STOP, sizeof(sP_FE2CL_PC_STOP));
}
} }
void PlayerManager::jumpPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::jumpPlayer(CNSocket* sock, CNPacketData* data) {
@ -371,9 +369,7 @@ void PlayerManager::jumpPlayer(CNSocket* sock, CNPacketData* data) {
jumpResponse.iCliTime = jumpData->iCliTime; // maybe don't send this??? seems unneeded... jumpResponse.iCliTime = jumpData->iCliTime; // maybe don't send this??? seems unneeded...
jumpResponse.iSvrTime = tm; jumpResponse.iSvrTime = tm;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&jumpResponse, P_FE2CL_PC_JUMP, sizeof(sP_FE2CL_PC_JUMP));
otherSock->sendPacket((void*)&jumpResponse, P_FE2CL_PC_JUMP, sizeof(sP_FE2CL_PC_JUMP));
}
} }
void PlayerManager::jumppadPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::jumppadPlayer(CNSocket* sock, CNPacketData* data) {
@ -400,9 +396,7 @@ void PlayerManager::jumppadPlayer(CNSocket* sock, CNPacketData* data) {
jumppadResponse.iCliTime = jumppadData->iCliTime; jumppadResponse.iCliTime = jumppadData->iCliTime;
jumppadResponse.iSvrTime = tm; jumppadResponse.iSvrTime = tm;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&jumppadResponse, P_FE2CL_PC_JUMPPAD, sizeof(sP_FE2CL_PC_JUMPPAD));
otherSock->sendPacket((void*)&jumppadResponse, P_FE2CL_PC_JUMPPAD, sizeof(sP_FE2CL_PC_JUMPPAD));
}
} }
void PlayerManager::launchPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::launchPlayer(CNSocket* sock, CNPacketData* data) {
@ -430,9 +424,7 @@ void PlayerManager::launchPlayer(CNSocket* sock, CNPacketData* data) {
launchResponse.iCliTime = launchData->iCliTime; launchResponse.iCliTime = launchData->iCliTime;
launchResponse.iSvrTime = tm; launchResponse.iSvrTime = tm;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&launchResponse, P_FE2CL_PC_LAUNCHER, sizeof(sP_FE2CL_PC_LAUNCHER));
otherSock->sendPacket((void*)&launchResponse, P_FE2CL_PC_LAUNCHER, sizeof(sP_FE2CL_PC_LAUNCHER));
}
} }
void PlayerManager::ziplinePlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::ziplinePlayer(CNSocket* sock, CNPacketData* data) {
@ -467,9 +459,7 @@ void PlayerManager::ziplinePlayer(CNSocket* sock, CNPacketData* data) {
ziplineResponse.iRollMax = ziplineData->iRollMax; ziplineResponse.iRollMax = ziplineData->iRollMax;
ziplineResponse.iRoll = ziplineData->iRoll; ziplineResponse.iRoll = ziplineData->iRoll;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&ziplineResponse, P_FE2CL_PC_ZIPLINE, sizeof(sP_FE2CL_PC_ZIPLINE));
otherSock->sendPacket((void*)&ziplineResponse, P_FE2CL_PC_ZIPLINE, sizeof(sP_FE2CL_PC_ZIPLINE));
}
} }
void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
@ -501,9 +491,7 @@ void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
platResponse.cKeyValue = platformData->cKeyValue; platResponse.cKeyValue = platformData->cKeyValue;
platResponse.iPlatformID = platformData->iPlatformID; platResponse.iPlatformID = platformData->iPlatformID;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM));
otherSock->sendPacket((void*)&platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM));
}
} }
void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) {
@ -531,9 +519,7 @@ void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) {
slopeResponse.cKeyValue = slopeData->cKeyValue; slopeResponse.cKeyValue = slopeData->cKeyValue;
slopeResponse.iSlopeID = slopeData->iSlopeID; slopeResponse.iSlopeID = slopeData->iSlopeID;
for (CNSocket* otherSock : players[sock].viewable) { sendToViewable(sock, (void*)&slopeResponse, P_FE2CL_PC_SLOPE, sizeof(sP_FE2CL_PC_SLOPE));
otherSock->sendPacket((void*)&slopeResponse, P_FE2CL_PC_SLOPE, sizeof(sP_FE2CL_PC_SLOPE));
}
} }
void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
@ -556,8 +542,8 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
response.iZ = plrv.plr->z = gotoData->iToZ; response.iZ = plrv.plr->z = gotoData->iToZ;
// force player & NPC reload // force player & NPC reload
plrv.viewable.clear(); plrv.chunkPos = std::make_pair<int, int>(0, 0);
plrv.viewableNPCs.clear(); plrv.currentChunks.clear();
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC)); sock->sendPacket((void*)&response, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC));
} }
@ -668,12 +654,10 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
resp2.PCRegenDataForOtherPC.iAngle = plr->angle; resp2.PCRegenDataForOtherPC.iAngle = plr->angle;
resp2.PCRegenDataForOtherPC.Nano = plr->Nanos[plr->activeNano]; resp2.PCRegenDataForOtherPC.Nano = plr->Nanos[plr->activeNano];
for (CNSocket *s : players[sock].viewable) sendToViewable(sock, (void*)&resp2, P_FE2CL_PC_REGEN, sizeof(sP_FE2CL_PC_REGEN));
s->sendPacket((void*)&resp2, P_FE2CL_PC_REGEN, sizeof(sP_FE2CL_PC_REGEN));
} }
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) { void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
PlayerView& plr = PlayerManager::players[sock]; PlayerView& plr = PlayerManager::players[sock];
if (plr.plr->Equip[8].iID > 0) { if (plr.plr->Equip[8].iID > 0) {
@ -686,10 +670,11 @@ void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
response2.iPC_ID = plr.plr->iID; response2.iPC_ID = plr.plr->iID;
response2.iState = 8; response2.iState = 8;
for (CNSocket* otherSock : plr.viewable) { 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)); otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
} }
}
} else { } else {
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_FAIL, response); 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)); sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_FAIL, sizeof(sP_FE2CL_PC_VEHICLE_ON_FAIL));
@ -709,9 +694,7 @@ void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
response2.iPC_ID = plr.plr->iID; response2.iPC_ID = plr.plr->iID;
response2.iState = 0; response2.iState = 0;
for (CNSocket* otherSock : plr.viewable) { sendToViewable(sock, (void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
}
} }
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {

View File

@ -4,15 +4,17 @@
#include "CNProtocol.hpp" #include "CNProtocol.hpp"
#include "CNStructs.hpp" #include "CNStructs.hpp"
#include "CNShardServer.hpp" #include "CNShardServer.hpp"
#include "ChunkManager.hpp"
#include <utility>
#include <map> #include <map>
#include <list> #include <list>
struct WarpLocation; struct WarpLocation;
struct PlayerView { struct PlayerView {
std::list<CNSocket*> viewable; std::pair<int, int> chunkPos;
std::list<int32_t> viewableNPCs; std::vector<Chunk*> currentChunks;
Player *plr; Player *plr;
time_t lastHeartbeat; time_t lastHeartbeat;
}; };
@ -25,9 +27,13 @@ namespace PlayerManager {
void addPlayer(CNSocket* key, Player plr); void addPlayer(CNSocket* key, Player plr);
void removePlayer(CNSocket* key); void removePlayer(CNSocket* key);
void removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket* sock);
void addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock);
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z); void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z);
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle); void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, int angle);
std::list<CNSocket*> getNearbyPlayers(int X, int Y, int dist);
void sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size);
void enterPlayer(CNSocket* sock, CNPacketData* data); void enterPlayer(CNSocket* sock, CNPacketData* data);
void loadPlayer(CNSocket* sock, CNPacketData* data); void loadPlayer(CNSocket* sock, CNPacketData* data);

View File

@ -5,6 +5,7 @@
#include "settings.hpp" #include "settings.hpp"
#include "MissionManager.hpp" #include "MissionManager.hpp"
#include "MobManager.hpp" #include "MobManager.hpp"
#include "ChunkManager.hpp"
#include "contrib/JSON.hpp" #include "contrib/JSON.hpp"
@ -27,9 +28,10 @@ void TableData::init() {
// Temporary fix, IDs will be pulled from json later // Temporary fix, IDs will be pulled from json later
tmp->appearanceData.iNPC_ID = i; tmp->appearanceData.iNPC_ID = i;
i++;
NPCManager::NPCs[tmp->appearanceData.iNPC_ID] = tmp; NPCManager::NPCs[i] = tmp;
ChunkManager::addNPC(npc["x"], npc["y"], i);
i++;
if (npc["id"] == 641 || npc["id"] == 642) if (npc["id"] == 641 || npc["id"] == 642)
NPCManager::RespawnPoints.push_back({ npc["x"], npc["y"], ((int)npc["z"]) + RESURRECT_HEIGHT }); NPCManager::RespawnPoints.push_back({ npc["x"], npc["y"], ((int)npc["z"]) + RESURRECT_HEIGHT });
@ -153,6 +155,7 @@ void TableData::init() {
NPCManager::NPCs[i] = tmp; NPCManager::NPCs[i] = tmp;
MobManager::Mobs[i] = (Mob*)NPCManager::NPCs[i]; MobManager::Mobs[i] = (Mob*)NPCManager::NPCs[i];
ChunkManager::addNPC(npc["iX"], npc["iY"], i);
i++; i++;
} }

View File

@ -137,8 +137,8 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data)
* same map tile you were already in, but we might as well force an NPC reload. * same map tile you were already in, but we might as well force an NPC reload.
*/ */
PlayerView& plrv = PlayerManager::players[sock]; PlayerView& plrv = PlayerManager::players[sock];
plrv.viewable.clear(); plrv.currentChunks.clear();
plrv.viewableNPCs.clear(); plrv.chunkPos = std::make_pair<int, int>(0, 0);
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC));
} }

View File

@ -10,6 +10,7 @@
#include "TransportManager.hpp" #include "TransportManager.hpp"
#include "Database.hpp" #include "Database.hpp"
#include "TableData.hpp" #include "TableData.hpp"
#include "ChunkManager.hpp"
#include "settings.hpp" #include "settings.hpp"
@ -48,9 +49,8 @@ void terminate(int arg) {
shardThread->join(); shardThread->join();
} }
#if defined(__SANITIZE_ADDRESS__)
TableData::cleanup(); TableData::cleanup();
#endif ChunkManager::cleanup();
exit(0); exit(0);
} }