diff --git a/build.gradle b/build.gradle index 1425a6c..8dc41cc 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,8 @@ repositories { // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. // See https://docs.gradle.org/current/userguide/declaring_repositories.html // for more information about repositories. + + maven { url 'https://maven.nucleoid.xyz' } } loom { @@ -27,7 +29,6 @@ loom { sourceSet sourceSets.client } } - } dependencies { @@ -38,11 +39,8 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - - // Uncomment the following line to enable the deprecated Fabric API modules. - // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. - // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + modImplementation include("eu.pb4:sgui:1.2.2+1.20") } processResources { diff --git a/src/client/resources/modid.client.mixins.json b/src/client/resources/modid.client.mixins.json index 1d193ab..d0ba880 100644 --- a/src/client/resources/modid.client.mixins.json +++ b/src/client/resources/modid.client.mixins.json @@ -2,9 +2,7 @@ "required": true, "package": "io.github.sunshinewzy.serverconductor.fabric.mixin.client", "compatibilityLevel": "JAVA_17", - "client": [ - "ExampleClientMixin" - ], + "client": [], "injectors": { "defaultRequire": 1 } diff --git a/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ConductorGameMenu.java b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ConductorGameMenu.java new file mode 100644 index 0000000..9de9632 --- /dev/null +++ b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ConductorGameMenu.java @@ -0,0 +1,44 @@ +package io.github.sunshinewzy.serverconductor.fabric; + +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import eu.pb4.sgui.api.gui.SimpleGui; +import net.minecraft.item.Items; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.List; + +public class ConductorGameMenu extends SimpleGui { + + private static final GuiElementBuilder EDGE = new GuiElementBuilder(Items.GRAY_STAINED_GLASS_PANE).setName(Text.of(" ")); + private static final GuiElementBuilder itemGameBingo = new GuiElementBuilder(Items.MAP) + .setName(Text.literal("宾果小游戏 - Bingo").formatted(Formatting.GREEN)) + .setLore(List.of(Text.empty(), Text.of("一种原版生存竞赛小游戏"), Text.of("玩家需要通过探索,采掘,搏斗"), Text.of("与合成来收集Bingo卡片上的物品"))) + .setCallback((index, clickType, action, gui) -> ConductorMenu.switchServer(gui.getPlayer(), "bingo")); + private static final GuiElementBuilder itemGameSkywar = new GuiElementBuilder(Items.ENDER_EYE) + .setName(Text.literal("空岛战争 - Skywar").formatted(Formatting.YELLOW)) + .setLore(List.of(Text.empty(), Text.of("一种多人PvP小游戏"), Text.of("玩家在各自的空岛上开始游戏"), Text.of("收集资源,并彼此交战"), Text.of("努力活到最后吧!"))) + .setCallback((index, clickType, action, gui) -> ConductorMenu.switchServer(gui.getPlayer(), "skywar")); + + + /** + * Constructs a conductor game menu for the supplied player. + * + * @param player the player to server this gui to + */ + public ConductorGameMenu(ServerPlayerEntity player) { + super(ScreenHandlerType.GENERIC_9X3, player, false); + setTitle(Text.of("选择小游戏服")); + + for (int i = 0; i <= 9; i++) + setSlot(i, EDGE); + for (int i = 17; i <= 26; i++) + setSlot(i, EDGE); + + setSlot(12, itemGameBingo); + setSlot(14, itemGameSkywar); + } + +} diff --git a/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ConductorMenu.java b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ConductorMenu.java new file mode 100644 index 0000000..195fb38 --- /dev/null +++ b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ConductorMenu.java @@ -0,0 +1,93 @@ +package io.github.sunshinewzy.serverconductor.fabric; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import eu.pb4.sgui.api.gui.SimpleGui; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.item.Items; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ConductorMenu extends SimpleGui { + + private static final GuiElementBuilder EDGE = new GuiElementBuilder(Items.GRAY_STAINED_GLASS_PANE).setName(Text.of(" ")); + private static final GuiElementBuilder itemSurvival = new GuiElementBuilder(Items.STONE_PICKAXE) + .setName(Text.literal("生存服 - Survival").formatted(Formatting.GREEN)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 普通生存服"), Text.of("(首次进服默认进入生存服)"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "s")); + private static final GuiElementBuilder itemMirror = new GuiElementBuilder(Items.GLASS) + .setName(Text.literal("镜像服 - Mirror").formatted(Formatting.AQUA)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 生存服的镜像"), Text.of("创造模式!想干什么就干什么"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "m")); + private static final GuiElementBuilder itemCreative = new GuiElementBuilder(Items.CRAFTING_TABLE) + .setName(Text.literal("创造服 - Creative").formatted(Formatting.YELLOW)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 超平坦"), Text.of("创造模式!建筑基地与红石实验室!"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "c")); + private static final GuiElementBuilder itemIsland = new GuiElementBuilder(Items.OAK_SAPLING) + .setName(Text.literal("空岛服 - Island").formatted(Formatting.GREEN)) + .setLore(List.of(Text.empty(), Text.of("1.17.1 空岛"), Text.of("有丰富的成就系统,推荐给萌新~"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "i")); + private static final GuiElementBuilder itemArchitecture = new GuiElementBuilder(Items.STONE_BRICKS) + .setName(Text.literal("建筑服 - Architecture").formatted(Formatting.GOLD)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 地皮世界"), Text.of("创造!可以领取一块自己的领地!"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "ar")); + private static final GuiElementBuilder itemForbiddenCity = new GuiElementBuilder(Items.BRICKS) + .setName(Text.literal("故宫服 - Forbidden City").formatted(Formatting.LIGHT_PURPLE)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 故宫"), Text.of("重檐翠瓦缀天绫,砌玉楼栏嵌彩龙!"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "fc")); + private static final GuiElementBuilder itemTest = new GuiElementBuilder(Items.STICK) + .setName(Text.literal("测试服 - Test").formatted(Formatting.RED)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 进行功能测试"), Text.of("用来整活的"))) + .setCallback((index, clickType, action, gui) -> switchServer(gui.getPlayer(), "t")); + private static final GuiElementBuilder itemGame = new GuiElementBuilder(Items.SLIME_BALL) + .setName(Text.literal("小游戏服 - Game").formatted(Formatting.GREEN)) + .setLore(List.of(Text.empty(), Text.of("1.20.1 小游戏"), Text.of("含有bingo和skywar等小游戏"))) + .setCallback((index, clickType, action, gui) -> new ConductorGameMenu(gui.getPlayer()).open()); + + + /** + * Constructs a conductor menu for the supplied player. + * + * @param player the player to server this gui to + */ + public ConductorMenu(ServerPlayerEntity player) { + super(ScreenHandlerType.GENERIC_9X5, player, false); + setTitle(Text.of("选择子服")); + + for (int i = 0; i <= 8; i++) + setSlot(i, EDGE); + for (int i = 36; i <= 44; i++) + setSlot(i, EDGE); + int[] otherEdges = new int[]{9, 17, 18, 26, 27, 35}; + for (int i : otherEdges) + setSlot(i, EDGE); + + setSlot(11, itemSurvival); + setSlot(13, itemMirror); + setSlot(15, itemCreative); + setSlot(20, itemIsland); + setSlot(22, itemArchitecture); + setSlot(24, itemForbiddenCity); + setSlot(30, itemTest); + setSlot(32, itemGame); + } + + @SuppressWarnings("UnstableApiUsage") + public static void switchServer(@NotNull ServerPlayerEntity player, @NotNull String server) { + PacketByteBuf packetBuf = PacketByteBufs.create(); + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.writeUTF(server); + packetBuf.writeBytes(output.toByteArray()); + ServerPlayNetworking.send(player, new Identifier("server_conductor:switch"), packetBuf); + } + +} diff --git a/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ItemUtils.java b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ItemUtils.java new file mode 100644 index 0000000..811209e --- /dev/null +++ b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ItemUtils.java @@ -0,0 +1,36 @@ +package io.github.sunshinewzy.serverconductor.fabric; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtString; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ItemUtils { + + @NotNull + public static NbtCompound getOrCreateDisplay(@NotNull ItemStack item) { + return item.getOrCreateSubNbt(ItemStack.DISPLAY_KEY); + } + + public static void setItemName(@NotNull ItemStack item, @NotNull Text name) { + if (name.getString().isEmpty()) getOrCreateDisplay(item).remove(ItemStack.NAME_KEY); + else getOrCreateDisplay(item).putString(ItemStack.NAME_KEY, Text.Serializer.toJson(name)); + } + + public static void setItemLore(@NotNull ItemStack item, @Nullable Text[] lore) { + if (lore == null || lore.length == 0) { + getOrCreateDisplay(item).remove(ItemStack.LORE_KEY); + return; + } + + NbtList list = new NbtList(); + for (Text text : lore) { + list.add(NbtString.of(Text.Serializer.toJson(text))); + } + getOrCreateDisplay(item).put(ItemStack.LORE_KEY, list); + } + +} diff --git a/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ServerConductor.java b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ServerConductor.java index 829aa29..adcb033 100644 --- a/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ServerConductor.java +++ b/src/main/java/io/github/sunshinewzy/serverconductor/fabric/ServerConductor.java @@ -1,10 +1,14 @@ package io.github.sunshinewzy.serverconductor.fabric; import net.fabricmc.api.ModInitializer; - +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.minecraft.server.network.ServerPlayerEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static net.minecraft.server.command.CommandManager.literal; + + public class ServerConductor implements ModInitializer { // This logger is used to write text to the console and the log file. // It is considered best practice to use your mod id as the logger's name. @@ -16,7 +20,14 @@ public void onInitialize() { // This code runs as soon as Minecraft is in a mod-load-ready state. // However, some things (like resources) may still be uninitialized. // Proceed with mild caution. + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("ser") + .executes(context -> { + ServerPlayerEntity player = context.getSource().getPlayer(); + if (player == null) return 0; + new ConductorMenu(player).open(); + return 1; + }))); - LOGGER.info("Hello Fabric world!"); + LOGGER.info("Successfully running ServerConductorFabric!"); } } \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index c992825..3de2f2e 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -17,9 +17,6 @@ "entrypoints": { "main": [ "io.github.sunshinewzy.serverconductor.fabric.ServerConductor" - ], - "client": [ - "io.github.sunshinewzy.serverconductor.fabric.ServerConductorClient" ] }, "mixins": [ @@ -30,7 +27,7 @@ } ], "depends": { - "fabricloader": ">=0.14.25", + "fabricloader": ">=0.14.21", "minecraft": "~1.20.1", "java": ">=17", "fabric-api": "*" diff --git a/src/main/resources/modid.mixins.json b/src/main/resources/modid.mixins.json index 2d4d6db..611a7a8 100644 --- a/src/main/resources/modid.mixins.json +++ b/src/main/resources/modid.mixins.json @@ -2,9 +2,7 @@ "required": true, "package": "io.github.sunshinewzy.serverconductor.fabric.mixin", "compatibilityLevel": "JAVA_17", - "mixins": [ - "ExampleMixin" - ], + "mixins": [], "injectors": { "defaultRequire": 1 }