This commit is contained in:
FinnHornhoover 2020-08-25 20:28:05 +03:00
commit 09b7bd947f
20 changed files with 393 additions and 185 deletions

4
.gitignore vendored
View File

@ -8,5 +8,5 @@ tags
CMakeFiles/
CMakeCache.txt
build/
.vs/
.idea/
.vs/
.idea/

9
.vimrc Normal file
View File

@ -0,0 +1,9 @@
" vim configuration file
" you will need to put 'set exrc' and 'set secure' into your main .vimrc file,
" in which case this file will be loaded automatically, but *only* if you
" start vim in this dir, or you can just load it directly with ':so .vimrc'
" every time.
set tabstop=4
set shiftwidth=4
set expandtab

View File

@ -25,6 +25,7 @@ SRC=\
src/CNStructs.cpp\
src/Defines.cpp\
src/main.cpp\
src/MissionManager.cpp\
src/NanoManager.cpp\
src/ItemManager.cpp\
src/NPCManager.cpp\
@ -43,6 +44,7 @@ HDR=\
src/Defines.hpp\
src/contrib/INIReader.hpp\
src/contrib/JSON.hpp\
src/MissionManager.hpp\
src/NanoManager.hpp\
src/ItemManager.hpp\
src/NPCManager.hpp\

View File

