Vehicle and trading bugfixes (#51)

* Sanity checks + Starting level changes

- Item movement handler checks to make sure items aren't moved from equipment slot to equipment slot.
- Item give command checks to make sure an out of bounds item is not spawned (Below iType 0 or above iType 8)
- Players now begin at level 36, consequently the item give command does not level you up now.

* Initial Trade Implementation

* Sanity Check

- Prevents out of bounds item movement by comparing it to AINVEN_COUNT.

* Taros and Trading

* Update ItemManager.cpp

* Update ItemManager.cpp

* working trading system

* Trading system code pointerified

- It works with the recent pointer changes needed.

* Vehicles and Trading bugfixes
This commit is contained in:
JadeShrineMaiden 2020-08-27 03:35:13 +01:00 committed by GitHub
parent 64d4b1d26a
commit 5c8a0069fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 132 additions and 70 deletions

View File

@ -93,6 +93,8 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
loginSessions[sock].characters[UID].z = charInfo.iZ;
loginSessions[sock].characters[UID].PCStyle = charInfo.sPC_Style;
loginSessions[sock].characters[UID].PCStyle2 = charInfo.sPC_Style2;
loginSessions[sock].characters[UID].isTrading = false;
loginSessions[sock].characters[UID].isTradeConfirm = false;
loginSessions[sock].characters[UID].IsGM = settings::GM;
for (int i = 0; i < AEQUIP_COUNT; i++) {
@ -228,7 +230,9 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
loginSessions[sock].characters[UID].Equip[2].iID = character->sOn_Item.iEquipLBID; // lower body
loginSessions[sock].characters[UID].Equip[2].iType = 2;
loginSessions[sock].characters[UID].Equip[3].iID = character->sOn_Item.iEquipFootID; // foot!
loginSessions[sock].characters[UID].Equip[3].iType = 3;
loginSessions[sock].characters[UID].Equip[3].iType = 3;
loginSessions[sock].characters[UID].isTrading = false;
loginSessions[sock].characters[UID].isTradeConfirm = false;
loginSessions[sock].characters[UID].IsGM = settings::GM;
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHAR_CREATE_SUCC, sizeof(sP_LS2CL_REP_CHAR_CREATE_SUCC));

View File

@ -32,7 +32,7 @@ void CNShardServer::keepAliveTimer(CNServer* serv, uint64_t currTime) {
auto cachedPlayers = PlayerManager::players;
for (auto pair : cachedPlayers) {
if (pair.second.lastHeartbeat != 0 && currTime - pair.second.lastHeartbeat > 4000) { // if the client hadn't responded in 4 seconds, its a dead connection so throw it out
if (pair.second.lastHeartbeat != 0 && currTime - pair.second.lastHeartbeat > 60000) { // if the client hadn't responded in 60 seconds, its a dead connection so throw it out
pair.first->kill();
continue;
}

View File

@ -17,6 +17,7 @@ void ItemManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, itemTradeRegisterItemHandler);
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);
}
void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
@ -41,7 +42,7 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
return;
}
if (itemmove->iToSlotNum > AINVEN_COUNT)
if (itemmove->iToSlotNum > AINVEN_COUNT || itemmove->iToSlotNum < 0)
return; // sanity checks
sItemBase fromItem;
@ -82,6 +83,10 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
equipChange.iEquipSlotNum = itemmove->iToSlotNum;
equipChange.EquipSlotItem = fromItem;
}
// unequip vehicle if equip slot 8 is 0
if (plr.plr->Equip[8].iID == 0)
plr.plr->iPCState = 0;
// send equip event to other players
for (CNSocket* otherSock : plr.viewable) {
@ -171,6 +176,20 @@ void ItemManager::itemTradeOfferHandler(CNSocket* sock, CNPacketData* data) {
}
}
PlayerView& plr = PlayerManager::players[otherSock];
if (plr.plr->isTrading) {
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp);
resp.iID_Request = pacdat->iID_To;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL));
return; //prevent trading with a player already trading
}
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER, resp);
resp.iID_Request = pacdat->iID_Request;
@ -213,8 +232,22 @@ void ItemManager::itemTradeOfferAcceptHandler(CNSocket* sock, CNPacketData* data
PlayerView& plr = PlayerManager::players[sock];
PlayerView& plr2 = PlayerManager::players[otherSock];
plr.plr->IsTradeConfirm = false;
plr2.plr->IsTradeConfirm = false;
if (plr2.plr->isTrading) {
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp);
resp.iID_Request = pacdat->iID_To;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL));
return; //prevent trading with a player already trading
}
plr.plr->isTrading = true;
plr2.plr->isTrading = true;
plr.plr->isTradeConfirm = false;
plr2.plr->isTradeConfirm = false;
for (int i = 0; i < 5; i++) {
plr.plr->Trade[i].iID = 0;
@ -290,12 +323,12 @@ void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) {
PlayerView& plr = PlayerManager::players[sock];
PlayerView& plr2 = PlayerManager::players[otherSock];
if (plr2.plr->IsTradeConfirm) {
if (plr2.plr->isTradeConfirm) {
plr.plr->IsTrading = false;
plr2.plr->IsTrading = false;
plr.plr->IsTradeConfirm = false;
plr2.plr->IsTradeConfirm = false;
plr.plr->isTrading = false;
plr2.plr->isTrading = false;
plr.plr->isTradeConfirm = false;
plr2.plr->isTradeConfirm = false;
// Check if we have enough free slots
int freeSlots = 0;
@ -323,23 +356,15 @@ void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) {
freeSlotsNeeded2++;
}
DEBUGLOG(
std::cout << "Slots Free and Needed:" << std::endl;
std::cout << "\tfreeSlots: " << (int)freeSlots << std::endl;
std::cout << "\tfreeSlotsNeeded: " << (int)freeSlotsNeeded << std::endl;
std::cout << "\tfreeSlots2: " << (int)freeSlots2 << std::endl;
std::cout << "\tfreeSlotsNeeded2: " << (int)freeSlotsNeeded2 << std::endl;
)
if (freeSlotsNeeded2 - freeSlotsNeeded > freeSlots) {
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, resp);
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, resp);
resp.iID_Request = pacdat->iID_Request;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL));
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT));
return; // Fail trade because of the lack of slots
}
@ -386,15 +411,6 @@ void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) {
plr2.plr->Inven[i].iType = plr.plr->Trade[freeSlotsNeeded - 1].iType;
plr2.plr->Inven[i].iOpt = plr.plr->Trade[freeSlotsNeeded - 1].iOpt;
plr.plr->Trade[freeSlotsNeeded - 1].iInvenNum = i;
DEBUGLOG(
std::cout << "Player 1 Trade Item #" << (int)freeSlotsNeeded << std::endl;
std::cout << "\tiID: " << (int)plr.plr->Trade[freeSlotsNeeded - 1].iID << std::endl;
std::cout << "\tiType: " << (int)plr.plr->Trade[freeSlotsNeeded - 1].iType << std::endl;
std::cout << "\tiOpt: " << (int)plr.plr->Trade[freeSlotsNeeded - 1].iOpt << std::endl;
std::cout << "\tiInvenNum: " << (int)plr.plr->Trade[freeSlotsNeeded - 1].iInvenNum << std::endl;
std::cout << "\tiSlotNum: " << (int)plr.plr->Trade[freeSlotsNeeded - 1].iSlotNum << std::endl;
std::cout << "\t added item " << (int)plr2.plr->Inven[i].iID << " to slot " << (int)i << std::endl;
)
freeSlotsNeeded--;
}
}
@ -409,15 +425,6 @@ void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) {
plr.plr->Inven[i].iType = plr2.plr->Trade[freeSlotsNeeded2 - 1].iType;
plr.plr->Inven[i].iOpt = plr2.plr->Trade[freeSlotsNeeded2 - 1].iOpt;
plr2.plr->Trade[freeSlotsNeeded2 - 1].iInvenNum = i;
DEBUGLOG(
std::cout << "Player 2 Trade Item #" << (int)freeSlotsNeeded2 << std::endl;
std::cout << "\tiID: " << (int)plr2.plr->Trade[freeSlotsNeeded2 - 1].iID << std::endl;
std::cout << "\tiType: " << (int)plr2.plr->Trade[freeSlotsNeeded2 - 1].iType << std::endl;
std::cout << "\tiOpt: " << (int)plr2.plr->Trade[freeSlotsNeeded2 - 1].iOpt << std::endl;
std::cout << "\tiInvenNum: " << (int)plr2.plr->Trade[freeSlotsNeeded2 - 1].iInvenNum << std::endl;
std::cout << "\tiSlotNum: " << (int)plr2.plr->Trade[freeSlotsNeeded2 - 1].iSlotNum << std::endl;
std::cout << "\t added item " << (int)plr.plr->Inven[i].iID << " to slot " << (int)i << std::endl;
)
freeSlotsNeeded2--;
}
}
@ -451,7 +458,7 @@ void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) {
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
plr.plr->IsTradeConfirm = true;
plr.plr->isTradeConfirm = true;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM));
@ -486,8 +493,12 @@ void ItemManager::itemTradeConfirmCancelHandler(CNSocket* sock, CNPacketData* da
}
PlayerView& plr = PlayerManager::players[sock];
PlayerView& plr2 = PlayerManager::players[otherSock];
plr.plr->IsTradeConfirm = false;
plr.plr->isTrading = false;
plr.plr->isTradeConfirm = false;
plr2.plr->isTrading = false;
plr2.plr->isTradeConfirm = false;
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL));
}
@ -527,6 +538,7 @@ void ItemManager::itemTradeRegisterItemHandler(CNSocket* sock, CNPacketData* dat
PlayerView& plr = PlayerManager::players[sock];
plr.plr->Trade[pacdat->Item.iSlotNum] = pacdat->Item;
plr.plr->isTradeConfirm = false;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC));
@ -546,6 +558,7 @@ void ItemManager::itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* d
PlayerView& plr = PlayerManager::players[sock];
resp.InvenItem = plr.plr->Trade[pacdat->Item.iSlotNum];
plr.plr->isTradeConfirm = false;
int iID_Check;
@ -583,7 +596,9 @@ void ItemManager::itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* dat
sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER*)data->buf;
if (pacdat->iCandy < 0)
PlayerView& plr = PlayerManager::players[sock];
if (pacdat->iCandy < 0 || pacdat->iCandy > plr.plr->money)
return; // famous glitch, begone
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, resp);
@ -609,10 +624,44 @@ void ItemManager::itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* dat
}
}
PlayerView& plr = PlayerManager::players[sock];
plr.plr->moneyInTrade = pacdat->iCandy;
plr.plr->isTradeConfirm = false;
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC));
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC));
}
void ItemManager::itemTradeChatHandler(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT))
return; // malformed packet
sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT* pacdat = (sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT*)data->buf;
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT, resp);
resp.iID_Request = pacdat->iID_Request;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
memcpy(resp.szFreeChat, pacdat->szFreeChat, sizeof(pacdat->szFreeChat));
resp.iEmoteCode = pacdat->iEmoteCode;
int iID_Check;
if (pacdat->iID_Request == pacdat->iID_From) {
iID_Check = pacdat->iID_To;
} else {
iID_Check = pacdat->iID_From;
}
CNSocket* otherSock = sock;
for (auto pair : PlayerManager::players) {
if (pair.second.plr->iID == iID_Check) {
otherSock = pair.first;
}
}
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));
}

