mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-12-23 03:40:05 +00:00
Improve sanity checks when opening crates and combining items
And ignore ITEM_MOVE packets while trading.
This commit is contained in:
parent
d781fae3ba
commit
0fbdb1dad2
@ -58,6 +58,11 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
return;
|
||||
// NOTE: sending a no-op, "move in-place" packet is not necessary
|
||||
|
||||
if (plr->isTrading) {
|
||||
std::cout << "[WARN] Player attempted to move item while trading" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the fromItem
|
||||
sItemBase *fromItem;
|
||||
switch ((SlotType)itemmove->eFrom) {
|
||||
@ -804,24 +809,31 @@ 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 *chest = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf;
|
||||
sP_CL2FE_REQ_ITEM_CHEST_OPEN *pkt = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf;
|
||||
|
||||
// sanity check
|
||||
if (chest->ChestItem.iType != 9) {
|
||||
if (pkt->eIL != 1 || pkt->iSlotNum < 0 || pkt->iSlotNum >= AINVEN_COUNT)
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
sItemBase *chest = &plr->Inven[pkt->iSlotNum];
|
||||
// we could reject the packet if the client thinks the item is different, but eh
|
||||
|
||||
if (chest->iType != 9) {
|
||||
std::cout << "[WARN] Player tried to open a crate with incorrect iType ?!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ACADEMY
|
||||
// check if chest isn't a nano capsule
|
||||
if (NanoCapsules.find(chest->ChestItem.iID) != NanoCapsules.end())
|
||||
return nanoCapsuleHandler(sock, chest);
|
||||
if (NanoCapsules.find(chest->iID) != NanoCapsules.end())
|
||||
return nanoCapsuleHandler(sock, pkt->iSlotNum, chest);
|
||||
#endif
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
// chest opening acknowledgement packet
|
||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
||||
resp.iSlotNum = chest->iSlotNum;
|
||||
resp.iSlotNum = pkt->iSlotNum;
|
||||
|
||||
// item giving packet
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
@ -844,21 +856,21 @@ void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
reward->m_iBatteryN = plr->batteryN;
|
||||
reward->m_iBatteryW = plr->batteryW;
|
||||
|
||||
item->iSlotNum = chest->iSlotNum;
|
||||
item->eIL = chest->eIL;
|
||||
item->iSlotNum = pkt->iSlotNum;
|
||||
item->eIL = 1;
|
||||
|
||||
int itemSetId = -1, rarity = -1, ret = -1;
|
||||
bool failing = false;
|
||||
|
||||
// find the crate
|
||||
if (Crates.find(chest->ChestItem.iID) == Crates.end()) {
|
||||
std::cout << "[WARN] Crate " << chest->ChestItem.iID << " not found!" << std::endl;
|
||||
if (Crates.find(chest->iID) == Crates.end()) {
|
||||
std::cout << "[WARN] Crate " << chest->iID << " not found!" << std::endl;
|
||||
failing = true;
|
||||
}
|
||||
Crate& crate = Crates[chest->ChestItem.iID];
|
||||
Crate& crate = Crates[chest->iID];
|
||||
|
||||
if (!failing)
|
||||
itemSetId = getItemSetId(crate, chest->ChestItem.iID);
|
||||
itemSetId = getItemSetId(crate, chest->iID);
|
||||
if (itemSetId == -1)
|
||||
failing = true;
|
||||
|
||||
@ -879,7 +891,7 @@ void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
item->sItem.iOpt = 1;
|
||||
}
|
||||
// update player
|
||||
plr->Inven[chest->iSlotNum] = item->sItem;
|
||||
plr->Inven[pkt->iSlotNum] = item->sItem;
|
||||
|
||||
// transmit item
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
@ -1064,13 +1076,13 @@ void ItemManager::updateEquips(CNSocket* sock, Player* plr) {
|
||||
}
|
||||
|
||||
#ifdef ACADEMY
|
||||
void ItemManager::nanoCapsuleHandler(CNSocket* sock, sP_CL2FE_REQ_ITEM_CHEST_OPEN* chest) {
|
||||
void ItemManager::nanoCapsuleHandler(CNSocket* sock, int slot, sItemBase *chest) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
int32_t nanoId = NanoCapsules[chest->ChestItem.iID];
|
||||
int32_t nanoId = NanoCapsules[chest->iID];
|
||||
|
||||
// chest opening acknowledgement packet
|
||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
||||
resp.iSlotNum = chest->iSlotNum;
|
||||
resp.iSlotNum = slot;
|
||||
|
||||
// in order to remove capsule form inventory, we have to send item reward packet with empty item
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
@ -1093,11 +1105,11 @@ void ItemManager::nanoCapsuleHandler(CNSocket* sock, sP_CL2FE_REQ_ITEM_CHEST_OPE
|
||||
reward->m_iBatteryN = plr->batteryN;
|
||||
reward->m_iBatteryW = plr->batteryW;
|
||||
|
||||
item->iSlotNum = chest->iSlotNum;
|
||||
item->eIL = chest->eIL;
|
||||
item->iSlotNum = slot;
|
||||
item->eIL = 1;
|
||||
|
||||
// update player serverside
|
||||
plr->Inven[chest->iSlotNum] = item->sItem;
|
||||
plr->Inven[slot] = item->sItem;
|
||||
|
||||
// transmit item
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
|
@ -23,7 +23,11 @@ namespace ItemManager {
|
||||
};
|
||||
struct Item {
|
||||
bool tradeable, sellable;
|
||||
int buyPrice, sellPrice, stackSize, level, rarity, pointDamage, groupDamage, fireRate, defense, gender; // TODO: implement more as needed
|
||||
int buyPrice, sellPrice;
|
||||
int stackSize, level, rarity;
|
||||
int pointDamage, groupDamage, fireRate, defense, gender;
|
||||
int weaponType;
|
||||
// TODO: implement more as needed
|
||||
};
|
||||
// hopefully this is fine since it's never modified after load
|
||||
extern std::map<std::pair<int32_t, int32_t>, Item> ItemData; // <id, type> -> data
|
||||
@ -69,6 +73,6 @@ namespace ItemManager {
|
||||
|
||||
#ifdef ACADEMY
|
||||
extern std::map<int32_t, int32_t> NanoCapsules; // crate id -> nano id
|
||||
void nanoCapsuleHandler(CNSocket* sock, sP_CL2FE_REQ_ITEM_CHEST_OPEN* chest);
|
||||
void nanoCapsuleHandler(CNSocket* sock, int slot, sItemBase *chest);
|
||||
#endif
|
||||
}
|
||||
|
@ -361,13 +361,16 @@ void NPCManager::npcCombineItems(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_ITEM_COMBINATION* req = (sP_CL2FE_REQ_PC_ITEM_COMBINATION*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (req->iCostumeItemSlot < 0 || req->iCostumeItemSlot >= AINVEN_COUNT || req->iStatItemSlot < 0 || req->iStatItemSlot >= AINVEN_COUNT) { // sanity check 1
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, failResp);
|
||||
failResp.iCostumeItemSlot = req->iCostumeItemSlot;
|
||||
failResp.iStatItemSlot = req->iStatItemSlot;
|
||||
failResp.iErrorCode = 0;
|
||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, sizeof(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL));
|
||||
// prepare fail packet
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, failResp);
|
||||
failResp.iCostumeItemSlot = req->iCostumeItemSlot;
|
||||
failResp.iStatItemSlot = req->iStatItemSlot;
|
||||
failResp.iErrorCode = 0;
|
||||
|
||||
// sanity check slot indices
|
||||
if (req->iCostumeItemSlot < 0 || req->iCostumeItemSlot >= AINVEN_COUNT || req->iStatItemSlot < 0 || req->iStatItemSlot >= AINVEN_COUNT) {
|
||||
std::cout << "[WARN] Inventory slot(s) out of range (" << req->iStatItemSlot << " and " << req->iCostumeItemSlot << ")" << std::endl;
|
||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, sizeof(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -376,17 +379,22 @@ void NPCManager::npcCombineItems(CNSocket* sock, CNPacketData* data) {
|
||||
ItemManager::Item* itemStatsDat = ItemManager::getItemData(itemStats->iID, itemStats->iType);
|
||||
ItemManager::Item* itemLooksDat = ItemManager::getItemData(itemLooks->iID, itemLooks->iType);
|
||||
|
||||
// sanity check item and combination entry existence
|
||||
if (itemStatsDat == nullptr || itemLooksDat == nullptr
|
||||
|| ItemManager::CrocPotTable.find(abs(itemStatsDat->level - itemLooksDat->level)) == ItemManager::CrocPotTable.end()) { // sanity check 2
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, failResp);
|
||||
failResp.iCostumeItemSlot = req->iCostumeItemSlot;
|
||||
failResp.iStatItemSlot = req->iStatItemSlot;
|
||||
failResp.iErrorCode = 0;
|
||||
|| ItemManager::CrocPotTable.find(abs(itemStatsDat->level - itemLooksDat->level)) == ItemManager::CrocPotTable.end()) {
|
||||
std::cout << "[WARN] Either item ids or croc pot value set not found" << std::endl;
|
||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, sizeof(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
// sanity check matching item types
|
||||
if (itemStats->iType != itemLooks->iType
|
||||
|| (itemStats->iType == 0 && itemStatsDat->weaponType != itemLooksDat->weaponType)) {
|
||||
std::cout << "[WARN] Player attempted to combine mismatched items" << std::endl;
|
||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, sizeof(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
CrocPotEntry* recipe = &ItemManager::CrocPotTable[abs(itemStatsDat->level - itemLooksDat->level)];
|
||||
int cost = itemStatsDat->buyPrice * recipe->multStats + itemLooksDat->buyPrice * recipe->multLooks;
|
||||
float successChance = recipe->base / 100.0f; // base success chance
|
||||
|
@ -160,6 +160,7 @@ void TableData::init() {
|
||||
itemData.fireRate = item["m_iDelayTime"];
|
||||
itemData.defense = item["m_iDefenseRat"];
|
||||
itemData.gender = item["m_iReqSex"];
|
||||
itemData.weaponType = item["m_iEquipType"];
|
||||
} else {
|
||||
itemData.rarity = 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user