@ -96,7 +96,18 @@ It's what's called a landwalker; enough of the server has been implemented to al
To make your landwalking experience more pleasant, you can make use of a few admin commands to get around easier:
### Movement commands
* A `/speed` of around 2400 or 3000 is nice.
* A `/jump` of about 50 will send you soaring
* [This map](res/dong_number_map.png) (credit to Danny O) is useful for `/warp` coordinates.
* `/goto` is useful for more precise teleportation (ie. for getting into Infected Zones, etc.).
### Item commands
* /itemN [type] [itemId] [amount]
(Refer to the [item list](https://docs.google.com/spreadsheets/d/1mpoJ9iTHl_xLI4wQ_9UvIDYNcsDYscdkyaGizs43TCg/))
### Nano commands
* /nano [id] (1-36)
* /nano_equip [id] (1-36) [slot] (0-2)
* /nano_unequip [slot] (0-2)
* /nano_active [slot] (0-2)

View File

@ -16,7 +16,6 @@ randomcharacters=true
# Shard Server configuration
[shard]
port=8002
# you'll want to change this one
ip=127.0.0.1
# distance at which other players and NPCs become visible
view=20000

View File

@ -208,11 +208,11 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
resp.sPC_Style2.iAppearanceFlag = 1;
resp.sPC_Style2.iTutorialFlag = 1;
resp.sPC_Style2.iPayzoneFlag = 1;
resp.iLevel = 1;
resp.iLevel = 36;
resp.sOn_Item = character->sOn_Item;
loginSessions[sock].characters[UID] = Player();
loginSessions[sock].characters[UID].level = 1;
loginSessions[sock].characters[UID].level = 36;
loginSessions[sock].characters[UID].FEKey = sock->getFEKey();
loginSessions[sock].characters[UID].PCStyle = character->PCStyle;
loginSessions[sock].characters[UID].PCStyle2.iAppearanceFlag = 1;
@ -275,7 +275,6 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
CNSharedData::setPlayer(resp.iEnterSerialKey, loginSessions[sock].characters[loginSessions[sock].selectedChar]);
sock->sendPacket((void*)&resp, P_LS2CL_REP_SHARD_SELECT_SUCC, sizeof(sP_LS2CL_REP_SHARD_SELECT_SUCC));
sock->kill(); // client should connect to the Shard server now
break;
}
default:

View File

@ -1,10 +1,6 @@
#include "CNProtocol.hpp"
#include "CNStructs.hpp"
#ifdef _MSC_VER
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
// ========================================================[[ CNSocketEncryption ]]========================================================
// literally C/P from the client and converted to C++ (does some byte swapping /shrug)
@ -78,11 +74,11 @@ bool CNSocket::sendData(uint8_t* data, int size) {
while (sentBytes < size) {
int sent = send(sock, (buffer_t*)(data + sentBytes), size - sentBytes, 0); // no flags defined
if (SOCKETERROR(sent)) {
if (errno == EAGAIN && maxTries > 0) {
if (OF_ERRNO == OF_EWOULD && maxTries > 0) {
maxTries--;
continue; // try again
}
std::cout << "[FATAL] SOCKET ERROR: " << errno << std::endl;
std::cout << "[FATAL] SOCKET ERROR: " << OF_ERRNO << std::endl;
return false; // error occured while sending bytes
}
sentBytes += sent;
@ -122,7 +118,7 @@ void CNSocket::kill() {
#endif
}
// we don't own buf
// we don't own buf, TODO: queue packets up to send in step()
void CNSocket::sendPacket(void* buf, uint32_t type, size_t size) {
if (!alive)
return;
@ -167,6 +163,8 @@ void CNSocket::setActiveKey(ACTIVEKEY key) {
}
void CNSocket::step() {
// read step
if (readSize <= 0) {
// we aren't reading a packet yet, try to start looking for one
int recved = recv(sock, (buffer_t*)readBuffer, sizeof(int32_t), 0);
@ -181,7 +179,7 @@ void CNSocket::step() {
// we'll just leave bufferIndex at 0 since we already have the packet size, it's safe to overwrite those bytes
activelyReading = true;
} else if (errno != EAGAIN) {
} else if (OF_ERRNO != OF_EWOULD) {
// serious socket issue, disconnect connection
kill();
return;
@ -193,7 +191,7 @@ void CNSocket::step() {
int recved = recv(sock, (buffer_t*)(readBuffer + readBufferIndex), readSize - readBufferIndex, 0);
if (!SOCKETERROR(recved))
readBufferIndex += recved;
else if (errno != EAGAIN) {
else if (OF_ERRNO != OF_EWOULD) {
// serious socket issue, disconnect connection
kill();
return;
@ -270,12 +268,8 @@ void CNServer::init() {
}
}
CNServer::CNServer() {
lastTimer = getTime();
};
CNServer::CNServer(uint16_t p): port(p) {
lastTimer = getTime();
}
CNServer::CNServer() {};
CNServer::CNServer(uint16_t p): port(p) {}
void CNServer::start() {
std::cout << "Starting server at *:" << port << std::endl;
@ -328,10 +322,7 @@ void CNServer::start() {
}
}
if (getTime() - lastTimer > 2000) { // every 2 seconds call the onTimer method
onTimer();
lastTimer = getTime();
}
onStep();
#ifdef _WIN32
Sleep(0);
@ -385,4 +376,4 @@ void CNServer::printPacket(CNPacketData *data, int type) {
void CNServer::newConnection(CNSocket* cns) {} // stubbed
void CNServer::killConnection(CNSocket* cns) {} // stubbed
void CNServer::onTimer() {} // stubbed
void CNServer::onStep() {} // stubbed

View File

@ -7,14 +7,16 @@
#include <stdio.h>
#include <stdint.h>
#ifdef _WIN32
// windows (UNTESTED)
// windows
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t;
//#define errno WSAGetLastError()
#define OF_ERRNO WSAGetLastError()
#define OF_EWOULD WSAEWOULDBLOCK
#define SOCKETINVALID(x) (x == INVALID_SOCKET)
#define SOCKETERROR(x) (x == SOCKET_ERROR)
#else
@ -27,6 +29,8 @@
typedef int SOCKET;
typedef void buffer_t;
#define OF_ERRNO errno
#define OF_EWOULD EWOULDBLOCK
#define SOCKETINVALID(x) (x < 0)
#define SOCKETERROR(x) (x == -1)
#endif
@ -108,6 +112,7 @@ private:
ACTIVEKEY activeKey;
bool sendData(uint8_t* data, int size);
int recvData(buffer_t* data, int size);
public:
SOCKET sock;
@ -127,6 +132,20 @@ public:
bool isAlive();
};
class CNServer;
typedef void (*TimerHandler)(CNServer* serv, uint64_t time);
// timer struct
struct TimerEvent {
TimerHandler handlr;
uint64_t delta; // time to be added to the current time on reset
uint64_t scheduledEvent; // time to call handlr()
TimerEvent(TimerHandler h, uint64_t d): handlr(h), delta(d) {
scheduledEvent = 0;
}
};
// in charge of accepting new connections and making sure each connection is kept alive
class CNServer {
protected:
@ -140,7 +159,6 @@ protected:
void init();
bool active = true;
uint64_t lastTimer;
public:
PacketHandler pHandler;
@ -153,5 +171,5 @@ public:
static void printPacket(CNPacketData *data, int type);
virtual void newConnection(CNSocket* cns);
virtual void killConnection(CNSocket* cns);
virtual void onTimer(); // called every 2 seconds
virtual void onStep(); // called every 2 seconds
};

View File

@ -10,10 +10,12 @@
#include <cstdlib>
std::map<uint32_t, PacketHandler> CNShardServer::ShardPackets;
std::list<TimerEvent> CNShardServer::Timers;
CNShardServer::CNShardServer(uint16_t p) {
port = p;
pHandler = &CNShardServer::handlePacket;
REGISTER_SHARD_TIMER(keepAliveTimer, 2000);
init();
}
@ -26,21 +28,7 @@ void CNShardServer::handlePacket(CNSocket* sock, CNPacketData* data) {
std::cerr << "OpenFusion: SHARD UNIMPLM ERR. PacketType: " << Defines::p2str(CL2FE, data->type) << " (" << data->type << ")" << std::endl;
}
void CNShardServer::newConnection(CNSocket* cns) {
cns->setActiveKey(SOCKETKEY_E); // by default they accept keys encrypted with the default key
}
void CNShardServer::killConnection(CNSocket* cns) {
// remove from CNSharedData
Player cachedPlr = PlayerManager::getPlayer(cns);
PlayerManager::removePlayer(cns);
CNSharedData::erasePlayer(cachedPlr.SerialKey);
}
void CNShardServer::onTimer() {
uint64_t currTime = getTime();
void CNShardServer::keepAliveTimer(CNServer* serv, uint64_t currTime) {
auto cachedPlayers = PlayerManager::players;
for (auto pair : cachedPlayers) {
@ -54,3 +42,37 @@ void CNShardServer::onTimer() {
pair.first->sendPacket((void*)&data, P_FE2CL_REQ_LIVE_CHECK, sizeof(sP_FE2CL_REQ_LIVE_CHECK));
}
}
void CNShardServer::newConnection(CNSocket* cns) {
cns->setActiveKey(SOCKETKEY_E); // by default they accept keys encrypted with the default key
}
void CNShardServer::killConnection(CNSocket* cns) {
// check if the player ever sent a REQ_PC_ENTER
if (PlayerManager::players.find(cns) == PlayerManager::players.end())
return;
// remove from CNSharedData
int64_t key = PlayerManager::getPlayer(cns)->SerialKey;
PlayerManager::removePlayer(cns);
CNSharedData::erasePlayer(key);
}
void CNShardServer::onStep() {
uint64_t currTime = getTime();
for (TimerEvent& event : Timers) {
if (event.scheduledEvent == 0) {
// event hasn't been queued yet, go ahead and do that
event.scheduledEvent = currTime + event.delta;
continue;
}
if (event.scheduledEvent < currTime) {
// timer needs to be called
event.handlr(this, currTime);
event.scheduledEvent = currTime + event.delta;
}
}
}

View File

@ -6,17 +6,21 @@
#include <map>
#define REGISTER_SHARD_PACKET(pactype, handlr) CNShardServer::ShardPackets[pactype] = handlr;
#define REGISTER_SHARD_TIMER(handlr, delta) CNShardServer::Timers.push_back(TimerEvent(handlr, delta));
class CNShardServer : public CNServer {
private:
static void handlePacket(CNSocket* sock, CNPacketData* data);
static void keepAliveTimer(CNServer*, uint64_t);
public:
static std::map<uint32_t, PacketHandler> ShardPackets;
static std::list<TimerEvent> Timers;
CNShardServer(uint16_t p);
void newConnection(CNSocket* cns);
void killConnection(CNSocket* cns);
void onTimer();
void onStep();
};

View File

@ -18,7 +18,7 @@ void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) {
// send to client
INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp);
memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat));
resp.iPC_ID = plr.plr.iID;
resp.iPC_ID = plr.plr->iID;
resp.iEmoteCode = chat->iEmoteCode;
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
@ -36,7 +36,7 @@ void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) {
// send to client
INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp);
memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat));
resp.iPC_ID = PlayerManager::players[sock].plr.iID;
resp.iPC_ID = PlayerManager::players[sock].plr->iID;
resp.iEmoteCode = chat->iEmoteCode;
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
@ -57,7 +57,7 @@ void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) {
// send to client
INITSTRUCT(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, resp);
resp.iEmoteCode = emote->iEmoteCode;
resp.iID_From = plr.plr.iID;
resp.iID_From = plr.plr->iID;
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)

View File

@ -16,39 +16,56 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_ITEM_MOVE* itemmove = (sP_CL2FE_REQ_ITEM_MOVE*)data->buf;
INITSTRUCT(sP_FE2CL_PC_ITEM_MOVE_SUCC, resp);
PlayerView& plr = PlayerManager::players[sock];
if (itemmove->eFrom == 0 && itemmove->eTo == 0) {
// this packet should never happen, tell the client to do nothing and do nothing ourself
resp.eTo = itemmove->eFrom;
resp.iToSlotNum = itemmove->iFromSlotNum;
resp.ToSlotItem = plr.plr->Equip[itemmove->iToSlotNum];
resp.eFrom = itemmove->eTo;
resp.iFromSlotNum = itemmove->iToSlotNum;
resp.FromSlotItem = plr.plr->Equip[itemmove->iFromSlotNum];
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC, sizeof(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC));
return;
}
if (itemmove->iToSlotNum > AINVEN_COUNT)
return; // sanity checks
sItemBase fromItem;
sItemBase toItem;
// eFrom 0 means from equip
if (itemmove->eFrom == 0) {
// unequiping an item
fromItem = plr.plr.Equip[itemmove->iFromSlotNum];
fromItem = plr.plr->Equip[itemmove->iFromSlotNum];
} else {
fromItem = plr.plr.Inven[itemmove->iFromSlotNum];
fromItem = plr.plr->Inven[itemmove->iFromSlotNum];
}
// eTo 0 means to equip
if (itemmove->eTo == 0) {
// equiping an item
toItem = plr.plr.Equip[itemmove->iToSlotNum];
plr.plr.Equip[itemmove->iToSlotNum] = fromItem;
toItem = plr.plr->Equip[itemmove->iToSlotNum];
plr.plr->Equip[itemmove->iToSlotNum] = fromItem;
} else {
toItem = plr.plr.Inven[itemmove->iToSlotNum];
plr.plr.Inven[itemmove->iToSlotNum] = fromItem;
toItem = plr.plr->Inven[itemmove->iToSlotNum];
plr.plr->Inven[itemmove->iToSlotNum] = fromItem;
}
if (itemmove->eFrom == 0) {
plr.plr.Equip[itemmove->iFromSlotNum] = toItem;
plr.plr->Equip[itemmove->iFromSlotNum] = toItem;
} else {
plr.plr.Inven[itemmove->iFromSlotNum] = toItem;
plr.plr->Inven[itemmove->iFromSlotNum] = toItem;
}
if (itemmove->eFrom == 0 || itemmove->eTo == 0) {
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange);
equipChange.iPC_ID = plr.plr.iID;
equipChange.iPC_ID = plr.plr->iID;
if (itemmove->eFrom == 0) {
equipChange.iEquipSlotNum = itemmove->iFromSlotNum;
equipChange.EquipSlotItem = toItem;
@ -86,9 +103,9 @@ void ItemManager::itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
resp.iSlotNum = itemdel->iSlotNum;
// so, im not sure what this eIL thing does since you always delete items in inventory and not equips
plr.plr.Inven[itemdel->iSlotNum].iID = 0;
plr.plr.Inven[itemdel->iSlotNum].iType = 0;
plr.plr.Inven[itemdel->iSlotNum].iOpt = 0;
plr.plr->Inven[itemdel->iSlotNum].iID = 0;
plr.plr->Inven[itemdel->iSlotNum].iType = 0;
plr.plr->Inven[itemdel->iSlotNum].iOpt = 0;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC, sizeof(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC));
}
@ -101,7 +118,7 @@ void ItemManager::itemGMGiveHandler(CNSocket* sock, CNPacketData* data) {
PlayerView& plr = PlayerManager::players[sock];
// Commented and disabled for future use
//if (!plr.plr.IsGM) {
//if (!plr.plr->IsGM) {
// TODO: send fail packet
// return;
//}
@ -109,25 +126,27 @@ void ItemManager::itemGMGiveHandler(CNSocket* sock, CNPacketData* data) {
if (itemreq->eIL == 2) {
// Quest item, not a real item, handle this later, stubbed for now
// sock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_GIVE_ITEM_FAIL, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_FAIL), sock->getFEKey()));
} else if (itemreq->eIL == 1) {
} else if (itemreq->eIL == 1 && itemreq->Item.iType >= 0 && itemreq->Item.iType <= 8) {
INITSTRUCT(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC, resp);
resp.eIL = itemreq->eIL;
resp.iSlotNum = itemreq->iSlotNum;
resp.Item = itemreq->Item;
plr.plr.Inven[itemreq->iSlotNum] = itemreq->Item;
plr.plr.level = 36;
plr.plr->Inven[itemreq->iSlotNum] = itemreq->Item;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_GIVE_ITEM_SUCC, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC));
// some items require a level, for now we're just going to bypass this by setting your level to 36
//plr.plr->level = 36;
sP_FE2CL_REP_PC_CHANGE_LEVEL resp2;
//sP_FE2CL_REP_PC_CHANGE_LEVEL resp2;
resp2.iPC_ID = plr.plr.iID;
resp2.iPC_Level = 36;
//resp2.iPC_ID = plr.plr->iID;
//resp2.iPC_Level = 36;
sock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL));
//sock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL));
// saving this for later use on a /level command
}
}
}

