diff --git a/docs/ARTIST_GUIDE.md b/docs/ARTIST_GUIDE.md index cb6f14b..602abcb 100644 --- a/docs/ARTIST_GUIDE.md +++ b/docs/ARTIST_GUIDE.md @@ -1019,6 +1019,28 @@ Use your own namespace (e.g., `mycreator`) to avoid conflicts with the base mod --- +## Validation & Debugging + +The mod includes built-in tools to help you catch issues with your GLB files. + +### `/tiedup validate` Command + +Run `/tiedup validate` in-game (client-side command) to see a diagnostic report for all loaded GLBs: + +- **RED** errors — item won't work (missing GLB, invalid file, no skin) +- **YELLOW** warnings — item works but something looks wrong (bone typo, multiple meshes, no Idle animation) +- **GRAY** info — informational (custom bones detected, vertex count) + +Filter by item: `/tiedup validate tiedup:leather_armbinder` + +The validation runs automatically on every resource reload (F3+T). Check your game log for a summary line: `[GltfValidation] Validated N GLBs: X passed, Y with warnings, Z with errors`. + +### Mesh Naming Convention + +If your GLB contains multiple meshes, name your item mesh `Item` in Blender. The mod prioritizes a mesh named `Item` over other meshes. If no `Item` mesh is found, the last non-`Player` mesh is used (backward compatible, but may pick the wrong one in multi-mesh files). + +--- + ## Common Mistakes ### Skeleton Issues @@ -1034,7 +1056,7 @@ Use your own namespace (e.g., `mycreator`) to avoid conflicts with the base mod | Mistake | Symptom | Fix | |---------|---------|-----| -| Action not prefixed with `PlayerArmature\|` | Animation not found, falls back to first clip | Rename: `Idle` → `PlayerArmature\|Idle` | +| Action not prefixed with `PlayerArmature\|` | Animation not found, falls back to first clip | Rename: `Idle` → `PlayerArmature\|Idle`. Note: the mod strips any `ArmatureName\|` prefix, so custom armature names also work. | | Wrong case (`idle` instead of `Idle`) | Animation not found | Use exact PascalCase: `Idle`, `SitIdle`, `KneelStruggle` | | Variant gap (`.1`, `.2`, `.4` — missing `.3`) | Only .1 and .2 are used | Number sequentially with no gaps | | Animating bones outside your regions | Keyframes silently ignored | Only animate bones in your declared regions | @@ -1553,11 +1575,15 @@ NEVER DO: GOOD TO KNOW: → Only Idle is required. Everything else has fallbacks. + → animation_bones is optional. Omit it and all owned bones work for all animations. → Templates let you skip animation entirely. + → Custom bones are supported — add chain/ribbon/twist bones parented to standard bones. → Free bones (not owned by any item) CAN be animated by your GLB. → Bones owned by another equipped item are always ignored. → The mod handles sitting, sneaking, walking — you don't have to. → Context GLBs in tiedup_contexts/ replace default postures. + → Name your item mesh "Item" in Blender for explicit selection in multi-mesh files. + → Run /tiedup validate in-game to check your GLBs for issues. → Slim model is optional. Steve mesh works on Alex (minor clipping). → Textures bake into the GLB. No separate file needed. ``` diff --git a/src/main/java/com/tiedup/remake/client/gltf/diagnostic/GlbValidationReloadListener.java b/src/main/java/com/tiedup/remake/client/gltf/diagnostic/GlbValidationReloadListener.java index bf724b4..346303d 100644 --- a/src/main/java/com/tiedup/remake/client/gltf/diagnostic/GlbValidationReloadListener.java +++ b/src/main/java/com/tiedup/remake/client/gltf/diagnostic/GlbValidationReloadListener.java @@ -6,6 +6,9 @@ import java.io.InputStream; import java.util.Collection; import java.util.List; import java.util.Optional; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.toasts.SystemToast; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; @@ -129,6 +132,21 @@ public class GlbValidationReloadListener "[GltfValidation] Validated {} GLBs: {} passed, {} with warnings, {} with errors", total, passed, withWarnings, withErrors ); + + // Show toast notification for errors so artists don't have to check logs + if (withErrors > 0) { + int errorCount = withErrors; + Minecraft.getInstance().tell(() -> + Minecraft.getInstance().getToasts().addToast( + SystemToast.multiline( + Minecraft.getInstance(), + SystemToast.SystemToastIds.PACK_LOAD_FAILURE, + Component.literal("TiedUp! GLB Validation"), + Component.literal(errorCount + " model(s) have errors. Run /tiedup validate") + ) + ) + ); + } } private static boolean hasWarnings(GlbValidationResult result) {