Merge pull request #55 from dongresource/combat1

Implemented combat, drops, crates and the guide changer
This commit is contained in:
CPunch 2020-08-28 19:11:56 -05:00 committed by GitHub
commit 50431024c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 339 additions and 53 deletions

6
.vimrc
View File

@ -1,9 +1,9 @@
" vim configuration file
" you will need to put 'set exrc' and 'set secure' into your main .vimrc 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.
" start vim in this dir. Alternatively you can just load it directly with
" ':so .vimrc' every time.
set tabstop=4
set shiftwidth=4
set expandtab

View File

@ -1,7 +1,7 @@
CC=clang
CXX=clang++
# -w suppresses all warnings (the part that's commented out helps me find memory leaks, it ruins performance though!)
CCFLAGS=-O3 #-g3 -fsanitize=address
CFLAGS=-O3 #-g3 -fsanitize=address
CXXFLAGS=-Wall -std=c++17 -O3 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) #-g3 -fsanitize=address
LDFLAGS=-lpthread -ldl
# specifies the name of our exectuable
@ -14,22 +14,23 @@ PROTOCOL_VERSION?=104
# Windows-specific
WIN_CC=x86_64-w64-mingw32-gcc
WIN_CXX=x86_64-w64-mingw32-g++
WIN_CCFLAGS=-O3 #-g3 -fsanitize=address
WIN_CFLAGS=-O3 #-g3 -fsanitize=address
WIN_CXXFLAGS=-Wall -std=c++17 -O3 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) #-g3 -fsanitize=address
WIN_LDFLAGS=-static -lws2_32 -lwsock32
WIN_SERVER=bin/winfusion.exe
CC_SRC=\
CSRC=\
src/contrib/bcrypt/bcrypt.c\
src/contrib/bcrypt/crypt_blowfish.c\
src/contrib/bcrypt/crypt_gensalt.c\
src/contrib/bcrypt/wrapper.c\
src/contrib/sqlite/sqlite3.c\
CXX_SRC=\
CXXSRC=\
src/contrib/sqlite/sqlite3pp.cpp\
src/contrib/sqlite/sqlite3ppext.cpp\
src/ChatManager.cpp\
src/CombatManager.cpp\
src/CNLoginServer.cpp\
src/CNProtocol.cpp\
src/CNShardServer.cpp\
@ -47,7 +48,7 @@ CXX_SRC=\
src/settings.cpp\
# headers (for timestamp purposes)
CC_HDR=\
CHDR=\
src/contrib/bcrypt/bcrypt.h\
src/contrib/bcrypt/crypt_blowfish.h\
src/contrib/bcrypt/crypt_gensalt.h\
@ -56,13 +57,14 @@ CC_HDR=\
src/contrib/sqlite/sqlite3.h\
src/contrib/sqlite/sqlite3ext.h\
CXX_HDR=\
CXXHDR=\
src/contrib/bcrypt/BCrypt.hpp\
src/contrib/sqlite/sqlite3pp.h\
src/contrib/sqlite/sqlite3ppext.h\
src/contrib/INIReader.hpp\
src/contrib/JSON.hpp\
src/ChatManager.hpp\
src/CombatManager.hpp\
src/CNLoginServer.hpp\
src/CNProtocol.hpp\
src/CNShardServer.hpp\
@ -80,10 +82,10 @@ CXX_HDR=\
src/PlayerManager.hpp\
src/settings.hpp\
CC_OBJ=$(CC_SRC:.c=.o)
CXX_OBJ=$(CXX_SRC:.cpp=.o)
COBJ=$(CSRC:.c=.o)
CXXOBJ=$(CXXSRC:.cpp=.o)
OBJ=$(CC_OBJ) $(CXX_OBJ)
OBJ=$(COBJ) $(CXXOBJ)
all: $(SERVER)
@ -92,18 +94,20 @@ windows: $(SERVER)
# assign Windows-specific values if targeting Windows
windows : CC=$(WIN_CC)
windows : CXX=$(WIN_CXX)
windows : CCFLAGS=$(WIN_CCFLAGS)
windows : CFLAGS=$(WIN_CFLAGS)
windows : CXXFLAGS=$(WIN_CXXFLAGS)
windows : LDFLAGS=$(WIN_LDFLAGS)
windows : SERVER=$(WIN_SERVER)
$(CC_OBJ): %.o: %.c $(CC_HDR)
$(CC) -c $(CCFLAGS) -o $@ $<
.SUFFIX: .o .c .cpp .hpp
$(CXX_OBJ): %.o: %.cpp $(CXX_HDR)
.c.o: $(CHDR)
$(CC) -c $(CFLAGS) -o $@ $<
.cpp.o: $(CXXHDR)
$(CXX) -c $(CXXFLAGS) -o $@ $<
$(SERVER): $(OBJ) $(CC_HDR) $(CXX_HDR)
$(SERVER): $(OBJ) $(CHDR) $(CXXHDR)
mkdir -p bin
$(CXX) $(OBJ) $(LDFLAGS) -o $(SERVER)

