From 3f6e04edb0e9197ceeeeb6cd188b6bb9ab2e0ff0 Mon Sep 17 00:00:00 2001 From: NotEvil Date: Fri, 17 Apr 2026 01:51:58 +0200 Subject: [PATCH] feat(validation): add /tiedup validate client command for GLB diagnostics --- .../remake/client/gltf/GltfClientSetup.java | 12 ++ .../remake/commands/ValidateGlbCommand.java | 133 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/main/java/com/tiedup/remake/commands/ValidateGlbCommand.java diff --git a/src/main/java/com/tiedup/remake/client/gltf/GltfClientSetup.java b/src/main/java/com/tiedup/remake/client/gltf/GltfClientSetup.java index 4fa21f6..c8625aa 100644 --- a/src/main/java/com/tiedup/remake/client/gltf/GltfClientSetup.java +++ b/src/main/java/com/tiedup/remake/client/gltf/GltfClientSetup.java @@ -144,5 +144,17 @@ public final class GltfClientSetup { GltfSkinCache.removeEntity(event.getEntity().getId()); } } + + @SubscribeEvent + public static void onRegisterClientCommands( + net.minecraftforge.client.event.RegisterClientCommandsEvent event + ) { + com.tiedup.remake.commands.ValidateGlbCommand.register( + event.getDispatcher() + ); + LOGGER.info( + "[GltfPipeline] Client command /tiedup validate registered" + ); + } } } diff --git a/src/main/java/com/tiedup/remake/commands/ValidateGlbCommand.java b/src/main/java/com/tiedup/remake/commands/ValidateGlbCommand.java new file mode 100644 index 0000000..66d9be7 --- /dev/null +++ b/src/main/java/com/tiedup/remake/commands/ValidateGlbCommand.java @@ -0,0 +1,133 @@ +package com.tiedup.remake.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.tiedup.remake.client.gltf.diagnostic.GlbDiagnostic; +import com.tiedup.remake.client.gltf.diagnostic.GlbDiagnosticRegistry; +import com.tiedup.remake.client.gltf.diagnostic.GlbValidationResult; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +/** + * Client-only command: /tiedup validate [item_id] + * + * Displays GLB validation diagnostics in chat. + * Registered via {@link net.minecraftforge.client.event.RegisterClientCommandsEvent} + * on the FORGE bus (never on the server). + */ +@OnlyIn(Dist.CLIENT) +public final class ValidateGlbCommand { + + private ValidateGlbCommand() {} + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("tiedup") + .then(Commands.literal("validate") + .executes(ctx -> validateAll(ctx.getSource())) + .then(Commands.argument("item_id", StringArgumentType.string()) + .executes(ctx -> validateOne( + ctx.getSource(), + StringArgumentType.getString(ctx, "item_id") + )) + ) + ) + ); + } + + private static int validateAll(CommandSourceStack source) { + var all = GlbDiagnosticRegistry.getAll(); + if (all.isEmpty()) { + source.sendSuccess( + () -> Component.literal( + "[TiedUp] No GLB validation results. " + + "Try reloading resources (F3+T)." + ).withStyle(ChatFormatting.YELLOW), + false + ); + return 0; + } + + int totalDiags = 0; + for (GlbValidationResult result : all) { + if (result.diagnostics().isEmpty()) continue; + source.sendSuccess( + () -> Component.literal("--- " + result.source() + " ---") + .withStyle( + result.passed() + ? ChatFormatting.GREEN + : ChatFormatting.RED + ), + false + ); + for (GlbDiagnostic d : result.diagnostics()) { + source.sendSuccess(() -> formatDiagnostic(d), false); + totalDiags++; + } + } + + int count = totalDiags; + source.sendSuccess( + () -> Component.literal( + "[TiedUp] " + count + " diagnostic(s) across " + + GlbDiagnosticRegistry.size() + " GLBs" + ).withStyle(ChatFormatting.GRAY), + false + ); + return 1; + } + + private static int validateOne(CommandSourceStack source, String itemId) { + ResourceLocation loc = ResourceLocation.tryParse(itemId); + if (loc == null) { + source.sendFailure( + Component.literal("Invalid resource location: " + itemId) + ); + return 0; + } + + for (GlbValidationResult result : GlbDiagnosticRegistry.getAll()) { + boolean match = result.source().equals(loc); + if (!match) { + match = result.diagnostics().stream() + .anyMatch(d -> loc.equals(d.itemDef())); + } + if (match) { + source.sendSuccess( + () -> Component.literal("--- " + result.source() + " ---") + .withStyle( + result.passed() + ? ChatFormatting.GREEN + : ChatFormatting.RED + ), + false + ); + for (GlbDiagnostic d : result.diagnostics()) { + source.sendSuccess(() -> formatDiagnostic(d), false); + } + return 1; + } + } + + source.sendFailure( + Component.literal("No validation results for: " + itemId) + ); + return 0; + } + + private static Component formatDiagnostic(GlbDiagnostic d) { + ChatFormatting color = switch (d.severity()) { + case ERROR -> ChatFormatting.RED; + case WARNING -> ChatFormatting.YELLOW; + case INFO -> ChatFormatting.GRAY; + }; + return Component.literal( + " [" + d.severity() + "] " + d.code() + ": " + d.message() + ).withStyle(color); + } +}