diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 3acfb136..ba762a80 100644 --- a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -208,5 +208,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { RenderSystem.recordRenderCall(AllMusicCore::renderInit); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } \ No newline at end of file diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..eb1d1c94 --- /dev/null +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,30 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager; + +/** + * Fabric(1.16.5)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandManager.DISPATCHER.register(ClientCommandManager.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(ClientCommandManager.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args")))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 53f2ae8e..ad834134 100644 --- a/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -138,5 +138,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { RenderSystem.recordRenderCall(AllMusicCore::renderInit); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_20_1/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index a2826149..648e20b0 100644 --- a/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -140,5 +140,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { RenderSystem.recordRenderCall(AllMusicCore::renderInit); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_21/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index d8a8c172..1ff14043 100644 --- a/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -135,5 +135,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { AllMusicCore.init(FabricLoader.getInstance().getConfigDir(), this); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_21_11/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 61ca28d8..f1384a4a 100644 --- a/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -140,5 +140,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { RenderSystem.recordRenderCall(AllMusicCore::renderInit); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_21_3/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 61ca28d8..f1384a4a 100644 --- a/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -140,5 +140,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { RenderSystem.recordRenderCall(AllMusicCore::renderInit); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_21_4/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 0dc948f7..4b172164 100644 --- a/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -133,5 +133,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { AllMusicCore.init(FabricLoader.getInstance().getConfigDir(), this); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_21_6/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 0dc948f7..4b172164 100644 --- a/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -133,5 +133,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { AllMusicCore.init(FabricLoader.getInstance().getConfigDir(), this); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_1_21_8/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 1c9d88a2..34587a88 100644 --- a/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -135,5 +135,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { AllMusicCore.init(FabricLoader.getInstance().getConfigDir(), this); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_26_1/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index cc5dd9bc..1242a08f 100644 --- a/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -134,5 +134,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { AllMusicCore.init(FabricLoader.getInstance().getConfigDir(), this); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_26_2/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 97073e42..3eb6c512 100644 --- a/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -131,5 +131,8 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { AllMusicCore.init(FabricLoader.getInstance().getConfigDir(), this); ClientLifecycleEvents.CLIENT_STOPPING.register((a) -> AllMusicCore.stop()); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + CommandMusicClientFabric.register(); } } diff --git a/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java b/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java new file mode 100644 index 00000000..1a02aa4a --- /dev/null +++ b/client/fabric_26_3/src/main/java/com/coloryr/allmusic/client/CommandMusicClientFabric.java @@ -0,0 +1,32 @@ +package com.coloryr.allmusic.client; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.commands.Commands; + +/** + * Fabric(1.19.3+)的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里 + */ +public final class CommandMusicClientFabric { + private CommandMusicClientFabric() { + } + + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(Commands.literal(CommandMusicClient.NAME) + .executes(context -> CommandMusicClient.run(new String[0])) + .then(Commands.argument("args", StringArgumentType.greedyString()) + .executes(context -> CommandMusicClient.run( + split(StringArgumentType.getString(context, "args"))))))); + } + + private static String[] split(String args) { + String text = args == null ? "" : args.trim(); + if (text.isEmpty()) { + return new String[0]; + } + return text.split("\\s+"); + } +} diff --git a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 6b029639..063494da 100644 --- a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -14,6 +14,7 @@ import net.minecraft.network.NetworkManager; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; import net.minecraft.util.text.TextComponentString; +import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.sound.PlaySoundEvent; import net.minecraftforge.common.MinecraftForge; @@ -61,6 +62,9 @@ public class AllMusicClient implements AllMusicBridge { } AllMusicCore.init(evt.getModConfigurationDirectory().toPath(), this); MinecraftForge.EVENT_BUS.register(this); + + // 客户端指令:/music_client help | info | test | imagesize <大小> + ClientCommandHandler.instance.registerCommand(new CommandMusicClientForge()); try { Class> server = Class.forName("com.coloryr.allmusic.server.AllMusicServer"); Field m = server.getField("channel"); diff --git a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CommandMusicClientForge.java b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CommandMusicClientForge.java new file mode 100644 index 00000000..968a9d7f --- /dev/null +++ b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CommandMusicClientForge.java @@ -0,0 +1,60 @@ +package com.coloryr.allmusic.client; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; + +import java.util.Collections; +import java.util.List; + +/** + * 1.12.2 的 /music_client 指令壳 + *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+public class CommandMusicClientForge extends CommandBase {
+ @Override
+ public String getName() {
+ return CommandMusicClient.NAME;
+ }
+
+ @Override
+ public String getUsage(ICommandSender sender) {
+ return CommandMusicClient.usage();
+ }
+
+ @Override
+ public List
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+public final class CommandMusicClientForge {
+ private CommandMusicClientForge() {
+ }
+
+ public static void register(CommandDispatcher
+ * 只负责把 {@link CommandMusicClient#execute(String[])} 的结果发到聊天栏,
+ * 具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+public class CommandMusicClientForge implements ICommand {
+ @Override
+ public String getCommandName() {
+ return CommandMusicClient.NAME;
+ }
+
+ @Override
+ public String getCommandUsage(ICommandSender sender) {
+ return CommandMusicClient.usage();
+ }
+
+ @Override
+ public List getCommandAliases() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) {
+ CommandMusicClient.Result result = CommandMusicClient.execute(args);
+
+ if (result.title != null) {
+ send(sender, result.title, EnumChatFormatting.YELLOW);
+ }
+ for (String line : result.lines) {
+ send(sender, line, color(CommandMusicClient.styleOf(line)));
+ }
+ }
+
+ private static EnumChatFormatting color(int style) {
+ switch (style) {
+ case CommandMusicClient.STYLE_OK:
+ return EnumChatFormatting.GREEN;
+ case CommandMusicClient.STYLE_ERROR:
+ return EnumChatFormatting.RED;
+ default:
+ return null;
+ }
+ }
+
+ private static void send(ICommandSender sender, String message, EnumChatFormatting color) {
+ ChatComponentText text = new ChatComponentText("[AllMusic Client] " + message);
+ if (color != null) {
+ text.getChatStyle().setColor(color);
+ }
+ sender.addChatMessage(text);
+ }
+
+ @Override
+ public boolean canCommandSenderUseCommand(ICommandSender sender) {
+ return true;
+ }
+
+ @Override
+ public List addTabCompletionOptions(ICommandSender sender, String[] args) {
+ if (args.length == 1) {
+ return CommandBase.getListOfStringsMatchingLastWord(args, CommandMusicClient.SUB_COMMANDS);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isUsernameIndex(String[] args, int index) {
+ return false;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return 0;
+ }
+}
diff --git a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java
index ffd142bf..028c79c3 100644
--- a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java
+++ b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java
@@ -38,6 +38,12 @@ public class PicRender extends PictureFrameBuffer {
}
}
+ @Override
+ public void dispose() {
+ sourceTexture.deleteGlTexture();
+ rotateTexture.deleteGlTexture();
+ }
+
@Override
public void draw(boolean rotate, int size, float x, float y, int ang, HudPosType dir, float alpha) {
Point2f point = AllMusicHud.getPos(size, size, x, y, dir);
diff --git a/client/neoforge_1_21/src/main/java/com/coloryr/allmusic/client/CommandMusicClientNeoForge.java b/client/neoforge_1_21/src/main/java/com/coloryr/allmusic/client/CommandMusicClientNeoForge.java
new file mode 100644
index 00000000..4749b3ec
--- /dev/null
+++ b/client/neoforge_1_21/src/main/java/com/coloryr/allmusic/client/CommandMusicClientNeoForge.java
@@ -0,0 +1,40 @@
+package com.coloryr.allmusic.client;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.neoforged.api.distmarker.Dist;
+import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.fml.common.EventBusSubscriber;
+import net.neoforged.neoforge.client.event.RegisterClientCommandsEvent;
+
+/**
+ * NeoForge 的 /music_client 指令壳
+ *
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 只负责注册指令,具体逻辑都在通用的 {@link CommandMusicClient} 里
+ */
+@EventBusSubscriber(modid = AllMusicClient.MODID, value = Dist.CLIENT)
+public final class CommandMusicClientNeoForge {
+ private CommandMusicClientNeoForge() {
+ }
+
+ @SubscribeEvent
+ public static void onRegisterCommands(RegisterClientCommandsEvent event) {
+ CommandDispatcher
+ * 这里只做参数解析和输出内容,不依赖任何 Minecraft 类,
+ * 每个版本各自实现一层很薄的指令壳(比如 1.7.10 的 {@code CommandMusicClientForge}),
+ * 把 {@link #execute(String[])} 的结果发给玩家即可
+ */
+public class CommandMusicClient {
+ public static final String NAME = "music_client";
+
+ private static final String ARG_HELP = "help";
+ private static final String ARG_INFO = "info";
+ private static final String ARG_TEST = "test";
+ private static final String ARG_IMAGE_SIZE = "imagesize";
+
+ /**
+ * 所有子指令,Tab 补全用
+ */
+ public static final String[] SUB_COMMANDS = {ARG_HELP, ARG_INFO, ARG_TEST, ARG_IMAGE_SIZE};
+
+ /**
+ * 普通输出
+ */
+ public static final int STYLE_NORMAL = 0;
+ /**
+ * 正常([OK])
+ */
+ public static final int STYLE_OK = 1;
+ /**
+ * 异常([!!])
+ */
+ public static final int STYLE_ERROR = 2;
+
+ /**
+ * 指令用法
+ *
+ * @return 用法
+ */
+ public static String usage() {
+ return "/" + NAME + " " + ARG_HELP;
+ }
+
+ /**
+ * 执行指令
+ *
+ * @param args 参数(不含指令名本身)
+ * @return 要显示的内容
+ */
+ public static Result execute(String[] args) {
+ if (args == null || args.length == 0) {
+ return help();
+ }
+
+ switch (args[0].toLowerCase(Locale.ROOT)) {
+ case ARG_HELP:
+ return help();
+ case ARG_INFO:
+ return new Result("AllMusic 客户端信息", new ArrayList<>(AllMusicCore.getInfoLines()));
+ case ARG_TEST:
+ return test();
+ case ARG_IMAGE_SIZE:
+ return imageSize(args);
+ default:
+ return help();
+ }
+ }
+
+ /**
+ * 执行指令并把结果发到聊天栏
+ *
+ * 各版本的指令壳解析出参数后直接调用这里,输出统一走游戏桥,
+ * 不用关心各版本聊天 API 的差异
+ *
+ * @param args 参数(不含指令名本身)
+ * @return Brigadier 需要的返回值
+ */
+ public static int run(String[] args) {
+ if (AllMusicCore.bridge == null) {
+ return 0;
+ }
+
+ Result result = execute(args);
+ if (result.title != null) {
+ AllMusicCore.bridge.sendMessage(result.title);
+ }
+ for (String line : result.lines) {
+ AllMusicCore.bridge.sendMessage(line);
+ }
+
+ return 1;
+ }
+
+ /**
+ * 输出行的样式,方便各版本上色
+ *
+ * @param line 一行内容
+ * @return 样式
+ */
+ public static int styleOf(String line) {
+ if (line == null) {
+ return STYLE_NORMAL;
+ }
+ if (line.startsWith("[OK]")) {
+ return STYLE_OK;
+ }
+ if (line.startsWith("[!!]")) {
+ return STYLE_ERROR;
+ }
+ return STYLE_NORMAL;
+ }
+
+ private static Result help() {
+ List
+ * httpclient 的调试输出会刷 debug.log;
+ * 旅行者地图则是按 debug 等级在屏幕上画调试标签(TileDrawStep 里 isDebugEnabled() 就画),
+ * 所以一起压到 INFO,避免 debug.log 和屏幕都被刷
+ */
+ public static final List
+ * {@link Configuration#getLoggerConfig(String)} 找不到同名 logger 时会返回父级或根 logger,
+ * 直接 setLevel 会顺带把根 logger 的等级改掉,等于把玩家自己的日志配置整个覆盖了。
+ * 这里只修改同名 logger;没有就新建一个(additive,日志依旧会输出到根 logger 的 appender)
+ *
+ * @param logConfig 日志配置
+ * @param name logger 名字
+ * @param level 日志等级
+ */
+ private static void setLoggerLevel(Configuration logConfig, String name, Level level) {
+ LoggerConfig loggerConfig = logConfig.getLoggerConfig(name);
- LoggerConfig coreConfig = config.getLoggerConfig("org.apache.hc.core5");
- coreConfig.setLevel(Level.INFO);
+ if (name.equals(loggerConfig.getName())) {
+ loggerConfig.setLevel(level);
+ return;
+ }
- ctx.updateLoggers(config);
+ // 没有同名 logger:新建一个挂进配置。
+ // Configuration#addLogger 只存在于实现类(1.7.10 自带的 2.0-beta9 里连接口都没有),
+ // 所以按运行时类型反射调用,避免换版本时 NoSuchMethodError
+ try {
+ Method addLogger = logConfig.getClass()
+ .getMethod("addLogger", String.class, LoggerConfig.class);
+ addLogger.invoke(logConfig, name, new LoggerConfig(name, level, true));
+ } catch (Exception ignored) {
+ // 实在加不进去就保持原样,绝不去改根 logger
+ }
}
public static void stop() {
@@ -165,6 +210,120 @@ public class AllMusicCore {
hud = new AllMusicHud(config.picSize);
}
+ /**
+ * 获取图片大小
+ *
+ * @return 图片大小
+ */
+ public static int getPicSize() {
+ return config == null ? 0 : config.picSize;
+ }
+
+ /**
+ * 设置图片大小
+ *
+ * 立即重建图片渲染缓冲;下一次收到图片(比如下一首歌的封面)时就会用新的大小生成。
+ * 当前正在显示的封面会重新拉取一次,没有封面时等下一首歌的图片包。
+ * 同时写回 allmusic_client.json,重启后依然生效
+ *
+ * @param size 图片大小
+ * @return 是否设置成功
+ */
+ public static boolean setPicSize(int size) {
+ if (config == null) {
+ return false;
+ }
+ if (size < MIN_PIC_SIZE || size > MAX_PIC_SIZE) {
+ return false;
+ }
+
+ config.picSize = size;
+ saveConfig();
+ if (hud != null) {
+ hud.setPicSize(size);
+ }
+ return true;
+ }
+
+ /**
+ * 保存配置文件
+ */
+ public static void saveConfig() {
+ if (configFile == null || config == null) {
+ return;
+ }
+ try {
+ String data = new GsonBuilder().setPrettyPrinting()
+ .create()
+ .toJson(config);
+ FileOutputStream out = new FileOutputStream(configFile);
+ OutputStreamWriter write = new OutputStreamWriter(out, StandardCharsets.UTF_8);
+ write.write(data);
+ write.close();
+ out.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 客户端信息
+ *
+ * @return 每一行内容
+ */
+ public static List
+ * 由下载线程写入、客户端线程读取,必须 volatile
+ */
+ private volatile String lastPicUrl;
/**
* 是否有图片
@@ -136,12 +160,17 @@ public class AllMusicHud {
offset = AllMusicCore.bridge.readText(PIC_SCALE);
picScale = Float.parseFloat(offset);
+ BufferedImage source = null;
try {
InputStream stream = AllMusicCore.bridge.readFile(BG2);
- bg2 = resizeImage(ImageIO.read(stream), size, size);
+ source = ImageIO.read(stream);
+ if (source != null) {
+ bg2 = resizeImage(source, size, size);
+ }
} catch (Exception e) {
e.printStackTrace();
}
+ bg2Source = source;
}
public void stop() {
@@ -324,6 +353,7 @@ public class AllMusicHud {
*/
private void loadPic(String picUrl) {
haveImg = false;
+ lastPicUrl = picUrl;
try {
while (save == null || imageNeedUpload) {
Thread.sleep(200);
@@ -332,6 +362,9 @@ public class AllMusicHud {
return;
}
+ // 固定本次使用的尺寸,避免下载过程中被改掉,生成出一张和缓冲对不上的图
+ final int size = this.size;
+
HttpGet request = new HttpGet(picUrl);
BufferedImage image = AllMusicCore.client.execute(request, (response -> {
InputStream inputStream = response.getEntity().getContent();
@@ -362,6 +395,7 @@ public class AllMusicHud {
rotateImage = outputStream.toByteArray();
request.clear();
+ loadedSize = size;
imageNeedUpload = true;
} catch (Exception e) {
e.printStackTrace();
@@ -374,6 +408,23 @@ public class AllMusicHud {
* 更新材质
*/
private void updateTexture() {
+ if (pendingPicRender != null) {
+ if (loadedSize != pendingSize) {
+ // 这张图是按旧尺寸生成的,缓冲对不上,丢掉重新拉一次
+ String url = lastPicUrl;
+ if (url != null && !url.isEmpty()) {
+ setImg(url);
+ }
+ return;
+ }
+ PictureFrameBuffer old = picRender;
+ picRender = pendingPicRender;
+ pendingPicRender = null;
+ // 旧大小的贴图已经用不到了,释放掉
+ if (old != null) {
+ old.dispose();
+ }
+ }
picRender.update(sourceImage, rotateImage);
haveImg = true;
}
@@ -433,6 +484,119 @@ public class AllMusicHud {
return true;
}
+ /**
+ * 获取图片大小
+ *
+ * @return 图片大小
+ */
+ public int getPicSize() {
+ return size;
+ }
+
+ /**
+ * 是否已经收到服务端的 HUD 数据
+ *
+ * @return 是否收到
+ */
+ public boolean hasHudData() {
+ return save != null;
+ }
+
+ /**
+ * 当前是否有封面可以显示
+ *
+ * @return 是否有封面
+ */
+ public boolean hasImage() {
+ return haveImg;
+ }
+
+ /**
+ * 最后加载的封面地址
+ *
+ * @return 封面地址
+ */
+ public String getLastPicUrl() {
+ return lastPicUrl;
+ }
+
+ /**
+ * 客户端自检信息
+ *
+ * @return 每一行结果,[OK] 正常,[!!] 异常
+ */
+ public List
+ * 只在客户端本地改,不需要服务端配合。新大小的贴图缓冲会立刻建好,
+ * 等新图片上传(重新拉取当前封面,或者下一首歌的图片包)时替换掉旧的
+ *
+ * @param size 图片大小
+ * @return 是否修改成功
+ */
+ public boolean setPicSize(int size) {
+ if (size <= 0 || size == this.size) {
+ return false;
+ }
+
+ this.size = size;
+
+ if (bg2Source != null) {
+ bg2 = resizeImage(bg2Source, size, size);
+ }
+
+ if (pendingPicRender != null) {
+ pendingPicRender.dispose();
+ }
+ pendingPicRender = AllMusicCore.bridge.makePictureRender(size);
+ pendingSize = size;
+
+ // 重新拉一次当前封面,让新大小马上生效;没有封面时就等下一首歌
+ String url = lastPicUrl;
+ if (url != null && !url.isEmpty()) {
+ setImg(url);
+ }
+
+ return true;
+ }
+
/**
* 显示更新
*/
diff --git a/client/src/main/java/com/coloryr/allmusic/client/core/objs/ConfigObj.java b/client/src/main/java/com/coloryr/allmusic/client/core/objs/ConfigObj.java
index f031750c..ec5c1ecc 100644
--- a/client/src/main/java/com/coloryr/allmusic/client/core/objs/ConfigObj.java
+++ b/client/src/main/java/com/coloryr/allmusic/client/core/objs/ConfigObj.java
@@ -1,5 +1,7 @@
package com.coloryr.allmusic.client.core.objs;
+import java.util.List;
+
public class ConfigObj {
/**
* 图片大小
@@ -9,4 +11,8 @@ public class ConfigObj {
* 音频队列大小
*/
public int queueSize;
+ /**
+ * 需要静音(设成 INFO)的日志
+ */
+ public List
+ * 修改图片大小时会换掉旧的渲染缓冲,旧的贴图需要释放
+ */
+ public void dispose() {
+ }
}