View File

@ -16,7 +16,7 @@ tl;dr:
From then on, any time you want to run the "game":
3. Run `OpenFusionRelease/winfusion.exe`
3. Run `Server/winfusion.exe`
4. Run `FreeClient/OpenFusionClient.exe`
Currently the client by default connects to a public server hosted by Cake. Change the loginInfo.php to point to your own server if you want to host your own.
@ -61,7 +61,7 @@ When the player clicks "ENTER THE GAME" (or completes the tutorial), the login s
## Configuration
You can change the ports the FusionFall server listens on in `OpenFusion/config.ini`. Make sure the login server port is in sync with `loginInfo.php`.
You can change the ports the FusionFall server listens on in `Server/config.ini`. Make sure the login server port is in sync with `loginInfo.php`.
The shard port needs no such synchronization.
You can also configure the distance at which you'll be able to see other players, though by default it's already as high as you'll want it.
@ -103,11 +103,11 @@ To make your landwalking experience more pleasant, you can make use of a few adm
* `/goto` is useful for more precise teleportation (ie. for getting into Infected Zones, etc.).
### Item commands
* /itemN [type] [itemId] [amount]
* `/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)
* `/nano [id] (1-36)`
* `/nano_equip [id] (1-36) [slot] (0-2)`
* `/nano_unequip [slot] (0-2)`
* `/nano_active [slot] (0-2)`

View File

@ -23,9 +23,9 @@ npcdistance=16000
# little message players see when they enter the game
motd=Welcome to OpenFusion!
# NPC json data
npcdata=NPCs.json
npcdata=data/NPCs.json
# warp target json data
warpdata=warps.json
warpdata=data/warps.json
# is everyone a GM?
gm=true

View File

@ -123,23 +123,25 @@ void CNSocket::sendPacket(void* buf, uint32_t type, size_t size) {
if (!alive)
return;
int tmpSize = size + sizeof(uint32_t);
uint8_t* tmpBuf = (uint8_t*)xmalloc(tmpSize);
size_t bodysize = size + sizeof(uint32_t);
uint8_t* fullpkt = (uint8_t*)xmalloc(bodysize+4);
uint8_t* body = fullpkt+4;
memcpy(fullpkt, (void*)&bodysize, 4);
// copy packet type to the front of the buffer & then the actual buffer
memcpy(tmpBuf, (void*)&type, sizeof(uint32_t));
memcpy(tmpBuf+sizeof(uint32_t), buf, size);
memcpy(body, (void*)&type, sizeof(uint32_t));
memcpy(body+sizeof(uint32_t), buf, size);
// encrypt the packet
switch (activeKey) {
case SOCKETKEY_E:
CNSocketEncryption::encryptData((uint8_t*)tmpBuf, (uint8_t*)(&EKey), tmpSize);
CNSocketEncryption::encryptData((uint8_t*)body, (uint8_t*)(&EKey), bodysize);
break;
case SOCKETKEY_FE:
CNSocketEncryption::encryptData((uint8_t*)tmpBuf, (uint8_t*)(&FEKey), tmpSize);
CNSocketEncryption::encryptData((uint8_t*)body, (uint8_t*)(&FEKey), bodysize);
break;
default: {
free(tmpBuf);
free(fullpkt);
DEBUGLOG(
std::cout << "[WARN]: UNSET KEYTYPE FOR SOCKET!! ABORTING SEND" << std::endl;
)
@ -147,15 +149,11 @@ void CNSocket::sendPacket(void* buf, uint32_t type, size_t size) {
}
}
// send packet size
if (!sendData((uint8_t*)&tmpSize, sizeof(uint32_t)))
kill();
// send packet data!
if (alive && !sendData(tmpBuf, tmpSize))
if (alive && !sendData(fullpkt, bodysize+4))
kill();
free(tmpBuf); // free tmp buffer
free(fullpkt);
}
void CNSocket::setActiveKey(ACTIVEKEY key) {
@ -172,7 +170,7 @@ void CNSocket::step() {
// we got out packet size!!!!
readSize = *((int32_t*)readBuffer);
// sanity check
if (readSize > MAX_PACKETSIZE) {
if (readSize > CN_PACKET_BUFFER_SIZE) {
kill();
return;
}

View File

@ -1,6 +1,5 @@
#pragma once
#define MAX_PACKETSIZE 8192
#define DEBUGLOG(x) if (settings::VERBOSITY) {x};
#include <iostream>
@ -56,7 +55,8 @@
[4 bytes] - size of packet including the 4 byte packet type
[size bytes] - Encrypted packet (byte swapped && xor'd with 8 byte key; see CNSocketEncryption)
[4 bytes] - packet type (which is a combination of the first 4 bytes of the packet and a checksum in some versions)
[structure]
[structure] - one member contains length of trailing data (expressed in packet-dependant structures)
[trailing data] - optional variable-length data that only some packets make use of
*/
// error checking calloc wrapper
@ -71,6 +71,42 @@ inline void* xmalloc(size_t sz) {
return res;
}
// overflow-safe validation of variable-length packets
// for outbound packets
inline bool validOutVarPacket(size_t base, int32_t npayloads, size_t plsize) {
// check for multiplication overflow
if (npayloads > 0 && CN_PACKET_BUFFER_SIZE / (size_t)npayloads < plsize)
return false;
// it's safe to multiply
size_t trailing = npayloads * plsize;
// does it fit in a packet?
if (base + trailing > CN_PACKET_BUFFER_SIZE)
return false;
// everything is a-ok!
return true;
}
// for inbound packets
inline bool validInVarPacket(size_t base, int32_t npayloads, size_t plsize, size_t datasize) {
// check for multiplication overflow
if (npayloads > 0 && CN_PACKET_BUFFER_SIZE / (size_t)npayloads < plsize)
return false;
// it's safe to multiply
size_t trailing = npayloads * plsize;
// make sure size is exact
// datasize has already been validated against CN_PACKET_BUFFER_SIZE
if (datasize != base + trailing)
return false;
// everything is a-ok!
return true;
}
namespace CNSocketEncryption {
// you won't believe how complicated they made it in the client :facepalm:
static constexpr const char* defaultKey = "m@rQn~W#";
@ -104,7 +140,7 @@ private:
uint64_t EKey;
uint64_t FEKey;
int32_t readSize = 0;
uint8_t readBuffer[MAX_PACKETSIZE];
uint8_t readBuffer[CN_PACKET_BUFFER_SIZE];
int readBufferIndex = 0;
bool activelyReading = false;
bool alive = true;

131
src/CombatManager.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "CombatManager.hpp"
#include "PlayerManager.hpp"
#include "NPCManager.hpp"
#include "ItemManager.hpp"
#include <assert.h>
void CombatManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_NPCs, pcAttackNpcs);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_COMBAT_BEGIN, combatBegin);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_COMBAT_END, combatEnd);
REGISTER_SHARD_PACKET(P_CL2FE_DOT_DAMAGE_ONOFF, dotDamageOnOff);
}
void CombatManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
sP_CL2FE_REQ_PC_ATTACK_NPCs* pkt = (sP_CL2FE_REQ_PC_ATTACK_NPCs*)data->buf;
Player *plr = PlayerManager::getPlayer(sock);
// sanity check
if (!validInVarPacket(sizeof(sP_CL2FE_REQ_PC_ATTACK_NPCs), pkt->iNPCCnt, sizeof(int32_t), data->size)) {
std::cout << "[WARN] bad sP_CL2FE_REQ_PC_ATTACK_NPCs packet size\n";
return;
}
int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_PC_ATTACK_NPCs));
/*
* Due to the possibility of multiplication overflow (and regular buffer overflow),
* both incoming and outgoing variable-length packets must be validated, at least if
* the number of trailing structs isn't well known (ie. it's from the client).
*/
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC), pkt->iNPCCnt, sizeof(sAttackResult))) {
std::cout << "[WARN] bad sP_FE2CL_PC_ATTACK_NPCs_SUCC packet size\n";
return;
}
// initialize response struct
size_t resplen = sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) + pkt->iNPCCnt * sizeof(sAttackResult);
uint8_t respbuf[4096];
memset(respbuf, 0, resplen);
sP_FE2CL_PC_ATTACK_NPCs_SUCC *resp = (sP_FE2CL_PC_ATTACK_NPCs_SUCC*)respbuf;
sAttackResult *respdata = (sAttackResult*)(respbuf+sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC));
resp->iNPCCnt = pkt->iNPCCnt;
for (int i = 0; i < pkt->iNPCCnt; i++) {
if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) {
// not sure how to best handle this
std::cout << "[WARN] pcAttackNpcs: mob ID not found" << std::endl;
return;
}
BaseNPC& mob = NPCManager::NPCs[pktdata[i]];
mob.appearanceData.iHP -= 100;
if (mob.appearanceData.iHP <= 0)
giveReward(sock);
// TODO: despawn mobs when they die
respdata[i].iID = mob.appearanceData.iNPC_ID;
respdata[i].iDamage = 100;
respdata[i].iHP = mob.appearanceData.iHP;
respdata[i].iHitFlag = 2;
}
sock->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs_SUCC, resplen);
// a bit of a hack: these are the same size, so we can reuse the output packet
assert(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) == sizeof(sP_FE2CL_PC_ATTACK_NPCs));
sP_FE2CL_PC_ATTACK_NPCs *resp1 = (sP_FE2CL_PC_ATTACK_NPCs*)respbuf;
resp1->iPC_ID = plr->iID;
// send to other players
for (CNSocket *s : PlayerManager::players[sock].viewable) {
if (s == sock)
continue;
s->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs, resplen);
}
}
void CombatManager::combatBegin(CNSocket *sock, CNPacketData *data) {} // stub
void CombatManager::combatEnd(CNSocket *sock, CNPacketData *data) {} // stub
void CombatManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {} // stub
void CombatManager::giveReward(CNSocket *sock) {
Player *plr = PlayerManager::getPlayer(sock);
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
assert(resplen < CN_PACKET_BUFFER_SIZE);
// we know it's only one trailing struct, so we can skip full validation
uint8_t respbuf[resplen]; // not a variable length array, don't worry
sP_FE2CL_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
// don't forget to zero the buffer!
memset(respbuf, 0, resplen);
// update player
plr->money += 50;
plr->fusionmatter += 70;
// simple rewards
reward->m_iCandy = plr->money;
reward->m_iFusionMatter = plr->fusionmatter;
reward->iFatigue = 100; // prevents warning message
reward->iFatigue_Level = 1;
reward->iItemCnt = 1; // remember to update resplen if you change this
int slot = ItemManager::findFreeSlot(plr);
if (slot == -1) {
// no room for an item, but you still get FM and taros
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM));
} else {
// item reward
item->sItem.iType = 9;
item->sItem.iID = 1;
item->iSlotNum = slot;
item->eIL = 1; // Inventory Location. 1 means player inventory.
// update player
plr->Inven[slot] = item->sItem;
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
}
}

16
src/CombatManager.hpp Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "CNProtocol.hpp"
#include "CNShared.hpp"
#include "CNShardServer.hpp"
namespace CombatManager {
void init();
void pcAttackNpcs(CNSocket *sock, CNPacketData *data);
void combatBegin(CNSocket *sock, CNPacketData *data);
void combatEnd(CNSocket *sock, CNPacketData *data);
void dotDamageOnOff(CNSocket *sock, CNPacketData *data);
void giveReward(CNSocket *sock);
}

View File

@ -5,7 +5,7 @@
#define STRINGIFY(x) PacketMap(x, #x)
/*
* Turns out there's not better way to do this...
* Turns out there isn't better way to do this...
* We'll only support CL2* packets for now, since we only
* need to print those.
*/

View File

@ -4,6 +4,9 @@
#include "PlayerManager.hpp"
#include "Player.hpp"
#include <string.h> // for memset() and memcmp()
#include <assert.h>
void ItemManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler);
@ -18,6 +21,7 @@ void ItemManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER, itemTradeUnregisterItemHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER, itemTradeRegisterCashHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, itemTradeChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_CHEST_OPEN, chestOpenHandler);
}
void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
@ -665,3 +669,63 @@ void ItemManager::itemTradeChatHandler(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
}
void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN))
return; // ignore the malformed packet
sP_CL2FE_REQ_ITEM_CHEST_OPEN *pkt = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf;
Player *plr = PlayerManager::getPlayer(sock);
// item giving packet
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
assert(resplen < CN_PACKET_BUFFER_SIZE);
// we know it's only one trailing struct, so we can skip full validation
uint8_t respbuf[resplen]; // not a variable length array, don't worry
sP_FE2CL_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
// don't forget to zero the buffer!
memset(respbuf, 0, resplen);
// simple rewards
reward->iFatigue = 100; // prevents warning message
reward->iFatigue_Level = 1;
reward->iItemCnt = 1; // remember to update resplen if you change this
// item reward
item->sItem.iType = 0;
item->sItem.iID = 96;
item->iSlotNum = pkt->iSlotNum;
item->eIL = pkt->eIL;
// update player
plr->Inven[pkt->iSlotNum] = item->sItem;
// transmit item
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
// chest opening acknowledgement packet
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
resp.iSlotNum = pkt->iSlotNum;
std::cout << "opening chest..." << std::endl;
sock->sendPacket((void*)&resp, P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, sizeof(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC));
}
// TODO: use this in cleaned up ItemManager
int ItemManager::findFreeSlot(Player *plr) {
int i;
sItemBase free;
memset((void*)&free, 0, sizeof(sItemBase));
for (i = 0; i < AINVEN_COUNT; i++)
if (memcmp((void*)&plr->Inven[i], (void*)&free, sizeof(sItemBase)) == 0)
return i;
// not found
return -1;
}

View File

@ -1,9 +1,11 @@
#pragma once
#include "CNShardServer.hpp"
#include "Player.hpp"
namespace ItemManager {
void init();
void itemMoveHandler(CNSocket* sock, CNPacketData* data);
void itemDeleteHandler(CNSocket* sock, CNPacketData* data);
void itemGMGiveHandler(CNSocket* sock, CNPacketData* data);
@ -17,4 +19,7 @@ namespace ItemManager {
void itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* data);
void itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* data);
void itemTradeChatHandler(CNSocket* sock, CNPacketData* data);
void chestOpenHandler(CNSocket* sock, CNPacketData* data);
int findFreeSlot(Player *plr);
}

View File

@ -37,7 +37,7 @@ void NPCManager::init() {
// load temporary mob dump
try {
std::ifstream inFile("mobs.json"); // not in settings, since it's temp
std::ifstream inFile("data/mobs.json"); // not in settings, since it's temp
nlohmann::json npcData;
// read file into json

View File

@ -15,6 +15,7 @@ struct Player {
int HP;
int slot; // player slot, not nano slot
int32_t money;
int32_t fusionmatter;
sPCStyle PCStyle;
sPCStyle2 PCStyle2;
sNano Nanos[37]; // acquired nanos

View File

@ -32,6 +32,7 @@ void PlayerManager::init() {
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);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, PlayerManager::changePlayerGuide);
}
void PlayerManager::addPlayer(CNSocket* key, Player plr) {
@ -651,6 +652,21 @@ void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC));
}
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
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_CHANGE_MENTOR_SUCC, sizeof(sP_FE2CL_REP_PC_CHANGE_MENTOR_SUCC));
}
#pragma region Helper methods
Player *PlayerManager::getPlayer(CNSocket* key) {
return players[key].plr;

View File

@ -45,6 +45,7 @@ namespace PlayerManager {
void exitGame(CNSocket* sock, CNPacketData* data);
void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data);
void changePlayerGuide(CNSocket *sock, CNPacketData *data);
void enterPlayerVehicle(CNSocket* sock, CNPacketData* data);
void exitPlayerVehicle(CNSocket* sock, CNPacketData* data);

View File

@ -2,6 +2,7 @@
#include "CNShardServer.hpp"
#include "PlayerManager.hpp"
#include "ChatManager.hpp"
#include "CombatManager.hpp"
#include "ItemManager.hpp"
#include "MissionManager.hpp"
#include "NanoManager.hpp"
@ -17,10 +18,21 @@
#endif
#include <string>
CNShardServer *shardServer;
std::thread *shardThread;
void startShard(CNShardServer* server) {
server->start();
}
// terminate gracefully on SIGINT (for gprof)
void terminate(int arg) {
std::cout << "OpenFusion: terminating" << std::endl;
shardServer->kill();
shardThread->join();
exit(0);
}
int main() {
#ifdef _WIN32
WSADATA wsaData;
@ -31,12 +43,14 @@ int main() {
#else
// tell the OS to not kill us if you use a broken pipe, just let us know thru recv() or send()
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, terminate); // TODO: use sigaction() instead
#endif
settings::init();
std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl;
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
PlayerManager::init();
ChatManager::init();
CombatManager::init();
ItemManager::init();
MissionManager::init();
NanoManager::init();
@ -46,14 +60,14 @@ int main() {
std::cout << "[INFO] Starting Server Threads..." << std::endl;
CNLoginServer loginServer(settings::LOGINPORT);
CNShardServer shardServer(settings::SHARDPORT);
shardServer = new CNShardServer(settings::SHARDPORT);
std::thread shardThread(startShard, (CNShardServer*)&shardServer);
shardThread = new std::thread(startShard, (CNShardServer*)shardServer);
loginServer.start();
shardServer.kill();
shardThread.join();
shardServer->kill();
shardThread->join();
#ifdef _WIN32
WSACleanup();

View File

@ -18,8 +18,8 @@ int settings::SPAWN_X = 179213;
int settings::SPAWN_Y = 268451;
int settings::SPAWN_Z = -4210;
std::string settings::GMPASS = "pass";
std::string settings::NPCJSON = "NPCs.json";
std::string settings::WARPJSON = "warps.json";
std::string settings::NPCJSON = "data/NPCs.json";
std::string settings::WARPJSON = "data/warps.json";
std::string settings::MOTDSTRING = "Welcome to OpenFusion!";
bool settings::GM = false;