diff options
-rw-r--r-- | run/servers.dat | bin | 23366 -> 23320 bytes | |||
-rw-r--r-- | run/servers.dat_old | bin | 23366 -> 23320 bytes | |||
-rw-r--r-- | src/main/java/de/hype/bbsentials/client/BBsentials.java | 236 | ||||
-rw-r--r-- | src/main/java/de/hype/bbsentials/communication/BBsentialConnection.java | 190 | ||||
-rw-r--r-- | src/main/java/de/hype/bbsentials/packets/PacketManager.java | 12 | ||||
-rw-r--r-- | src/main/java/de/hype/bbsentials/packets/packets/BingoChatMessagePacket.java | 1 | ||||
-rw-r--r-- | src/main/resources/fabric.mod.json | 3 |
7 files changed, 257 insertions, 185 deletions
diff --git a/run/servers.dat b/run/servers.dat Binary files differindex f7df290..5cb7e4b 100644 --- a/run/servers.dat +++ b/run/servers.dat diff --git a/run/servers.dat_old b/run/servers.dat_old Binary files differindex f7df290..5cb7e4b 100644 --- a/run/servers.dat_old +++ b/run/servers.dat_old diff --git a/src/main/java/de/hype/bbsentials/client/BBsentials.java b/src/main/java/de/hype/bbsentials/client/BBsentials.java index e133d04..f6feea6 100644 --- a/src/main/java/de/hype/bbsentials/client/BBsentials.java +++ b/src/main/java/de/hype/bbsentials/client/BBsentials.java @@ -33,35 +33,152 @@ public class BBsentials implements ClientModInitializer { public static BBsentialConnection bbserver; public static CommandsOLD coms; public static ScheduledExecutorService executionService = Executors.newScheduledThreadPool(1000); + /** * Runs the mod initializer on the client environment. */ @Override public void onInitializeClient() { + System.out.println("ide: " + Boolean.getBoolean("runningFromIDE")); ClientPlayConnectionEvents.JOIN.register((a, b, c) -> { if (!initialised) { config = Config.load(); Options.setGamma(10); Chat chat = new Chat(); - if (Config.isBingoTime() || config.overrideBingoTime()) { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { + dispatcher.register(ClientCommandManager.literal("bbi") + .then(ClientCommandManager.literal("reconnect") + .executes((context) -> { + connectToBBserver(); + return 1; + })) + .then(ClientCommandManager.literal("config") + .then(ClientCommandManager.argument("category", StringArgumentType.string()) + .suggests((context, builder) -> { + // Provide tab-completion options for config subfolder + return CommandSource.suggestMatching(new String[]{"save", "reset", "load"}, builder); + }).executes((context) -> { + String category = StringArgumentType.getString(context, "category"); + switch (category) { + case "save": + getConfig().save(); + sendPrivateMessageToSelf(Formatting.GREEN + "Saved config successfully"); + break; + case "load": + BBsentials.config = Config.load(); + break; + case "reset": + // Reset logic here + break; + } + return 1; + })) + .then(ClientCommandManager.literal("set-value") + .then(ClientCommandManager.argument("className", StringArgumentType.string()) + .suggests((context, builder) -> { + // Provide tab-completion options for classes + ArrayList<String> classNames = new ArrayList<>(); + classNames.add("Config"); + // Replace with your own logic to retrieve class names + return CommandSource.suggestMatching(classNames, builder); + }) + .then(ClientCommandManager.argument("variableName", StringArgumentType.string()) + .suggests((context, builder) -> { + // Provide tab-completion options for variable names + List<String> variableNames; + variableNames = List.of(getVariableInfo("de.hype.bbsentials.client", "Config")); + return CommandSource.suggestMatching(variableNames, builder); + }) + .then(ClientCommandManager.argument("variableValue", StringArgumentType.string()) + .executes((context) -> { + // Handle "variableName" and "variableValue" logic here + String variableName = StringArgumentType.getString(context, "variableName"); + String variableValue = StringArgumentType.getString(context, "variableValue"); + try { + if (!variableName.toLowerCase().contains("dev") || config.hasBBRoles("dev")) { + setVariableValue(getConfig(), variableName, variableValue); + } + getConfig().save(); + } catch (ClassNotFoundException | + NoSuchFieldException | + IllegalAccessException | + InstantiationException | + InvocationTargetException | + NoSuchMethodException e) { + Chat.sendPrivateMessageToSelf("§cInvalid variable or value"); + } + return 1; + }))))) + .then(ClientCommandManager.literal("get-value") + .then(ClientCommandManager.argument("className", StringArgumentType.string()) + .suggests((context, builder) -> { + // Provide tab-completion options for classes + ArrayList<String> classNames = new ArrayList<>(); + classNames.add("Config"); + // Replace with your own logic to retrieve class names + return CommandSource.suggestMatching(classNames, builder); + }) + .then(ClientCommandManager.argument("variableName", StringArgumentType.string()) + .suggests((context, builder) -> { + // Provide tab-completion options for variable names + List<String> variableNames; + variableNames = List.of(getVariableInfo("de.hype.bbsentials.client", "Config")); + return CommandSource.suggestMatching(variableNames, builder); + }) + .executes((context) -> { + // Handle "variableName" and "variableValue" logic here + String variableName = StringArgumentType.getString(context, "variableName"); + try { + Chat.getVariableValue(getConfig(), variableName); + } catch (Exception e) { + e.printStackTrace(); + } + return 1; + }))).executes((context) -> { + // Handle the case when "config" argument is not provided + // ... + return 1; + }))) + ); + }); //bbi} + if (Config.isBingoTime() || config.overrideBingoTime() || Boolean.getBoolean("runningFromIDE")) { connectToBBserver(); } initialised = true; } } ); - KeyBinding promptKeyBind = new KeyBinding("Chat Prompt Yes / Open Menu", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_R, "BBsentials"); - KeyBindingHelper.registerKeyBinding(promptKeyBind); - ClientTickEvents.END_CLIENT_TICK.register(client -> { - if (promptKeyBind.wasPressed()) { - if (config.getLastChatPromptAnswer() != null) { - if (config.isDetailedDevModeEnabled()){ - Chat.sendPrivateMessageToSelf(config.getLastChatPromptAnswer());} - MinecraftClient.getInstance().getNetworkHandler().sendChatMessage(config.getLastChatPromptAnswer()); + { + KeyBinding promptKeyBind = new KeyBinding("Chat Prompt Yes / Open Menu", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_R, "BBsentials"); + KeyBindingHelper.registerKeyBinding(promptKeyBind); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (promptKeyBind.wasPressed()) { + if (config.getLastChatPromptAnswer() != null) { + if (config.isDetailedDevModeEnabled()) { + Chat.sendPrivateMessageToSelf(config.getLastChatPromptAnswer()); + } + MinecraftClient.getInstance().getNetworkHandler().sendChatMessage(config.getLastChatPromptAnswer()); + } + config.setLastChatPromptAnswer(null); } - config.setLastChatPromptAnswer(null); + }); + KeyBinding craftKeyBind = new KeyBinding("Craft", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_V, "BBsentials"); + KeyBindingHelper.registerKeyBinding(craftKeyBind); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (craftKeyBind.wasPressed()) Chat.sendCommand("/craft"); + }); + for (int i = 1; i <= 9; i++) { + KeyBinding ecPageKeyBind = new KeyBinding("Ender Chest Page " + i, InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_1 + (i - 1), "BBsentials"); + KeyBindingHelper.registerKeyBinding(ecPageKeyBind); + int pageNum = i; // Capture the page number for lambda + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (ecPageKeyBind.wasPressed()) { + BBsentials.getConfig().sender.addImmediateSendTask("/ec " + pageNum); + } + }); } - }); + } // KeyBinds + } public static Config getConfig() { @@ -73,103 +190,10 @@ public class BBsentials implements ClientModInitializer { bbserver.sendHiddenMessage("exit"); } bbserver = new BBsentialConnection(); + coms = new CommandsOLD(); bbserver.setMessageReceivedCallback(message -> bbserver.onMessageReceived(message)); bbserver.connect(config.getBBServerURL(), 5000); - ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { - dispatcher.register(ClientCommandManager.literal("bbi") - .then(ClientCommandManager.literal("reconnect") - .executes((context) -> { - connectToBBserver(); - return 1; - })) - .then(ClientCommandManager.literal("config") - .then(ClientCommandManager.argument("category", StringArgumentType.string()) - .suggests((context, builder) -> { - // Provide tab-completion options for config subfolder - return CommandSource.suggestMatching(new String[]{"save", "reset", "load"}, builder); - }).executes((context) -> { - String category = StringArgumentType.getString(context, "category"); - switch (category) { - case "save": - getConfig().save(); - sendPrivateMessageToSelf(Formatting.GREEN + "Saved config successfully"); - break; - case "load": - BBsentials.config = Config.load(); - break; - case "reset": - // Reset logic here - break; - } - return 1; - })) - .then(ClientCommandManager.literal("set-value") - .then(ClientCommandManager.argument("className", StringArgumentType.string()) - .suggests((context, builder) -> { - // Provide tab-completion options for classes - ArrayList<String> classNames = new ArrayList<>(); - classNames.add("Config"); - // Replace with your own logic to retrieve class names - return CommandSource.suggestMatching(classNames, builder); - }) - .then(ClientCommandManager.argument("variableName", StringArgumentType.string()) - .suggests((context, builder) -> { - // Provide tab-completion options for variable names - List<String> variableNames; - variableNames = List.of(getVariableInfo("de.hype.bbsentials.client", "Config")); - return CommandSource.suggestMatching(variableNames, builder); - }) - .then(ClientCommandManager.argument("variableValue", StringArgumentType.string()) - .executes((context) -> { - // Handle "variableName" and "variableValue" logic here - String variableName = StringArgumentType.getString(context, "variableName"); - String variableValue = StringArgumentType.getString(context, "variableValue"); - try { - if (!variableName.toLowerCase().contains("dev")||config.hasBBRoles("dev")){ - setVariableValue(getConfig(), variableName, variableValue);} - getConfig().save(); - } catch (ClassNotFoundException | NoSuchFieldException | - IllegalAccessException | - InstantiationException | - InvocationTargetException | - NoSuchMethodException e) { - Chat.sendPrivateMessageToSelf("§cInvalid variable or value"); - } - return 1; - }))))) - .then(ClientCommandManager.literal("get-value") - .then(ClientCommandManager.argument("className", StringArgumentType.string()) - .suggests((context, builder) -> { - // Provide tab-completion options for classes - ArrayList<String> classNames = new ArrayList<>(); - classNames.add("Config"); - // Replace with your own logic to retrieve class names - return CommandSource.suggestMatching(classNames, builder); - }) - .then(ClientCommandManager.argument("variableName", StringArgumentType.string()) - .suggests((context, builder) -> { - // Provide tab-completion options for variable names - List<String> variableNames; - variableNames = List.of(getVariableInfo("de.hype.bbsentials.client", "Config")); - return CommandSource.suggestMatching(variableNames, builder); - }) - .executes((context) -> { - // Handle "variableName" and "variableValue" logic here - String variableName = StringArgumentType.getString(context, "variableName"); - try { - Chat.getVariableValue(getConfig(), variableName); - } catch (Exception e) { - e.printStackTrace(); - } - return 1; - }))).executes((context) -> { - // Handle the case when "config" argument is not provided - // ... - return 1; - }))) - ); - }); //bbi} - executionService.scheduleAtFixedRate(new DebugThread(),0,20, TimeUnit.SECONDS); + executionService.scheduleAtFixedRate(new DebugThread(), 0, 20, TimeUnit.SECONDS); } public static void refreshCommands() { diff --git a/src/main/java/de/hype/bbsentials/communication/BBsentialConnection.java b/src/main/java/de/hype/bbsentials/communication/BBsentialConnection.java index c5ca6b8..3b18870 100644 --- a/src/main/java/de/hype/bbsentials/communication/BBsentialConnection.java +++ b/src/main/java/de/hype/bbsentials/communication/BBsentialConnection.java @@ -10,8 +10,11 @@ import de.hype.bbsentials.packets.PacketManager; import de.hype.bbsentials.packets.PacketUtils; import de.hype.bbsentials.packets.packets.*; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; @@ -43,49 +46,6 @@ public class BBsentialConnection { public BBsentialConnection() { packetManager = new PacketManager(this); } - - public void onBingoChatMessagePacket(BingoChatMessagePacket packet) { - if (BBsentials.config.showBingoChat) { - Chat.sendPrivateMessageToSelf("[" + packet.prefix + "] " + packet.username + ": " + packet.message); - } - } - - public void onChChestPackage(ChChestPacket packet) { - if (isCommandSafe(packet.bbcommand)) { - String tellrawText = ("{\"text\":\"BB: @username found @item in a chest at (@coords). Click here to get a party invite @extramessage\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"@inviteCommand\"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"On clicking you will get invited to a party. Command executed: @inviteCommand\"]}}"); - tellrawText = tellrawText.replace("@username", packet.announcerUsername).replace("@item", Arrays.stream(packet.items).map(ChChestItem::getDisplayName).toList().toString()).replace("@coords", packet.locationCoords).replace("@inviteCommand", packet.bbcommand); - if (!(packet.extraMessage == null || packet.extraMessage.isEmpty())) { - tellrawText = tellrawText.replace("@extramessage", " : " + packet.extraMessage); - } - Chat.sendPrivateMessageToSelfText(Chat.createClientSideTellraw(tellrawText)); - } - else { - Chat.sendPrivateMessageToSelf("§cFiltered out a suspicious packet! Please send a screenshot of this message with ping Hype_the_Time (hackthetime) in Bingo Apothecary, BB, SBZ, offical Hypixel,..."); - Chat.sendPrivateMessageToSelf(PacketUtils.parsePacketToJson(packet)); - } - } - - public void onMiningEventPacket(MiningEventPacket packet) { - if (BBsentials.config.toDisplayConfig.getValue("disableAll")) { - //its will returns false cause disabled is checked already before. - Chat.sendPrivateMessageToSelf(packet.username + "There is a " + packet.event.getDisplayName() + "in the " + packet.island.getDisplayName() + " now/soon."); - } - } - - public void onWelcomePacket(WelcomeClientPacket packet) { - if (packet.success) { - BBsentials.config.bbsentialsRoles = packet.roles; - Chat.sendPrivateMessageToSelf("Login Success"); - if (!packet.motd.isEmpty()) { - Chat.sendPrivateMessageToSelf(packet.motd); - } - } - else { - Chat.sendPrivateMessageToSelf("Login Failed"); - } - - } - public interface MessageReceivedCallback { void onMessageReceived(String message); } @@ -305,35 +265,6 @@ public class BBsentialConnection { } } - public void onBroadcastMessage(BroadcastMessagePacket packet) { - String message = packet.message; - } - - public void onSplashNotify(SplashNotifyPacket packet) { - int waitTime; - if (packet.lessWaste) { - waitTime = (getPotTime() * 1000) / 80; - } - else { - waitTime = 0; - } - String where; - if (packet.hubType.equals(Islands.DUNGEON_HUB)) { - where = "§5DUNGEON HUB§6"; - } - else { - where = "Hub"; - } - BBsentials.executionService.schedule(() -> { - splashHighlightItem("HUB #" + packet.hub, 20); - String timeLoss = ""; - if (packet.lessWaste) { - timeLoss = "§c(" + waitTime + ")"; - } - Chat.sendPrivateMessageToSelf("§6" + packet.splasherUsername + " is Splashing in " + where + " #" + packet.hub + " at " + packet.location + ":" + packet.extraMessage + " | " + timeLoss); - }, waitTime, TimeUnit.MILLISECONDS); - } - public void dummy(Object o) { //this does absoloutely nothing } @@ -400,4 +331,117 @@ public class BBsentialConnection { sendHiddenMessage(packetName + "." + PacketUtils.parsePacketToJson(packet)); } } -} + + public void onBroadcastMessagePacket(BroadcastMessagePacket packet) { + Chat.sendPrivateMessageToSelf("§6[A]§r ["+packet.prefix+"] "+packet.username+": "+packet.message); + } + + public void onSplashNotifyPacket(SplashNotifyPacket packet) { + int waitTime; + if (packet.lessWaste) { + waitTime = (getPotTime() * 1000) / 80; + } + else { + waitTime = 0; + } + String where; + if (packet.hubType.equals(Islands.DUNGEON_HUB)) { + where = "§5DUNGEON HUB§6"; + } + else { + where = "Hub"; + } + BBsentials.executionService.schedule(() -> { + splashHighlightItem("HUB #" + packet.hub, 20); + String timeLoss = ""; + if (packet.lessWaste) { + timeLoss = "§c(" + waitTime + ")"; + } + Chat.sendPrivateMessageToSelf("§6" + packet.splasherUsername + " is Splashing in " + where + " #" + packet.hub + " at " + packet.location + ":" + packet.extraMessage + " | " + timeLoss); + }, waitTime, TimeUnit.MILLISECONDS); + } + + public void onBingoChatMessagePacket(BingoChatMessagePacket packet) { + if (BBsentials.config.showBingoChat) { + Chat.sendPrivateMessageToSelf("[" + packet.prefix + "] " + packet.username + ": " + packet.message); + } + } + + public void onChChestPacket(ChChestPacket packet) { + if (isCommandSafe(packet.bbcommand)) { + String tellrawText = ("{\"text\":\"BB: @username found @item in a chest at (@coords). Click here to get a party invite @extramessage\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"@inviteCommand\"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"On clicking you will get invited to a party. Command executed: @inviteCommand\"]}}"); + tellrawText = tellrawText.replace("@username", packet.announcerUsername).replace("@item", Arrays.stream(packet.items).map(ChChestItem::getDisplayName).toList().toString()).replace("@coords", packet.locationCoords).replace("@inviteCommand", packet.bbcommand); + if (!(packet.extraMessage == null || packet.extraMessage.isEmpty())) { + tellrawText = tellrawText.replace("@extramessage", " : " + packet.extraMessage); + } + Chat.sendPrivateMessageToSelfText(Chat.createClientSideTellraw(tellrawText)); + } + else { + Chat.sendPrivateMessageToSelf("§cFiltered out a suspicious packet! Please send a screenshot of this message with ping Hype_the_Time (hackthetime) in Bingo Apothecary, BB, SBZ, offical Hypixel,..."); + Chat.sendPrivateMessageToSelf(PacketUtils.parsePacketToJson(packet)); + } + } + + public void onMiningEventPacket(MiningEventPacket packet) { + if (BBsentials.config.toDisplayConfig.getValue("disableAll")) { + //its will returns false cause disabled is checked already before. + Chat.sendPrivateMessageToSelf(packet.username + "There is a " + packet.event.getDisplayName() + "in the " + packet.island.getDisplayName() + " now/soon."); + } + } + + public void onWelcomePacket(WelcomeClientPacket packet) { + if (packet.success) { + BBsentials.config.bbsentialsRoles = packet.roles; + Chat.sendPrivateMessageToSelf("§aLogin Success"); + if (!packet.motd.isEmpty()) { + Chat.sendPrivateMessageToSelf(packet.motd); + } + } + else { + Chat.sendPrivateMessageToSelf("Login Failed"); + } + } + + public void onDisconnectPacket(DisconnectPacket packet) { + + } + + public void onDisplayMessagePacket(DisplayMessagePacket packet) { + Chat.sendPrivateMessageToSelf("§r"+packet.message); + } + + public void onDisplayTellrawMessagePacket(DisplayTellrawMessagePacket packet) { + /*Chat.sendPrivateMessageToSelfText(Chat.createClientSideTellraw(packet.rawJson));*/ + Chat.sendPrivateMessageToSelf("You received a tellraw Packet but it got ignored due too there being no safety checks in this version."); + } + + public void onInternalCommandPacket(InternalCommandPacket packet) { + + } + + public void onInvalidCommandFeedbackPacket(InvalidCommandFeedbackPacket packet) { + Chat.sendPrivateMessageToSelf(packet.displayMessage); + } + + public void onPartyPacket(PartyPacket packet) { + Chat.sendCommand("/p "+packet.type+String.join(" ",packet.users)); + } + + public void onSystemMessagePacket(SystemMessagePacket packet) { + if (packet.important) { + Chat.sendPrivateMessageToSelf("§c§n"+packet.message); + }else { + Chat.sendPrivateMessageToSelf("§r"+packet.message); + } + if (packet.ping){ + playsound(SoundEvents.ENTITY_WARDEN_DIG); + } + } + + + public static void playsound(SoundEvent event){ + MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance + .master(event, 1.0F, 1.0F)); + } + +}
\ No newline at end of file diff --git a/src/main/java/de/hype/bbsentials/packets/PacketManager.java b/src/main/java/de/hype/bbsentials/packets/PacketManager.java index 03d25ed..9c4a6b3 100644 --- a/src/main/java/de/hype/bbsentials/packets/PacketManager.java +++ b/src/main/java/de/hype/bbsentials/packets/PacketManager.java @@ -23,13 +23,19 @@ public class PacketManager { } public static void initializePacketActions(BBsentialConnection connection) { - packets.add(new Packet<>(SplashNotifyPacket.class, connection::onSplashNotify)); packets.add(new Packet<>(BingoChatMessagePacket.class, connection::onBingoChatMessagePacket)); - packets.add(new Packet<>(ChChestPacket.class, connection::onChChestPackage)); -// packets.add(new Packet<>(DisconnectPacket.class, connection::dummy)); + packets.add(new Packet<>(BroadcastMessagePacket.class, connection::onBroadcastMessagePacket)); + packets.add(new Packet<>(ChChestPacket.class, connection::onChChestPacket)); + packets.add(new Packet<>(DisconnectPacket.class, connection::onDisconnectPacket)); + packets.add(new Packet<>(DisplayMessagePacket.class, connection::onDisplayMessagePacket)); + packets.add(new Packet<>(DisplayTellrawMessagePacket.class, connection::onDisplayTellrawMessagePacket)); // packets.add(new Packet<>(InternalCommandPacket.class, connection::dummy)); + packets.add(new Packet<>(InvalidCommandFeedbackPacket.class, connection::onInvalidCommandFeedbackPacket)); packets.add(new Packet<>(MiningEventPacket.class, connection::onMiningEventPacket)); + packets.add(new Packet<>(PartyPacket.class, connection::onPartyPacket)); // packets.add(new Packet<>(RequestConnectPacket.class, connection::dummy)); + packets.add(new Packet<>(SplashNotifyPacket.class, connection::onSplashNotifyPacket)); + packets.add(new Packet<>(SystemMessagePacket.class, connection::onSystemMessagePacket)); packets.add(new Packet<>(WelcomeClientPacket.class, connection::onWelcomePacket)); } diff --git a/src/main/java/de/hype/bbsentials/packets/packets/BingoChatMessagePacket.java b/src/main/java/de/hype/bbsentials/packets/packets/BingoChatMessagePacket.java index 56a7152..b62db7d 100644 --- a/src/main/java/de/hype/bbsentials/packets/packets/BingoChatMessagePacket.java +++ b/src/main/java/de/hype/bbsentials/packets/packets/BingoChatMessagePacket.java @@ -20,7 +20,6 @@ public class BingoChatMessagePacket extends AbstractPacket { public boolean baseCheck() { boolean cancelPacket = false; - return !cancelPacket; } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index cd5d125..354192c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -34,13 +34,12 @@ "links": { "modmenu.discord": "https://discord.gg/m7gX2GyQYj" }, - "parent": { "id": "bbsentials", "name": "BBsentials", "description": "Mod to connect to the BBsentials Network for Splashes and more", "icon": "logo.png" }, "update_checker": false - } + } }
\ No newline at end of file |