diff --git a/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemDefinition.java b/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemDefinition.java index ce1a4db..da1e07c 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemDefinition.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemDefinition.java @@ -103,7 +103,8 @@ public record DataDrivenItemDefinition( * is not present in this map (or null), the item falls back to its full * {@code ownedParts}.

* - *

This field is required in the JSON definition. Never null, never empty.

+ *

Optional in JSON. When absent, defaults to empty map (= all owned bones + * enabled for all animations, no filtering).

*/ Map> animationBones, @@ -111,9 +112,10 @@ public record DataDrivenItemDefinition( Map componentConfigs ) { - /** Compact constructor: default null componentConfigs to empty immutable map. */ + /** Compact constructor: default null maps to empty immutable maps. */ public DataDrivenItemDefinition { if (componentConfigs == null) componentConfigs = Map.of(); + if (animationBones == null) animationBones = Map.of(); } /** Check whether this definition declares a given component type. */ diff --git a/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemParser.java b/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemParser.java index 91f5d91..a8b9a03 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemParser.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/datadriven/DataDrivenItemParser.java @@ -261,17 +261,27 @@ public final class DataDrivenItemParser { // Optional: creator (author name for tooltip) String creator = getStringOrNull(root, "creator"); - // Required: animation_bones (per-animation bone whitelist) - Map> animationBones = parseAnimationBones( - root, - fileId - ); - if (animationBones == null) { - LOGGER.error( - "[DataDrivenItems] Skipping {}: missing or invalid 'animation_bones'", + // Optional: animation_bones (per-animation bone whitelist) + // When absent, all owned bones are enabled for all animations. + Map> animationBones; + if (!root.has("animation_bones")) { + // Not an error — absent means "permissive" (all owned bones, all animations) + animationBones = null; + LOGGER.info( + "[DataDrivenItems] {}: animation_bones not declared — all owned bones enabled for all animations", fileId ); - return null; + // null is fine — the record constructor defaults it to Map.of() + } else { + animationBones = parseAnimationBones(root, fileId); + if (animationBones == null) { + // Field was present but malformed — parseAnimationBones already logged details + LOGGER.error( + "[DataDrivenItems] Skipping {}: 'animation_bones' is present but invalid", + fileId + ); + return null; + } } // Optional: components (per-component JSON configs)