More directives optimization

This commit is contained in:
Kae 2023-06-25 18:12:54 +10:00
parent e2424b7dcf
commit 7d205330db
22 changed files with 231 additions and 157 deletions

View File

@ -221,7 +221,7 @@ Color::Color(const String& name) {
if (i != NamedColors.end()) if (i != NamedColors.end())
*this = i->second; *this = i->second;
else else
throw ColorException(strf("Named color %s not found", name)); throw ColorException(strf("Named color %s not found", name), false);
} }
} }
@ -303,30 +303,7 @@ uint32_t Color::toUint32() const {
} }
Color Color::fromHex(String const& s) { Color Color::fromHex(String const& s) {
uint8_t cbytes[4]; return Color::rgba(hexToVec4B(s));
if (s.utf8Size() == 3) {
nibbleDecode(s.utf8Ptr(), 3, (char*)cbytes, 4);
cbytes[0] = (cbytes[0] << 4) | cbytes[0];
cbytes[1] = (cbytes[1] << 4) | cbytes[1];
cbytes[2] = (cbytes[2] << 4) | cbytes[2];
cbytes[3] = 255;
} else if (s.utf8Size() == 4) {
nibbleDecode(s.utf8Ptr(), 4, (char*)cbytes, 4);
cbytes[0] = (cbytes[0] << 4) | cbytes[0];
cbytes[1] = (cbytes[1] << 4) | cbytes[1];
cbytes[2] = (cbytes[2] << 4) | cbytes[2];
cbytes[3] = (cbytes[3] << 4) | cbytes[3];
} else if (s.utf8Size() == 6) {
hexDecode(s.utf8Ptr(), 6, (char*)cbytes, 4);
cbytes[3] = 255;
} else if (s.utf8Size() == 8) {
hexDecode(s.utf8Ptr(), 8, (char*)cbytes, 4);
} else {
throw ColorException(strf("Improper size for hex string '%s' in Color::fromHex", s));
}
return Color::rgba(cbytes[0], cbytes[1], cbytes[2], cbytes[3]);
} }
Vec4B Color::toRgba() const { Vec4B Color::toRgba() const {
@ -624,4 +601,31 @@ Vec4B Color::hueShiftVec4B(Vec4B color, float hue) {
} }
} }
Vec4B Color::hexToVec4B(String const& s) {
Array<uint8_t, 4> cbytes;
if (s.utf8Size() == 3) {
nibbleDecode(s.utf8Ptr(), 3, (char*)cbytes.data(), 4);
cbytes[0] = (cbytes[0] << 4) | cbytes[0];
cbytes[1] = (cbytes[1] << 4) | cbytes[1];
cbytes[2] = (cbytes[2] << 4) | cbytes[2];
cbytes[3] = 255;
} else if (s.utf8Size() == 4) {
nibbleDecode(s.utf8Ptr(), 4, (char*)cbytes.data(), 4);
cbytes[0] = (cbytes[0] << 4) | cbytes[0];
cbytes[1] = (cbytes[1] << 4) | cbytes[1];
cbytes[2] = (cbytes[2] << 4) | cbytes[2];
cbytes[3] = (cbytes[3] << 4) | cbytes[3];
} else if (s.utf8Size() == 6) {
hexDecode(s.utf8Ptr(), 6, (char*)cbytes.data(), 4);
cbytes[3] = 255;
} else if (s.utf8Size() == 8) {
hexDecode(s.utf8Ptr(), 8, (char*)cbytes.data(), 4);
} else {
throw ColorException(strf("Improper size for hex string '%s' in Color::hexToVec4B", s), false);
}
return Vec4B(move(cbytes));
}
} }

View File

@ -67,7 +67,7 @@ public:
static Color temperature(float temp); static Color temperature(float temp);
static Vec4B hueShiftVec4B(Vec4B color, float hue); static Vec4B hueShiftVec4B(Vec4B color, float hue);
static Vec4B Color::hexToVec4B(String const& s);
// Black // Black
Color(); Color();

View File

@ -229,6 +229,10 @@ inline size_t DirectivesGroup::hash() const {
return hasher.digest(); return hasher.digest();
} }
const List<Directives>& DirectivesGroup::list() const {
return m_directives;
}
bool operator==(DirectivesGroup const& a, DirectivesGroup const& b) { bool operator==(DirectivesGroup const& a, DirectivesGroup const& b) {
return a.compare(b); return a.compare(b);
} }
@ -237,6 +241,21 @@ bool operator!=(DirectivesGroup const& a, DirectivesGroup const& b) {
return !a.compare(b); return !a.compare(b);
} }
DataStream& operator>>(DataStream& ds, DirectivesGroup& directivesGroup) {
String string;
ds.read(string);
directivesGroup = move(DirectivesGroup(move(string)));
return ds;
}
DataStream& operator<<(DataStream& ds, DirectivesGroup const& directivesGroup) {
ds.write(directivesGroup.toString());
return ds;
}
size_t hash<DirectivesGroup>::operator()(DirectivesGroup const& s) const { size_t hash<DirectivesGroup>::operator()(DirectivesGroup const& s) const {
return s.hash(); return s.hash();
} }

View File

@ -73,9 +73,13 @@ public:
void applyExistingImage(Image& image) const; void applyExistingImage(Image& image) const;
inline size_t hash() const; inline size_t hash() const;
const List<Directives>& list() const;
friend bool operator==(DirectivesGroup const& a, DirectivesGroup const& b); friend bool operator==(DirectivesGroup const& a, DirectivesGroup const& b);
friend bool operator!=(DirectivesGroup const& a, DirectivesGroup const& b); friend bool operator!=(DirectivesGroup const& a, DirectivesGroup const& b);
friend DataStream& operator>>(DataStream& ds, DirectivesGroup& directives);
friend DataStream& operator<<(DataStream& ds, DirectivesGroup const& directives);
private: private:
void buildString(String& string, const DirectivesGroup& directives) const; void buildString(String& string, const DirectivesGroup& directives) const;

View File

