package ru.nevetime.clientirc; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.message.v1.ClientSendMessageEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class ClientIrcMod implements ClientModInitializer { public static final String MOD_ID = "clientirc"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); private static final String COMMAND_PREFIX = ".irc"; private static IrcConfig config; private static IrcService service; @Override public void onInitializeClient() { config = IrcConfig.load(FabricLoader.getInstance().getConfigDir().resolve("clientirc.json")); service = new IrcService(config, LOGGER); ClientLifecycleEvents.CLIENT_STARTED.register(client -> { if (config.autoConnect) { service.connect(resolvePlayerName(client)); } }); ClientTickEvents.END_CLIENT_TICK.register(client -> { IrcService.DisplayLine line; while ((line = service.pollLine()) != null) { Formatting color = line.system() ? Formatting.GRAY : Formatting.AQUA; pushClientChat(client, Text.literal(line.text()).formatted(color)); } }); ClientSendMessageEvents.ALLOW_CHAT.register(message -> !interceptOutgoingChat(message)); } private static boolean interceptOutgoingChat(String rawMessage) { String trimmed = rawMessage.trim(); if (!trimmed.startsWith(COMMAND_PREFIX)) { return false; } MinecraftClient client = MinecraftClient.getInstance(); String argument = trimmed.length() == COMMAND_PREFIX.length() ? "" : trimmed.substring(COMMAND_PREFIX.length()).trim(); if (argument.isBlank()) { pushClientChat(client, Text.literal("[IRC] Usage: .irc | .irc status | .irc reconnect | .irc reload").formatted(Formatting.YELLOW)); return true; } if ("status".equalsIgnoreCase(argument)) { String status = service.isConnected() ? "connected" : "disconnected"; pushClientChat(client, Text.literal("[IRC] " + status + " | " + config.host + ":" + config.port + " | clientName=" + config.clientName).formatted(Formatting.YELLOW)); return true; } if ("reconnect".equalsIgnoreCase(argument)) { boolean connected = service.reconnect(resolvePlayerName(client)); Formatting color = connected ? Formatting.GREEN : Formatting.RED; pushClientChat(client, Text.literal("[IRC] reconnect " + (connected ? "ok" : "failed")).formatted(color)); return true; } if ("reload".equalsIgnoreCase(argument)) { config = IrcConfig.load(FabricLoader.getInstance().getConfigDir().resolve("clientirc.json")); service.updateConfig(config); pushClientChat(client, Text.literal("[IRC] config reloaded").formatted(Formatting.YELLOW)); return true; } if (!service.ensureConnected(resolvePlayerName(client))) { pushClientChat(client, Text.literal("[IRC] server is offline or config is wrong").formatted(Formatting.RED)); return true; } boolean sent = service.sendChat(resolvePlayerName(client), argument); if (!sent) { pushClientChat(client, Text.literal("[IRC] send failed").formatted(Formatting.RED)); } return true; } private static void pushClientChat(MinecraftClient client, Text text) { if (client == null) { return; } client.execute(() -> client.inGameHud.getChatHud().addMessage(text)); } private static String resolvePlayerName(MinecraftClient client) { if (client != null && client.player != null) { return client.player.getGameProfile().getName(); } if (client != null && client.getSession() != null) { return client.getSession().getUsername(); } return "unknown"; } }