Now nude meshes work as intended
This commit is contained in:
@@ -231,13 +231,21 @@ Ogre::String CharacterSlotSystem::resolveMesh(
|
||||
const Ogre::String &slot, const SlotSelection &sel,
|
||||
int outfitLevel)
|
||||
{
|
||||
if (!sel.explicitMesh.empty())
|
||||
if (!sel.explicitMesh.empty()) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> explicit: " + sel.explicitMesh);
|
||||
return sel.explicitMesh;
|
||||
}
|
||||
|
||||
if (!s_catalogLoaded || !s_bodyParts.contains(age) ||
|
||||
!s_bodyParts[age].contains(sex) ||
|
||||
!s_bodyParts[age][sex].contains(slot))
|
||||
!s_bodyParts[age][sex].contains(slot)) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> catalog miss");
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto &slotEntries = s_bodyParts[age][sex][slot];
|
||||
|
||||
@@ -245,37 +253,55 @@ Ogre::String CharacterSlotSystem::resolveMesh(
|
||||
if (outfitLevel >= 2 && sel.layer2Mesh != "none" &&
|
||||
!sel.layer2Mesh.empty()) {
|
||||
for (const auto &entry : slotEntries) {
|
||||
if (entry.value("mesh", "") == sel.layer2Mesh)
|
||||
if (entry.value("mesh", "") == sel.layer2Mesh) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> layer2: " + sel.layer2Mesh);
|
||||
return sel.layer2Mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outfitLevel >= 1 && sel.layer1Mesh != "none" &&
|
||||
!sel.layer1Mesh.empty()) {
|
||||
for (const auto &entry : slotEntries) {
|
||||
if (entry.value("mesh", "") == sel.layer1Mesh)
|
||||
if (entry.value("mesh", "") == sel.layer1Mesh) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> layer1: " + sel.layer1Mesh);
|
||||
return sel.layer1Mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback to layer 0 (nude base) — prefer canonical base mesh */
|
||||
Ogre::String canonicalBase = sex + "_" + slot + ".mesh";
|
||||
Ogre::String firstLayer0;
|
||||
/* Fallback to layer 0 (nude base) — prefer shortest name
|
||||
* (base mesh name is shortest, combined meshes add suffixes) */
|
||||
Ogre::String bestLayer0;
|
||||
for (const auto &entry : slotEntries) {
|
||||
if (entry.value("layer", 0) == 0) {
|
||||
Ogre::String mesh = entry["mesh"].get<Ogre::String>();
|
||||
if (mesh == canonicalBase)
|
||||
return mesh;
|
||||
if (firstLayer0.empty())
|
||||
firstLayer0 = mesh;
|
||||
if (bestLayer0.empty() || mesh.length() < bestLayer0.length())
|
||||
bestLayer0 = mesh;
|
||||
}
|
||||
}
|
||||
if (!firstLayer0.empty())
|
||||
return firstLayer0;
|
||||
if (!bestLayer0.empty()) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> layer0base: " + bestLayer0);
|
||||
return bestLayer0;
|
||||
}
|
||||
|
||||
/* Last resort: first available entry */
|
||||
if (!slotEntries.empty())
|
||||
return slotEntries[0]["mesh"].get<Ogre::String>();
|
||||
if (!slotEntries.empty()) {
|
||||
Ogre::String mesh = slotEntries[0]["mesh"].get<Ogre::String>();
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> lastResort: " + mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] resolveMesh(" + age + "," + sex +
|
||||
"," + slot + ") -> empty fallback");
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -291,10 +317,20 @@ void CharacterSlotSystem::update()
|
||||
total++;
|
||||
if (cs.dirty) {
|
||||
dirtyCount++;
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] update: entity " +
|
||||
Ogre::StringConverter::toString(e.id()) +
|
||||
" is dirty, rebuilding");
|
||||
buildCharacter(e, cs);
|
||||
cs.dirty = false;
|
||||
}
|
||||
});
|
||||
if (dirtyCount > 0) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] update: total=" +
|
||||
Ogre::StringConverter::toString(total) + " dirty=" +
|
||||
Ogre::StringConverter::toString(dirtyCount));
|
||||
}
|
||||
}
|
||||
|
||||
static const nlohmann::json *findCatalogEntry(
|
||||
@@ -341,6 +377,13 @@ static void ensureMeshPoseAnimation(const Ogre::String &meshName)
|
||||
void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
CharacterSlotsComponent &cs)
|
||||
{
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: age=" + cs.age +
|
||||
" sex=" + cs.sex + " outfitLevel=" +
|
||||
Ogre::StringConverter::toString(cs.outfitLevel) +
|
||||
" slots=" + Ogre::StringConverter::toString(
|
||||
(size_t)cs.slotSelections.size()));
|
||||
|
||||
destroyCharacterParts(e);
|
||||
|
||||
/* Migrate old slots map to slotSelections if needed */
|
||||
@@ -361,12 +404,18 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
}
|
||||
}
|
||||
|
||||
if (!e.has<TransformComponent>())
|
||||
if (!e.has<TransformComponent>()) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: no TransformComponent");
|
||||
return;
|
||||
}
|
||||
|
||||
auto &transform = e.get_mut<TransformComponent>();
|
||||
if (!transform.node)
|
||||
if (!transform.node) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: no transform node");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine master slot (face preferred, else first non-empty) */
|
||||
Ogre::String masterSlot;
|
||||
@@ -390,6 +439,9 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
}
|
||||
|
||||
if (masterSlot.empty()) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: masterSlot EMPTY — "
|
||||
"no valid mesh for any slot");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -397,8 +449,16 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
cs.slotSelections[masterSlot],
|
||||
cs.outfitLevel);
|
||||
|
||||
if (masterMesh.empty())
|
||||
if (masterMesh.empty()) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: masterMesh empty for " +
|
||||
masterSlot);
|
||||
return;
|
||||
}
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: masterSlot=" + masterSlot +
|
||||
" masterMesh=" + masterMesh);
|
||||
|
||||
/* Pre-create pose animation on mesh so entity knows about it */
|
||||
ensureMeshPoseAnimation(masterMesh);
|
||||
@@ -412,6 +472,12 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
m_entities[e.id()].parts[masterSlot] = masterEnt;
|
||||
cs.masterEntity = masterEnt;
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: created master entity " +
|
||||
masterMesh + " (submeshes=" +
|
||||
Ogre::StringConverter::toString(meshPtr->getNumSubMeshes()) +
|
||||
")");
|
||||
|
||||
/* Setup pose animation for shape keys */
|
||||
const nlohmann::json *entry = findCatalogEntry(
|
||||
cs.age, cs.sex, masterSlot, masterMesh);
|
||||
@@ -422,7 +488,7 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
e.get_mut<AnimationTreeComponent>().dirty = true;
|
||||
} catch (const Ogre::Exception &ex) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"CharacterSlotSystem: Failed to load master mesh '" +
|
||||
"[CharacterSlotSystem] buildCharacter: FAILED to load master mesh '" +
|
||||
masterMesh + "': " + ex.getDescription());
|
||||
return;
|
||||
}
|
||||
@@ -453,11 +519,17 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
applyShapeKeys(e, partEnt, entry);
|
||||
} catch (const Ogre::Exception &ex) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"CharacterSlotSystem: Failed to load part '" +
|
||||
"[CharacterSlotSystem] buildCharacter: FAILED to load part '" +
|
||||
slot + "' mesh '" + mesh +
|
||||
"': " + ex.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"[CharacterSlotSystem] buildCharacter: DONE for entity " +
|
||||
Ogre::StringConverter::toString(e.id()) +
|
||||
" parts=" + Ogre::StringConverter::toString(
|
||||
(size_t)m_entities[e.id()].parts.size()));
|
||||
}
|
||||
|
||||
void CharacterSlotSystem::applyShapeKeys(flecs::entity e,
|
||||
|
||||
Reference in New Issue
Block a user