@ -13,7 +13,7 @@ public:
StarException() noexcept; StarException() noexcept;
virtual ~StarException() noexcept; virtual ~StarException() noexcept;
explicit StarException(std::string message) noexcept; explicit StarException(std::string message, bool genStackTrace = true) noexcept;
explicit StarException(std::exception const& cause) noexcept; explicit StarException(std::exception const& cause) noexcept;
StarException(std::string message, std::exception const& cause) noexcept; StarException(std::string message, std::exception const& cause) noexcept;
@ -26,7 +26,7 @@ public:
friend OutputProxy outputException(std::exception const& e, bool fullStacktrace); friend OutputProxy outputException(std::exception const& e, bool fullStacktrace);
protected: protected:
StarException(char const* type, std::string message) noexcept; StarException(char const* type, std::string message, bool genStackTrace = true) noexcept;
StarException(char const* type, std::string message, std::exception const& cause) noexcept; StarException(char const* type, std::string message, std::exception const& cause) noexcept;
private: private:
@ -68,22 +68,22 @@ void fatalException(std::exception const& e, bool showStackTrace);
{} {}
#endif #endif
#define STAR_EXCEPTION(ClassName, BaseName) \ #define STAR_EXCEPTION(ClassName, BaseName) \
class ClassName : public BaseName { \ class ClassName : public BaseName { \
public: \ public: \
template <typename... Args> \ template <typename... Args> \
static ClassName format(char const* fmt, Args const&... args) { \ static ClassName format(char const* fmt, Args const&... args) { \
return ClassName(strf(fmt, args...)); \ return ClassName(strf(fmt, args...)); \
} \ } \
ClassName() : BaseName(#ClassName, std::string()) {} \ ClassName() : BaseName(#ClassName, std::string()) {} \
explicit ClassName(std::string message) : BaseName(#ClassName, move(message)) {} \ explicit ClassName(std::string message, bool genStackTrace = true) : BaseName(#ClassName, move(message), genStackTrace) {} \
explicit ClassName(std::exception const& cause) : BaseName(#ClassName, std::string(), cause) {} \ explicit ClassName(std::exception const& cause) : BaseName(#ClassName, std::string(), cause) {} \
ClassName(std::string message, std::exception const& cause) : BaseName(#ClassName, move(message), cause) {} \ ClassName(std::string message, std::exception const& cause) : BaseName(#ClassName, move(message), cause) {} \
\ \
protected: \ protected: \
ClassName(char const* type, std::string message) : BaseName(type, move(message)) {} \ ClassName(char const* type, std::string message, bool genStackTrace = true) : BaseName(type, move(message), genStackTrace) {} \
ClassName(char const* type, std::string message, std::exception const& cause) \ ClassName(char const* type, std::string message, std::exception const& cause) \
: BaseName(type, move(message), cause) {} \ : BaseName(type, move(message), cause) {} \
} }
STAR_EXCEPTION(OutOfRangeException, StarException); STAR_EXCEPTION(OutOfRangeException, StarException);

View File

@ -38,8 +38,8 @@ StarException::StarException() noexcept
StarException::~StarException() noexcept {} StarException::~StarException() noexcept {}
StarException::StarException(std::string message) noexcept StarException::StarException(std::string message, bool genStackTrace) noexcept
: StarException("StarException", move(message)) {} : StarException("StarException", move(message), genStackTrace) {}
StarException::StarException(std::exception const& cause) noexcept StarException::StarException(std::exception const& cause) noexcept
: StarException("StarException", std::string(), cause) {} : StarException("StarException", std::string(), cause) {}
@ -56,19 +56,19 @@ const char* StarException::what() const throw() {
return m_whatBuffer.c_str(); return m_whatBuffer.c_str();
} }
StarException::StarException(char const* type, std::string message) noexcept { StarException::StarException(char const* type, std::string message, bool genStackTrace) noexcept {
auto printException = [](std::ostream& os, bool fullStacktrace, char const* type, std::string message, StackCapture stack) { auto printException = [](std::ostream& os, bool fullStacktrace, char const* type, std::string message, Maybe<StackCapture> stack) {
os << "(" << type << ")"; os << "(" << type << ")";
if (!message.empty()) if (!message.empty())
os << " " << message; os << " " << message;
if (fullStacktrace) { if (fullStacktrace && stack) {
os << std::endl; os << std::endl;
os << outputStack(stack); os << outputStack(*stack);
} }
}; };
m_printException = bind(printException, _1, _2, type, move(message), captureStack()); m_printException = bind(printException, _1, _2, type, move(message), genStackTrace ? captureStack() : Maybe<StackCapture>());
} }
StarException::StarException(char const* type, std::string message, std::exception const& cause) noexcept StarException::StarException(char const* type, std::string message, std::exception const& cause) noexcept

View File

@ -145,7 +145,7 @@ StarException::StarException() noexcept : StarException(std::string("StarExcepti
StarException::~StarException() noexcept {} StarException::~StarException() noexcept {}
StarException::StarException(std::string message) noexcept : StarException("StarException", move(message)) {} StarException::StarException(std::string message, bool genStackTrace) noexcept : StarException("StarException", move(message), genStackTrace) {}
StarException::StarException(std::exception const& cause) noexcept StarException::StarException(std::exception const& cause) noexcept
: StarException("StarException", std::string(), cause) {} : StarException("StarException", std::string(), cause) {}
@ -162,20 +162,20 @@ const char* StarException::what() const throw() {
return m_whatBuffer.c_str(); return m_whatBuffer.c_str();
} }
StarException::StarException(char const* type, std::string message) noexcept { StarException::StarException(char const* type, std::string message, bool genStackTrace) noexcept {
auto printException = []( auto printException = [](
std::ostream& os, bool fullStacktrace, char const* type, std::string message, StackCapture stack) { std::ostream& os, bool fullStacktrace, char const* type, std::string message, Maybe<StackCapture> stack) {
os << "(" << type << ")"; os << "(" << type << ")";
if (!message.empty()) if (!message.empty())
os << " " << message; os << " " << message;
if (fullStacktrace) { if (fullStacktrace && stack) {
os << std::endl; os << std::endl;
os << outputStack(stack); os << outputStack(*stack);
} }
}; };
m_printException = bind(printException, _1, _2, type, move(message), captureStack()); m_printException = bind(printException, _1, _2, type, move(message), genStackTrace ? captureStack() : Maybe<StackCapture>());
} }
StarException::StarException(char const* type, std::string message, std::exception const& cause) noexcept StarException::StarException(char const* type, std::string message, std::exception const& cause) noexcept

View File

@ -173,7 +173,7 @@ ImageOperation imageOperationFromString(String const& string) {
} else if (type == "replace") { } else if (type == "replace") {
ColorReplaceImageOperation operation; ColorReplaceImageOperation operation;
for (size_t i = 0; i < (bits.size() - 1) / 2; ++i) for (size_t i = 0; i < (bits.size() - 1) / 2; ++i)
operation.colorReplaceMap[Color::fromHex(bits[i * 2 + 1]).toRgba()] = Color::fromHex(bits[i * 2 + 2]).toRgba(); operation.colorReplaceMap[Color::hexToVec4B(bits[i * 2 + 1])] = Color::hexToVec4B(bits[i * 2 + 2]);
return operation; return operation;
@ -259,7 +259,7 @@ ImageOperation imageOperationFromString(String const& string) {
return FlipImageOperation{FlipImageOperation::FlipXY}; return FlipImageOperation{FlipImageOperation::FlipXY};
} else { } else {
throw ImageOperationException(strf("Could not recognize ImageOperation type %s", type)); throw ImageOperationException(strf("Could not recognize ImageOperation type %s", type), false);
} }
} catch (OutOfRangeException const& e) { } catch (OutOfRangeException const& e) {
throw ImageOperationException("Error reading ImageOperation", e); throw ImageOperationException("Error reading ImageOperation", e);

View File

@ -16,7 +16,7 @@
namespace Star { namespace Star {
ArmorWearer::ArmorWearer() : m_lastNude(true), m_needsHumanoidSync(true) { ArmorWearer::ArmorWearer() : m_lastNude(true) {
addNetElement(&m_headItemDataNetState); addNetElement(&m_headItemDataNetState);
addNetElement(&m_chestItemDataNetState); addNetElement(&m_chestItemDataNetState);
addNetElement(&m_legsItemDataNetState); addNetElement(&m_legsItemDataNetState);
@ -25,26 +25,34 @@ ArmorWearer::ArmorWearer() : m_lastNude(true), m_needsHumanoidSync(true) {
addNetElement(&m_chestCosmeticItemDataNetState); addNetElement(&m_chestCosmeticItemDataNetState);
addNetElement(&m_legsCosmeticItemDataNetState); addNetElement(&m_legsCosmeticItemDataNetState);
addNetElement(&m_backCosmeticItemDataNetState); addNetElement(&m_backCosmeticItemDataNetState);
m_headNeedsSync = m_chestNeedsSync = m_legsNeedsSync = m_backNeedsSync = true;
} }
void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceNude) { void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceNude) {
if (m_lastNude != forceNude) bool nudeChanged = m_lastNude != forceNude;
if (nudeChanged)
m_lastNude = forceNude; m_lastNude = forceNude;
else if (!m_needsHumanoidSync)
return;
m_needsHumanoidSync = false; bool headNeedsSync = nudeChanged || m_headNeedsSync;
bool chestNeedsSync = nudeChanged || m_chestNeedsSync;
bool legsNeedsSync = nudeChanged || m_legsNeedsSync;
bool backNeedsSync = nudeChanged || m_backNeedsSync;
bool bodyHidden = false; bool bodyHidden = false;
if (m_headCosmeticItem && !forceNude) { if (m_headCosmeticItem && !forceNude) {
humanoid.setHeadArmorFrameset(m_headCosmeticItem->frameset(humanoid.identity().gender)); if (headNeedsSync) {
humanoid.setHeadArmorDirectives(m_headCosmeticItem->directives()); humanoid.setHeadArmorFrameset(m_headCosmeticItem->frameset(humanoid.identity().gender));
humanoid.setHelmetMaskDirectives(m_headCosmeticItem->maskDirectives()); humanoid.setHeadArmorDirectives(m_headCosmeticItem->directives());
humanoid.setHelmetMaskDirectives(m_headCosmeticItem->maskDirectives());
}
bodyHidden = bodyHidden || m_headCosmeticItem->hideBody(); bodyHidden = bodyHidden || m_headCosmeticItem->hideBody();
} else if (m_headItem && !forceNude) { } else if (m_headItem && !forceNude) {
humanoid.setHeadArmorFrameset(m_headItem->frameset(humanoid.identity().gender)); if (headNeedsSync) {
humanoid.setHeadArmorDirectives(m_headItem->directives()); humanoid.setHeadArmorFrameset(m_headItem->frameset(humanoid.identity().gender));
humanoid.setHelmetMaskDirectives(m_headItem->maskDirectives()); humanoid.setHeadArmorDirectives(m_headItem->directives());
humanoid.setHelmetMaskDirectives(m_headItem->maskDirectives());
}
bodyHidden = bodyHidden || m_headItem->hideBody(); bodyHidden = bodyHidden || m_headItem->hideBody();
} else { } else {
humanoid.setHeadArmorFrameset(""); humanoid.setHeadArmorFrameset("");
@ -52,16 +60,20 @@ void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceN
} }
if (m_chestCosmeticItem && !forceNude) { if (m_chestCosmeticItem && !forceNude) {
humanoid.setBackSleeveFrameset(m_chestCosmeticItem->backSleeveFrameset(humanoid.identity().gender)); if (chestNeedsSync) {
humanoid.setFrontSleeveFrameset(m_chestCosmeticItem->frontSleeveFrameset(humanoid.identity().gender)); humanoid.setBackSleeveFrameset(m_chestCosmeticItem->backSleeveFrameset(humanoid.identity().gender));
humanoid.setChestArmorFrameset(m_chestCosmeticItem->bodyFrameset(humanoid.identity().gender)); humanoid.setFrontSleeveFrameset(m_chestCosmeticItem->frontSleeveFrameset(humanoid.identity().gender));
humanoid.setChestArmorDirectives(m_chestCosmeticItem->directives()); humanoid.setChestArmorFrameset(m_chestCosmeticItem->bodyFrameset(humanoid.identity().gender));
humanoid.setChestArmorDirectives(m_chestCosmeticItem->directives());
}
bodyHidden = bodyHidden || m_chestCosmeticItem->hideBody(); bodyHidden = bodyHidden || m_chestCosmeticItem->hideBody();
} else if (m_chestItem && !forceNude) { } else if (m_chestItem && !forceNude) {
humanoid.setBackSleeveFrameset(m_chestItem->backSleeveFrameset(humanoid.identity().gender)); if (chestNeedsSync) {
humanoid.setFrontSleeveFrameset(m_chestItem->frontSleeveFrameset(humanoid.identity().gender)); humanoid.setBackSleeveFrameset(m_chestItem->backSleeveFrameset(humanoid.identity().gender));
humanoid.setChestArmorFrameset(m_chestItem->bodyFrameset(humanoid.identity().gender)); humanoid.setFrontSleeveFrameset(m_chestItem->frontSleeveFrameset(humanoid.identity().gender));
humanoid.setChestArmorDirectives(m_chestItem->directives()); humanoid.setChestArmorFrameset(m_chestItem->bodyFrameset(humanoid.identity().gender));
humanoid.setChestArmorDirectives(m_chestItem->directives());
}
bodyHidden = bodyHidden || m_chestItem->hideBody(); bodyHidden = bodyHidden || m_chestItem->hideBody();
} else { } else {
humanoid.setBackSleeveFrameset(""); humanoid.setBackSleeveFrameset("");
@ -70,29 +82,39 @@ void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceN
} }
if (m_legsCosmeticItem && !forceNude) { if (m_legsCosmeticItem && !forceNude) {
humanoid.setLegsArmorFrameset(m_legsCosmeticItem->frameset(humanoid.identity().gender)); if (legsNeedsSync) {
humanoid.setLegsArmorDirectives(m_legsCosmeticItem->directives()); humanoid.setLegsArmorFrameset(m_legsCosmeticItem->frameset(humanoid.identity().gender));
humanoid.setLegsArmorDirectives(m_legsCosmeticItem->directives());
}
bodyHidden = bodyHidden || m_legsCosmeticItem->hideBody(); bodyHidden = bodyHidden || m_legsCosmeticItem->hideBody();
} else if (m_legsItem && !forceNude) { } else if (m_legsItem && !forceNude) {
humanoid.setLegsArmorFrameset(m_legsItem->frameset(humanoid.identity().gender)); if (legsNeedsSync) {
humanoid.setLegsArmorDirectives(m_legsItem->directives()); humanoid.setLegsArmorFrameset(m_legsItem->frameset(humanoid.identity().gender));
humanoid.setLegsArmorDirectives(m_legsItem->directives());
}
bodyHidden = bodyHidden || m_legsItem->hideBody(); bodyHidden = bodyHidden || m_legsItem->hideBody();
} else { } else {
humanoid.setLegsArmorFrameset(""); humanoid.setLegsArmorFrameset("");
} }
if (m_backCosmeticItem && !forceNude) { if (m_backCosmeticItem && !forceNude) {
humanoid.setBackArmorFrameset(m_backCosmeticItem->frameset(humanoid.identity().gender)); if (backNeedsSync) {
humanoid.setBackArmorDirectives(m_backCosmeticItem->directives()); humanoid.setBackArmorFrameset(m_backCosmeticItem->frameset(humanoid.identity().gender));
humanoid.setBackArmorDirectives(m_backCosmeticItem->directives());
}
bodyHidden = bodyHidden || m_backCosmeticItem->hideBody(); bodyHidden = bodyHidden || m_backCosmeticItem->hideBody();
} else if (m_backItem && !forceNude) { } else if (m_backItem && !forceNude) {
humanoid.setBackArmorFrameset(m_backItem->frameset(humanoid.identity().gender)); if (backNeedsSync) {
humanoid.setBackArmorDirectives(m_backItem->directives()); humanoid.setBackArmorFrameset(m_backItem->frameset(humanoid.identity().gender));
humanoid.setBackArmorDirectives(m_backItem->directives());
}
bodyHidden = bodyHidden || m_backItem->hideBody(); bodyHidden = bodyHidden || m_backItem->hideBody();
} else { } else {
humanoid.setBackArmorFrameset(""); humanoid.setBackArmorFrameset("");
} }
m_headNeedsSync = m_chestNeedsSync = m_legsNeedsSync = m_backNeedsSync = false;
humanoid.setBodyHidden(bodyHidden); humanoid.setBodyHidden(bodyHidden);
} }
@ -171,56 +193,56 @@ void ArmorWearer::setHeadItem(HeadArmorPtr headItem) {
if (Item::itemsEqual(m_headItem, headItem)) if (Item::itemsEqual(m_headItem, headItem))
return; return;
m_headItem = headItem; m_headItem = headItem;
m_needsHumanoidSync = true; m_headNeedsSync |= !m_headCosmeticItem;
} }
void ArmorWearer::setHeadCosmeticItem(HeadArmorPtr headCosmeticItem) { void ArmorWearer::setHeadCosmeticItem(HeadArmorPtr headCosmeticItem) {
if (Item::itemsEqual(m_headCosmeticItem, headCosmeticItem)) if (Item::itemsEqual(m_headCosmeticItem, headCosmeticItem))
return; return;
m_headCosmeticItem = headCosmeticItem; m_headCosmeticItem = headCosmeticItem;
m_needsHumanoidSync = true; m_headNeedsSync = true;
}
void ArmorWearer::setChestCosmeticItem(ChestArmorPtr chestCosmeticItem) {
if (Item::itemsEqual(m_chestCosmeticItem, chestCosmeticItem))
return;
m_chestCosmeticItem = chestCosmeticItem;
m_needsHumanoidSync = true;
} }
void ArmorWearer::setChestItem(ChestArmorPtr chestItem) { void ArmorWearer::setChestItem(ChestArmorPtr chestItem) {
if (Item::itemsEqual(m_chestItem, chestItem)) if (Item::itemsEqual(m_chestItem, chestItem))
return; return;
m_chestItem = chestItem; m_chestItem = chestItem;
m_needsHumanoidSync = true; m_chestNeedsSync |= !m_chestCosmeticItem;
}
void ArmorWearer::setChestCosmeticItem(ChestArmorPtr chestCosmeticItem) {
if (Item::itemsEqual(m_chestCosmeticItem, chestCosmeticItem))
return;
m_chestCosmeticItem = chestCosmeticItem;
m_chestNeedsSync = true;
} }
void ArmorWearer::setLegsItem(LegsArmorPtr legsItem) { void ArmorWearer::setLegsItem(LegsArmorPtr legsItem) {
if (Item::itemsEqual(m_legsItem, legsItem)) if (Item::itemsEqual(m_legsItem, legsItem))
return; return;
m_legsItem = legsItem; m_legsItem = legsItem;
m_needsHumanoidSync = true; m_legsNeedsSync |= !m_legsCosmeticItem;
} }
void ArmorWearer::setLegsCosmeticItem(LegsArmorPtr legsCosmeticItem) { void ArmorWearer::setLegsCosmeticItem(LegsArmorPtr legsCosmeticItem) {
if (Item::itemsEqual(m_legsCosmeticItem, legsCosmeticItem)) if (Item::itemsEqual(m_legsCosmeticItem, legsCosmeticItem))
return; return;
m_legsCosmeticItem = legsCosmeticItem; m_legsCosmeticItem = legsCosmeticItem;
m_needsHumanoidSync = true; m_legsNeedsSync = true;
} }
void ArmorWearer::setBackItem(BackArmorPtr backItem) { void ArmorWearer::setBackItem(BackArmorPtr backItem) {
if (Item::itemsEqual(m_backItem, backItem)) if (Item::itemsEqual(m_backItem, backItem))
return; return;
m_backItem = backItem; m_backItem = backItem;
m_needsHumanoidSync = true; m_backNeedsSync |= !m_backCosmeticItem;
} }
void ArmorWearer::setBackCosmeticItem(BackArmorPtr backCosmeticItem) { void ArmorWearer::setBackCosmeticItem(BackArmorPtr backCosmeticItem) {
if (Item::itemsEqual(m_backCosmeticItem, backCosmeticItem)) if (Item::itemsEqual(m_backCosmeticItem, backCosmeticItem))
return; return;
m_backCosmeticItem = backCosmeticItem; m_backCosmeticItem = backCosmeticItem;
m_needsHumanoidSync = true; m_backNeedsSync = true;
} }
HeadArmorPtr ArmorWearer::headItem() const { HeadArmorPtr ArmorWearer::headItem() const {
@ -306,26 +328,23 @@ ItemDescriptor ArmorWearer::backCosmeticItemDescriptor() const {
void ArmorWearer::netElementsNeedLoad(bool) { void ArmorWearer::netElementsNeedLoad(bool) {
auto itemDatabase = Root::singleton().itemDatabase(); auto itemDatabase = Root::singleton().itemDatabase();
bool changed = false;
if (m_headItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_headItemDataNetState.get(), m_headItem);
if (m_chestItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_chestItemDataNetState.get(), m_chestItem);
if (m_legsItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_legsItemDataNetState.get(), m_legsItem);
if (m_backItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_backItemDataNetState.get(), m_backItem);
if (m_headCosmeticItemDataNetState.pullUpdated()) if (m_headCosmeticItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_headCosmeticItemDataNetState.get(), m_headCosmeticItem); m_headNeedsSync |= itemDatabase->loadItem(m_headCosmeticItemDataNetState.get(), m_headCosmeticItem);
if (m_chestCosmeticItemDataNetState.pullUpdated()) if (m_chestCosmeticItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_chestCosmeticItemDataNetState.get(), m_chestCosmeticItem); m_chestNeedsSync |= itemDatabase->loadItem(m_chestCosmeticItemDataNetState.get(), m_chestCosmeticItem);
if (m_legsCosmeticItemDataNetState.pullUpdated()) if (m_legsCosmeticItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_legsCosmeticItemDataNetState.get(), m_legsCosmeticItem); m_legsNeedsSync |= itemDatabase->loadItem(m_legsCosmeticItemDataNetState.get(), m_legsCosmeticItem);
if (m_backCosmeticItemDataNetState.pullUpdated()) if (m_backCosmeticItemDataNetState.pullUpdated())
changed |= itemDatabase->loadItem(m_backCosmeticItemDataNetState.get(), m_backCosmeticItem); m_backNeedsSync |= itemDatabase->loadItem(m_backCosmeticItemDataNetState.get(), m_backCosmeticItem);
m_needsHumanoidSync = changed; if (m_headItemDataNetState.pullUpdated())
m_headNeedsSync |= !m_headCosmeticItem && itemDatabase->loadItem(m_headItemDataNetState.get(), m_headItem);
if (m_chestItemDataNetState.pullUpdated())
m_chestNeedsSync |= !m_chestCosmeticItem && itemDatabase->loadItem(m_chestItemDataNetState.get(), m_chestItem);
if (m_legsItemDataNetState.pullUpdated())
m_legsNeedsSync |= !m_legsCosmeticItem && itemDatabase->loadItem(m_legsItemDataNetState.get(), m_legsItem);
if (m_backItemDataNetState.pullUpdated())
m_backNeedsSync |= !m_backCosmeticItem && itemDatabase->loadItem(m_backItemDataNetState.get(), m_backItem);
} }
void ArmorWearer::netElementsNeedStore() { void ArmorWearer::netElementsNeedStore() {

View File

@ -35,8 +35,8 @@ public:
void setHeadItem(HeadArmorPtr headItem); void setHeadItem(HeadArmorPtr headItem);
void setHeadCosmeticItem(HeadArmorPtr headCosmeticItem); void setHeadCosmeticItem(HeadArmorPtr headCosmeticItem);
void setChestCosmeticItem(ChestArmorPtr chestCosmeticItem);
void setChestItem(ChestArmorPtr chestItem); void setChestItem(ChestArmorPtr chestItem);
void setChestCosmeticItem(ChestArmorPtr chestCosmeticItem);
void setLegsItem(LegsArmorPtr legsItem); void setLegsItem(LegsArmorPtr legsItem);
void setLegsCosmeticItem(LegsArmorPtr legsCosmeticItem); void setLegsCosmeticItem(LegsArmorPtr legsCosmeticItem);
void setBackItem(BackArmorPtr backItem); void setBackItem(BackArmorPtr backItem);
@ -84,7 +84,10 @@ private:
NetElementData<ItemDescriptor> m_backCosmeticItemDataNetState; NetElementData<ItemDescriptor> m_backCosmeticItemDataNetState;
bool m_lastNude; bool m_lastNude;
bool m_needsHumanoidSync; bool m_headNeedsSync;
bool m_chestNeedsSync;
bool m_legsNeedsSync;
bool m_backNeedsSync;
}; };
} }

View File

@ -29,6 +29,28 @@ Drawable::ImagePart& Drawable::ImagePart::addDirectives(Directives const& direct
return *this; return *this;
} }
Drawable::ImagePart& Drawable::ImagePart::addDirectivesGroup(DirectivesGroup const& directivesGroup, bool keepImageCenterPosition) {
if (directivesGroup.empty())
return *this;
if (keepImageCenterPosition) {
auto imageMetadata = Root::singleton().imageMetadataDatabase();
Vec2F imageSize = Vec2F(imageMetadata->imageSize(image));
for (Directives const& directives : directivesGroup.list())
image.directives += directives;
Vec2F newImageSize = Vec2F(imageMetadata->imageSize(image));
// If we are trying to maintain the image center, PRE translate the image by
// the change in size / 2
transformation *= Mat3F::translation((imageSize - newImageSize) / 2);
} else {
for (Directives const& directives : directivesGroup.list())
image.directives += directives;
}
return *this;
}
Drawable::ImagePart& Drawable::ImagePart::removeDirectives(bool keepImageCenterPosition) { Drawable::ImagePart& Drawable::ImagePart::removeDirectives(bool keepImageCenterPosition) {
if (keepImageCenterPosition) { if (keepImageCenterPosition) {
auto imageMetadata = Root::singleton().imageMetadataDatabase(); auto imageMetadata = Root::singleton().imageMetadataDatabase();

View File

@ -30,6 +30,7 @@ struct Drawable {
// transformed center of the image the same if the directives change the // transformed center of the image the same if the directives change the
// image size. // image size.
ImagePart& addDirectives(Directives const& directives, bool keepImageCenterPosition = false); ImagePart& addDirectives(Directives const& directives, bool keepImageCenterPosition = false);
ImagePart& addDirectivesGroup(DirectivesGroup const& directivesGroup, bool keepImageCenterPosition = false);
// Remove directives from this ImagePart, while optionally keeping the // Remove directives from this ImagePart, while optionally keeping the
// transformed center of the image the same if the directives change the // transformed center of the image the same if the directives change the

View File

@ -487,7 +487,7 @@ void Monster::update(uint64_t) {
void Monster::render(RenderCallback* renderCallback) { void Monster::render(RenderCallback* renderCallback) {
for (auto& drawable : m_networkedAnimator.drawables(position())) { for (auto& drawable : m_networkedAnimator.drawables(position())) {
if (drawable.isImage()) if (drawable.isImage())
drawable.imagePart().addDirectives(m_statusController->parentDirectives(), true); drawable.imagePart().addDirectivesGroup(m_statusController->parentDirectives(), true);
renderCallback->addDrawable(move(drawable), m_monsterVariant.renderLayer); renderCallback->addDrawable(move(drawable), m_monsterVariant.renderLayer);
} }

View File

@ -385,7 +385,7 @@ void NetworkedAnimator::setPartTag(String const& partType, String tagName, Strin
m_partTags[partType].set(move(tagName), move(tagValue)); m_partTags[partType].set(move(tagName), move(tagValue));
} }
void NetworkedAnimator::setProcessingDirectives(String const& directives) { void NetworkedAnimator::setProcessingDirectives(Directives const& directives) {
m_processingDirectives.set(directives); m_processingDirectives.set(directives);
} }
@ -562,8 +562,7 @@ List<Drawable> NetworkedAnimator::drawables(Vec2F const& position) const {
} }
List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& position) const { List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& position) const {
String baseProcessingDirectives = "?"; List<Directives> baseProcessingDirectives = { m_processingDirectives.get() };
baseProcessingDirectives.append(m_processingDirectives.get());
for (auto& pair : m_effects) { for (auto& pair : m_effects) {
auto const& effectState = pair.second; auto const& effectState = pair.second;
@ -571,11 +570,9 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
auto const& effect = m_effects.get(pair.first); auto const& effect = m_effects.get(pair.first);
if (effect.type == "flash") { if (effect.type == "flash") {
if (effectState.timer > effect.time / 2) { if (effectState.timer > effect.time / 2) {
baseProcessingDirectives.append("?");
baseProcessingDirectives.append(effect.directives); baseProcessingDirectives.append(effect.directives);
} }
} else if (effect.type == "directive") { } else if (effect.type == "directive") {
baseProcessingDirectives.append("?");
baseProcessingDirectives.append(effect.directives); baseProcessingDirectives.append(effect.directives);
} else { } else {
throw NetworkedAnimatorException(strf("No such NetworkedAnimator effect type '%s'", effect.type)); throw NetworkedAnimatorException(strf("No such NetworkedAnimator effect type '%s'", effect.type));
@ -595,10 +592,9 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
maybeZLevel = activePart.properties.value("flippedZLevel").optFloat().orMaybe(maybeZLevel); maybeZLevel = activePart.properties.value("flippedZLevel").optFloat().orMaybe(maybeZLevel);
float zLevel = maybeZLevel.value(0.0f); float zLevel = maybeZLevel.value(0.0f);
String processingDirectives = baseProcessingDirectives; size_t originalDirectivesSize = baseProcessingDirectives.size();
if (auto directives = activePart.properties.value("processingDirectives").optString()) { if (auto directives = activePart.properties.value("processingDirectives").optString()) {
processingDirectives.append("?"); baseProcessingDirectives.append(*directives);
processingDirectives.append(*directives);
} }
Maybe<unsigned> frame; Maybe<unsigned> frame;
@ -606,8 +602,7 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
frame = activePart.activeState->frame; frame = activePart.activeState->frame;
if (auto directives = activePart.activeState->properties.value("processingDirectives").optString()) { if (auto directives = activePart.activeState->properties.value("processingDirectives").optString()) {
processingDirectives.append("?"); baseProcessingDirectives.append(*directives);
processingDirectives.append(*directives);
} }
} }
@ -629,9 +624,12 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
}); });
if (!image.empty() && image[0] != ':' && image[0] != '?') { if (!image.empty() && image[0] != ':' && image[0] != '?') {
image = AssetPath::relativeTo(m_relativePath, image) + processingDirectives; image = AssetPath::relativeTo(m_relativePath, image);
auto drawable = Drawable::makeImage(move(image), 1.0f / TilePixels, centered, Vec2F()); auto drawable = Drawable::makeImage(move(image), 1.0f / TilePixels, centered, Vec2F());
auto& imagePart = drawable.imagePart();
for (Directives const& directives : baseProcessingDirectives)
imagePart.addDirectives(directives);
drawable.transform(partTransformation(partName)); drawable.transform(partTransformation(partName));
drawable.transform(globalTransformation()); drawable.transform(globalTransformation());
drawable.fullbright = fullbright; drawable.fullbright = fullbright;
@ -639,6 +637,8 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
drawables.append({move(drawable), zLevel}); drawables.append({move(drawable), zLevel});
} }
baseProcessingDirectives.resize(originalDirectivesSize);
}); });
sort(drawables, [](auto const& a, auto const& b) { return a.second < b.second; }); sort(drawables, [](auto const& a, auto const& b) { return a.second < b.second; });

View File

@ -117,7 +117,7 @@ public:
void setGlobalTag(String tagName, String tagValue); void setGlobalTag(String tagName, String tagValue);
void setPartTag(String const& partType, String tagName, String tagValue); void setPartTag(String const& partType, String tagName, String tagValue);
void setProcessingDirectives(String const& directives); void setProcessingDirectives(Directives const& directives);
void setZoom(float zoom); void setZoom(float zoom);
bool flipped() const; bool flipped() const;
float flippedRelativeCenterLine() const; float flippedRelativeCenterLine() const;
@ -287,7 +287,7 @@ private:
struct Effect { struct Effect {
String type; String type;
float time; float time;
String directives; Directives directives;
NetElementBool enabled; NetElementBool enabled;
float timer; float timer;
@ -314,7 +314,7 @@ private:
OrderedHashMap<String, Sound> m_sounds; OrderedHashMap<String, Sound> m_sounds;
OrderedHashMap<String, Effect> m_effects; OrderedHashMap<String, Effect> m_effects;
NetElementString m_processingDirectives; NetElementData<Directives> m_processingDirectives;
NetElementFloat m_zoom; NetElementFloat m_zoom;
NetElementBool m_flipped; NetElementBool m_flipped;

View File

@ -454,7 +454,7 @@ void Npc::render(RenderCallback* renderCallback) {
for (auto& drawable : m_humanoid.render()) { for (auto& drawable : m_humanoid.render()) {
drawable.translate(position()); drawable.translate(position());
if (drawable.isImage()) if (drawable.isImage())
drawable.imagePart().addDirectives(m_statusController->parentDirectives(), true); drawable.imagePart().addDirectivesGroup(m_statusController->parentDirectives(), true);
renderCallback->addDrawable(move(drawable), renderLayer); renderCallback->addDrawable(move(drawable), renderLayer);
} }

View File

@ -353,11 +353,11 @@ List<Drawable> Player::drawables() const {
for (auto& drawable : m_humanoid->render()) { for (auto& drawable : m_humanoid->render()) {
drawable.translate(position() + m_techController->parentOffset()); drawable.translate(position() + m_techController->parentOffset());
if (drawable.isImage()) { if (drawable.isImage()) {
drawable.imagePart().addDirectives(m_techController->parentDirectives(), true); drawable.imagePart().addDirectivesGroup(m_techController->parentDirectives(), true);
drawable.imagePart().addDirectives(m_statusController->parentDirectives(), true); drawable.imagePart().addDirectivesGroup(m_statusController->parentDirectives(), true);
if (auto anchor = as<LoungeAnchor>(m_movementController->entityAnchor())) { if (auto anchor = as<LoungeAnchor>(m_movementController->entityAnchor())) {
if (auto directives = anchor->directives) if (auto& directives = anchor->directives)
drawable.imagePart().addDirectives(*directives, true); drawable.imagePart().addDirectives(*directives, true);
} }
} }

View File

@ -337,11 +337,11 @@ bool StatusController::uniqueStatusEffectActive(String const& effectName) const
return false; return false;
} }
String StatusController::primaryDirectives() const { const Directives& StatusController::primaryDirectives() const {
return m_primaryDirectives; return m_primaryDirectives;
} }
void StatusController::setPrimaryDirectives(String const& directives) { void StatusController::setPrimaryDirectives(Directives const& directives) {
m_primaryDirectives = directives; m_primaryDirectives = directives;
} }
@ -509,11 +509,11 @@ void StatusController::tickMaster() {
removeUniqueEffect(key); removeUniqueEffect(key);
} }
String parentDirectives = m_primaryDirectives; DirectivesGroup parentDirectives;
for (auto const& pair : m_uniqueEffects) { parentDirectives.append(m_primaryDirectives);
parentDirectives.append("?"); for (auto const& pair : m_uniqueEffects)
parentDirectives.append(pair.second.parentDirectives); parentDirectives.append(pair.second.parentDirectives);
}
m_parentDirectives.set(move(parentDirectives)); m_parentDirectives.set(move(parentDirectives));
updateAnimators(); updateAnimators();
@ -524,7 +524,7 @@ void StatusController::tickSlave() {
updateAnimators(); updateAnimators();
} }
String StatusController::parentDirectives() const { const DirectivesGroup& StatusController::parentDirectives() const {
return m_parentDirectives.get(); return m_parentDirectives.get();
} }

View File

@ -78,8 +78,8 @@ public:
bool uniqueStatusEffectActive(String const& effectName) const; bool uniqueStatusEffectActive(String const& effectName) const;
String primaryDirectives() const; const Directives& primaryDirectives() const;
void setPrimaryDirectives(String const& directives); void setPrimaryDirectives(Directives const& directives);
// damage request and notification methods should only be called on the master controller. // damage request and notification methods should only be called on the master controller.
List<DamageNotification> applyDamageRequest(DamageRequest const& damageRequest); List<DamageNotification> applyDamageRequest(DamageRequest const& damageRequest);
@ -118,7 +118,7 @@ public:
void tickMaster(); void tickMaster();
void tickSlave(); void tickSlave();
String parentDirectives() const; const DirectivesGroup& parentDirectives() const;
List<Drawable> drawables() const; List<Drawable> drawables() const;
List<LightSource> lightSources() const; List<LightSource> lightSources() const;
List<OverheadBar> overheadBars(); List<OverheadBar> overheadBars();
@ -180,7 +180,7 @@ private:
struct UniqueEffectInstance { struct UniqueEffectInstance {
UniqueStatusEffectConfig effectConfig; UniqueStatusEffectConfig effectConfig;
String parentDirectives; Directives parentDirectives;
HashSet<StatModifierGroupId> modifierGroups; HashSet<StatModifierGroupId> modifierGroups;
StatScript script; StatScript script;
UniqueEffectMetadataGroup::ElementId metadataId; UniqueEffectMetadataGroup::ElementId metadataId;
@ -205,7 +205,7 @@ private:
NetElementGroup m_netGroup; NetElementGroup m_netGroup;
StatCollection m_statCollection; StatCollection m_statCollection;
NetElementData<JsonObject> m_statusProperties; NetElementData<JsonObject> m_statusProperties;
NetElementString m_parentDirectives; NetElementData<DirectivesGroup> m_parentDirectives;
UniqueEffectMetadataGroup m_uniqueEffectMetadata; UniqueEffectMetadataGroup m_uniqueEffectMetadata;
EffectAnimatorGroup m_effectAnimators; EffectAnimatorGroup m_effectAnimators;
@ -226,7 +226,7 @@ private:
Maybe<String> m_primaryAnimationConfig; Maybe<String> m_primaryAnimationConfig;
StatScript m_primaryScript; StatScript m_primaryScript;
String m_primaryDirectives; Directives m_primaryDirectives;
EffectAnimatorGroup::ElementId m_primaryAnimatorId; EffectAnimatorGroup::ElementId m_primaryAnimatorId;
List<DamageNotification> m_pendingSelfDamageNotifications; List<DamageNotification> m_pendingSelfDamageNotifications;

View File

@ -251,7 +251,7 @@ Maybe<TechController::ParentState> TechController::parentState() const {
return m_parentState.get(); return m_parentState.get();
} }
String TechController::parentDirectives() const { DirectivesGroup const& TechController::parentDirectives() const {
return m_parentDirectives.get(); return m_parentDirectives.get();
} }
@ -501,10 +501,11 @@ LuaCallbacks TechController::makeTechCallbacks(TechModule& techModule) {
callbacks.registerCallback("setParentDirectives", [this, &techModule](Maybe<String> const& directives) { callbacks.registerCallback("setParentDirectives", [this, &techModule](Maybe<String> const& directives) {
techModule.parentDirectives = directives.value(); techModule.parentDirectives = directives.value();
String newParentDirectives;
DirectivesGroup newParentDirectives;
for (auto& module : m_techModules) for (auto& module : m_techModules)
newParentDirectives += module.parentDirectives; newParentDirectives.append(module.parentDirectives);
m_parentDirectives.set(newParentDirectives); m_parentDirectives.set(move(newParentDirectives));
}); });
callbacks.registerCallback("setParentHidden", [this](bool hidden) { callbacks.registerCallback("setParentHidden", [this](bool hidden) {

View File

@ -6,6 +6,7 @@
#include "StarLuaComponents.hpp" #include "StarLuaComponents.hpp"
#include "StarLuaActorMovementComponent.hpp" #include "StarLuaActorMovementComponent.hpp"
#include "StarTechDatabase.hpp" #include "StarTechDatabase.hpp"
#include "StarDirectives.hpp"
namespace Star { namespace Star {
@ -67,7 +68,7 @@ public:
void tickSlave(); void tickSlave();
Maybe<ParentState> parentState() const; Maybe<ParentState> parentState() const;
String parentDirectives() const; DirectivesGroup const& parentDirectives() const;
Vec2F parentOffset() const; Vec2F parentOffset() const;
bool toolUsageSuppressed() const; bool toolUsageSuppressed() const;
@ -120,7 +121,7 @@ private:
scriptComponent; scriptComponent;
bool visible; bool visible;
bool toolUsageSuppressed; bool toolUsageSuppressed;
String parentDirectives; Directives parentDirectives;
TechAnimatorGroup::ElementId animatorId; TechAnimatorGroup::ElementId animatorId;
}; };
@ -159,7 +160,7 @@ private:
Vec2F m_aimPosition; Vec2F m_aimPosition;
NetElementData<Maybe<ParentState>> m_parentState; NetElementData<Maybe<ParentState>> m_parentState;
NetElementString m_parentDirectives; NetElementData<DirectivesGroup> m_parentDirectives;
NetElementFloat m_xParentOffset; NetElementFloat m_xParentOffset;
NetElementFloat m_yParentOffset; NetElementFloat m_yParentOffset;
NetElementBool m_parentHidden; NetElementBool m_parentHidden;

View File

@ -28,7 +28,7 @@ struct LoungeAnchor : EntityAnchor {
StringSet effectEmitters; StringSet effectEmitters;
Maybe<String> emote; Maybe<String> emote;
Maybe<String> dance; Maybe<String> dance;
Maybe<String> directives; Maybe<Directives> directives;
JsonObject armorCosmeticOverrides; JsonObject armorCosmeticOverrides;
Maybe<String> cursorOverride; Maybe<String> cursorOverride;
bool cameraFocus; bool cameraFocus;