package de.winniepat.citrus.client; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.*; import de.winniepat.citrus.Client; import de.winniepat.citrus.cosmetics.capes.*; import de.winniepat.citrus.cosmetics.capes.sync.CapeSyncManager; import de.winniepat.citrus.cosmetics.wings.ClientWingManager; import de.winniepat.citrus.managers.ClientRegistrationManager; import de.winniepat.citrus.gui.*; import icyllis.modernui.mc.MuiModApi; import net.fabricmc.fabric.api.client.command.v2.*; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.text.Text; import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.UUID; public class ClientCommands { public static void register() { ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { LiteralArgumentBuilder citrusCommand = LiteralArgumentBuilder.literal("citrus") .executes(context -> { context.getSource().sendFeedback(Text.literal("§f#### §aCitrus §7- by WinniePatGG §f####")); context.getSource().sendFeedback(Text.literal("§7Version: §7" + Client.CLIENT_BUILD)); context.getSource().sendFeedback(Text.literal("")); context.getSource().sendFeedback(Text.literal("§7Available commands:")); context.getSource().sendFeedback(Text.literal("§e/citrus cape set §7- Set your cape")); context.getSource().sendFeedback(Text.literal("§e/citrus cape reload §7- Reload available capes from cdn")); context.getSource().sendFeedback(Text.literal("")); context.getSource().sendFeedback(Text.literal("§e/citrus capesync clearcache §7- Clear cape sync cache")); context.getSource().sendFeedback(Text.literal("§e/citrus capesync forcefetch §7- Force fetch capes for all players")); context.getSource().sendFeedback(Text.literal("")); context.getSource().sendFeedback(Text.literal("§e/citrus wings toggle §7- Toggle wings visibility")); context.getSource().sendFeedback(Text.literal("§e/citrus wings set §7- Set your wing type")); context.getSource().sendFeedback(Text.literal("§e/citrus wings list §7- List available wing types")); context.getSource().sendFeedback(Text.literal("")); context.getSource().sendFeedback(Text.literal("§e/citrus status §7- Show Citrus status")); context.getSource().sendFeedback(Text.literal("§e/citrus screen §7- Open a client screen")); return 1; }); citrusCommand.then(LiteralArgumentBuilder.literal("screen") .then(RequiredArgumentBuilder .argument("name", StringArgumentType.word()) .suggests((context, builder) -> { builder.suggest("showcase"); builder.suggest("friends"); builder.suggest("profiles"); builder.suggest("hud"); builder.suggest("menu"); return builder.buildFuture(); }) .executes(context -> { String name = StringArgumentType.getString(context, "name").toLowerCase(); MinecraftClient client = MinecraftClient.getInstance(); client.execute(() -> { switch (name) { case "friends" -> client.setScreen(MuiModApi.get().createScreen(new FriendsFragment(), null, client.currentScreen)); case "profiles" -> client.setScreen(MuiModApi.get().createScreen(new ProfileScreen(), null, client.currentScreen)); case "hud" -> client.setScreen(MuiModApi.get().createScreen(new HudEditorFragment(), null, client.currentScreen)); case "menu" -> client.setScreen(MuiModApi.get().createScreen(new MainMenuScreen(), null, null)); case "showcase" -> client.setScreen(MuiModApi.get().createScreen(new TestScreen(), null, client.currentScreen)); default -> context.getSource().sendError(Text.literal("§cUnknown screen: §e" + name)); } }); return 1; }) ) ); citrusCommand.then(LiteralArgumentBuilder.literal("cape") .then(LiteralArgumentBuilder.literal("set") .then(RequiredArgumentBuilder .argument("cape_name", StringArgumentType.string()) .suggests((context, builder) -> { builder.suggest("none"); builder.suggest("auto"); for (String cape : CapeHandler.getAvailableCapes()) { builder.suggest(cape); } return builder.buildFuture(); }) .executes(context -> { String capeName = StringArgumentType.getString(context, "cape_name"); MinecraftClient client = MinecraftClient.getInstance(); if (client.player == null) { context.getSource().sendError(Text.literal("§cYou must be in-game!")); return 0; } if (CapeHandler.capeExists(capeName)) { CapeHandler.setLocalPlayerCape(capeName, false); context.getSource().sendFeedback(Text.literal("§aCape set to: §e" + capeName)); } else { context.getSource().sendError(Text.literal("§cUnknown cape: " + capeName)); } return 1; }) ) ) .then(LiteralArgumentBuilder.literal("reload") .executes(context -> { context.getSource().sendFeedback(Text.literal("§aReloading capes...")); CapeHandler.reloadCapes(); return 1; }) ) ); citrusCommand.then(LiteralArgumentBuilder.literal("capesync") .then(LiteralArgumentBuilder.literal("clearcache") .executes(context -> { CapeSyncManager.clearAllCache(); context.getSource().sendFeedback(Text.literal("§aCache cleared.")); return 1; }) ) .then(LiteralArgumentBuilder.literal("forcefetch") .executes(context -> { MinecraftClient client = MinecraftClient.getInstance(); if (client.player == null || client.world == null) { context.getSource().sendError(Text.literal("§cYou must be in-game!")); return 0; } List playerUUIDs = client.world.getPlayers().stream() .filter(p -> p != client.player) .map(PlayerEntity::getUuid) .toList(); CapeSyncManager.batchFetchCapes(playerUUIDs); context.getSource().sendFeedback(Text.literal( "§aFetching capes for §e" + playerUUIDs.size() + "§a players..." )); return 1; }) ) ); citrusCommand.then(LiteralArgumentBuilder.literal("status") .executes(context -> { context.getSource().sendFeedback(Text.literal("--- §aCitrus Status §7---")); context.getSource().sendFeedback(Text.literal("")); boolean healthy = CapeSyncManager.isIsHealthy(); String serverHealth = healthy ? "§ahealthy" : "§cexperiencing issues or is offline"; context.getSource().sendFeedback(Text.literal("CapeSync Server: " + serverHealth)); int capesAvailable = CapeHandler.getAvailableCapes().size(); context.getSource().sendFeedback(Text.literal("§aCapes available: §e" + capesAvailable)); MinecraftClient client = MinecraftClient.getInstance(); if (client.player != null) { String activeWings = de.winniepat.citrus.cosmetics.wings.ClientWingManager.getActiveWings(client.player.getUuid()); boolean wingsVisible = ClientWingManager.areWingsVisible(client.player.getUuid()); String wingStatus = "§aWing type: §e" + activeWings + "§a, " + (wingsVisible ? "§avisible" : "§chidden"); context.getSource().sendFeedback(Text.literal(wingStatus)); } String registrationStatus = getRegistrationStatus(healthy); context.getSource().sendFeedback(Text.literal("Registration: " + registrationStatus)); return 1; }) ); dispatcher.register(citrusCommand); }); } private static @NotNull String getRegistrationStatus(boolean healthy) { boolean registered = ClientRegistrationManager.isRegistered(); String registrationStatus = registered ? "§aYou are registered with the Citrus API" : "§cYou are not registered with the Citrus API"; if (!healthy && registered) { registrationStatus += " §7(§eStatus may be inaccurate because Backend has issues or is offline§7)"; } return registrationStatus; } }