Cache certain item generation calls from interfaces
Helps a little with the lag from recipes when having crafting interfaces open, but it's still noticeable. Also micro-optimized Root maintenance by unlocking the Root mutexes for their respective shared_ptrs earlier once we have our own shared_ptr.
This commit is contained in:
parent
121d27446b
commit
0aee45a117
@ -142,7 +142,7 @@ ContainerPane::ContainerPane(WorldClientPtr worldClient, PlayerPtr player, Conta
|
|||||||
|
|
||||||
if (container->iconItem()) {
|
if (container->iconItem()) {
|
||||||
auto itemDatabase = Root::singleton().itemDatabase();
|
auto itemDatabase = Root::singleton().itemDatabase();
|
||||||
auto iconItem = itemDatabase->item(container->iconItem());
|
auto iconItem = itemDatabase->itemShared(container->iconItem());
|
||||||
auto icon = make_shared<ItemSlotWidget>(iconItem, "/interface/inventory/portrait.png");
|
auto icon = make_shared<ItemSlotWidget>(iconItem, "/interface/inventory/portrait.png");
|
||||||
icon->showDurability(false);
|
icon->showDurability(false);
|
||||||
icon->showRarity(false);
|
icon->showRarity(false);
|
||||||
|
@ -127,7 +127,7 @@ CraftingPane::CraftingPane(WorldClientPtr worldClient, PlayerPtr player, Json co
|
|||||||
if (auto container = as<ContainerEntity>(entity)) {
|
if (auto container = as<ContainerEntity>(entity)) {
|
||||||
if (container->iconItem()) {
|
if (container->iconItem()) {
|
||||||
auto itemDatabase = Root::singleton().itemDatabase();
|
auto itemDatabase = Root::singleton().itemDatabase();
|
||||||
auto iconItem = itemDatabase->item(container->iconItem());
|
auto iconItem = itemDatabase->itemShared(container->iconItem());
|
||||||
auto icon = make_shared<ItemSlotWidget>(iconItem, "/interface/inventory/portrait.png");
|
auto icon = make_shared<ItemSlotWidget>(iconItem, "/interface/inventory/portrait.png");
|
||||||
String title = this->title();
|
String title = this->title();
|
||||||
if (title.empty())
|
if (title.empty())
|
||||||
@ -259,7 +259,7 @@ void CraftingPane::update(float dt) {
|
|||||||
auto description = fetchChild<Widget>("description");
|
auto description = fetchChild<Widget>("description");
|
||||||
description->removeAllChildren();
|
description->removeAllChildren();
|
||||||
|
|
||||||
auto item = Root::singleton().itemDatabase()->item(recipe.output);
|
auto item = Root::singleton().itemDatabase()->itemShared(recipe.output);
|
||||||
ItemTooltipBuilder::buildItemDescription(description, item);
|
ItemTooltipBuilder::buildItemDescription(description, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,7 +383,7 @@ void CraftingPane::setupWidget(WidgetPtr const& widget, ItemRecipe const& recipe
|
|||||||
auto single = recipe.output.singular();
|
auto single = recipe.output.singular();
|
||||||
ItemPtr item = m_itemCache[single];
|
ItemPtr item = m_itemCache[single];
|
||||||
if (!item) {
|
if (!item) {
|
||||||
item = root.itemDatabase()->item(single);
|
item = root.itemDatabase()->itemShared(single);
|
||||||
m_itemCache[single] = item;
|
m_itemCache[single] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,13 +475,13 @@ PanePtr CraftingPane::setupTooltip(ItemRecipe const& recipe) {
|
|||||||
auto currenciesConfig = root.assets()->json("/currencies.config");
|
auto currenciesConfig = root.assets()->json("/currencies.config");
|
||||||
for (auto const& p : recipe.currencyInputs) {
|
for (auto const& p : recipe.currencyInputs) {
|
||||||
if (p.second > 0) {
|
if (p.second > 0) {
|
||||||
auto currencyItem = root.itemDatabase()->item(ItemDescriptor(currenciesConfig.get(p.first).getString("representativeItem")));
|
auto currencyItem = root.itemDatabase()->itemShared(ItemDescriptor(currenciesConfig.get(p.first).getString("representativeItem")));
|
||||||
addIngredient(currencyItem, m_player->currency(p.first), p.second);
|
addIngredient(currencyItem, m_player->currency(p.first), p.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& input : recipe.inputs) {
|
for (auto const& input : recipe.inputs) {
|
||||||
auto item = root.itemDatabase()->item(input.singular());
|
auto item = root.itemDatabase()->itemShared(input.singular());
|
||||||
size_t itemCount = itemDb->getCountOfItem(normalizedBag, input, recipe.matchInputParameters);
|
size_t itemCount = itemDb->getCountOfItem(normalizedBag, input, recipe.matchInputParameters);
|
||||||
addIngredient(item, itemCount, input.count());
|
addIngredient(item, itemCount, input.count());
|
||||||
}
|
}
|
||||||
@ -576,7 +576,7 @@ void CraftingPane::craft(int count) {
|
|||||||
remainingItemCount -= craftedItem->count();
|
remainingItemCount -= craftedItem->count();
|
||||||
m_player->giveItem(craftedItem);
|
m_player->giveItem(craftedItem);
|
||||||
|
|
||||||
for (auto collectable : recipe.collectables)
|
for (auto& collectable : recipe.collectables)
|
||||||
m_player->addCollectable(collectable.first, collectable.second);
|
m_player->addCollectable(collectable.first, collectable.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,10 +666,10 @@ List<ItemRecipe> CraftingPane::determineRecipes() {
|
|||||||
|
|
||||||
float printTime = m_settings.getFloat("printTime", 0);
|
float printTime = m_settings.getFloat("printTime", 0);
|
||||||
float printFactor = m_settings.getFloat("printCostFactor", 1.0);
|
float printFactor = m_settings.getFloat("printCostFactor", 1.0);
|
||||||
for (auto itemName : itemList) {
|
for (auto& itemName : itemList) {
|
||||||
ItemRecipe recipe;
|
ItemRecipe recipe;
|
||||||
recipe.output = ItemDescriptor(itemName, 1);
|
recipe.output = ItemDescriptor(itemName, 1);
|
||||||
auto recipeItem = itemDb->item(recipe.output);
|
auto recipeItem = itemDb->itemShared(recipe.output);
|
||||||
int itemPrice = int(recipeItem->price() * printFactor);
|
int itemPrice = int(recipeItem->price() * printFactor);
|
||||||
recipe.currencyInputs["money"] = itemPrice;
|
recipe.currencyInputs["money"] = itemPrice;
|
||||||
recipe.outputRarity = recipeItem->rarity();
|
recipe.outputRarity = recipeItem->rarity();
|
||||||
@ -679,7 +679,7 @@ List<ItemRecipe> CraftingPane::determineRecipes() {
|
|||||||
recipes.add(recipe);
|
recipes.add(recipe);
|
||||||
}
|
}
|
||||||
} else if (m_settings.contains("recipes")) {
|
} else if (m_settings.contains("recipes")) {
|
||||||
for (auto entry : m_settings.getArray("recipes")) {
|
for (auto& entry : m_settings.getArray("recipes")) {
|
||||||
if (entry.type() == Json::Type::String)
|
if (entry.type() == Json::Type::String)
|
||||||
recipes.addAll(itemDb->recipesForOutputItem(entry.toString()));
|
recipes.addAll(itemDb->recipesForOutputItem(entry.toString()));
|
||||||
else
|
else
|
||||||
|
@ -127,7 +127,7 @@ PanePtr MerchantPane::createTooltip(Vec2I const& screenPosition) {
|
|||||||
auto entry = m_itemGuiList->itemAt(i);
|
auto entry = m_itemGuiList->itemAt(i);
|
||||||
if (entry->getChildAt(screenPosition)) {
|
if (entry->getChildAt(screenPosition)) {
|
||||||
auto itemConfig = m_itemList.get(i);
|
auto itemConfig = m_itemList.get(i);
|
||||||
ItemPtr item = Root::singleton().itemDatabase()->item(ItemDescriptor(itemConfig.get("item")));
|
ItemPtr item = Root::singleton().itemDatabase()->itemShared(ItemDescriptor(itemConfig.get("item")));
|
||||||
return ItemTooltipBuilder::buildItemTooltip(item, m_player);
|
return ItemTooltipBuilder::buildItemTooltip(item, m_player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ void MerchantPane::buildItemList() {
|
|||||||
void MerchantPane::setupWidget(WidgetPtr const& widget, Json const& itemConfig) {
|
void MerchantPane::setupWidget(WidgetPtr const& widget, Json const& itemConfig) {
|
||||||
auto& root = Root::singleton();
|
auto& root = Root::singleton();
|
||||||
auto assets = root.assets();
|
auto assets = root.assets();
|
||||||
ItemPtr item = root.itemDatabase()->item(ItemDescriptor(itemConfig.get("item")));
|
ItemPtr item = root.itemDatabase()->itemShared(ItemDescriptor(itemConfig.get("item")));
|
||||||
|
|
||||||
String name = item->friendlyName();
|
String name = item->friendlyName();
|
||||||
if (item->count() > 1)
|
if (item->count() > 1)
|
||||||
@ -265,7 +265,7 @@ void MerchantPane::updateSelection() {
|
|||||||
|
|
||||||
if (m_selectedIndex != NPos) {
|
if (m_selectedIndex != NPos) {
|
||||||
auto itemConfig = m_itemList.get(m_selectedIndex);
|
auto itemConfig = m_itemList.get(m_selectedIndex);
|
||||||
m_selectedItem = Root::singleton().itemDatabase()->item(ItemDescriptor(itemConfig.get("item")));
|
m_selectedItem = Root::singleton().itemDatabase()->itemShared(ItemDescriptor(itemConfig.get("item")));
|
||||||
findChild<ButtonWidget>("spinCount.up")->enable();
|
findChild<ButtonWidget>("spinCount.up")->enable();
|
||||||
findChild<ButtonWidget>("spinCount.down")->enable();
|
findChild<ButtonWidget>("spinCount.down")->enable();
|
||||||
m_countTextBox->setColor(Color::White);
|
m_countTextBox->setColor(Color::White);
|
||||||
|
@ -109,7 +109,7 @@ Collectable CollectionDatabase::parseMonsterCollectable(String const& name, Json
|
|||||||
Collectable CollectionDatabase::parseItemCollectable(String const& name, Json const& config) const {
|
Collectable CollectionDatabase::parseItemCollectable(String const& name, Json const& config) const {
|
||||||
Collectable collectable = parseGenericCollectable(name, config);
|
Collectable collectable = parseGenericCollectable(name, config);
|
||||||
auto itemDatabase = Root::singleton().itemDatabase();
|
auto itemDatabase = Root::singleton().itemDatabase();
|
||||||
auto item = itemDatabase->item(ItemDescriptor(config.getString("item")));
|
auto item = itemDatabase->itemShared(ItemDescriptor(config.getString("item")));
|
||||||
|
|
||||||
collectable.title = item->friendlyName();
|
collectable.title = item->friendlyName();
|
||||||
collectable.description = item->description();
|
collectable.description = item->description();
|
||||||
|
@ -140,6 +140,15 @@ ItemDatabase::ItemDatabase()
|
|||||||
addBlueprints();
|
addBlueprints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemDatabase::cleanup() {
|
||||||
|
{
|
||||||
|
MutexLocker locker(m_cacheMutex);
|
||||||
|
m_itemCache.cleanup([](ItemCacheEntry const&, ItemPtr const& item) {
|
||||||
|
return !item.unique();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ItemPtr ItemDatabase::diskLoad(Json const& diskStore) const {
|
ItemPtr ItemDatabase::diskLoad(Json const& diskStore) const {
|
||||||
if (diskStore) {
|
if (diskStore) {
|
||||||
return item(ItemDescriptor::loadStore(diskStore));
|
return item(ItemDescriptor::loadStore(diskStore));
|
||||||
@ -204,20 +213,30 @@ ItemDatabase::ItemConfig ItemDatabase::itemConfig(String const& itemName, Json p
|
|||||||
return itemConfig;
|
return itemConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemPtr ItemDatabase::item(ItemDescriptor descriptor, Maybe<float> level, Maybe<uint64_t> seed) const {
|
ItemPtr ItemDatabase::itemShared(ItemDescriptor descriptor, Maybe<float> level, Maybe<uint64_t> seed) const {
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
ItemPtr item;
|
ItemCacheEntry entry{ descriptor, level, seed };
|
||||||
try {
|
MutexLocker locker(m_cacheMutex);
|
||||||
item = createItem(m_items.get(descriptor.name()).type, itemConfig(descriptor.name(), descriptor.parameters(), level, seed));
|
if (ItemPtr* cached = m_itemCache.ptr(entry))
|
||||||
} catch (std::exception const& e) {
|
return *cached;
|
||||||
Logger::error("Could not instantiate item '{}'. {}", descriptor, outputException(e, false));
|
else {
|
||||||
item = createItem(m_items.get("perfectlygenericitem").type, itemConfig("perfectlygenericitem", {}, {}));
|
locker.unlock();
|
||||||
}
|
|
||||||
item->setCount(descriptor.count());
|
|
||||||
|
|
||||||
return item;
|
ItemPtr item = tryCreateItem(descriptor, level, seed);
|
||||||
|
get<2>(entry) = item->parameters().optUInt("seed"); // Seed could've been changed by the buildscript
|
||||||
|
|
||||||
|
locker.lock();
|
||||||
|
return m_itemCache.get(entry, [&](ItemCacheEntry const&) -> ItemPtr { return move(item); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemPtr ItemDatabase::item(ItemDescriptor descriptor, Maybe<float> level, Maybe<uint64_t> seed) const {
|
||||||
|
if (!descriptor)
|
||||||
|
return {};
|
||||||
|
else
|
||||||
|
return tryCreateItem(descriptor, level, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ItemDatabase::hasRecipeToMake(ItemDescriptor const& item) const {
|
bool ItemDatabase::hasRecipeToMake(ItemDescriptor const& item) const {
|
||||||
@ -332,7 +351,7 @@ ItemRecipe ItemDatabase::parseRecipe(Json const& config) const {
|
|||||||
for (auto input : config.getArray("input")) {
|
for (auto input : config.getArray("input")) {
|
||||||
auto id = ItemDescriptor(input);
|
auto id = ItemDescriptor(input);
|
||||||
if (itemType(id.name()) == ItemType::CurrencyItem) {
|
if (itemType(id.name()) == ItemType::CurrencyItem) {
|
||||||
auto currencyItem = as<CurrencyItem>(item(id));
|
auto currencyItem = as<CurrencyItem>(itemShared(id));
|
||||||
res.currencyInputs[currencyItem->currencyType()] += currencyItem->totalValue();
|
res.currencyInputs[currencyItem->currencyType()] += currencyItem->totalValue();
|
||||||
} else {
|
} else {
|
||||||
res.inputs.push_back(id);
|
res.inputs.push_back(id);
|
||||||
@ -342,7 +361,7 @@ ItemRecipe ItemDatabase::parseRecipe(Json const& config) const {
|
|||||||
res.output = ItemDescriptor(config.get("output"));
|
res.output = ItemDescriptor(config.get("output"));
|
||||||
res.duration = config.getFloat("duration", Root::singleton().assets()->json("/items/defaultParameters.config:defaultCraftDuration").toFloat());
|
res.duration = config.getFloat("duration", Root::singleton().assets()->json("/items/defaultParameters.config:defaultCraftDuration").toFloat());
|
||||||
res.groups = StringSet::from(jsonToStringList(config.get("groups", JsonArray())));
|
res.groups = StringSet::from(jsonToStringList(config.get("groups", JsonArray())));
|
||||||
if (auto item = ItemDatabase::item(res.output)) {
|
if (auto item = ItemDatabase::itemShared(res.output)) {
|
||||||
res.outputRarity = item->rarity();
|
res.outputRarity = item->rarity();
|
||||||
res.guiFilterString = guiFilterString(item);
|
res.guiFilterString = guiFilterString(item);
|
||||||
}
|
}
|
||||||
@ -480,6 +499,20 @@ ItemPtr ItemDatabase::createItem(ItemType type, ItemConfig const& config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemPtr ItemDatabase::tryCreateItem(ItemDescriptor const& descriptor, Maybe<float> level, Maybe<uint64_t> seed) const {
|
||||||
|
ItemPtr result;
|
||||||
|
try {
|
||||||
|
result = createItem(m_items.get(descriptor.name()).type, itemConfig(descriptor.name(), descriptor.parameters(), level, seed));
|
||||||
|
}
|
||||||
|
catch (std::exception const& e) {
|
||||||
|
Logger::error("Could not instantiate item '{}'. {}", descriptor, outputException(e, false));
|
||||||
|
result = createItem(m_items.get("perfectlygenericitem").type, itemConfig("perfectlygenericitem", {}, {}));
|
||||||
|
}
|
||||||
|
result->setCount(descriptor.count());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ItemDatabase::ItemData const& ItemDatabase::itemData(String const& name) const {
|
ItemDatabase::ItemData const& ItemDatabase::itemData(String const& name) const {
|
||||||
if (auto p = m_items.ptr(name))
|
if (auto p = m_items.ptr(name))
|
||||||
return *p;
|
return *p;
|
||||||
@ -492,7 +525,7 @@ ItemRecipe ItemDatabase::makeRecipe(List<ItemDescriptor> inputs, ItemDescriptor
|
|||||||
res.output = move(output);
|
res.output = move(output);
|
||||||
res.duration = duration;
|
res.duration = duration;
|
||||||
res.groups = move(groups);
|
res.groups = move(groups);
|
||||||
if (auto item = ItemDatabase::item(res.output)) {
|
if (auto item = ItemDatabase::itemShared(res.output)) {
|
||||||
res.outputRarity = item->rarity();
|
res.outputRarity = item->rarity();
|
||||||
res.guiFilterString = guiFilterString(item);
|
res.guiFilterString = guiFilterString(item);
|
||||||
}
|
}
|
||||||
@ -627,7 +660,7 @@ void ItemDatabase::addBlueprints() {
|
|||||||
|
|
||||||
for (auto const& recipe : m_recipes) {
|
for (auto const& recipe : m_recipes) {
|
||||||
auto baseDesc = recipe.output;
|
auto baseDesc = recipe.output;
|
||||||
auto baseItem = item(baseDesc);
|
auto baseItem = itemShared(baseDesc);
|
||||||
|
|
||||||
String blueprintName = strf("{}-recipe", baseItem->name());
|
String blueprintName = strf("{}-recipe", baseItem->name());
|
||||||
if (m_items.contains(blueprintName))
|
if (m_items.contains(blueprintName))
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "StarItem.hpp"
|
#include "StarItem.hpp"
|
||||||
#include "StarCasting.hpp"
|
#include "StarCasting.hpp"
|
||||||
#include "StarLuaRoot.hpp"
|
#include "StarLuaRoot.hpp"
|
||||||
|
#include "StarTtlCache.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -75,6 +76,8 @@ public:
|
|||||||
|
|
||||||
ItemDatabase();
|
ItemDatabase();
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
// Load an item based on item descriptor. If loadItem is called with a
|
// Load an item based on item descriptor. If loadItem is called with a
|
||||||
// live ptr, and the ptr matches the descriptor read, then no new item is
|
// live ptr, and the ptr matches the descriptor read, then no new item is
|
||||||
// constructed. If ItemT is some other type than Item, then loadItem will
|
// constructed. If ItemT is some other type than Item, then loadItem will
|
||||||
@ -112,8 +115,12 @@ public:
|
|||||||
// from the appropriate factory. If there is a problem instantiating the
|
// from the appropriate factory. If there is a problem instantiating the
|
||||||
// item, will return a default item instead. If item is passed a null
|
// item, will return a default item instead. If item is passed a null
|
||||||
// ItemDescriptor, it will return a null pointer.
|
// ItemDescriptor, it will return a null pointer.
|
||||||
|
// The returned item pointer will be shared. Either call ->clone() or use item() instead for a copy.
|
||||||
|
ItemPtr itemShared(ItemDescriptor descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}) const;
|
||||||
|
// Same as itemShared, but makes a copy instead. Does not cache.
|
||||||
ItemPtr item(ItemDescriptor descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}) const;
|
ItemPtr item(ItemDescriptor descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}) const;
|
||||||
|
|
||||||
|
|
||||||
bool hasRecipeToMake(ItemDescriptor const& item) const;
|
bool hasRecipeToMake(ItemDescriptor const& item) const;
|
||||||
bool hasRecipeToMake(ItemDescriptor const& item, StringSet const& allowedTypes) const;
|
bool hasRecipeToMake(ItemDescriptor const& item, StringSet const& allowedTypes) const;
|
||||||
|
|
||||||
@ -153,6 +160,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static ItemPtr createItem(ItemType type, ItemConfig const& config);
|
static ItemPtr createItem(ItemType type, ItemConfig const& config);
|
||||||
|
ItemPtr tryCreateItem(ItemDescriptor const& descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}) const;
|
||||||
|
|
||||||
ItemData const& itemData(String const& name) const;
|
ItemData const& itemData(String const& name) const;
|
||||||
ItemRecipe makeRecipe(List<ItemDescriptor> inputs, ItemDescriptor output, float duration, StringSet groups) const;
|
ItemRecipe makeRecipe(List<ItemDescriptor> inputs, ItemDescriptor output, float duration, StringSet groups) const;
|
||||||
@ -171,6 +179,11 @@ private:
|
|||||||
|
|
||||||
mutable RecursiveMutex m_luaMutex;
|
mutable RecursiveMutex m_luaMutex;
|
||||||
LuaRootPtr m_luaRoot;
|
LuaRootPtr m_luaRoot;
|
||||||
|
|
||||||
|
typedef tuple<ItemDescriptor, Maybe<float>, Maybe<uint64_t>> ItemCacheEntry;
|
||||||
|
|
||||||
|
mutable Mutex m_cacheMutex;
|
||||||
|
mutable HashTtlCache<ItemCacheEntry, ItemPtr> m_itemCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ItemT>
|
template <typename ItemT>
|
||||||
|
@ -1151,7 +1151,7 @@ ItemPtr Player::pickupItems(ItemPtr const& items) {
|
|||||||
m_effectsAnimator->playSound("pickup");
|
m_effectsAnimator->playSound("pickup");
|
||||||
}
|
}
|
||||||
auto itemDb = Root::singleton().itemDatabase();
|
auto itemDb = Root::singleton().itemDatabase();
|
||||||
queueItemPickupMessage(itemDb->item(items->descriptor()));
|
queueItemPickupMessage(itemDb->itemShared(items->descriptor()));
|
||||||
return m_inventory->addItems(items);
|
return m_inventory->addItems(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,12 +279,12 @@ String questParamText(QuestParam const& parameter) {
|
|||||||
|
|
||||||
if (parameter.detail.is<QuestItem>()) {
|
if (parameter.detail.is<QuestItem>()) {
|
||||||
QuestItem item = parameter.detail.get<QuestItem>();
|
QuestItem item = parameter.detail.get<QuestItem>();
|
||||||
return itemDatabase->item(item.descriptor())->friendlyName();
|
return itemDatabase->itemShared(item.descriptor())->friendlyName();
|
||||||
|
|
||||||
} else if (parameter.detail.is<QuestItemList>()) {
|
} else if (parameter.detail.is<QuestItemList>()) {
|
||||||
QuestItemList itemList = parameter.detail.get<QuestItemList>();
|
QuestItemList itemList = parameter.detail.get<QuestItemList>();
|
||||||
StringList itemStrings = itemList.transformed([&itemDatabase](ItemDescriptor const& itemDesc) -> String {
|
StringList itemStrings = itemList.transformed([&itemDatabase](ItemDescriptor const& itemDesc) -> String {
|
||||||
return strf("{} {}", itemDesc.count(), itemDatabase->item(itemDesc)->friendlyName());
|
return strf("{} {}", itemDesc.count(), itemDatabase->itemShared(itemDesc)->friendlyName());
|
||||||
});
|
});
|
||||||
return itemStrings.join(", ");
|
return itemStrings.join(", ");
|
||||||
|
|
||||||
|
@ -106,23 +106,38 @@ Root::Root(Settings settings) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_objectDatabaseMutex);
|
MutexLocker locker(m_objectDatabaseMutex);
|
||||||
if (m_objectDatabase)
|
if (ObjectDatabasePtr objectDb = m_objectDatabase) {
|
||||||
m_objectDatabase->cleanup();
|
locker.unlock();
|
||||||
|
objectDb->cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
MutexLocker locker(m_itemDatabaseMutex);
|
||||||
|
if (ItemDatabasePtr itemDb = m_itemDatabase) {
|
||||||
|
locker.unlock();
|
||||||
|
itemDb->cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_monsterDatabaseMutex);
|
MutexLocker locker(m_monsterDatabaseMutex);
|
||||||
if (m_monsterDatabase)
|
if (MonsterDatabasePtr monsterDb = m_monsterDatabase) {
|
||||||
m_monsterDatabase->cleanup();
|
locker.unlock();
|
||||||
|
monsterDb->cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_assetsMutex);
|
MutexLocker locker(m_assetsMutex);
|
||||||
if (m_assets)
|
if (AssetsPtr assets = m_assets) {
|
||||||
m_assets->cleanup();
|
locker.unlock();
|
||||||
|
assets->cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_tenantDatabaseMutex);
|
MutexLocker locker(m_tenantDatabaseMutex);
|
||||||
if (m_tenantDatabase)
|
if (TenantDatabasePtr tenantDb = m_tenantDatabase) {
|
||||||
m_tenantDatabase->cleanup();
|
locker.unlock();
|
||||||
|
tenantDb->cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Random::addEntropy();
|
Random::addEntropy();
|
||||||
|
Loading…
Reference in New Issue
Block a user