diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/GameRendererMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/GameRendererMixin.java index 5c5cddd310..9fdad8a1b8 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/GameRendererMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/GameRendererMixin.java @@ -90,6 +90,7 @@ public abstract class GameRendererMixin { @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;render3dHud(Lnet/minecraft/client/renderer/state/level/CameraRenderState;Lnet/minecraft/client/renderer/state/level/PlayerRenderState;Lnet/minecraft/client/renderer/state/OptionsRenderState;Z)V")) private void onRenderLevel(CallbackInfo ci, @Local(name = "projectionMatrix") Matrix4f projectionMatrix, @Local(name = "cameraState") CameraRenderState cameraState, @Local(name = "worldPartialTicks") float worldPartialTicks, @Local(name = "bobStack") PoseStack bobStack) { + Modules.get().updateModuleSubscriptions(); if (!Utils.canUpdate()) return; Profiler.get().push(MeteorClient.MOD_ID + "_render"); @@ -139,6 +140,7 @@ private void onRenderLevel(CallbackInfo ci, @Local(name = "projectionMatrix") Ma @Inject(method = "renderLevel", at = @At("TAIL")) private void onRenderLevelTail(CallbackInfo ci) { + Modules.get().updateModuleSubscriptions(); MeteorClient.EVENT_BUS.post(RenderAfterWorldEvent.get()); } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/MinecraftMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/MinecraftMixin.java index 30ca66bafe..6cf834fbdb 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/MinecraftMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/MinecraftMixin.java @@ -117,6 +117,8 @@ private void onPreTick(CallbackInfo ci) { startUseItemCalled = false; + Modules.get().updateModuleSubscriptions(); + Profiler.get().push(MeteorClient.MOD_ID + "_pre_update"); MeteorClient.EVENT_BUS.post(TickEvent.Pre.get()); Profiler.get().pop(); @@ -127,6 +129,8 @@ private void onPreTick(CallbackInfo ci) { @Inject(at = @At("TAIL"), method = "tick") private void onTick(CallbackInfo ci) { + Modules.get().updateModuleSubscriptions(); + Profiler.get().push(MeteorClient.MOD_ID + "_post_update"); MeteorClient.EVENT_BUS.post(TickEvent.Post.get()); Profiler.get().pop(); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java index d0423ebc1e..a15a146e4b 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java @@ -40,6 +40,9 @@ public abstract class Module implements ISerializable, Comparable { private final Set active = new ReferenceOpenHashSet<>(); private @Nullable Module moduleToBind; private boolean awaitingKeyRelease = false; + private boolean inGame, moduleSubscriptionsDirty = true, lastCanUpdate; public Modules() { super("modules"); @@ -317,24 +318,57 @@ private void onOpenScreen(OpenScreenEvent event) { @EventHandler private void onGameJoined(GameJoinedEvent event) { synchronized (active) { + inGame = true; + moduleSubscriptionsDirty = true; + for (Module module : getAll()) { - if (module.isActive() && !module.runInMainMenu) { - MeteorClient.EVENT_BUS.subscribe(module); - module.onActivate(); - } + if (module.isActive() && !module.runInMainMenu) module.activate(); } + + updateModuleSubscriptions(); } } @EventHandler private void onGameLeft(GameLeftEvent event) { synchronized (active) { + inGame = false; + moduleSubscriptionsDirty = true; + for (Module module : getAll()) { - if (module.isActive() && !module.runInMainMenu) { - MeteorClient.EVENT_BUS.unsubscribe(module); - module.onDeactivate(); - } + if (!module.runInMainMenu) module.deactivate(); + } + + updateModuleSubscriptions(); + } + } + + boolean isInGame() { + return inGame; + } + + void markModuleSubscriptionsDirty() { + moduleSubscriptionsDirty = true; + } + + /** + * Suspends event delivery while the player or world is unavailable without changing module + * activation state. Lifecycle callbacks are driven by explicit game join/leave events. + */ + public void updateModuleSubscriptions() { + synchronized (active) { + boolean canUpdate = inGame && Utils.canUpdate(); + if (!moduleSubscriptionsDirty && canUpdate == lastCanUpdate) return; + + for (Module module : getAll()) { + if (module.runInMainMenu) continue; + + if (canUpdate && module.isActive() && !module.isActivated()) module.activate(); + module.updateSubscription(); } + + lastCanUpdate = canUpdate; + moduleSubscriptionsDirty = false; } } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/Zoom.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/Zoom.java index f8e9d6fdd8..f12f967758 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/Zoom.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/Zoom.java @@ -5,7 +5,6 @@ package meteordevelopment.meteorclient.systems.modules.render; -import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.events.meteor.MouseScrollEvent; import meteordevelopment.meteorclient.events.render.GetFovEvent; import meteordevelopment.meteorclient.events.render.Render3DEvent; @@ -87,7 +86,7 @@ public void onActivate() { value = zoom.get(); time = 0.001; - MeteorClient.EVENT_BUS.subscribe(this); + subscribeToEvents(); enabled = true; } @@ -105,7 +104,7 @@ private void onTick(TickEvent.Post event) { } if (time == 0) { - MeteorClient.EVENT_BUS.unsubscribe(this); + unsubscribeFromEvents(); enabled = false; onStop(); diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/InvUtils.java b/src/main/java/meteordevelopment/meteorclient/utils/player/InvUtils.java index 48f97756ed..6fb21cd999 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/InvUtils.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/InvUtils.java @@ -104,12 +104,10 @@ public static FindItemResult find(Item... items) { } public static FindItemResult find(Predicate isGood) { - if (mc.player == null) return new FindItemResult(0, 0); return find(isGood, 0, mc.player.getInventory().getContainerSize()); } public static FindItemResult find(Predicate isGood, int start, int end) { - if (mc.player == null) return new FindItemResult(0, 0); int slot = -1, count = 0;