diff options
-rw-r--r-- | src/account-server/storage.cpp | 42 | ||||
-rw-r--r-- | src/common/inventorydata.h | 46 | ||||
-rw-r--r-- | src/game-server/buysell.cpp | 6 | ||||
-rw-r--r-- | src/game-server/inventory.cpp | 50 | ||||
-rw-r--r-- | src/game-server/state.cpp | 8 | ||||
-rw-r--r-- | src/serialize/characterdata.h | 45 | ||||
-rw-r--r-- | src/sql/mysql/createTables.sql | 6 | ||||
-rw-r--r-- | src/sql/sqlite/createTables.sql | 3 |
8 files changed, 117 insertions, 89 deletions
diff --git a/src/account-server/storage.cpp b/src/account-server/storage.cpp index 96601207..05f8ec69 100644 --- a/src/account-server/storage.cpp +++ b/src/account-server/storage.cpp @@ -490,17 +490,26 @@ Character *Storage::getCharacterBySQL(Account *owner) try { std::ostringstream sql; - sql << " select slot_type, inventory_slot from " + sql << " select slot_type, item_id, item_instance from " << CHAR_EQUIPS_TBL_NAME << " where owner_id = '" << character->getDatabaseID() << "' order by slot_type desc;"; + EquipData equipData; const dal::RecordSet &equipInfo = mDb->execSql(sql.str()); if (!equipInfo.isEmpty()) + { + EquipmentItem equipItem; for (int k = 0, size = equipInfo.rows(); k < size; ++k) - poss.equipSlots.insert(std::pair<unsigned int, unsigned int>( - toUint(equipInfo(k, 0)), - toUint(equipInfo(k, 1)))); + { + equipItem.itemId = toUint(equipInfo(k, 1)); + equipItem.itemInstance = toUint(equipInfo(k, 2)); + equipData.insert(std::pair<unsigned int, EquipmentItem>( + toUint(equipInfo(k, 0)), + equipItem)); + } + } + poss.setEquipment(equipData); } catch (const dal::DbSqlQueryExecFailure &e) { @@ -515,6 +524,7 @@ Character *Storage::getCharacterBySQL(Account *owner) << " where owner_id = '" << character->getDatabaseID() << "' order by slot asc;"; + InventoryData inventoryData; const dal::RecordSet &itemInfo = mDb->execSql(sql.str()); if (!itemInfo.isEmpty()) { @@ -524,9 +534,10 @@ Character *Storage::getCharacterBySQL(Account *owner) unsigned short slot = toUint(itemInfo(k, 2)); item.itemId = toUint(itemInfo(k, 3)); item.amount = toUint(itemInfo(k, 4)); - poss.inventory[slot] = item; + inventoryData[slot] = item; } } + poss.setInventory(inventoryData); } catch (const dal::DbSqlQueryExecFailure &e) { @@ -798,18 +809,18 @@ bool Storage::updateCharacter(Character *character) std::ostringstream sql; sql << "insert into " << CHAR_EQUIPS_TBL_NAME - << " (owner_id, slot_type, inventory_slot) values (" + << " (owner_id, slot_type, item_id, item_instance) values (" << character->getDatabaseID() << ", "; std::string base = sql.str(); const Possessions &poss = character->getPossessions(); - for (EquipData::const_iterator it = poss.equipSlots.begin(), - it_end = poss.equipSlots.end(); - it != it_end; - ++it) + const EquipData &equipData = poss.getEquipment(); + for (EquipData::const_iterator it = equipData.begin(), + it_end = equipData.end(); it != it_end; ++it) { sql.str(""); - sql << base << it->first << ", " << it->second << ");"; + sql << base << it->first << ", " << it->second.itemId + << ", " << it->second.itemInstance << ");"; mDb->execSql(sql.str()); } @@ -820,13 +831,14 @@ bool Storage::updateCharacter(Character *character) << character->getDatabaseID() << ", "; base = sql.str(); - for (InventoryData::const_iterator j = poss.inventory.begin(), - j_end = poss.inventory.end(); j != j_end; ++j) + const InventoryData &inventoryData = poss.getInventory(); + for (InventoryData::const_iterator j = inventoryData.begin(), + j_end = inventoryData.end(); j != j_end; ++j) { sql.str(""); unsigned short slot = j->first; - unsigned int itemId = j->second.itemId; - unsigned int amount = j->second.amount; + unsigned int itemId = j->second.itemId; + unsigned int amount = j->second.amount; assert(itemId); sql << base << slot << ", " << itemId << ", " << amount << ");"; mDb->execSql(sql.str()); diff --git a/src/common/inventorydata.h b/src/common/inventorydata.h index 9127c816..e7c81170 100644 --- a/src/common/inventorydata.h +++ b/src/common/inventorydata.h @@ -35,20 +35,56 @@ */ struct InventoryItem { + InventoryItem(): + itemId(0), amount(0) + {} + unsigned int itemId; unsigned int amount; }; -// slot id -> { item } -typedef std::map< unsigned short, InventoryItem > InventoryData; -// equip slot type -> { slot ids } -// Equipment taking up multiple slots will be referenced multiple times -typedef std::multimap< unsigned int, unsigned int > EquipData; + +struct EquipmentItem +{ + EquipmentItem(): + itemId(0), itemInstance(0) + {} + + // The item id taken from the item db. + unsigned int itemId; + // A unique instance number used to separate items when equipping the same + // item id multiple times on possible multiple slots. + unsigned int itemInstance; +}; + +// inventory slot id -> { item } +typedef std::map< unsigned int, InventoryItem > InventoryData; + +// equip slot id -> { item id } +// Equipment taking up multiple equip slot ids will be referenced multiple times +typedef std::multimap< unsigned int, EquipmentItem > EquipData; /** * Structure storing the equipment and inventory of a Player. */ struct Possessions { + friend class Inventory; +public: + const EquipData &getEquipment() const + { return equipSlots; } + + const InventoryData &getInventory() const + { return inventory; } + + /** + * Should be done only at character serialization and storage load time. + */ + void setEquipment(EquipData &equipData) + { equipSlots.swap(equipData); } + void setInventory(InventoryData &inventoryData) + { inventory.swap(inventoryData); } + +private: InventoryData inventory; EquipData equipSlots; }; diff --git a/src/game-server/buysell.cpp b/src/game-server/buysell.cpp index a9658546..78c2bfe0 100644 --- a/src/game-server/buysell.cpp +++ b/src/game-server/buysell.cpp @@ -72,9 +72,9 @@ int BuySell::registerPlayerItems() // We parse the player inventory and add all item // in a sell list. - const Possessions &charPoss = mChar->getPossessions(); - for (InventoryData::const_iterator it = charPoss.inventory.begin(), - it_end = charPoss.inventory.end(); it != it_end; ++it) + const InventoryData &inventoryData = mChar->getPossessions().getInventory(); + for (InventoryData::const_iterator it = inventoryData.begin(), + it_end = inventoryData.end(); it != it_end; ++it) { unsigned int nb = it->second.amount; if (!nb) diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp index e218a916..8689f299 100644 --- a/src/game-server/inventory.cpp +++ b/src/game-server/inventory.cpp @@ -54,8 +54,9 @@ void Inventory::sendFull() const k != k_end; ++k) { - m.writeInt8(k->first); // equip slot - m.writeInt16(k->second); // inventory slot + m.writeInt16(k->first); // Equip slot id + m.writeInt16(k->second.itemId); // Item id + m.writeInt16(k->second.itemInstance); // Item instance } gameHandler->sendTo(mCharacter, m); @@ -106,7 +107,7 @@ void Inventory::initialize() */ for (it2 = mPoss->equipSlots.begin(); it2 != it2_end; ++it2) { - if (equipment.insert(it2->second).second) + if (equipment.insert(it2->second.itemInstance).second) { /* * Perform checks for equipped items @@ -117,7 +118,7 @@ void Inventory::initialize() /* * Apply all equip triggers. */ - itemManager->getItem(mPoss->inventory.at(it2->second).itemId) + itemManager->getItem(it2->second.itemId) ->useTrigger(mCharacter, ITT_EQUIP); } } @@ -239,8 +240,7 @@ unsigned int Inventory::count(unsigned int itemId) const unsigned int Inventory::remove(unsigned int itemId, unsigned int amount, bool force) { - bool inv = false, - eq = !itemManager->getItem(itemId)->getItemEquipData().empty(); + bool inv = false; MessageOut invMsg(GPMSG_INVENTORY); bool triggerLeaveInventory = true; @@ -251,26 +251,6 @@ unsigned int Inventory::remove(unsigned int itemId, unsigned int amount, bool fo { if (amount) { - if (eq) - { - // If the item is equippable, - // we have additional checks to make. - bool ch = false; - for (EquipData::iterator it2 = mPoss->equipSlots.begin(), - it2_end = mPoss->equipSlots.end(); - it2 != it2_end; - ++it2) - if (it2->second == it->first) - { - if (force) - unequip(it2); - else - ch = inv = true; - break; - } - if (ch && !force) - continue; - } unsigned int sub = std::min(amount, it->second.amount); amount -= sub; it->second.amount -= sub; @@ -320,15 +300,6 @@ unsigned int Inventory::move(unsigned int slot1, unsigned int slot2, if (it1 == inv_end) return amount; - EquipData::iterator it, it_end = mPoss->equipSlots.end(); - for (it = mPoss->equipSlots.begin(); - it != it_end; - ++it) - if (it->second == slot1) - // Bad things will happen when you can stack multiple equippable - // items in the same slot anyway. - it->second = slot2; - MessageOut invMsg(GPMSG_INVENTORY); unsigned int nb = std::min(amount, it1->second.amount); @@ -538,9 +509,10 @@ bool Inventory::equip(int slot, bool override) * compile time options optimising for other usage. * For now, this is adequate assuming `normal' usage. */ - for (unsigned int i = 0; i < it3->second; ++i) + /** Part disabled until reimplemented*/ + /*for (unsigned int i = 0; i < it3->second; ++i) mPoss->equipSlots.insert( - std::make_pair(it3->first, slot)); + std::make_pair(it3->first, slot));*/ } changeEquipment(0, it->second.itemId); @@ -598,7 +570,7 @@ bool Inventory::equip(int slot, bool override) bool Inventory::unequip(EquipData::iterator it) { - return unequip(it->second, &it); + return unequip(it->first, &it); } bool Inventory::unequip(unsigned int slot, EquipData::iterator *itp) @@ -611,7 +583,7 @@ bool Inventory::unequip(unsigned int slot, EquipData::iterator *itp) // Erase all equip entries that point to the given inventory slot while (it != it_end) { - if (it->second == slot) + if (it->first == slot) { changed = true; mPoss->equipSlots.erase(it++); diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp index 03d4b71c..1a9c0204 100644 --- a/src/game-server/state.cpp +++ b/src/game-server/state.cpp @@ -108,7 +108,7 @@ static void updateMap(MapComposite *map) */ static void serializeLooks(Character *ch, MessageOut &msg, bool full) { - const Possessions &poss = ch->getPossessions(); + const EquipData &equipData = ch->getPossessions().getEquipment(); unsigned int nb_slots = itemManager->getVisibleSlotCount(); // Bitmask describing the changed entries. @@ -125,8 +125,8 @@ static void serializeLooks(Character *ch, MessageOut &msg, bool full) // Partially build both kinds of packet, to get their sizes. unsigned int mask_full = 0, mask_diff = 0; unsigned int nb_full = 0, nb_diff = 0; - std::map<unsigned int, unsigned int>::const_iterator it = - poss.equipSlots.begin(); + std::map<unsigned int, EquipmentItem>::const_iterator it = + equipData.begin(); for (unsigned int i = 0; i < nb_slots; ++i) { if (changed & (1 << i)) @@ -135,7 +135,7 @@ static void serializeLooks(Character *ch, MessageOut &msg, bool full) ++nb_diff; mask_diff |= 1 << i; } - if (it == poss.equipSlots.end() || it->first > i) continue; + if (it == equipData.end() || it->first > i) continue; ItemClass *eq; items[i] = it->first && (eq = itemManager->getItem(it->first)) ? eq->getSpriteID() : 0; diff --git a/src/serialize/characterdata.h b/src/serialize/characterdata.h index 4466c98e..c453e685 100644 --- a/src/serialize/characterdata.h +++ b/src/serialize/characterdata.h @@ -97,20 +97,22 @@ void serializeCharacterData(const T &data, MessageOut &msg) // inventory - must be last because size isn't transmitted const Possessions &poss = data.getPossessions(); - msg.writeInt16(poss.equipSlots.size()); // number of equipment - for (EquipData::const_iterator k = poss.equipSlots.begin(), - k_end = poss.equipSlots.end(); - k != k_end; - ++k) + const EquipData &equipData = poss.getEquipment(); + msg.writeInt16(equipData.size()); // number of equipment + for (EquipData::const_iterator k = equipData.begin(), + k_end = equipData.end(); k != k_end; ++k) { - msg.writeInt8(k->first); // Equip slot type - msg.writeInt16(k->second); // Inventory slot + msg.writeInt16(k->first); // Equip slot id + msg.writeInt16(k->second.itemId); // ItemId + msg.writeInt16(k->second.itemInstance); // Item Instance id } - for (InventoryData::const_iterator j = poss.inventory.begin(), - j_end = poss.inventory.end(); j != j_end; ++j) + + const InventoryData &inventoryData = poss.getInventory(); + for (InventoryData::const_iterator j = inventoryData.begin(), + j_end = inventoryData.end(); j != j_end; ++j) { msg.writeInt16(j->first); // slot id - msg.writeInt16(j->second.itemId); // item type + msg.writeInt16(j->second.itemId); // item id msg.writeInt16(j->second.amount); // amount } } @@ -185,26 +187,31 @@ void deserializeCharacterData(T &data, MessageIn &msg) Possessions &poss = data.getPossessions(); - poss.equipSlots.clear(); + EquipData equipData; int equipSlotsSize = msg.readInt16(); - unsigned int eqSlot, invSlot; + unsigned int eqSlot; + EquipmentItem equipItem; for (int j = 0; j < equipSlotsSize; ++j) { - eqSlot = msg.readInt8(); - invSlot = msg.readInt16(); - poss.equipSlots.insert(poss.equipSlots.end(), - std::make_pair(eqSlot, invSlot)); + eqSlot = msg.readInt16(); + equipItem.itemId = msg.readInt16(); + equipItem.itemInstance = msg.readInt16(); + equipData.insert(equipData.end(), + std::make_pair(eqSlot, equipItem)); } - poss.inventory.clear(); - // inventory - must be last because size isn't transmitted + poss.setEquipment(equipData); + + // Loads inventory - must be last because size isn't transmitted + InventoryData inventoryData; while (msg.getUnreadLength()) { InventoryItem i; int slotId = msg.readInt16(); i.itemId = msg.readInt16(); i.amount = msg.readInt16(); - poss.inventory.insert(poss.inventory.end(), std::make_pair(slotId, i)); + inventoryData.insert(inventoryData.end(), std::make_pair(slotId, i)); } + poss.setInventory(inventoryData); } #endif // SERIALIZE_CHARACTERDATA_H diff --git a/src/sql/mysql/createTables.sql b/src/sql/mysql/createTables.sql index 9e1e31a6..d017ceee 100644 --- a/src/sql/mysql/createTables.sql +++ b/src/sql/mysql/createTables.sql @@ -184,11 +184,11 @@ AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `mana_char_equips` ( `id` int(10) unsigned NOT NULL auto_increment, `owner_id` int(10) unsigned NOT NULL, - `slot_type` tinyint(3) unsigned NOT NULL, - `inventory_slot` tinyint(3) unsigned NOT NULL, + `slot_type` int(10) unsigned NOT NULL, + `item_id` int(10) unsigned NOT NULL, + `item_instance` int(10) unsigned NOT NULL, -- PRIMARY KEY (`id`), - UNIQUE KEY `owner_id` (`owner_id`, `inventory_slot`), FOREIGN KEY (`owner_id`) REFERENCES `mana_characters` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql index b366606b..1027b580 100644 --- a/src/sql/sqlite/createTables.sql +++ b/src/sql/sqlite/createTables.sql @@ -178,7 +178,8 @@ CREATE TABLE mana_char_equips id INTEGER PRIMARY KEY, owner_id INTEGER NOT NULL, slot_type INTEGER NOT NULL, - inventory_slot INTEGER NOT NULL, + item_id INTEGER NOT NULL, + item_instance INTEGER NOT NULL, -- FOREIGN KEY (owner_id) REFERENCES mana_characters(id) ); |