55
src/MissionManager.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "CNShardServer.hpp"
#include "CNStructs.hpp"
#include "MissionManager.hpp"
#include "PlayerManager.hpp"
void MissionManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, acceptMission);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_END, completeMission);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID, setMission);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_STOP, quitMission);
}
void MissionManager::acceptMission(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_START))
return; // malformed packet
sP_CL2FE_REQ_PC_TASK_START* missionData = (sP_CL2FE_REQ_PC_TASK_START*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_TASK_START_SUCC, response);
response.iTaskNum = missionData->iTaskNum;
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC));
}
void MissionManager::completeMission(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_END))
return; // malformed packet
sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
response.iTaskNum = missionData->iTaskNum;
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
}
void MissionManager::setMission(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID))
return; // malformed packet
sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response);
response.iCurrentMissionID = missionData->iCurrentMissionID;
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
}
void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP))
return; // malformed packet
sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response);
response.iTaskNum = missionData->iTaskNum;
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC));
}

12
src/MissionManager.hpp Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "CNShardServer.hpp"
namespace MissionManager {
void init();
void acceptMission(CNSocket* sock, CNPacketData* data);
void completeMission(CNSocket* sock, CNPacketData* data);
void setMission(CNSocket* sock, CNPacketData* data);
void quitMission(CNSocket* sock, CNPacketData* data);
}

