diff --git a/source/core/StarDirectives.cpp b/source/core/StarDirectives.cpp index 8dcf8da..4a2ca4c 100644 --- a/source/core/StarDirectives.cpp +++ b/source/core/StarDirectives.cpp @@ -2,6 +2,7 @@ #include "StarImageProcessing.hpp" #include "StarDirectives.hpp" #include "StarXXHash.hpp" +#include "StarLogging.hpp" namespace Star { @@ -20,17 +21,17 @@ Directives::Entry::Entry(Entry const& other) { string = other.string; } -Directives::Directives() {} -Directives::Directives(String const& directives) { +Directives::Directives() : hash(0) {} +Directives::Directives(String const& directives) : hash(0) { parse(directives); } -Directives::Directives(String&& directives) { +Directives::Directives(String&& directives) : hash(0) { String mine = move(directives); parse(mine); } -Directives::Directives(const char* directives) { +Directives::Directives(const char* directives) : hash(0) { String string(directives); parse(string); } @@ -42,6 +43,9 @@ Directives::Directives(List&& newEntries) { } void Directives::parse(String const& directives) { + if (directives.empty()) + return; + List newList; StringList split = directives.split('?'); newList.reserve(split.size()); @@ -51,25 +55,35 @@ void Directives::parse(String const& directives) { newList.emplace_back(move(operation), move(str)); } } + + if (newList.empty()) + return; + entries = std::make_shared const>(move(newList)); hash = XXH3_64bits(directives.utf8Ptr(), directives.utf8Size()); + //if (directives.utf8Size() > 1000) + // Logger::logf(LogLevel::Debug, "Directives: Parsed %u character long string", directives.utf8Size()); } void Directives::buildString(String& out) const { - for (auto& entry : *entries) { - out += "?"; - out += entry.string; + if (entries) { + for (auto& entry : *entries) { + out += "?"; + out += entry.string; + } } } String Directives::toString() const { String result; buildString(result); + //if (result.utf8Size() > 1000) + // Logger::logf(LogLevel::Debug, "Directives: Rebuilt %u character long string", result.utf8Size()); return result; } inline bool Directives::empty() const { - return entries->empty(); + return !entries || entries->empty(); } @@ -114,7 +128,8 @@ inline bool DirectivesGroup::compare(DirectivesGroup const& other) const { void DirectivesGroup::append(Directives const& directives) { m_directives.emplace_back(directives); - m_count += m_directives.back().entries->size(); + if (directives.entries) + m_count += m_directives.back().entries->size(); } void DirectivesGroup::append(List&& entries) { @@ -146,16 +161,20 @@ void DirectivesGroup::addToString(String& string) const { void DirectivesGroup::forEach(DirectivesCallback callback) const { for (auto& directives : m_directives) { - for (auto& entry : *directives.entries) - callback(entry); + if (directives.entries) { + for (auto& entry : *directives.entries) + callback(entry); + } } } bool DirectivesGroup::forEachAbortable(AbortableDirectivesCallback callback) const { for (auto& directives : m_directives) { - for (auto& entry : *directives.entries) { - if (!callback(entry)) - return false; + if (directives.entries) { + for (auto& entry : *directives.entries) { + if (!callback(entry)) + return false; + } } } diff --git a/source/game/StarArmorWearer.cpp b/source/game/StarArmorWearer.cpp index 86f05fc..fffde38 100644 --- a/source/game/StarArmorWearer.cpp +++ b/source/game/StarArmorWearer.cpp @@ -16,7 +16,7 @@ namespace Star { -ArmorWearer::ArmorWearer() { +ArmorWearer::ArmorWearer() : m_lastNude(true), m_needsHumanoidSync(true) { addNetElement(&m_headItemDataNetState); addNetElement(&m_chestItemDataNetState); addNetElement(&m_legsItemDataNetState); @@ -27,7 +27,14 @@ ArmorWearer::ArmorWearer() { addNetElement(&m_backCosmeticItemDataNetState); } -void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceNude) const { +void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceNude) { + if (m_lastNude != forceNude) + m_lastNude = forceNude; + else if (!m_needsHumanoidSync) + return; + + m_needsHumanoidSync = false; + bool bodyHidden = false; if (m_headCosmeticItem && !forceNude) { humanoid.setHeadArmorFrameset(m_headCosmeticItem->frameset(humanoid.identity().gender)); @@ -161,35 +168,59 @@ List ArmorWearer::statusEffects() const { } void ArmorWearer::setHeadItem(HeadArmorPtr headItem) { + if (!Item::itemsEqual(m_headItem, headItem)) + return; m_headItem = headItem; + m_needsHumanoidSync = true; } void ArmorWearer::setHeadCosmeticItem(HeadArmorPtr headCosmeticItem) { + if (!Item::itemsEqual(m_headCosmeticItem, headCosmeticItem)) + return; m_headCosmeticItem = headCosmeticItem; + m_needsHumanoidSync = true; } void ArmorWearer::setChestCosmeticItem(ChestArmorPtr chestCosmeticItem) { + if (!Item::itemsEqual(m_chestCosmeticItem, chestCosmeticItem)) + return; m_chestCosmeticItem = chestCosmeticItem; + m_needsHumanoidSync = true; } void ArmorWearer::setChestItem(ChestArmorPtr chestItem) { + if (!Item::itemsEqual(m_chestItem, chestItem)) + return; m_chestItem = chestItem; + m_needsHumanoidSync = true; } void ArmorWearer::setLegsItem(LegsArmorPtr legsItem) { + if (!Item::itemsEqual(m_legsItem, legsItem)) + return; m_legsItem = legsItem; + m_needsHumanoidSync = true; } void ArmorWearer::setLegsCosmeticItem(LegsArmorPtr legsCosmeticItem) { + if (!Item::itemsEqual(m_legsCosmeticItem, legsCosmeticItem)) + return; m_legsCosmeticItem = legsCosmeticItem; + m_needsHumanoidSync = true; } void ArmorWearer::setBackItem(BackArmorPtr backItem) { + if (!Item::itemsEqual(m_backItem, backItem)) + return; m_backItem = backItem; + m_needsHumanoidSync = true; } void ArmorWearer::setBackCosmeticItem(BackArmorPtr backCosmeticItem) { + if (!Item::itemsEqual(m_backCosmeticItem, backCosmeticItem)) + return; m_backCosmeticItem = backCosmeticItem; + m_needsHumanoidSync = true; } HeadArmorPtr ArmorWearer::headItem() const { @@ -275,23 +306,26 @@ ItemDescriptor ArmorWearer::backCosmeticItemDescriptor() const { void ArmorWearer::netElementsNeedLoad(bool) { auto itemDatabase = Root::singleton().itemDatabase(); + bool changed = false; if (m_headItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_headItemDataNetState.get(), m_headItem); + changed |= itemDatabase->loadItem(m_headItemDataNetState.get(), m_headItem); if (m_chestItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_chestItemDataNetState.get(), m_chestItem); + changed |= itemDatabase->loadItem(m_chestItemDataNetState.get(), m_chestItem); if (m_legsItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_legsItemDataNetState.get(), m_legsItem); + changed |= itemDatabase->loadItem(m_legsItemDataNetState.get(), m_legsItem); if (m_backItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_backItemDataNetState.get(), m_backItem); + changed |= itemDatabase->loadItem(m_backItemDataNetState.get(), m_backItem); if (m_headCosmeticItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_headCosmeticItemDataNetState.get(), m_headCosmeticItem); + changed |= itemDatabase->loadItem(m_headCosmeticItemDataNetState.get(), m_headCosmeticItem); if (m_chestCosmeticItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_chestCosmeticItemDataNetState.get(), m_chestCosmeticItem); + changed |= itemDatabase->loadItem(m_chestCosmeticItemDataNetState.get(), m_chestCosmeticItem); if (m_legsCosmeticItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_legsCosmeticItemDataNetState.get(), m_legsCosmeticItem); + changed |= itemDatabase->loadItem(m_legsCosmeticItemDataNetState.get(), m_legsCosmeticItem); if (m_backCosmeticItemDataNetState.pullUpdated()) - itemDatabase->loadItem(m_backCosmeticItemDataNetState.get(), m_backCosmeticItem); + changed |= itemDatabase->loadItem(m_backCosmeticItemDataNetState.get(), m_backCosmeticItem); + + m_needsHumanoidSync = changed; } void ArmorWearer::netElementsNeedStore() { diff --git a/source/game/StarArmorWearer.hpp b/source/game/StarArmorWearer.hpp index 4297d59..e4ddf01 100644 --- a/source/game/StarArmorWearer.hpp +++ b/source/game/StarArmorWearer.hpp @@ -26,7 +26,7 @@ class ArmorWearer : public NetElementSyncGroup { public: ArmorWearer(); - void setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceNude) const; + void setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceNude); void effects(EffectEmitter& effectEmitter); List statusEffects() const; @@ -82,6 +82,9 @@ private: NetElementData m_chestCosmeticItemDataNetState; NetElementData m_legsCosmeticItemDataNetState; NetElementData m_backCosmeticItemDataNetState; + + bool m_lastNude; + bool m_needsHumanoidSync; }; } diff --git a/source/game/StarDrawable.cpp b/source/game/StarDrawable.cpp index 0aea570..e259aa2 100644 --- a/source/game/StarDrawable.cpp +++ b/source/game/StarDrawable.cpp @@ -10,7 +10,7 @@ namespace Star { Drawable::ImagePart& Drawable::ImagePart::addDirectives(Directives const& directives, bool keepImageCenterPosition) { - if (directives.entries->empty()) + if (!directives.entries || directives.entries->empty()) return *this; if (keepImageCenterPosition) { diff --git a/source/game/StarItem.cpp b/source/game/StarItem.cpp index 68590b5..e25870b 100644 --- a/source/game/StarItem.cpp +++ b/source/game/StarItem.cpp @@ -285,4 +285,13 @@ ItemPtr GenericItem::clone() const { return make_shared(*this); } +bool Item::itemsEqual(ItemConstPtr const& a, ItemConstPtr const& b) { + if (!a && !b) // Both are null + return true; + if (a && b) // Both aren't null, compare + return a->stackableWith(b); + else // One is null, so not equal + return true; +} + } diff --git a/source/game/StarItem.hpp b/source/game/StarItem.hpp index 0dba854..ed13f82 100644 --- a/source/game/StarItem.hpp +++ b/source/game/StarItem.hpp @@ -114,6 +114,8 @@ public: // Returns just the dynamic parameters Json parameters() const; + static bool itemsEqual(ItemConstPtr const& a, ItemConstPtr const& b); + protected: void setMaxStack(uint64_t maxStack); void setDescription(String const& description); diff --git a/source/game/items/StarArmors.cpp b/source/game/items/StarArmors.cpp index 4abcde8..883f3b2 100644 --- a/source/game/items/StarArmors.cpp +++ b/source/game/items/StarArmors.cpp @@ -21,7 +21,7 @@ ArmorItem::ArmorItem(Json const& config, String const& directory, Json const& da m_directives = instanceValue("directives", "").toString(); m_colorOptions = colorDirectivesFromConfig(config.getArray("colorOptions", JsonArray{""})); - if (m_directives.entries->empty()) + if (!m_directives.entries || m_directives.entries->empty()) m_directives = "?" + m_colorOptions.wrap(instanceValue("colorIndex", 0).toUInt()); refreshIconDrawables();