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())
*this = i->second;
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) {
uint8_t cbytes[4];
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]);
return Color::rgba(hexToVec4B(s));
}
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 Vec4B hueShiftVec4B(Vec4B color, float hue);
static Vec4B Color::hexToVec4B(String const& s);
// Black
Color();

View File

@ -229,6 +229,10 @@ inline size_t DirectivesGroup::hash() const {
return hasher.digest();
}
const List<Directives>& DirectivesGroup::list() const {
return m_directives;
}
bool operator==(DirectivesGroup const& a, DirectivesGroup const& b) {
return a.compare(b);
}
@ -237,6 +241,21 @@ bool operator!=(DirectivesGroup const& a, DirectivesGroup const& 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 {
return s.hash();
}

View File

@ -73,9 +73,13 @@ public:
void applyExistingImage(Image& image) 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 DataStream& operator>>(DataStream& ds, DirectivesGroup& directives);
friend DataStream& operator<<(DataStream& ds, DirectivesGroup const& directives);
private:
void buildString(String& string, const DirectivesGroup& directives) const;

View File

@ -13,7 +13,7 @@ public:
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;
StarException(std::string message, std::exception const& cause) noexcept;
@ -26,7 +26,7 @@ public:
friend OutputProxy outputException(std::exception const& e, bool fullStacktrace);
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;
private:
@ -76,12 +76,12 @@ void fatalException(std::exception const& e, bool showStackTrace);
return ClassName(strf(fmt, args...)); \
} \
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) {} \
ClassName(std::string message, std::exception const& cause) : BaseName(#ClassName, move(message), cause) {} \
\
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) \
: BaseName(type, move(message), cause) {} \
}

View File

@ -38,8 +38,8 @@ 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::string(), cause) {}
@ -56,19 +56,19 @@ const char* StarException::what() const throw() {
return m_whatBuffer.c_str();
}
StarException::StarException(char const* type, std::string message) noexcept {
auto printException = [](std::ostream& os, bool fullStacktrace, char const* type, std::string message, StackCapture stack) {
StarException::StarException(char const* type, std::string message, bool genStackTrace) noexcept {
auto printException = [](std::ostream& os, bool fullStacktrace, char const* type, std::string message, Maybe<StackCapture> stack) {
os << "(" << type << ")";
if (!message.empty())
os << " " << message;
if (fullStacktrace) {
if (fullStacktrace && stack) {
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

View File

@ -145,7 +145,7 @@ StarException::StarException() noexcept : StarException(std::string("StarExcepti
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::string(), cause) {}
@ -162,20 +162,20 @@ const char* StarException::what() const throw() {
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) {
std::ostream& os, bool fullStacktrace, char const* type, std::string message, Maybe<StackCapture> stack) {
os << "(" << type << ")";
if (!message.empty())
os << " " << message;
if (fullStacktrace) {
if (fullStacktrace && stack) {
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

View File

@ -173,7 +173,7 @@ ImageOperation imageOperationFromString(String const& string) {
} else if (type == "replace") {
ColorReplaceImageOperation operation;
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;
@ -259,7 +259,7 @@ ImageOperation imageOperationFromString(String const& string) {
return FlipImageOperation{FlipImageOperation::FlipXY};
} 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) {
throw ImageOperationException("Error reading ImageOperation", e);

View File

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

View File

@ -35,8 +35,8 @@ public:
void setHeadItem(HeadArmorPtr headItem);
void setHeadCosmeticItem(HeadArmorPtr headCosmeticItem);
void setChestCosmeticItem(ChestArmorPtr chestCosmeticItem);
void setChestItem(ChestArmorPtr chestItem);
void setChestCosmeticItem(ChestArmorPtr chestCosmeticItem);
void setLegsItem(LegsArmorPtr legsItem);
void setLegsCosmeticItem(LegsArmorPtr legsCosmeticItem);
void setBackItem(BackArmorPtr backItem);
@ -84,7 +84,10 @@ private:
NetElementData<ItemDescriptor> m_backCosmeticItemDataNetState;
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;
}
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) {
if (keepImageCenterPosition) {
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
// image size.
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
// 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) {
for (auto& drawable : m_networkedAnimator.drawables(position())) {
if (drawable.isImage())
drawable.imagePart().addDirectives(m_statusController->parentDirectives(), true);
drawable.imagePart().addDirectivesGroup(m_statusController->parentDirectives(), true);
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));
}
void NetworkedAnimator::setProcessingDirectives(String const& directives) {
void NetworkedAnimator::setProcessingDirectives(Directives const& 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 {
String baseProcessingDirectives = "?";
baseProcessingDirectives.append(m_processingDirectives.get());
List<Directives> baseProcessingDirectives = { m_processingDirectives.get() };
for (auto& pair : m_effects) {
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);
if (effect.type == "flash") {
if (effectState.timer > effect.time / 2) {
baseProcessingDirectives.append("?");
baseProcessingDirectives.append(effect.directives);
}
} else if (effect.type == "directive") {
baseProcessingDirectives.append("?");
baseProcessingDirectives.append(effect.directives);
} else {
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);
float zLevel = maybeZLevel.value(0.0f);
String processingDirectives = baseProcessingDirectives;
size_t originalDirectivesSize = baseProcessingDirectives.size();
if (auto directives = activePart.properties.value("processingDirectives").optString()) {
processingDirectives.append("?");
processingDirectives.append(*directives);
baseProcessingDirectives.append(*directives);
}
Maybe<unsigned> frame;
@ -606,8 +602,7 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
frame = activePart.activeState->frame;
if (auto directives = activePart.activeState->properties.value("processingDirectives").optString()) {
processingDirectives.append("?");
processingDirectives.append(*directives);
baseProcessingDirectives.append(*directives);
}
}
@ -629,9 +624,12 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
});
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& imagePart = drawable.imagePart();
for (Directives const& directives : baseProcessingDirectives)
imagePart.addDirectives(directives);
drawable.transform(partTransformation(partName));
drawable.transform(globalTransformation());
drawable.fullbright = fullbright;
@ -639,6 +637,8 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const&
drawables.append({move(drawable), zLevel});
}
baseProcessingDirectives.resize(originalDirectivesSize);
});
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 setPartTag(String const& partType, String tagName, String tagValue);
void setProcessingDirectives(String const& directives);
void setProcessingDirectives(Directives const& directives);
void setZoom(float zoom);
bool flipped() const;
float flippedRelativeCenterLine() const;
@ -287,7 +287,7 @@ private:
struct Effect {
String type;
float time;
String directives;
Directives directives;
NetElementBool enabled;
float timer;
@ -314,7 +314,7 @@ private:
OrderedHashMap<String, Sound> m_sounds;
OrderedHashMap<String, Effect> m_effects;
NetElementString m_processingDirectives;
NetElementData<Directives> m_processingDirectives;
NetElementFloat m_zoom;
NetElementBool m_flipped;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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