summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorBradley Sherman <sirrus233@gmail.com>2026-07-16 05:10:50 -0700
committerGitHub <noreply@github.com>2026-07-16 08:10:50 -0400
commited47d2ec9874104a9ec619c91ce72c065152b25c (patch)
treeebbaf4b894a9b2e97057a46da053de410a2aa113 /mm
parentb41f365aa1629b8517ec74d3b8af99d66c97c580 (diff)
Fix mod load time regression (#1793)
* Cosmetic editor based on OoT harkinian * Bugfix and eager validation * Fix formatting * Move struct definition
Diffstat (limited to 'mm')
-rw-r--r--mm/2s2h/BenGui/DynamicCosmeticEditor.cpp90
1 files changed, 77 insertions, 13 deletions
diff --git a/mm/2s2h/BenGui/DynamicCosmeticEditor.cpp b/mm/2s2h/BenGui/DynamicCosmeticEditor.cpp
index 67fbcaa10..955a88582 100644
--- a/mm/2s2h/BenGui/DynamicCosmeticEditor.cpp
+++ b/mm/2s2h/BenGui/DynamicCosmeticEditor.cpp
@@ -46,6 +46,15 @@ struct CustomCosmeticEntry {
std::vector<CustomCosmeticBinding> bindings;
};
+struct ManifestEntry {
+ std::string materialPath;
+ std::string cosmeticEntry;
+ std::string key;
+ std::string cosmeticCategory;
+ bool hasCosmeticCategory = false;
+ bool isPrimColor = false;
+};
+
static std::vector<CustomCosmeticEntry> customCosmeticEntries;
static bool customHumanModelActive = false;
static bool customDekuModelActive = false;
@@ -416,14 +425,72 @@ void ScanDynamicCosmetics() {
auto resourceManager = Ship::Context::GetInstance()->GetResourceManager();
auto archiveManager = resourceManager->GetArchiveManager();
RefreshCustomModelActiveFlags(archiveManager.get());
- auto materialPaths = archiveManager->ListFiles("*");
+ auto archives = archiveManager->GetArchives();
+ std::vector<ManifestEntry> manifestEntries;
std::unordered_map<std::string, size_t> entryIndicesByKey;
- for (const auto& materialPath : *materialPaths) {
- if (!IsCustomArchive(archiveManager->GetArchiveFromFile(materialPath))) {
+ for (const auto& archive : *archives) {
+ if (!IsCustomArchive(archive)) {
continue;
}
+ auto manifestFile = archive->LoadFile("CosmeticEntries");
+ if (manifestFile == nullptr || !manifestFile->IsLoaded || manifestFile->Buffer == nullptr) {
+ continue;
+ }
+
+ tinyxml2::XMLDocument manifestDocument;
+ manifestDocument.Parse(manifestFile->Buffer->data(), manifestFile->Buffer->size());
+ if (manifestDocument.Error()) {
+ continue;
+ }
+
+ tinyxml2::XMLElement* manifestRoot = manifestDocument.FirstChildElement();
+ if (manifestRoot == nullptr) {
+ continue;
+ }
+
+ for (auto* manifestEntry = manifestRoot->FirstChildElement(); manifestEntry != nullptr;
+ manifestEntry = manifestEntry->NextSiblingElement()) {
+ const char* cosmeticEntry = manifestEntry->Attribute("CosmeticEntry");
+ const char* materialPath = manifestEntry->Attribute("MaterialPath");
+ std::string resolvedMaterialPath;
+ if (materialPath != nullptr && materialPath[0] != '\0') {
+ resolvedMaterialPath = materialPath;
+ if (!archiveManager->HasFile(resolvedMaterialPath)) {
+ if (!resolvedMaterialPath.starts_with("alt/") &&
+ archiveManager->HasFile("alt/" + resolvedMaterialPath)) {
+ resolvedMaterialPath = "alt/" + resolvedMaterialPath;
+ } else {
+ resolvedMaterialPath.clear();
+ }
+ }
+ }
+
+ const char* cosmeticType = manifestEntry->Attribute("CosmeticType");
+ const bool isPrimColor = cosmeticType != nullptr && std::string(cosmeticType) == "Prim";
+ const bool isEnvColor = cosmeticType != nullptr && std::string(cosmeticType) == "Env";
+
+ if (cosmeticEntry == nullptr || cosmeticEntry[0] == '\0' || resolvedMaterialPath.empty() ||
+ (!isPrimColor && !isEnvColor)) {
+ continue;
+ }
+
+ std::string key = cosmeticEntry;
+ SanitizeCustomKey(key);
+ if (key.empty()) {
+ continue;
+ }
+
+ const char* cosmeticCategory = manifestEntry->Attribute("CosmeticCategory");
+ manifestEntries.push_back({ resolvedMaterialPath, cosmeticEntry, std::move(key),
+ cosmeticCategory != nullptr ? cosmeticCategory : "",
+ cosmeticCategory != nullptr, isPrimColor });
+ }
+ }
+
+ for (const auto& manifestEntry : manifestEntries) {
+ const auto& materialPath = manifestEntry.materialPath;
tinyxml2::XMLDocument document;
std::shared_ptr<Fast::DisplayList> material;
tinyxml2::XMLElement* root = nullptr;
@@ -436,21 +503,18 @@ void ScanDynamicCosmetics() {
for (auto* child = root->FirstChildElement(); child != nullptr; child = child->NextSiblingElement()) {
std::string childName = child->Name();
bool isPrimColor = childName == "SetPrimColor";
- if (!isPrimColor && childName != "SetEnvColor") {
+ if ((!isPrimColor && childName != "SetEnvColor") || isPrimColor != manifestEntry.isPrimColor) {
continue;
}
const char* cosmeticEntry = child->Attribute("CosmeticEntry");
- const char* cosmeticCategory = child->Attribute("CosmeticCategory");
- if (cosmeticEntry == nullptr || cosmeticEntry[0] == '\0') {
+ if (cosmeticEntry == nullptr || cosmeticEntry != manifestEntry.cosmeticEntry) {
continue;
}
+ const char* cosmeticCategory = manifestEntry.hasCosmeticCategory ? manifestEntry.cosmeticCategory.c_str()
+ : child->Attribute("CosmeticCategory");
- std::string key = cosmeticEntry;
- SanitizeCustomKey(key);
- if (key.empty()) {
- continue;
- }
+ const auto& key = manifestEntry.key;
Gfx expectedInstruction;
if (isPrimColor) {
@@ -511,8 +575,8 @@ void ScanDynamicCosmetics() {
std::stable_sort(
customCosmeticEntries.begin(), customCosmeticEntries.end(),
[](const CustomCosmeticEntry& lhs, const CustomCosmeticEntry& rhs) {
- int lhsOrder = 2;
- int rhsOrder = 2;
+ int lhsOrder = GetDynamicMaterialFormSortOrder(DynamicCosmeticForm::Other);
+ int rhsOrder = GetDynamicMaterialFormSortOrder(DynamicCosmeticForm::Other);
for (const auto& binding : lhs.bindings) {
lhsOrder =