View File

@ -16,4 +16,5 @@ namespace ItemManager {
void itemTradeRegisterItemHandler(CNSocket* sock, CNPacketData* data);
void itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* data);
void itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* data);
void itemTradeChatHandler(CNSocket* sock, CNPacketData* data);
}

View File

@ -27,7 +27,7 @@ struct Player {
sItemBase Inven[AINVEN_COUNT];
sItemTrade Trade[12];
int32_t moneyInTrade;
bool IsTrading;
bool IsTradeConfirm;
bool isTrading;
bool isTradeConfirm;
bool IsGM;
};

View File

@ -601,37 +601,45 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
}
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));
PlayerView& plr = PlayerManager::players[sock];
if (plr.plr->Equip[8].iID > 0) {
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response);
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
//send to other players
plr.plr->iPCState = 8;
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
response2.iPC_ID = plr.plr->iID;
response2.iState = 8;
for (CNSocket* otherSock : plr.viewable) {
otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
}
} else {
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_FAIL, response);
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_FAIL, sizeof(sP_FE2CL_PC_VEHICLE_ON_FAIL));
}
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];
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC));
PlayerView plr = 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));
plr.plr->iPCState = 0;
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
response2.iPC_ID = plr.plr->iID;
response2.iState = 0;
for (CNSocket* otherSock : plr.viewable) {
otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
}
}
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {