diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..da500f0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,91 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Mellow is a Minecraft 1.8.9 Forge client mod for Hypixel BedWars & Duels stats checking. It's a fork of [Fontaine](https://github.com/xanning/Fontaine), using OneConfig for GUI (Right Shift to open). No API key required for core features. + +## Build Commands + +```bash +# Requires Java 21 locally (CI uses Java 17) +export JAVA_HOME=$(/usr/libexec/java_home -v 21) + +# Build (also runs tests, copies jar to PrismLauncher mods dir automatically) +./gradlew build + +# Tests only (JUnit 4) +./gradlew test +``` + +Output jar: `versions/1.8.9-forge/build/libs/Mellow-1.8.9-forge-{version}.jar` + +## Build System + +Polyfrost Gradle Toolkit with multi-version support (currently only 1.8.9-forge active). Uses ShadowJar to shade OkHttp3, Hypixel Mod API, and XZ. Blossom for token replacement. Mixin 0.7.11 for bytecode injection. Target compatibility is Java 8. + +## Architecture + +### Entry Point +`Mellow.java` — `@Mod` class. Initializes all services, registers 19 commands and 7 event routers on the Forge event bus. Static fields hold singleton services accessed throughout the codebase. + +- `Mellow.isEnabled()` — central mod toggle check. **All features must gate on this** before doing work. +- `Mellow.config` — the `MellowOneConfig` instance (OneConfig-based, ~1600 lines). + +### Event Flow +Forge events → **Event Routers** (`core/event/`) → **Feature Services** + +Routers are thin dispatchers registered on `MinecraftForge.EVENT_BUS`: +- `ChatEventRouter` — chat messages → denicker, pregame stats, request popups, auto /who +- `ClientTickRouter` — per-tick → HypixelFeatures game state, replay manager +- `TabOverlayRouter` — tab key rendering → extended stats tab overlay +- `WorldLifecycleRouter` — world load → cache clearing +- `NametagColorRouter` — pre/post render → nametag color + client icon context +- `RequestPopupRouter` — overlay render + keybind input → popup accept/deny +- `ReplayHudRouter` / `ReplayInputRouter` — replay UI + +### Game State +`HypixelFeatures` (singleton) tracks Hypixel server state via scoreboard/tab parsing. Produces `GameSnapshot` objects consumed by listeners via `addGameStateListener()`. This runs even when the mod is toggled off so state is available on re-enable. + +### Stats Pipeline +1. **ProviderManager** selects active provider (HypixelPublicApi, NadeshikoApi, AbyssApi) +2. **PlayerCache** fetches/caches profiles with scoped stat requests (`StatScope`) +3. **StatsChecker** formats stats for display +4. **InGameTabStatsSyncService** pushes stats into `Mellow.tabStats` map (consumed by tab mixin) +5. **GuiPlayerTabOverlayMixin** reads `tabStats` to modify vanilla tab list names + +### Async Execution +`AsyncExecutor` singleton manages 5 thread pools: `profileIo` (8), `chat` (4), `command` (4), `supplementalIo` (4), `replayIo` (1). `MainThreadDispatcher` posts runnables back to the client thread. + +### Mixin Layer (`mixin/`) +- `GuiPlayerTabOverlayMixin` — injects stats into tab list player names +- `PingMixin` — overrides `NetworkPlayerInfo.getResponseTime` with external ping data +- `nametag/` — color backgrounds + client icon rendering on nametags +- `hitbox/` — team-colored hitboxes +- `replay/` — packet capture via `NetworkManager` injection +- `compat/` — compatibility with PolyNametag, PolyHitbox, VanillaHUD, Overflow Animations + +### API Integrations (`api/`) +External services with their own caching: Aurora (denicking, pings, winstreaks), Seraph (client detection, pings, tags), Urchin (tags), Luna (pings), Mojang (UUID/profile), Hypixel Mod API (game state). + +### Feature Modules (`feature/`) +- `stats/` — pregame stats, in-game tab sync, extended tab overlay with scrolling +- `replay/` — packet-level game recording/playback with seeking, browser GUI +- `nicks/` — skin denicking + number-pattern denicking +- `requestpopup/` — friend/party request accept/deny overlay +- `profileviewer/` — `/pv` GUI with parsed stats +- `party/` — blacklisted party member warnings +- `tags/` — Urchin/Seraph tag display + +### Lists (`util/`) +Blacklist, annoylist, and tag-ignore — file-backed with import support. Stored in `.minecraft/config/mellow/`. + +## Key Conventions + +- Config lives in one large `MellowOneConfig` class with OneConfig annotations (`@Switch`, `@Dropdown`, `@Number`, etc.) +- Commands extend Forge's `ICommand`, registered in `Mellow.init()` +- Mixin config: `src/main/resources/mixins.mellow.json` +- Assets: `src/main/resources/assets/mellow/` (textures for client icons, GUI, socials) +- All API calls should go through the async executor, never on the main thread +- Feature gating pattern: check `Mellow.isEnabled()` at event handler / mixin entry points diff --git a/build.gradle.kts b/build.gradle.kts index c8d2488..7d9f81a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -222,23 +222,17 @@ tasks.named("build") { // Ensure the built JAR file exists before proceeding if (finalJar.exists()) { - // Additional destination directory val home = System.getProperty("user.home") - val additionalDestDir = + val modrinthDestDir = file( - "$home/Library/Application Support/PrismLauncher/instances/1.8.9/.minecraft/mods" + "$home/Library/Application Support/ModrinthApp/profiles/1.8.9/mods" ) - - // Ensure the destination directory exists - additionalDestDir.mkdirs() - - // Copy the final JAR to the additional directory + modrinthDestDir.mkdirs() copy { from(finalJar) - into(additionalDestDir) + into(modrinthDestDir) } - - println("JAR file copied to: ${additionalDestDir.absolutePath}") + println("JAR file copied to: ${modrinthDestDir.absolutePath}") } else { println("Built JAR file does not exist: ${finalJar.absolutePath}") } diff --git a/src/main/java/com/roxiun/mellow/Mellow.java b/src/main/java/com/roxiun/mellow/Mellow.java index bdede05..0778dc8 100644 --- a/src/main/java/com/roxiun/mellow/Mellow.java +++ b/src/main/java/com/roxiun/mellow/Mellow.java @@ -48,6 +48,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import net.minecraft.client.settings.KeyBinding; +import net.minecraft.command.ICommand; import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.common.MinecraftForge; @@ -224,57 +225,25 @@ public void run() { new TabOverlayInputRouter(tabOverlayRouter) ); - ClientCommandHandler.instance.registerCommand( - new BedwarsCommand(playerCache, config) - ); - ClientCommandHandler.instance.registerCommand( - new SkywarsCommand(playerCache, config) - ); - ClientCommandHandler.instance.registerCommand( - new PVCommand(playerCache, config) - ); - ClientCommandHandler.instance.registerCommand(new MellowCommand()); - ClientCommandHandler.instance.registerCommand(new DebugStateCommand()); - ClientCommandHandler.instance.registerCommand( - new ClearCacheCommand(playerCache, tabStats) - ); - ClientCommandHandler.instance.registerCommand( - new RefreshCommand(inGameTabStatsSyncService) - ); - ClientCommandHandler.instance.registerCommand( - new DenickCommand(config, auroraApi) - ); - ClientCommandHandler.instance.registerCommand( - new SkinDenickCommand(playerCache) - ); - ClientCommandHandler.instance.registerCommand( - new BlacklistCommand(blacklistManager, mojangApi) - ); - ClientCommandHandler.instance.registerCommand( - new AnnoylistCommand(annoylistManager, mojangApi) - ); - ClientCommandHandler.instance.registerCommand( - new TagIgnoreCommand(tagIgnoreManager, mojangApi) - ); - ClientCommandHandler.instance.registerCommand( - new UrchinCommand(urchinApi, mojangApi, config) - ); - ClientCommandHandler.instance.registerCommand( - new SeraphCommand(seraphApi, mojangApi, config) - ); - ClientCommandHandler.instance.registerCommand( - new StatusCommand(mojangApi, config) - ); - ClientCommandHandler.instance.registerCommand( - new NameHistoryCommand(mojangApi) - ); - ClientCommandHandler.instance.registerCommand( - new ClientCommand(seraphApi, mojangApi, config) - ); - ClientCommandHandler.instance.registerCommand( - new WinstreakCommand(playerCache, config) - ); - ClientCommandHandler.instance.registerCommand(new ReplayCommand(replayManager)); + registerCommand(new BedwarsCommand(playerCache, config)); + registerCommand(new SkywarsCommand(playerCache, config)); + registerCommand(new PVCommand(playerCache, config)); + registerCommand(new MellowCommand()); + registerCommand(new DebugStateCommand()); + registerCommand(new ClearCacheCommand(playerCache, tabStats)); + registerCommand(new RefreshCommand(inGameTabStatsSyncService)); + registerCommand(new DenickCommand(config, auroraApi)); + registerCommand(new SkinDenickCommand(playerCache)); + registerCommand(new BlacklistCommand(blacklistManager, mojangApi)); + registerCommand(new AnnoylistCommand(annoylistManager, mojangApi)); + registerCommand(new TagIgnoreCommand(tagIgnoreManager, mojangApi)); + registerCommand(new UrchinCommand(urchinApi, mojangApi, config)); + registerCommand(new SeraphCommand(seraphApi, mojangApi, config)); + registerCommand(new StatusCommand(mojangApi, config)); + registerCommand(new NameHistoryCommand(mojangApi)); + registerCommand(new ClientCommand(seraphApi, mojangApi, config)); + registerCommand(new WinstreakCommand(playerCache, config)); + registerCommand(new ReplayCommand(replayManager)); } public StatsProvider getStatsProvider() { @@ -284,7 +253,21 @@ public StatsProvider getStatsProvider() { return providerManager.getSelectedProvider(config); } + /** + * Central mod-enabled check. All features, event handlers, mixins, + * and HUD elements should gate on this before doing any work. + */ + public static boolean isEnabled() { + return config != null && config.modEnabled; + } + public static AnticheatManager getAnticheatManager() { return anticheatManager; } + + private void registerCommand(ICommand command) { + ClientCommandHandler + .instance + .registerCommand(CommandToggleWrapper.wrap(command)); + } } diff --git a/src/main/java/com/roxiun/mellow/anticheat/event/AnticheatListener.java b/src/main/java/com/roxiun/mellow/anticheat/event/AnticheatListener.java index f40e936..2ba9d0d 100644 --- a/src/main/java/com/roxiun/mellow/anticheat/event/AnticheatListener.java +++ b/src/main/java/com/roxiun/mellow/anticheat/event/AnticheatListener.java @@ -28,7 +28,7 @@ public void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public void onPlayerTick(TickEvent.PlayerTickEvent event) { - if (!Mellow.config.anticheatEnabled) return; + if (!Mellow.isEnabled() || !Mellow.config.anticheatEnabled) return; if (event.phase == TickEvent.Phase.START) { ACPlayerData data = manager.getPlayerData(event.player); @@ -114,7 +114,7 @@ public void onPlayerTick(TickEvent.PlayerTickEvent event) { @SubscribeEvent public void onEntityJoinWorld(EntityJoinWorldEvent event) { - if (!Mellow.config.anticheatEnabled) return; + if (!Mellow.isEnabled() || !Mellow.config.anticheatEnabled) return; if (event.entity instanceof EntityPlayer) { manager.registerPlayer((EntityPlayer) event.entity); } diff --git a/src/main/java/com/roxiun/mellow/commands/CommandToggleWrapper.java b/src/main/java/com/roxiun/mellow/commands/CommandToggleWrapper.java new file mode 100644 index 0000000..3711152 --- /dev/null +++ b/src/main/java/com/roxiun/mellow/commands/CommandToggleWrapper.java @@ -0,0 +1,81 @@ +package com.roxiun.mellow.commands; + +import com.roxiun.mellow.Mellow; +import com.roxiun.mellow.util.ChatUtils; +import java.util.Collections; +import java.util.List; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.BlockPos; + +public class CommandToggleWrapper implements ICommand { + + private final ICommand delegate; + + private CommandToggleWrapper(ICommand delegate) { + this.delegate = delegate; + } + + public static ICommand wrap(ICommand command) { + if (command instanceof CommandToggleWrapper) { + return command; + } + return new CommandToggleWrapper(command); + } + + @Override + public String getCommandName() { + return delegate.getCommandName(); + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return delegate.getCommandUsage(sender); + } + + @Override + public List getCommandAliases() { + return delegate.getCommandAliases(); + } + + @Override + public void processCommand(ICommandSender sender, String[] args) + throws CommandException { + if (!Mellow.isEnabled()) { + ChatUtils.sendCommandMessage( + sender, + "§cMellow is disabled. Enable it in the config to use commands." + ); + return; + } + delegate.processCommand(sender, args); + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + return Mellow.isEnabled() && delegate.canCommandSenderUseCommand(sender); + } + + @Override + public List addTabCompletionOptions( + ICommandSender sender, + String[] args, + BlockPos pos + ) { + if (!Mellow.isEnabled()) { + return Collections.emptyList(); + } + return delegate.addTabCompletionOptions(sender, args, pos); + } + + @Override + public boolean isUsernameIndex(String[] args, int index) { + return delegate.isUsernameIndex(args, index); + } + + @Override + public int compareTo(ICommand other) { + return delegate.compareTo(other); + } +} diff --git a/src/main/java/com/roxiun/mellow/config/MellowOneConfig.java b/src/main/java/com/roxiun/mellow/config/MellowOneConfig.java index 54cd84a..db60d95 100644 --- a/src/main/java/com/roxiun/mellow/config/MellowOneConfig.java +++ b/src/main/java/com/roxiun/mellow/config/MellowOneConfig.java @@ -21,9 +21,15 @@ public class MellowOneConfig extends Config { + @Switch(name = "Mod Enabled", subcategory = "General", description = "Master toggle to enable or disable the entire mod.") + public boolean modEnabled = true; + @Switch(name = "Auto /who", subcategory = "General") public boolean autoWho = false; + @Switch(name = "Hide Auto /who Response", subcategory = "General", description = "Hides the ONLINE: player list response when auto /who is triggered.") + public boolean hideAutoWhoResponse = true; + @Switch(name = "Show Tab Stats", subcategory = "General") public boolean tabStats = true; diff --git a/src/main/java/com/roxiun/mellow/core/event/ChatEventRouter.java b/src/main/java/com/roxiun/mellow/core/event/ChatEventRouter.java index ca9d6f7..5277ecb 100644 --- a/src/main/java/com/roxiun/mellow/core/event/ChatEventRouter.java +++ b/src/main/java/com/roxiun/mellow/core/event/ChatEventRouter.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.core.event; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.api.hypixel.HypixelFeatures; import com.roxiun.mellow.config.MellowOneConfig; import com.roxiun.mellow.feature.nicks.NumberDenicker; @@ -9,16 +10,25 @@ import com.roxiun.mellow.module.bedwars.BedwarsChatSignalParser; import net.minecraft.client.Minecraft; import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class ChatEventRouter { + private static final String AUTO_WHO_RESPONSE_PREFIX = "ONLINE: "; + private static final int AUTO_WHO_RESPONSE_PREFIX_LENGTH = + AUTO_WHO_RESPONSE_PREFIX.length(); + // Few chat lines immediately follow the server-side /who response. + private static final int AUTO_WHO_RESPONSE_WATCH_LIMIT = 6; + private final Minecraft mc = Minecraft.getMinecraft(); private final MellowOneConfig config; private final NumberDenicker numberDenicker; private final PregameStats pregameStats; private final RequestPopupService requestPopupService; + private int autoWhoResponseWatchRemaining; + public ChatEventRouter( MellowOneConfig config, NumberDenicker numberDenicker, @@ -31,25 +41,57 @@ public ChatEventRouter( this.requestPopupService = requestPopupService; } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.HIGH) public void onChat(ClientChatReceivedEvent event) { + String message = event.message.getUnformattedText(); + + // Game state tracking and replay always run regardless of mod toggle + HypixelFeatures.getInstance().onChat(message); + ReplayManager.getInstance().onChatReceived(event.message, event.type); + + if (!Mellow.isEnabled()) { + autoWhoResponseWatchRemaining = 0; + return; + } + + boolean autoWhoEnabled = config.autoWho; + boolean hideAutoWhoResponse = + autoWhoEnabled && config.hideAutoWhoResponse; + + if (!hideAutoWhoResponse) { + autoWhoResponseWatchRemaining = 0; + } else if (autoWhoResponseWatchRemaining > 0) { + if ( + message.length() >= AUTO_WHO_RESPONSE_PREFIX_LENGTH && + message.regionMatches( + 0, + AUTO_WHO_RESPONSE_PREFIX, + 0, + AUTO_WHO_RESPONSE_PREFIX_LENGTH + ) + ) { + autoWhoResponseWatchRemaining = 0; + event.setCanceled(true); + return; + } + autoWhoResponseWatchRemaining--; + } + numberDenicker.onChat(event); pregameStats.onChat(event); - String message = event.message.getUnformattedText(); if (requestPopupService != null) { requestPopupService.onChatMessage(message); } - HypixelFeatures.getInstance().onChat(message); - ReplayManager.getInstance().onChatReceived(event.message, event.type); if ( - BedwarsChatSignalParser.isBedwarsStartMessage(message) || - BedwarsChatSignalParser.isBedwarsRespawnMessage(message) + autoWhoEnabled && + (BedwarsChatSignalParser.isBedwarsStartMessage(message) || + BedwarsChatSignalParser.isBedwarsRespawnMessage(message)) ) { - if (config.autoWho) { - mc.thePlayer.sendChatMessage("/who"); - } + autoWhoResponseWatchRemaining = + hideAutoWhoResponse ? AUTO_WHO_RESPONSE_WATCH_LIMIT : 0; + mc.thePlayer.sendChatMessage("/who"); } } } diff --git a/src/main/java/com/roxiun/mellow/core/event/NametagColorRouter.java b/src/main/java/com/roxiun/mellow/core/event/NametagColorRouter.java index a549dea..66247ef 100644 --- a/src/main/java/com/roxiun/mellow/core/event/NametagColorRouter.java +++ b/src/main/java/com/roxiun/mellow/core/event/NametagColorRouter.java @@ -25,7 +25,7 @@ public void onPreRenderNametag( ) { NametagRenderContext.clear(); - if (config == null) { + if (!Mellow.isEnabled()) { return; } diff --git a/src/main/java/com/roxiun/mellow/core/event/RequestPopupRouter.java b/src/main/java/com/roxiun/mellow/core/event/RequestPopupRouter.java index 31374a8..b72c669 100644 --- a/src/main/java/com/roxiun/mellow/core/event/RequestPopupRouter.java +++ b/src/main/java/com/roxiun/mellow/core/event/RequestPopupRouter.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.core.event; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.config.MellowOneConfig; import com.roxiun.mellow.feature.requestpopup.RequestPopupManager; import com.roxiun.mellow.feature.requestpopup.RequestPopupPosition; @@ -51,6 +52,9 @@ public void onRenderOverlay(RenderGameOverlayEvent.Post event) { if (mc == null || mc.fontRendererObj == null || popupManager == null) { return; } + if (!Mellow.isEnabled()) { + return; + } RequestPopupManager.ActiveRequest activeRequest = popupManager.getActiveRequest(); if (activeRequest == null) { @@ -65,6 +69,7 @@ public void onKeyInput(InputEvent.KeyInputEvent event) { if ( config == null || popupManager == null || + !Mellow.isEnabled() || !config.requestPopupsEnabled || !Keyboard.getEventKeyState() || mc == null diff --git a/src/main/java/com/roxiun/mellow/core/event/TabOverlayRouter.java b/src/main/java/com/roxiun/mellow/core/event/TabOverlayRouter.java index 0cd76f1..1404841 100644 --- a/src/main/java/com/roxiun/mellow/core/event/TabOverlayRouter.java +++ b/src/main/java/com/roxiun/mellow/core/event/TabOverlayRouter.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.core.event; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.api.hypixel.HypixelFeatures; import com.roxiun.mellow.api.provider.model.StatScope; import com.roxiun.mellow.config.MellowOneConfig; @@ -147,7 +148,7 @@ public ExtendedStatsTabOverlay getOverlay() { private boolean isExtendedModeActive(StatScope scope) { return ( - config != null && + Mellow.isEnabled() && config.tabStats && config.extendedTabStatsView && scope != null && diff --git a/src/main/java/com/roxiun/mellow/feature/party/PartyBlacklistWarningService.java b/src/main/java/com/roxiun/mellow/feature/party/PartyBlacklistWarningService.java index 8f92f6a..c8da023 100644 --- a/src/main/java/com/roxiun/mellow/feature/party/PartyBlacklistWarningService.java +++ b/src/main/java/com/roxiun/mellow/feature/party/PartyBlacklistWarningService.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.feature.party; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.cache.PlayerCache; import com.roxiun.mellow.config.MellowOneConfig; import com.roxiun.mellow.core.async.AsyncExecutor; @@ -94,7 +95,7 @@ public PartyBlacklistWarningService( } public synchronized void onSnapshotUpdate(GameSnapshot snapshot) { - if (config == null || !config.partyBlacklistWarning) { + if (!Mellow.isEnabled() || config == null || !config.partyBlacklistWarning) { resetState(); return; } diff --git a/src/main/java/com/roxiun/mellow/feature/replay/ReplayHudRouter.java b/src/main/java/com/roxiun/mellow/feature/replay/ReplayHudRouter.java index a4556c8..b6d95cf 100644 --- a/src/main/java/com/roxiun/mellow/feature/replay/ReplayHudRouter.java +++ b/src/main/java/com/roxiun/mellow/feature/replay/ReplayHudRouter.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.feature.replay; +import com.roxiun.mellow.Mellow; import java.util.List; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; @@ -16,7 +17,7 @@ public ReplayHudRouter(ReplayManager replayManager) { @SubscribeEvent public void onRenderOverlay(RenderGameOverlayEvent.Text event) { - if (!replayManager.isPlaybackActive()) { + if (!Mellow.isEnabled() || !replayManager.isPlaybackActive()) { return; } diff --git a/src/main/java/com/roxiun/mellow/feature/replay/ReplayInputRouter.java b/src/main/java/com/roxiun/mellow/feature/replay/ReplayInputRouter.java index 184ef8e..2e043f4 100644 --- a/src/main/java/com/roxiun/mellow/feature/replay/ReplayInputRouter.java +++ b/src/main/java/com/roxiun/mellow/feature/replay/ReplayInputRouter.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.feature.replay; +import com.roxiun.mellow.Mellow; import net.minecraft.client.Minecraft; import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -15,6 +16,9 @@ public ReplayInputRouter(ReplayManager replayManager) { @SubscribeEvent public void onMouse(MouseEvent event) { + if (!Mellow.isEnabled()) { + return; + } if (event.dwheel != 0 || !event.buttonstate) { return; } diff --git a/src/main/java/com/roxiun/mellow/feature/stats/InGameTabStatsSyncService.java b/src/main/java/com/roxiun/mellow/feature/stats/InGameTabStatsSyncService.java index 6c78767..1e7ce85 100644 --- a/src/main/java/com/roxiun/mellow/feature/stats/InGameTabStatsSyncService.java +++ b/src/main/java/com/roxiun/mellow/feature/stats/InGameTabStatsSyncService.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.feature.stats; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.config.MellowOneConfig; import com.roxiun.mellow.data.TabStats; import com.roxiun.mellow.feature.nicks.NickUtils; @@ -47,6 +48,13 @@ public InGameTabStatsSyncService( public synchronized void onSnapshotUpdate(GameSnapshot snapshot) { currentSnapshot = snapshot; + if (!Mellow.isEnabled()) { + if (inSupportedMatch) { + tabStats.clear(); + } + resetTracking(); + return; + } boolean supportedNow = isSupportedMatch(snapshot); if (!supportedNow) { if (inSupportedMatch) { diff --git a/src/main/java/com/roxiun/mellow/hud/BedwarsUpgradesTrapsHUD.java b/src/main/java/com/roxiun/mellow/hud/BedwarsUpgradesTrapsHUD.java index 8fbd41a..befc018 100644 --- a/src/main/java/com/roxiun/mellow/hud/BedwarsUpgradesTrapsHUD.java +++ b/src/main/java/com/roxiun/mellow/hud/BedwarsUpgradesTrapsHUD.java @@ -4,6 +4,7 @@ import cc.polyfrost.oneconfig.config.annotations.Switch; import cc.polyfrost.oneconfig.config.core.OneColor; import cc.polyfrost.oneconfig.hud.TextHud; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.api.hypixel.HypixelFeatures; import com.roxiun.mellow.util.MinecraftColor; import java.util.List; @@ -92,6 +93,7 @@ public BedwarsUpgradesTrapsHUD() { @Override public boolean shouldShow() { return ( + Mellow.isEnabled() && super.shouldShow() && HypixelFeatures.getInstance().isInBedwars() ); } diff --git a/src/main/java/com/roxiun/mellow/hud/DiamondCounterHUD.java b/src/main/java/com/roxiun/mellow/hud/DiamondCounterHUD.java index c868957..fc4114b 100644 --- a/src/main/java/com/roxiun/mellow/hud/DiamondCounterHUD.java +++ b/src/main/java/com/roxiun/mellow/hud/DiamondCounterHUD.java @@ -2,6 +2,7 @@ import cc.polyfrost.oneconfig.config.core.OneColor; import cc.polyfrost.oneconfig.hud.SingleTextHud; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.api.hypixel.HypixelFeatures; public class DiamondCounterHUD extends SingleTextHud { @@ -29,6 +30,7 @@ public DiamondCounterHUD() { @Override public boolean shouldShow() { return ( + Mellow.isEnabled() && super.shouldShow() && HypixelFeatures.getInstance().isInBedwars() ); } diff --git a/src/main/java/com/roxiun/mellow/hud/EmeraldCounterHUD.java b/src/main/java/com/roxiun/mellow/hud/EmeraldCounterHUD.java index 59f0c25..43d29c5 100644 --- a/src/main/java/com/roxiun/mellow/hud/EmeraldCounterHUD.java +++ b/src/main/java/com/roxiun/mellow/hud/EmeraldCounterHUD.java @@ -2,6 +2,7 @@ import cc.polyfrost.oneconfig.config.core.OneColor; import cc.polyfrost.oneconfig.hud.SingleTextHud; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.api.hypixel.HypixelFeatures; public class EmeraldCounterHUD extends SingleTextHud { @@ -29,6 +30,7 @@ public EmeraldCounterHUD() { @Override public boolean shouldShow() { return ( + Mellow.isEnabled() && super.shouldShow() && HypixelFeatures.getInstance().isInBedwars() ); } diff --git a/src/main/java/com/roxiun/mellow/mixin/GuiPlayerTabOverlayMixin.java b/src/main/java/com/roxiun/mellow/mixin/GuiPlayerTabOverlayMixin.java index c654f62..12139d8 100644 --- a/src/main/java/com/roxiun/mellow/mixin/GuiPlayerTabOverlayMixin.java +++ b/src/main/java/com/roxiun/mellow/mixin/GuiPlayerTabOverlayMixin.java @@ -31,7 +31,7 @@ public void getPlayerName( NetworkPlayerInfo networkPlayerInfoIn, CallbackInfoReturnable cir ) { - if (Mellow.config == null || !Mellow.config.tabStats) { + if (!Mellow.isEnabled() || !Mellow.config.tabStats) { return; } diff --git a/src/main/java/com/roxiun/mellow/mixin/PingMixin.java b/src/main/java/com/roxiun/mellow/mixin/PingMixin.java index a5ad940..4f0c11d 100644 --- a/src/main/java/com/roxiun/mellow/mixin/PingMixin.java +++ b/src/main/java/com/roxiun/mellow/mixin/PingMixin.java @@ -20,6 +20,10 @@ public class PingMixin { @Inject(method = "getResponseTime", at = @At("HEAD"), cancellable = true) private void onGetResponseTime(CallbackInfoReturnable cir) { + if (!Mellow.isEnabled()) { + return; + } + int original = this.responseTime; NetworkPlayerInfo info = (NetworkPlayerInfo) (Object) this; diff --git a/src/main/java/com/roxiun/mellow/mixin/hitbox/RenderGlobalHitboxColorMixin.java b/src/main/java/com/roxiun/mellow/mixin/hitbox/RenderGlobalHitboxColorMixin.java index cc704c6..e48c404 100644 --- a/src/main/java/com/roxiun/mellow/mixin/hitbox/RenderGlobalHitboxColorMixin.java +++ b/src/main/java/com/roxiun/mellow/mixin/hitbox/RenderGlobalHitboxColorMixin.java @@ -35,6 +35,9 @@ public static void drawOutlinedBoundingBox( int alpha, CallbackInfo ci ) { + if (!Mellow.isEnabled()) { + return; + } MellowOneConfig config = Mellow.config; if ( config == null || diff --git a/src/main/java/com/roxiun/mellow/mixin/replay/NetworkManagerReplayCaptureMixin.java b/src/main/java/com/roxiun/mellow/mixin/replay/NetworkManagerReplayCaptureMixin.java index 9f36f6a..16a9465 100644 --- a/src/main/java/com/roxiun/mellow/mixin/replay/NetworkManagerReplayCaptureMixin.java +++ b/src/main/java/com/roxiun/mellow/mixin/replay/NetworkManagerReplayCaptureMixin.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.mixin.replay; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.feature.replay.ReplayManager; import io.netty.channel.ChannelHandlerContext; import net.minecraft.network.NetworkManager; @@ -18,14 +19,22 @@ public class NetworkManagerReplayCaptureMixin { Packet packet, CallbackInfo ci ) { - ReplayManager.getInstance().onInboundPacket(packet); + if (Mellow.isEnabled()) { + ReplayManager.getInstance().onInboundPacket(packet); + } } - @Inject(method = "sendPacket(Lnet/minecraft/network/Packet;)V", at = @At("HEAD")) + @Inject( + method = "sendPacket(Lnet/minecraft/network/Packet;)V", + at = @At("HEAD"), + cancellable = true + ) private void mellow$captureOutboundPacket( Packet packet, CallbackInfo ci ) { - ReplayManager.getInstance().onOutboundPacket(packet); + if (Mellow.isEnabled()) { + ReplayManager.getInstance().onOutboundPacket(packet); + } } } diff --git a/src/main/java/com/roxiun/mellow/module/ModuleManager.java b/src/main/java/com/roxiun/mellow/module/ModuleManager.java index 3b3760e..12fc220 100644 --- a/src/main/java/com/roxiun/mellow/module/ModuleManager.java +++ b/src/main/java/com/roxiun/mellow/module/ModuleManager.java @@ -1,5 +1,6 @@ package com.roxiun.mellow.module; +import com.roxiun.mellow.Mellow; import com.roxiun.mellow.gamestate.GameSnapshot; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -13,12 +14,18 @@ public void registerModule(GameModule module) { } public void tick(GameSnapshot snapshot) { + if (!Mellow.isEnabled()) { + return; + } for (GameModule module : modules) { module.onTick(snapshot); } } public void chat(String message, GameSnapshot snapshot) { + if (!Mellow.isEnabled()) { + return; + } for (GameModule module : modules) { module.onChat(message, snapshot); }