diff --git a/src/CNLoginServer.cpp b/src/CNLoginServer.cpp index 5217c7d..5af4c72 100644 --- a/src/CNLoginServer.cpp +++ b/src/CNLoginServer.cpp @@ -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)); diff --git a/src/CNShardServer.cpp b/src/CNShardServer.cpp index 9c3f49c..b9969e1 100644 --- a/src/CNShardServer.cpp +++ b/src/CNShardServer.cpp @@ -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; } diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index bb7b61c..ad11e55 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -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)); +} \ No newline at end of file diff --git a/src/ItemManager.hpp b/src/ItemManager.hpp index 197b863..44cf281 100644 --- a/src/ItemManager.hpp +++ b/src/ItemManager.hpp @@ -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); } diff --git a/src/Player.hpp b/src/Player.hpp index c228b91..e60bdf8 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -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; }; diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 78441dd..2b1ad85 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -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) {