View File

@ -58,8 +58,8 @@ void NPCManager::updatePlayerNPCS(CNSocket* sock, PlayerView& view) {
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);
int diffX = abs(view.plr->x - pair.second.appearanceData.iX);
int diffY = abs(view.plr->y - pair.second.appearanceData.iY);
if (diffX < settings::VIEWDISTANCE && diffY < settings::VIEWDISTANCE) {
yesView.push_back(pair.first);

View File

@ -18,7 +18,7 @@ void NanoManager::nanoEquipHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_NANO_EQUIP* nano = (sP_CL2FE_REQ_NANO_EQUIP*)data->buf;
INITSTRUCT(sP_FE2CL_REP_NANO_EQUIP_SUCC, resp);
Player plr = PlayerManager::getPlayer(sock);
Player *plr = PlayerManager::getPlayer(sock);
if (nano->iNanoSlotNum > 2)
return;
@ -28,8 +28,7 @@ void NanoManager::nanoEquipHandler(CNSocket* sock, CNPacketData* data) {
// Update player
plr.equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
PlayerManager::updatePlayer(sock, plr);
plr->equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_EQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_EQUIP_SUCC));
}
@ -40,7 +39,7 @@ void NanoManager::nanoUnEquipHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_NANO_UNEQUIP* nano = (sP_CL2FE_REQ_NANO_UNEQUIP*)data->buf;
INITSTRUCT(sP_FE2CL_REP_NANO_UNEQUIP_SUCC, resp);
Player plr = PlayerManager::getPlayer(sock);
Player *plr = PlayerManager::getPlayer(sock);
if (nano->iNanoSlotNum > 2)
return;
@ -48,8 +47,7 @@ void NanoManager::nanoUnEquipHandler(CNSocket* sock, CNPacketData* data) {
resp.iNanoSlotNum = nano->iNanoSlotNum;
// update player
plr.equippedNanos[nano->iNanoSlotNum] = 0;
PlayerManager::updatePlayer(sock, plr);
plr->equippedNanos[nano->iNanoSlotNum] = 0;
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_UNEQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_UNEQUIP_SUCC));
}
@ -60,13 +58,13 @@ void NanoManager::nanoGMGiveHandler(CNSocket* sock, CNPacketData* data) {
// Cmd: /nano <nanoId>
sP_CL2FE_REQ_PC_GIVE_NANO* nano = (sP_CL2FE_REQ_PC_GIVE_NANO*)data->buf;
Player plr = PlayerManager::getPlayer(sock);
Player *plr = PlayerManager::getPlayer(sock);
// Add nano to player
addNano(sock, nano->iNanoID, 0);
DEBUGLOG(
std::cout << U16toU8(plr.PCStyle.szFirstName) << U16toU8(plr.PCStyle.szLastName) << " requested to add nano id: " << nano->iNanoID << std::endl;
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to add nano id: " << nano->iNanoID << std::endl;
)
}
@ -75,7 +73,7 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) {
return; // malformed packet
sP_CL2FE_REQ_NANO_ACTIVE* pkt = (sP_CL2FE_REQ_NANO_ACTIVE*)data->buf;
PlayerView plr = PlayerManager::players[sock];
Player *plr = PlayerManager::getPlayer(sock);
// Send to client
INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp);
@ -85,28 +83,27 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) {
if (pkt->iNanoSlotNum > 2)
return;
int nanoId = plr.plr.equippedNanos[pkt->iNanoSlotNum];
int nanoId = plr->equippedNanos[pkt->iNanoSlotNum];
if (nanoId > 36)
return; // sanity check
sNano nano = plr.plr.Nanos[nanoId];
sNano nano = plr->Nanos[nanoId];
// Send to other players
INITSTRUCT(sP_FE2CL_NANO_ACTIVE, pkt1);
pkt1.iPC_ID = plr.plr.iID;
pkt1.iPC_ID = plr->iID;
pkt1.Nano = nano;
for (CNSocket *s : PlayerManager::players[sock].viewable)
for (CNSocket* s : PlayerManager::players[sock].viewable)
s->sendPacket((void*)&pkt1, P_FE2CL_NANO_ACTIVE, sizeof(sP_FE2CL_NANO_ACTIVE));
// update player
plr.plr.nano = nanoId;
PlayerManager::updatePlayer(sock, plr.plr);
plr->activeNano = nanoId;
DEBUGLOG(
std::cout << U16toU8(plr.plr.PCStyle.szFirstName) << U16toU8(plr.plr.PCStyle.szLastName) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl;
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl;
)
}
@ -115,7 +112,7 @@ void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
return; // malformed packet
sP_CL2FE_REQ_NANO_SKILL_USE* skill = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf;
PlayerView plr = PlayerManager::players[sock];
Player *plr = PlayerManager::getPlayer(sock);
// Send to client
INITSTRUCT(sP_FE2CL_NANO_SKILL_USE_SUCC, resp);
@ -124,13 +121,13 @@ void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
resp.iArg3 = skill->iArg3;
resp.iBulletID = skill->iBulletID;
resp.iTargetCnt = skill->iTargetCnt;
resp.iPC_ID = plr.plr.iID;
resp.iPC_ID = plr->iID;
resp.iNanoStamina = 150; // Hardcoded for now
sock->sendPacket((void*)&resp, P_FE2CL_NANO_SKILL_USE_SUCC, sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC));
DEBUGLOG(
std::cout << U16toU8(plr.plr.PCStyle.szFirstName) << U16toU8(plr.plr.PCStyle.szLastName) << " requested to summon nano skill " << std::endl;
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano skill " << std::endl;
)
}
@ -147,7 +144,7 @@ void NanoManager::addNano(CNSocket* sock, int16_t nanoId, int16_t slot) {
if (nanoId > 36)
return;
Player plr = PlayerManager::getPlayer(sock);
Player *plr = PlayerManager::getPlayer(sock);
// Send to client
INITSTRUCT(sP_FE2CL_REP_PC_NANO_CREATE_SUCC, resp);
@ -158,19 +155,18 @@ void NanoManager::addNano(CNSocket* sock, int16_t nanoId, int16_t slot) {
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_NANO_CREATE_SUCC, sizeof(sP_FE2CL_REP_PC_NANO_CREATE_SUCC));
// Update player
plr.Nanos[nanoId] = resp.Nano;
PlayerManager::updatePlayer(sock, plr);
plr->Nanos[nanoId] = resp.Nano;
}
void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId) {
if (nanoId > 36)
return;
Player plr = PlayerManager::getPlayer(sock);
sNano nano = plr.Nanos[nanoId];
Player *plr = PlayerManager::getPlayer(sock);
sNano nano = plr->Nanos[nanoId];
nano.iSkillID = skillId;
plr.Nanos[nanoId] = nano;
plr->Nanos[nanoId] = nano;
// Send to client
INITSTRUCT(sP_FE2CL_REP_NANO_TUNE_SUCC, resp);
@ -180,24 +176,19 @@ void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId)
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC));
DEBUGLOG(
std::cout << U16toU8(plr.PCStyle.szFirstName) << U16toU8(plr.PCStyle.szLastName) << " set skill id " << skillId << " for nano: " << nanoId << std::endl;
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skillId << " for nano: " << nanoId << std::endl;
)
// Update the player
PlayerManager::updatePlayer(sock, plr);
}
void NanoManager::resetNanoSkill(CNSocket* sock, int16_t nanoId) {
if (nanoId > 36)
return;
Player plr = PlayerManager::getPlayer(sock);
sNano nano = plr.Nanos[nanoId];
Player *plr = PlayerManager::getPlayer(sock);
sNano nano = plr->Nanos[nanoId];
// 0 is reset
nano.iSkillID = 0;
plr.Nanos[nanoId] = nano;
// Update the player
PlayerManager::updatePlayer(sock, plr);
plr->Nanos[nanoId] = nano;
}
#pragma endregion

