mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Per-instance NPC hair/skin textures, fix binary search float comparison
- NPC hair/skin textures now use per-instance overrides instead of shared model-level textures, so each NPC shows its own hair color/style - Hair/skin DBC lookup runs for every NPC instance (including cached models) rather than only on first load - Fix keyframe binary search to use float comparison matching original linear scan semantics
This commit is contained in:
parent
e6acb4ac9a
commit
84b04446c1
3 changed files with 77 additions and 6 deletions
|
|
@ -4790,6 +4790,77 @@ void Application::spawnOnlineCreature(uint64_t guid, uint32_t displayId, float x
|
|||
return;
|
||||
}
|
||||
|
||||
// Per-instance hair/skin texture overrides — runs for ALL NPCs (including cached models)
|
||||
// so that each NPC gets its own hair/skin color regardless of model sharing.
|
||||
{
|
||||
auto itDD = displayDataMap_.find(displayId);
|
||||
if (itDD != displayDataMap_.end() && itDD->second.extraDisplayId != 0) {
|
||||
auto itExtra2 = humanoidExtraMap_.find(itDD->second.extraDisplayId);
|
||||
if (itExtra2 != humanoidExtraMap_.end()) {
|
||||
const auto& extra = itExtra2->second;
|
||||
const auto* md = charRenderer->getModelData(modelId);
|
||||
if (md) {
|
||||
auto charSectionsDbc2 = assetManager->loadDBC("CharSections.dbc");
|
||||
if (charSectionsDbc2) {
|
||||
const auto* csL = pipeline::getActiveDBCLayout()
|
||||
? pipeline::getActiveDBCLayout()->getLayout("CharSections") : nullptr;
|
||||
uint32_t tgtRace = static_cast<uint32_t>(extra.raceId);
|
||||
uint32_t tgtSex = static_cast<uint32_t>(extra.sexId);
|
||||
|
||||
// Look up hair texture (section 3)
|
||||
for (uint32_t r = 0; r < charSectionsDbc2->getRecordCount(); r++) {
|
||||
uint32_t rId = charSectionsDbc2->getUInt32(r, csL ? (*csL)["RaceID"] : 1);
|
||||
uint32_t sId = charSectionsDbc2->getUInt32(r, csL ? (*csL)["SexID"] : 2);
|
||||
if (rId != tgtRace || sId != tgtSex) continue;
|
||||
uint32_t sec = charSectionsDbc2->getUInt32(r, csL ? (*csL)["BaseSection"] : 3);
|
||||
if (sec != 3) continue;
|
||||
uint32_t var = charSectionsDbc2->getUInt32(r, csL ? (*csL)["VariationIndex"] : 4);
|
||||
uint32_t col = charSectionsDbc2->getUInt32(r, csL ? (*csL)["ColorIndex"] : 5);
|
||||
if (var != static_cast<uint32_t>(extra.hairStyleId)) continue;
|
||||
if (col != static_cast<uint32_t>(extra.hairColorId)) continue;
|
||||
std::string hairPath = charSectionsDbc2->getString(r, csL ? (*csL)["Texture1"] : 6);
|
||||
if (!hairPath.empty()) {
|
||||
rendering::VkTexture* hairTex = charRenderer->loadTexture(hairPath);
|
||||
if (hairTex) {
|
||||
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
||||
if (md->textures[ti].type == 6) {
|
||||
charRenderer->setTextureSlotOverride(instanceId, static_cast<uint16_t>(ti), hairTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Look up skin texture (section 0) for per-instance skin color
|
||||
for (uint32_t r = 0; r < charSectionsDbc2->getRecordCount(); r++) {
|
||||
uint32_t rId = charSectionsDbc2->getUInt32(r, csL ? (*csL)["RaceID"] : 1);
|
||||
uint32_t sId = charSectionsDbc2->getUInt32(r, csL ? (*csL)["SexID"] : 2);
|
||||
if (rId != tgtRace || sId != tgtSex) continue;
|
||||
uint32_t sec = charSectionsDbc2->getUInt32(r, csL ? (*csL)["BaseSection"] : 3);
|
||||
if (sec != 0) continue;
|
||||
uint32_t col = charSectionsDbc2->getUInt32(r, csL ? (*csL)["ColorIndex"] : 5);
|
||||
if (col != static_cast<uint32_t>(extra.skinId)) continue;
|
||||
std::string skinPath = charSectionsDbc2->getString(r, csL ? (*csL)["Texture1"] : 6);
|
||||
if (!skinPath.empty()) {
|
||||
rendering::VkTexture* skinTex = charRenderer->loadTexture(skinPath);
|
||||
if (skinTex) {
|
||||
for (size_t ti = 0; ti < md->textures.size(); ti++) {
|
||||
uint32_t tt = md->textures[ti].type;
|
||||
if (tt == 1 || tt == 11) {
|
||||
charRenderer->setTextureSlotOverride(instanceId, static_cast<uint16_t>(ti), skinTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional humanoid NPC geoset mask. Disabled by default because forcing geosets
|
||||
// causes long-standing visual artifacts on some models (missing waist, phantom
|
||||
// bracers, flickering apron overlays). Prefer model defaults.
|
||||
|
|
|
|||
|
|
@ -1580,9 +1580,9 @@ int CharacterRenderer::findKeyframeIndex(const std::vector<uint32_t>& timestamps
|
|||
if (timestamps.empty()) return -1;
|
||||
if (timestamps.size() == 1) return 0;
|
||||
|
||||
// Binary search: find first element > t, then back up one
|
||||
uint32_t t = static_cast<uint32_t>(time);
|
||||
auto it = std::upper_bound(timestamps.begin(), timestamps.end(), t);
|
||||
// Binary search using float comparison to match original semantics exactly
|
||||
auto it = std::upper_bound(timestamps.begin(), timestamps.end(), time,
|
||||
[](float t, uint32_t ts) { return t < static_cast<float>(ts); });
|
||||
if (it == timestamps.begin()) return 0;
|
||||
size_t idx = static_cast<size_t>(it - timestamps.begin()) - 1;
|
||||
return static_cast<int>(std::min(idx, timestamps.size() - 2));
|
||||
|
|
|
|||
|
|
@ -1741,9 +1741,9 @@ uint32_t M2Renderer::createInstanceWithMatrix(uint32_t modelId, const glm::mat4&
|
|||
static int findKeyframeIndex(const std::vector<uint32_t>& timestamps, float time) {
|
||||
if (timestamps.empty()) return -1;
|
||||
if (timestamps.size() == 1) return 0;
|
||||
uint32_t t = static_cast<uint32_t>(time);
|
||||
// Binary search: find first element > t, then back up one
|
||||
auto it = std::upper_bound(timestamps.begin(), timestamps.end(), t);
|
||||
// Binary search using float comparison to match original semantics exactly
|
||||
auto it = std::upper_bound(timestamps.begin(), timestamps.end(), time,
|
||||
[](float t, uint32_t ts) { return t < static_cast<float>(ts); });
|
||||
if (it == timestamps.begin()) return 0;
|
||||
size_t idx = static_cast<size_t>(it - timestamps.begin()) - 1;
|
||||
return static_cast<int>(std::min(idx, timestamps.size() - 2));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue