mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 13:30:06 +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;
|
return;
|
||||||
// NOTE: sending a no-op, "move in-place" packet is not necessary
|
// 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
|
// get the fromItem
|
||||||
sItemBase *fromItem;
|
sItemBase *fromItem;
|
||||||
switch ((SlotType)itemmove->eFrom) {
|
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))
|
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN))
|
||||||
return; // ignore the malformed packet
|
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
|
// 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;
|
std::cout << "[WARN] Player tried to open a crate with incorrect iType ?!" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ACADEMY
|
#ifdef ACADEMY
|
||||||
// check if chest isn't a nano capsule
|
// check if chest isn't a nano capsule
|
||||||
if (NanoCapsules.find(chest->ChestItem.iID) != NanoCapsules.end())
|
if (NanoCapsules.find(chest->iID) != NanoCapsules.end())
|
||||||
return nanoCapsuleHandler(sock, chest);
|
return nanoCapsuleHandler(sock, pkt->iSlotNum, chest);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Player *plr = PlayerManager::getPlayer(sock);
|
|
||||||
// chest opening acknowledgement packet
|
// chest opening acknowledgement packet
|
||||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
||||||
resp.iSlotNum = chest->iSlotNum;
|
resp.iSlotNum = pkt->iSlotNum;
|
||||||
|
|
||||||
// item giving packet
|
// item giving packet
|
||||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
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_iBatteryN = plr->batteryN;
|
||||||
reward->m_iBatteryW = plr->batteryW;
|
reward->m_iBatteryW = plr->batteryW;
|
||||||
|
|
||||||
item->iSlotNum = chest->iSlotNum;
|
item->iSlotNum = pkt->iSlotNum;
|
||||||
item->eIL = chest->eIL;
|
item->eIL = 1;
|
||||||
|
|
||||||
int itemSetId = -1, rarity = -1, ret = -1;
|
int itemSetId = -1, rarity = -1, ret = -1;
|
||||||
bool failing = false;
|
bool failing = false;
|
||||||
|
|
||||||
// find the crate
|
// find the crate
|
||||||
if (Crates.find(chest->ChestItem.iID) == Crates.end()) {
|
if (Crates.find(chest->iID) == Crates.end()) {
|
||||||
std::cout << "[WARN] Crate " << chest->ChestItem.iID << " not found!" << std::endl;
|
std::cout << "[WARN] Crate " << chest->iID << " not found!" << std::endl;
|
||||||
failing = true;
|
failing = true;
|
||||||
}
|
}
|
||||||
Crate& crate = Crates[chest->ChestItem.iID];
|
Crate& crate = Crates[chest->iID];
|
||||||
|
|
||||||
if (!failing)
|
if (!failing)
|
||||||
itemSetId = getItemSetId(crate, chest->ChestItem.iID);
|
itemSetId = getItemSetId(crate, chest->iID);
|
||||||
if (itemSetId == -1)
|
if (itemSetId == -1)
|
||||||
failing = true;
|
failing = true;
|
||||||
|
|
||||||
@ -879,7 +891,7 @@ void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
|||||||
item->sItem.iOpt = 1;
|
item->sItem.iOpt = 1;
|
||||||
}
|
}
|
||||||
// update player
|
// update player
|
||||||
plr->Inven[chest->iSlotNum] = item->sItem;
|
plr->Inven[pkt->iSlotNum] = item->sItem;
|
||||||
|
|
||||||
// transmit item
|
// transmit item
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
@ -1064,13 +1076,13 @@ void ItemManager::updateEquips(CNSocket* sock, Player* plr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ACADEMY
|
#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);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
int32_t nanoId = NanoCapsules[chest->ChestItem.iID];
|
int32_t nanoId = NanoCapsules[chest->iID];
|
||||||
|
|
||||||
// chest opening acknowledgement packet
|
// chest opening acknowledgement packet
|
||||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
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
|
// 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);
|
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_iBatteryN = plr->batteryN;
|
||||||
reward->m_iBatteryW = plr->batteryW;
|
reward->m_iBatteryW = plr->batteryW;
|
||||||
|
|
||||||
item->iSlotNum = chest->iSlotNum;
|
item->iSlotNum = slot;
|
||||||
item->eIL = chest->eIL;
|
item->eIL = 1;
|
||||||
|
|
||||||
// update player serverside
|
// update player serverside
|
||||||
plr->Inven[chest->iSlotNum] = item->sItem;
|
plr->Inven[slot] = item->sItem;
|
||||||
|
|
||||||
// transmit item
|
// transmit item
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
|
@ -23,7 +23,11 @@ namespace ItemManager {
|
|||||||
};
|
};
|
||||||
struct Item {
|
struct Item {
|
||||||
bool tradeable, sellable;
|
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
|
// 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
|
extern std::map<std::pair<int32_t, int32_t>, Item> ItemData; // <id, type> -> data
|
||||||
@ -69,6 +73,6 @@ namespace ItemManager {
|
|||||||
|
|
||||||
#ifdef ACADEMY
|
#ifdef ACADEMY
|
||||||
extern std::map<int32_t, int32_t> NanoCapsules; // crate id -> nano id
|
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
|
#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;
|
sP_CL2FE_REQ_PC_ITEM_COMBINATION* req = (sP_CL2FE_REQ_PC_ITEM_COMBINATION*)data->buf;
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
if (req->iCostumeItemSlot < 0 || req->iCostumeItemSlot >= AINVEN_COUNT || req->iStatItemSlot < 0 || req->iStatItemSlot >= AINVEN_COUNT) { // sanity check 1
|
// prepare fail packet
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, failResp);
|
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, failResp);
|
||||||
failResp.iCostumeItemSlot = req->iCostumeItemSlot;
|
failResp.iCostumeItemSlot = req->iCostumeItemSlot;
|
||||||
failResp.iStatItemSlot = req->iStatItemSlot;
|
failResp.iStatItemSlot = req->iStatItemSlot;
|
||||||
failResp.iErrorCode = 0;
|
failResp.iErrorCode = 0;
|
||||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, sizeof(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL));
|
|
||||||
|
// 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;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,17 +379,22 @@ void NPCManager::npcCombineItems(CNSocket* sock, CNPacketData* data) {
|
|||||||
ItemManager::Item* itemStatsDat = ItemManager::getItemData(itemStats->iID, itemStats->iType);
|
ItemManager::Item* itemStatsDat = ItemManager::getItemData(itemStats->iID, itemStats->iType);
|
||||||
ItemManager::Item* itemLooksDat = ItemManager::getItemData(itemLooks->iID, itemLooks->iType);
|
ItemManager::Item* itemLooksDat = ItemManager::getItemData(itemLooks->iID, itemLooks->iType);
|
||||||
|
|
||||||
|
// sanity check item and combination entry existence
|
||||||
if (itemStatsDat == nullptr || itemLooksDat == nullptr
|
if (itemStatsDat == nullptr || itemLooksDat == nullptr
|
||||||
|| ItemManager::CrocPotTable.find(abs(itemStatsDat->level - itemLooksDat->level)) == ItemManager::CrocPotTable.end()) { // sanity check 2
|
|| ItemManager::CrocPotTable.find(abs(itemStatsDat->level - itemLooksDat->level)) == ItemManager::CrocPotTable.end()) {
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, failResp);
|
|
||||||
failResp.iCostumeItemSlot = req->iCostumeItemSlot;
|
|
||||||
failResp.iStatItemSlot = req->iStatItemSlot;
|
|
||||||
failResp.iErrorCode = 0;
|
|
||||||
std::cout << "[WARN] Either item ids or croc pot value set not found" << std::endl;
|
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));
|
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL, sizeof(sP_FE2CL_REP_PC_ITEM_COMBINATION_FAIL));
|
||||||
return;
|
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)];
|
CrocPotEntry* recipe = &ItemManager::CrocPotTable[abs(itemStatsDat->level - itemLooksDat->level)];
|
||||||
int cost = itemStatsDat->buyPrice * recipe->multStats + itemLooksDat->buyPrice * recipe->multLooks;
|
int cost = itemStatsDat->buyPrice * recipe->multStats + itemLooksDat->buyPrice * recipe->multLooks;
|
||||||
float successChance = recipe->base / 100.0f; // base success chance
|
float successChance = recipe->base / 100.0f; // base success chance
|
||||||
|
@ -160,6 +160,7 @@ void TableData::init() {
|
|||||||
itemData.fireRate = item["m_iDelayTime"];
|
itemData.fireRate = item["m_iDelayTime"];
|
||||||
itemData.defense = item["m_iDefenseRat"];
|
itemData.defense = item["m_iDefenseRat"];
|
||||||
itemData.gender = item["m_iReqSex"];
|
itemData.gender = item["m_iReqSex"];
|
||||||
|
itemData.weaponType = item["m_iEquipType"];
|
||||||
} else {
|
} else {
|
||||||
itemData.rarity = 1;
|
itemData.rarity = 1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user