View File

@ -17,9 +17,10 @@ struct Player {
int slot; // player slot, not nano slot
sPCStyle PCStyle;
sPCStyle2 PCStyle2;
sNano Nanos[37];
sNano Nanos[37]; // acquired nanos
int equippedNanos[3];
int nano; // active nano (index into Nanos)
int activeNano; // active nano (index into Nanos)
int8_t iPCState;
int x, y, z, angle;
sItemBase Equip[AEQUIP_COUNT];

View File

@ -27,13 +27,21 @@ void PlayerManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, PlayerManager::gotoPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, PlayerManager::setSpecialPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, PlayerManager::heartbeatPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, PlayerManager::revivePlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, PlayerManager::exitGame);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setSpecialSwitchPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, PlayerManager::enterPlayerVehicle);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, PlayerManager::exitPlayerVehicle);
}
void PlayerManager::addPlayer(CNSocket* key, Player plr) {
Player *p = new Player();
memcpy(p, &plr, sizeof(Player));
players[key] = PlayerView();
players[key].viewable = std::list<CNSocket*>();
players[key].plr = plr;
players[key].plr = p;
players[key].lastHeartbeat = 0;
std::cout << U16toU8(plr.PCStyle.szFirstName) << " " << U16toU8(plr.PCStyle.szLastName) << " has joined!" << std::endl;
@ -49,25 +57,22 @@ void PlayerManager::removePlayer(CNSocket* key) {
// now sent PC_EXIT packet
sP_FE2CL_PC_EXIT exitPacket;
exitPacket.iID = players[key].plr.iID;
exitPacket.iID = players[key].plr->iID;
otherSock->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
}
delete cachedView.plr;
players.erase(key);
std::cout << U16toU8(cachedView.plr.PCStyle.szFirstName) << U16toU8(cachedView.plr.PCStyle.szLastName) << " has left!" << std::endl;
std::cout << U16toU8(cachedView.plr->PCStyle.szFirstName) << U16toU8(cachedView.plr->PCStyle.szLastName) << " has left!" << std::endl;
std::cout << players.size() << " players" << std::endl;
}
Player PlayerManager::getPlayer(CNSocket* key) {
return players[key].plr;
}
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;
players[sock].plr->x = X;
players[sock].plr->y = Y;
players[sock].plr->z = Z;
std::vector<CNSocket*> noView;
std::vector<CNSocket*> yesView;
@ -77,8 +82,8 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
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);
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::VIEWDISTANCE && diffY < settings::VIEWDISTANCE) {
yesView.push_back(pair.first);
@ -95,9 +100,9 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
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;
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;
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
@ -114,32 +119,34 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
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
Player otherPlr = players[otherSock].plr;
Player plr = players[sock].plr;
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.nano];
memcpy(newPlayer.PCAppearanceData.ItemEquip, plr.Equip, sizeof(sItemBase) * AEQUIP_COUNT);
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;
memcpy(newPlayer.PCAppearanceData.ItemEquip, plr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
otherSock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
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.nano];
memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr.Equip, sizeof(sItemBase) * AEQUIP_COUNT);
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;
memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
@ -155,8 +162,8 @@ std::list<CNSocket*> PlayerManager::getNearbyPlayers(int x, int y, int dist) {
std::list<CNSocket*> plrs;
for (auto pair : players) {
int diffX = abs(pair.second.plr.x - x);
int diffY = abs(pair.second.plr.x - x);
int diffX = abs(pair.second.plr->x - x);
int diffY = abs(pair.second.plr->x - x);
if (diffX < dist && diffY < dist)
plrs.push_back(pair.first);
@ -178,16 +185,16 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
DEBUGLOG(
std::cout << "P_CL2FE_REQ_PC_ENTER:" << std::endl;
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;
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;
)
response.iID = rand();
response.uiSvrTime = getTime();
response.PCLoadData2CL.iUserLevel = 1;
response.PCLoadData2CL.iHP = 1000 * plr.level;
response.PCLoadData2CL.iHP = 3625; //TODO: Check player levelupdata and get this right
response.PCLoadData2CL.iLevel = plr.level;
response.PCLoadData2CL.iMentor = 1;
response.PCLoadData2CL.iMentorCount = 4;
@ -203,7 +210,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
for (int i = 0; i < AEQUIP_COUNT; i++)
response.PCLoadData2CL.aEquip[i] = plr.Equip[i];
for (int i = 0; i < AINVEN_COUNT; i++)
for (int i = 0; i < AINVEN_COUNT; i++)
response.PCLoadData2CL.aInven[i] = plr.Inven[i];
// don't ask..
@ -248,7 +255,7 @@ void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) {
DEBUGLOG(
std::cout << "P_CL2FE_REQ_PC_LOADING_COMPLETE:" << std::endl;
std::cout << "\tPC_ID: " << complete->iPC_ID << std::endl;
std::cout << "\tPC_ID: " << complete->iPC_ID << std::endl;
)
response.iPC_ID = complete->iPC_ID;
@ -263,12 +270,12 @@ void PlayerManager::movePlayer(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_MOVE* moveData = (sP_CL2FE_REQ_PC_MOVE*)data->buf;
updatePlayerPosition(sock, moveData->iX, moveData->iY, moveData->iZ);
players[sock].plr.angle = moveData->iAngle;
players[sock].plr->angle = moveData->iAngle;
uint64_t tm = getTime();
INITSTRUCT(sP_FE2CL_PC_MOVE, moveResponse);
moveResponse.iID = players[sock].plr.iID;
moveResponse.iID = players[sock].plr->iID;
moveResponse.cKeyValue = moveData->cKeyValue;
moveResponse.iX = moveData->iX;
@ -299,7 +306,7 @@ void PlayerManager::stopPlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_STOP, stopResponse);
stopResponse.iID = players[sock].plr.iID;
stopResponse.iID = players[sock].plr->iID;
stopResponse.iX = stopData->iX;
stopResponse.iY = stopData->iY;
@ -324,7 +331,7 @@ void PlayerManager::jumpPlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_JUMP, jumpResponse);
jumpResponse.iID = players[sock].plr.iID;
jumpResponse.iID = players[sock].plr->iID;
jumpResponse.cKeyValue = jumpData->cKeyValue;
jumpResponse.iX = jumpData->iX;
@ -355,7 +362,7 @@ void PlayerManager::jumppadPlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_JUMPPAD, jumppadResponse);
jumppadResponse.iPC_ID = players[sock].plr.iID;
jumppadResponse.iPC_ID = players[sock].plr->iID;
jumppadResponse.cKeyValue = jumppadData->cKeyValue;
jumppadResponse.iX = jumppadData->iX;
@ -384,7 +391,7 @@ void PlayerManager::launchPlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_LAUNCHER, launchResponse);
launchResponse.iPC_ID = players[sock].plr.iID;
launchResponse.iPC_ID = players[sock].plr->iID;
launchResponse.iX = launchData->iX;
launchResponse.iY = launchData->iY;
@ -414,7 +421,7 @@ void PlayerManager::ziplinePlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_ZIPLINE, ziplineResponse);
ziplineResponse.iPC_ID = players[sock].plr.iID;
ziplineResponse.iPC_ID = players[sock].plr->iID;
ziplineResponse.iCliTime = ziplineData->iCliTime;
ziplineResponse.iSvrTime = tm;
ziplineResponse.iX = ziplineData->iX;
@ -451,7 +458,7 @@ void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_MOVEPLATFORM, platResponse);
platResponse.iPC_ID = players[sock].plr.iID;
platResponse.iPC_ID = players[sock].plr->iID;
platResponse.iCliTime = platformData->iCliTime;
platResponse.iSvrTime = tm;
platResponse.iX = platformData->iX;
@ -485,7 +492,7 @@ void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_SLOPE, slopeResponse);
slopeResponse.iPC_ID = players[sock].plr.iID;
slopeResponse.iPC_ID = players[sock].plr->iID;
slopeResponse.iCliTime = slopeData->iCliTime;
slopeResponse.iSvrTime = tm;
slopeResponse.iX = slopeData->iX;
@ -513,9 +520,9 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
DEBUGLOG(
std::cout << "P_CL2FE_REQ_PC_GOTO:" << std::endl;
std::cout << "\tX: " << gotoData->iToX << std::endl;
std::cout << "\tY: " << gotoData->iToY << std::endl;
std::cout << "\tZ: " << gotoData->iToZ << std::endl;
std::cout << "\tX: " << gotoData->iToX << std::endl;
std::cout << "\tY: " << gotoData->iToY << std::endl;
std::cout << "\tZ: " << gotoData->iToZ << std::endl;
)
response.iX = gotoData->iToX;
@ -534,9 +541,9 @@ void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) {
DEBUGLOG(
std::cout << "P_CL2FE_GM_REQ_PC_SET_VALUE:" << std::endl;
std::cout << "\tPC_ID: " << setData->iPC_ID << std::endl;
std::cout << "\tSetValueType: " << setData->iSetValueType << std::endl;
std::cout << "\tSetValue: " << setData->iSetValue << std::endl;
std::cout << "\tPC_ID: " << setData->iPC_ID << std::endl;
std::cout << "\tSetValueType: " << setData->iSetValueType << std::endl;
std::cout << "\tSetValue: " << setData->iSetValue << std::endl;
)
response.iPC_ID = setData->iPC_ID;
@ -553,7 +560,7 @@ void PlayerManager::heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_EXIT))
return;
sP_CL2FE_REQ_PC_EXIT* exitData = (sP_CL2FE_REQ_PC_EXIT*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, response);
@ -563,9 +570,70 @@ void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC));
}
void PlayerManager::updatePlayer(CNSocket* key, Player plr) {
PlayerView plrv = players[key];
plrv.plr = plr;
void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_REGEN))
return;
players[key] = plrv;
Player *plr = PlayerManager::getPlayer(sock);
// players respawn at same spot they died at for now...
sP_CL2FE_REQ_PC_REGEN* reviveData = (sP_CL2FE_REQ_PC_REGEN*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_REGEN_SUCC, response);
response.bMoveLocation = reviveData->eIL;
response.PCRegenData.iMapNum = reviveData->iIndex;
response.PCRegenData.iHP = 1000 * plr->level;
response.PCRegenData.iX = plr->x;
response.PCRegenData.iY = plr->y;
response.PCRegenData.iZ = plr->z;
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_REGEN_SUCC, sizeof(sP_FE2CL_REP_PC_REGEN_SUCC));
}
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response);
PlayerView plrv = PlayerManager::players[sock];
//send to other players
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, pkt);
pkt.EquipSlotItem.iType = 1;
pkt.iEquipSlotNum = 8;
for (CNSocket* otherSock : plrv.viewable) {
otherSock->sendPacket((void*)&pkt, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
}
plrv.plr->iPCState = 8;
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
}
void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response);
PlayerView plrv = PlayerManager::players[sock];
//send to other players
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, pkt);
pkt.EquipSlotItem.iType = 1;
pkt.iEquipSlotNum = 8;
for (CNSocket* otherSock : plrv.viewable) {
otherSock->sendPacket((void*)&pkt, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
}
plrv.plr->iPCState = 0;
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC));
}
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH* specialData = (sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, response);
response.iPC_ID = specialData->iPC_ID;
response.iReqSpecialStateFlag = specialData->iSpecialStateFlag;
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC));
}
#pragma region Helper methods
Player *PlayerManager::getPlayer(CNSocket* key) {
return players[key].plr;
}
#pragma endregion

