diff options
| author | plutorocks <> | 2026-02-26 16:53:24 -0500 |
|---|---|---|
| committer | plutorocks <> | 2026-02-26 16:53:24 -0500 |
| commit | 8b123f240f098b24f8e348f1f36ab3eb72599176 (patch) | |
| tree | 91a532a9a422104a667137a18137527c83c6889f /src/main/java/dev/plutorocks/PlutoBridge.java | |
Diffstat (limited to 'src/main/java/dev/plutorocks/PlutoBridge.java')
| -rw-r--r-- | src/main/java/dev/plutorocks/PlutoBridge.java | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/src/main/java/dev/plutorocks/PlutoBridge.java b/src/main/java/dev/plutorocks/PlutoBridge.java new file mode 100644 index 0000000..aa3438f --- /dev/null +++ b/src/main/java/dev/plutorocks/PlutoBridge.java @@ -0,0 +1,248 @@ +package dev.plutorocks; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.loader.api.FabricLoader; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class PlutoBridge implements ClientModInitializer { + public static final String MOD_ID = "PlutoBridge"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + + private static final Gson GSON = new Gson(); + private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("bridge.json"); + + public static final int MAX_NICK_LEN = 15; + public static final int MAX_MESSAGE_LEN = 400; // must match server + + public static String bridgeHost = "bridge.plutorocks.dev"; + public static String bridgeToken = ""; + public static String bridgeNick; // will be set from config/session + + public static BridgeClient BRIDGE_CLIENT; + + // false = normal chat default, true = bridge default + public static boolean bridgeChatDefault = false; + + @Override + public void onInitializeClient() { + loadConfig(); + + // Auto-connect if we already have a token + if (bridgeToken != null && !bridgeToken.isEmpty()) { + BRIDGE_CLIENT = new BridgeClient(bridgeHost, bridgeToken, bridgeNick); + BRIDGE_CLIENT.connect(); + } + + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { + dispatcher.register( + literal("bridge") + .then(literal("connect").executes(this::handleConnect)) + .then(literal("disconnect").executes(this::handleDisconnect)) + .then(literal("status").executes(this::handleStatus)) + .then(literal("host") + .then(argument("host", StringArgumentType.word()) + .executes(this::handleSetHost))) + .then(literal("token") + .then(argument("token", StringArgumentType.word()) + .executes(this::handleSetToken))) + .then(literal("nick") + .then(argument("nick", StringArgumentType.word()) + .executes(this::handleSetNick))) + .then(literal("toggle") + .executes(this::handleToggle)) + ); + }); + + LOGGER.info("Bridge client loaded!"); + } + + private static void loadConfig() { + if (!Files.exists(CONFIG_PATH)) { + applyDefaultsFromSession(); + saveConfig(); + return; + } + + try (Reader reader = Files.newBufferedReader(CONFIG_PATH)) { + Config cfg = GSON.fromJson(reader, Config.class); + if (cfg == null) { + applyDefaultsFromSession(); + saveConfig(); + return; + } + + if (cfg.host != null && !cfg.host.isEmpty()) { + bridgeHost = cfg.host; + } else { + bridgeHost = "bridge.plutorocks.dev"; + } + + if (cfg.token != null && !cfg.token.isEmpty()) { + bridgeToken = cfg.token; + } else { + bridgeToken = ""; + } + + if (cfg.nick != null && !cfg.nick.isEmpty()) { + bridgeNick = cfg.nick; + } else { + bridgeNick = defaultNickFromSession(); + } + } catch (IOException | JsonSyntaxException e) { + LOGGER.warn("Failed to read bridge config, using defaults", e); + applyDefaultsFromSession(); + } + } + + private static void saveConfig() { + Config cfg = new Config(); + cfg.host = bridgeHost; + cfg.token = bridgeToken; + cfg.nick = bridgeNick; + + try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { + GSON.toJson(cfg, writer); + } catch (IOException e) { + LOGGER.warn("Failed to save bridge config", e); + } + } + + private static void applyDefaultsFromSession() { + bridgeHost = "bridge.plutorocks.dev"; + bridgeToken = ""; + bridgeNick = defaultNickFromSession(); + } + + private static String defaultNickFromSession() { + MinecraftClient client = MinecraftClient.getInstance(); + if (client != null && client.getSession() != null) { + String name = client.getSession().getUsername(); + if (name != null && !name.isEmpty()) { + return name; + } + } + return "Player"; + } + + private int handleConnect(CommandContext<FabricClientCommandSource> ctx) { + if (bridgeToken == null || bridgeToken.isEmpty()) { + sendCmdFeedback(ctx, "Token is empty. Set it with /bridge token <token> first."); + return 1; + } + + if (BRIDGE_CLIENT != null && BRIDGE_CLIENT.isConnected()) { + sendCmdFeedback(ctx, "Already connected."); + return 1; + } + + if (BRIDGE_CLIENT != null) { + BRIDGE_CLIENT.disconnect(); + } + + BRIDGE_CLIENT = new BridgeClient(bridgeHost, bridgeToken, bridgeNick); + + sendCmdFeedback(ctx, "Connecting to " + bridgeHost + " as " + bridgeNick + "..."); + BRIDGE_CLIENT.connect(); + return 1; + } + + private int handleDisconnect(CommandContext<FabricClientCommandSource> ctx) { + if (BRIDGE_CLIENT == null || !BRIDGE_CLIENT.isConnected()) { + sendCmdFeedback(ctx, "Already disconnected."); + return 1; + } + + BRIDGE_CLIENT.disconnect(); + sendCmdFeedback(ctx, "Disconnected."); + return 1; + } + + private int handleStatus(CommandContext<FabricClientCommandSource> ctx) { + String state = (BRIDGE_CLIENT != null && BRIDGE_CLIENT.isConnected()) ? "Connected" : "Not connected"; + sendCmdFeedback(ctx, state + ". Host=" + bridgeHost + " Nick=" + bridgeNick + + " Mode=" + (bridgeChatDefault ? "BRIDGE" : "CHAT")); + return 1; + } + + private int handleToggle(CommandContext<FabricClientCommandSource> ctx) { + bridgeChatDefault = !bridgeChatDefault; + + if (bridgeChatDefault) { + sendCmdFeedback(ctx, "Bridge mode ON. Messages go to the bridge by default; prefix with ! to send to normal chat."); + } else { + sendCmdFeedback(ctx, "Bridge mode OFF. Messages go to normal chat by default; prefix with ! to send to the bridge."); + } + + return 1; + } + + private int handleSetHost(CommandContext<FabricClientCommandSource> ctx) { + bridgeHost = StringArgumentType.getString(ctx, "host"); + saveConfig(); + sendCmdFeedback(ctx, "Host set to " + bridgeHost + ". Use /bridge connect to apply."); + return 1; + } + + private int handleSetToken(CommandContext<FabricClientCommandSource> ctx) { + bridgeToken = StringArgumentType.getString(ctx, "token"); + saveConfig(); + sendCmdFeedback(ctx, "Token set. Use /bridge connect to apply."); + return 1; + } + + private int handleSetNick(CommandContext<FabricClientCommandSource> ctx) { + String requested = StringArgumentType.getString(ctx, "nick"); + + int nickLength = requested.codePointCount(0, requested.length()); + if (nickLength > MAX_NICK_LEN) { + sendCmdFeedback(ctx, "Nick too long (max " + MAX_NICK_LEN + " characters)."); + return 1; + } + + bridgeNick = requested; + saveConfig(); + + if (PlutoBridge.BRIDGE_CLIENT != null && PlutoBridge.BRIDGE_CLIENT.isConnected()) { + PlutoBridge.BRIDGE_CLIENT.updateNick(bridgeNick); + sendCmdFeedback(ctx, "Nick set to " + bridgeNick + " (updated live)."); + } else { + sendCmdFeedback(ctx, "Nick set to " + bridgeNick + ". Use /bridge connect to apply."); + } + return 1; + } + + private void sendCmdFeedback(CommandContext<FabricClientCommandSource> ctx, String grayMessage) { + MutableText prefix = Text.literal("[Bridge] ").formatted(Formatting.AQUA); + MutableText body = Text.literal(grayMessage).formatted(Formatting.GRAY); + ctx.getSource().sendFeedback(prefix.append(body)); + } + + private static class Config { + String host; + String token; + String nick; + } +}
\ No newline at end of file |
