Skip to content

Commit

Permalink
fix: overload when setting item decay when player logs in (opentibiab…
Browse files Browse the repository at this point in the history
…r#2927)

This change optimizes the decay initiation process for items within
containers. Previously, `Container::startDecaying()` method would
recursively start the decay for each item in a container upon the
container's own decay initiation. This could lead to inefficiencies,
especially with many nested containers. The updated
approach collects all decaying items in a vector first and then
initiates decay after all have been added, improving performance by
reducing overhead and simplifying the management of decay states.

In the stop decay process, instead of iterating through all containers, we will now halt the decay immediately after each item is saved. This approach leverages an existing function, eliminating the need for an additional overlay and enhancing efficiency.
  • Loading branch information
dudantas authored Oct 9, 2024
1 parent 1fcb348 commit adbe715
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 45 deletions.
54 changes: 34 additions & 20 deletions src/io/functions/iologindata_load_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,26 +475,24 @@ void IOLoginDataLoad::loadPlayerInventoryItems(std::shared_ptr<Player> player, D
}

bool oldProtocol = g_configManager().getBoolean(OLD_PROTOCOL, __FUNCTION__) && player->getProtocolVersion() < 1200;
Database &db = Database::getInstance();
std::ostringstream query;
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_items` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
auto query = fmt::format("SELECT pid, sid, itemtype, count, attributes FROM player_items WHERE player_id = {} ORDER BY sid DESC", player->getGUID());

ItemsMap inventoryItems;
std::vector<std::pair<uint8_t, std::shared_ptr<Container>>> openContainersList;
std::vector<std::shared_ptr<Item>> itemsToStartDecaying;

try {
if ((result = db.storeQuery(query.str()))) {
if ((result = g_database().storeQuery(query))) {
loadItems(inventoryItems, result, player);

for (ItemsMap::const_reverse_iterator it = inventoryItems.rbegin(), end = inventoryItems.rend(); it != end; ++it) {
const std::pair<std::shared_ptr<Item>, int32_t> &pair = it->second;
std::shared_ptr<Item> item = pair.first;
const std::shared_ptr<Item> &item = pair.first;
if (!item) {
continue;
}

int32_t pid = pair.second;

if (pid >= CONST_SLOT_FIRST && pid <= CONST_SLOT_LAST) {
player->internalAddThing(pid, item);
item->startDecaying();
Expand All @@ -504,14 +502,15 @@ void IOLoginDataLoad::loadPlayerInventoryItems(std::shared_ptr<Player> player, D
continue;
}

std::shared_ptr<Container> container = it2->second.first->getContainer();
const std::shared_ptr<Container> &container = it2->second.first->getContainer();
if (container) {
container->internalAddThing(item);
item->startDecaying();
// Here, the sub-containers do not yet have a parent, since the main backpack has not yet been added to the player, so we need to postpone
itemsToStartDecaying.emplace_back(item);
}
}

std::shared_ptr<Container> itemContainer = item->getContainer();
const std::shared_ptr<Container> &itemContainer = item->getContainer();
if (itemContainer) {
if (!oldProtocol) {
auto cid = item->getAttribute<int64_t>(ItemAttribute_t::OPENCONTAINER);
Expand All @@ -535,6 +534,11 @@ void IOLoginDataLoad::loadPlayerInventoryItems(std::shared_ptr<Player> player, D
}
}

// Now that all items and containers have been added and parent chain is established, start decay
for (const auto &item : itemsToStartDecaying) {
item->startDecaying();
}

if (!oldProtocol) {
std::ranges::sort(openContainersList.begin(), openContainersList.end(), [](const std::pair<uint8_t, std::shared_ptr<Container>> &left, const std::pair<uint8_t, std::shared_ptr<Container>> &right) {
return left.first < right.first;
Expand All @@ -545,8 +549,9 @@ void IOLoginDataLoad::loadPlayerInventoryItems(std::shared_ptr<Player> player, D
player->onSendContainer(it.second);
}
}

} catch (const std::exception &e) {
g_logger().error("[IOLoginDataLoad::loadPlayerInventoryItems] - Exceção durante o carregamento do inventário: {}", e.what());
g_logger().error("[IOLoginDataLoad::loadPlayerInventoryItems] - Exception during inventory loading: {}", e.what());
}
}

Expand Down Expand Up @@ -585,11 +590,10 @@ void IOLoginDataLoad::loadPlayerDepotItems(std::shared_ptr<Player> player, DBRes
return;
}

Database &db = Database::getInstance();
ItemsMap depotItems;
std::ostringstream query;
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_depotitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
if ((result = db.storeQuery(query.str()))) {
std::vector<std::shared_ptr<Item>> itemsToStartDecaying;
auto query = fmt::format("SELECT pid, sid, itemtype, count, attributes FROM player_depotitems WHERE player_id = {} ORDER BY sid DESC", player->getGUID());
if ((result = g_database().storeQuery(query))) {
loadItems(depotItems, result, player);
for (ItemsMap::const_reverse_iterator it = depotItems.rbegin(), end = depotItems.rend(); it != end; ++it) {
const std::pair<std::shared_ptr<Item>, int32_t> &pair = it->second;
Expand All @@ -611,11 +615,17 @@ void IOLoginDataLoad::loadPlayerDepotItems(std::shared_ptr<Player> player, DBRes
std::shared_ptr<Container> container = it2->second.first->getContainer();
if (container) {
container->internalAddThing(item);
item->startDecaying();
// Here, the sub-containers do not yet have a parent, since the main backpack has not yet been added to the player, so we need to postpone
itemsToStartDecaying.emplace_back(item);
}
}
}
}

// Now that all items and containers have been added and parent chain is established, start decay
for (const auto &item : itemsToStartDecaying) {
item->startDecaying();
}
}

void IOLoginDataLoad::loadPlayerInboxItems(std::shared_ptr<Player> player, DBResult_ptr result) {
Expand All @@ -624,10 +634,9 @@ void IOLoginDataLoad::loadPlayerInboxItems(std::shared_ptr<Player> player, DBRes
return;
}

Database &db = Database::getInstance();
std::ostringstream query;
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_inboxitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
if ((result = db.storeQuery(query.str()))) {
std::vector<std::shared_ptr<Item>> itemsToStartDecaying;
auto query = fmt::format("SELECT pid, sid, itemtype, count, attributes FROM player_inboxitems WHERE player_id = {} ORDER BY sid DESC", player->getGUID());
if ((result = g_database().storeQuery(query))) {
ItemsMap inboxItems;
loadItems(inboxItems, result, player);

Expand All @@ -647,11 +656,16 @@ void IOLoginDataLoad::loadPlayerInboxItems(std::shared_ptr<Player> player, DBRes
std::shared_ptr<Container> container = it2->second.first->getContainer();
if (container) {
container->internalAddThing(item);
item->startDecaying();
itemsToStartDecaying.emplace_back(item);
}
}
}
}

// Now that all items and containers have been added and parent chain is established, start decay
for (const auto &item : itemsToStartDecaying) {
item->startDecaying();
}
}

void IOLoginDataLoad::loadPlayerStorageMap(std::shared_ptr<Player> player, DBResult_ptr result) {
Expand Down
5 changes: 3 additions & 2 deletions src/io/functions/iologindata_save_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ bool IOLoginDataSave::saveItems(std::shared_ptr<Player> player, const ItemBlockL
}

// Loop through items in container
for (std::shared_ptr<Item> item : container->getItemList()) {
for (auto &item : container->getItemList()) {
if (!item) {
continue; // Check for null item
}

++runningId;

// Update sub-container attributes if necessary
std::shared_ptr<Container> subContainer = item->getContainer();
const auto &subContainer = item->getContainer();
if (subContainer) {
queue.emplace_back(subContainer, runningId);
if (subContainer->getAttribute<int64_t>(ItemAttribute_t::OPENCONTAINER) > 0) {
Expand All @@ -121,6 +121,7 @@ bool IOLoginDataSave::saveItems(std::shared_ptr<Player> player, const ItemBlockL
try {
propWriteStream.clear();
item->serializeAttr(propWriteStream);
item->stopDecaying();
} catch (...) {
g_logger().error("Error serializing item attributes in container.");
return false;
Expand Down
14 changes: 0 additions & 14 deletions src/items/containers/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,20 +904,6 @@ void Container::internalAddThing(uint32_t, std::shared_ptr<Thing> thing) {
updateItemWeight(item->getWeight());
}

void Container::startDecaying() {
g_decay().startDecay(getContainer());
for (ContainerIterator it = iterator(); it.hasNext(); it.advance()) {
g_decay().startDecay(*it);
}
}

void Container::stopDecaying() {
g_decay().stopDecay(getContainer());
for (ContainerIterator it = iterator(); it.hasNext(); it.advance()) {
g_decay().stopDecay(*it);
}
}

uint16_t Container::getFreeSlots() {
uint16_t counter = std::max<uint16_t>(0, capacity() - size());

Expand Down
2 changes: 0 additions & 2 deletions src/items/containers/container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ class Container : public Item, public Cylinder {

void internalAddThing(std::shared_ptr<Thing> thing) override final;
void internalAddThing(uint32_t index, std::shared_ptr<Thing> thing) override final;
void startDecaying() override;
void stopDecaying() override;

virtual void removeItem(std::shared_ptr<Thing> thing, bool sendUpdateToClient = false);

Expand Down
15 changes: 12 additions & 3 deletions src/items/decay/decay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Decay &Decay::getInstance() {
return inject<Decay>();
}

void Decay::startDecay(std::shared_ptr<Item> item) {
void Decay::startDecay(const std::shared_ptr<Item> &item) {
if (!item) {
return;
}
Expand All @@ -32,6 +32,8 @@ void Decay::startDecay(std::shared_ptr<Item> item) {
return;
}

g_logger().trace("Try decay item {}", item->getName());

const auto duration = item->getAttribute<int64_t>(ItemAttribute_t::DURATION);
if (duration <= 0 && item->hasAttribute(ItemAttribute_t::DURATION)) {
internalDecayItem(item);
Expand Down Expand Up @@ -63,7 +65,10 @@ void Decay::startDecay(std::shared_ptr<Item> item) {
}
}

void Decay::stopDecay(std::shared_ptr<Item> item) {
void Decay::stopDecay(const std::shared_ptr<Item> &item) {
if (!item) {
return;
}
if (item->hasAttribute(ItemAttribute_t::DECAYSTATE)) {
auto timestamp = item->getAttribute<int64_t>(ItemAttribute_t::DURATION_TIMESTAMP);
if (item->hasAttribute(ItemAttribute_t::DURATION_TIMESTAMP)) {
Expand Down Expand Up @@ -146,7 +151,11 @@ void Decay::checkDecay() {
}
}

void Decay::internalDecayItem(std::shared_ptr<Item> item) {
void Decay::internalDecayItem(const std::shared_ptr<Item> &item) {
if (!item) {
return;
}

const ItemType &it = Item::items[item->getID()];
// Remove the item and halt the decay process if a player triggers a bug where the item's decay ID matches its equip or de-equip transformation ID
if (it.id == it.transformEquipTo || it.id == it.transformDeEquipTo) {
Expand Down
6 changes: 3 additions & 3 deletions src/items/decay/decay.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ class Decay {

static Decay &getInstance();

void startDecay(std::shared_ptr<Item> item);
void stopDecay(std::shared_ptr<Item> item);
void startDecay(const std::shared_ptr<Item> &item);
void stopDecay(const std::shared_ptr<Item> &item);

private:
void checkDecay();
void internalDecayItem(std::shared_ptr<Item> item);
void internalDecayItem(const std::shared_ptr<Item> &item);

uint32_t eventId { 0 };
// order is important, so we use an std::map
Expand Down
4 changes: 3 additions & 1 deletion src/map/mapcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ std::shared_ptr<Item> MapCache::createItem(const std::shared_ptr<BasicItem> &Bas
item->setItemCount(1);
}

item->startDecaying();
if (item->canDecay()) {
item->startDecaying();
}
item->loadedFromMap = true;
item->decayDisabled = Item::items[item->getID()].decayTo != -1;

Expand Down

0 comments on commit adbe715

Please sign in to comment.