fix(animation): fix variant caching bug in multi-item path — same fix as single-item
This commit is contained in:
@@ -7,6 +7,7 @@ import com.tiedup.remake.client.animation.context.GlbAnimationResolver;
|
|||||||
import com.tiedup.remake.client.animation.context.RegionBoneMapper;
|
import com.tiedup.remake.client.animation.context.RegionBoneMapper;
|
||||||
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -251,7 +252,40 @@ public final class GltfAnimationApplier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === Layer 2: Composite item animation ===
|
// === Layer 2: Composite item animation ===
|
||||||
String compositeCacheKey = "multi#" + stateKey;
|
// Pre-resolve animation data and variant names for all items BEFORE cache lookup.
|
||||||
|
// This ensures random variant selection happens fresh on each context change,
|
||||||
|
// and each variant combination gets its own cache entry.
|
||||||
|
record ResolvedItem(
|
||||||
|
GltfData animData,
|
||||||
|
String glbAnimName,
|
||||||
|
RegionBoneMapper.V2ItemAnimInfo info
|
||||||
|
) {}
|
||||||
|
|
||||||
|
List<ResolvedItem> resolvedItems = new ArrayList<>();
|
||||||
|
StringBuilder variantKeyBuilder = new StringBuilder("multi#").append(stateKey);
|
||||||
|
|
||||||
|
for (RegionBoneMapper.V2ItemAnimInfo item : items) {
|
||||||
|
ResourceLocation animSource =
|
||||||
|
item.animSource() != null ? item.animSource() : item.modelLoc();
|
||||||
|
|
||||||
|
GltfData animData = GlbAnimationResolver.resolveAnimationData(
|
||||||
|
item.modelLoc(), item.animSource()
|
||||||
|
);
|
||||||
|
if (animData == null) {
|
||||||
|
LOGGER.warn(
|
||||||
|
"[GltfPipeline] Failed to load GLB for multi-item: {}",
|
||||||
|
animSource
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String glbAnimName = GlbAnimationResolver.resolve(animData, context);
|
||||||
|
resolvedItems.add(new ResolvedItem(animData, glbAnimName, item));
|
||||||
|
variantKeyBuilder.append('#')
|
||||||
|
.append(glbAnimName != null ? glbAnimName : "default");
|
||||||
|
}
|
||||||
|
|
||||||
|
String compositeCacheKey = variantKeyBuilder.toString();
|
||||||
|
|
||||||
if (failedLoadKeys.contains(compositeCacheKey)) {
|
if (failedLoadKeys.contains(compositeCacheKey)) {
|
||||||
activeStateKeys.put(entity.getUUID(), stateKey);
|
activeStateKeys.put(entity.getUUID(), stateKey);
|
||||||
@@ -273,29 +307,13 @@ public final class GltfAnimationApplier {
|
|||||||
|
|
||||||
boolean anyLoaded = false;
|
boolean anyLoaded = false;
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (ResolvedItem resolved : resolvedItems) {
|
||||||
RegionBoneMapper.V2ItemAnimInfo item = items.get(i);
|
RegionBoneMapper.V2ItemAnimInfo item = resolved.info();
|
||||||
|
GltfData animData = resolved.animData();
|
||||||
|
String glbAnimName = resolved.glbAnimName();
|
||||||
ResourceLocation animSource =
|
ResourceLocation animSource =
|
||||||
item.animSource() != null
|
item.animSource() != null ? item.animSource() : item.modelLoc();
|
||||||
? item.animSource()
|
|
||||||
: item.modelLoc();
|
|
||||||
|
|
||||||
GltfData animData = GlbAnimationResolver.resolveAnimationData(
|
|
||||||
item.modelLoc(),
|
|
||||||
item.animSource()
|
|
||||||
);
|
|
||||||
if (animData == null) {
|
|
||||||
LOGGER.warn(
|
|
||||||
"[GltfPipeline] Failed to load GLB for multi-item: {}",
|
|
||||||
animSource
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String glbAnimName = GlbAnimationResolver.resolve(
|
|
||||||
animData,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
GltfData.AnimationClip rawClip;
|
GltfData.AnimationClip rawClip;
|
||||||
if (glbAnimName != null) {
|
if (glbAnimName != null) {
|
||||||
rawClip = animData.getRawAnimation(glbAnimName);
|
rawClip = animData.getRawAnimation(glbAnimName);
|
||||||
@@ -310,9 +328,7 @@ public final class GltfAnimationApplier {
|
|||||||
// if the item declares per-animation bone filtering.
|
// if the item declares per-animation bone filtering.
|
||||||
Set<String> effectiveParts = item.ownedParts();
|
Set<String> effectiveParts = item.ownedParts();
|
||||||
if (glbAnimName != null && !item.animationBones().isEmpty()) {
|
if (glbAnimName != null && !item.animationBones().isEmpty()) {
|
||||||
Set<String> override = item
|
Set<String> override = item.animationBones().get(glbAnimName);
|
||||||
.animationBones()
|
|
||||||
.get(glbAnimName);
|
|
||||||
if (override != null) {
|
if (override != null) {
|
||||||
Set<String> filtered = new HashSet<>(override);
|
Set<String> filtered = new HashSet<>(override);
|
||||||
filtered.retainAll(item.ownedParts());
|
filtered.retainAll(item.ownedParts());
|
||||||
@@ -323,19 +339,13 @@ public final class GltfAnimationApplier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GltfPoseConverter.addBonesToBuilder(
|
GltfPoseConverter.addBonesToBuilder(
|
||||||
builder,
|
builder, animData, rawClip, effectiveParts
|
||||||
animData,
|
|
||||||
rawClip,
|
|
||||||
effectiveParts
|
|
||||||
);
|
);
|
||||||
anyLoaded = true;
|
anyLoaded = true;
|
||||||
|
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"[GltfPipeline] Multi-item: {} -> owned={}, effective={}, anim={}",
|
"[GltfPipeline] Multi-item: {} -> owned={}, effective={}, anim={}",
|
||||||
animSource,
|
animSource, item.ownedParts(), effectiveParts, glbAnimName
|
||||||
item.ownedParts(),
|
|
||||||
effectiveParts,
|
|
||||||
glbAnimName
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user