View File

@ -11,7 +11,7 @@
struct PlayerView {
std::list<CNSocket*> viewable;
std::list<int32_t> viewableNPCs;
Player plr;
Player *plr;
uint64_t lastHeartbeat;
};
@ -22,9 +22,8 @@ namespace PlayerManager {
void addPlayer(CNSocket* key, Player plr);
void removePlayer(CNSocket* key);
Player getPlayer(CNSocket* key);
Player *getPlayer(CNSocket* key);
void updatePlayer(CNSocket* key, Player plr);
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z);
std::list<CNSocket*> getNearbyPlayers(int X, int Y, int dist);
@ -41,5 +40,11 @@ namespace PlayerManager {
void gotoPlayer(CNSocket* sock, CNPacketData* data);
void setSpecialPlayer(CNSocket* sock, CNPacketData* data);
void heartbeatPlayer(CNSocket* sock, CNPacketData* data);
void revivePlayer(CNSocket* sock, CNPacketData* data);
void exitGame(CNSocket* sock, CNPacketData* data);
void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data);
void enterPlayerVehicle(CNSocket* sock, CNPacketData* data);
void exitPlayerVehicle(CNSocket* sock, CNPacketData* data);
}

View File

@ -3,6 +3,7 @@
#include "PlayerManager.hpp"
#include "ChatManager.hpp"
#include "ItemManager.hpp"
#include "MissionManager.hpp"
#include "NanoManager.hpp"
#include "NPCManager.hpp"
@ -11,7 +12,7 @@
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
#include "mingw/mingw.thread.h"
#else
#include <thread>
#include <thread>
#endif
#include <string>
@ -22,9 +23,9 @@ void startShard(CNShardServer* server) {
int main() {
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
std::cerr << "OpenFusion: WSAStartup failed" << std::endl;
exit(EXIT_FAILURE);
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
std::cerr << "OpenFusion: WSAStartup failed" << std::endl;
exit(EXIT_FAILURE);
}
#endif
settings::init();
@ -33,6 +34,7 @@ int main() {
PlayerManager::init();
ChatManager::init();
ItemManager::init();
MissionManager::init();
NanoManager::init();
NPCManager::init();
@ -41,12 +43,12 @@ int main() {
CNShardServer shardServer(settings::SHARDPORT);
std::thread shardThread(startShard, (CNShardServer*)&shardServer);
loginServer.start();
shardServer.kill();
shardThread.join();
#ifdef _WIN32
WSACleanup();
#endif