Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
import meteordevelopment.meteorclient.utils.PreInit;
import meteordevelopment.meteorclient.utils.ReflectInit;
import meteordevelopment.meteorclient.utils.Utils;
import meteordevelopment.meteorclient.utils.misc.MeteorEventBus;
import meteordevelopment.meteorclient.utils.misc.Version;
import meteordevelopment.meteorclient.utils.misc.input.KeyAction;
import meteordevelopment.meteorclient.utils.misc.input.KeyBinds;
import meteordevelopment.meteorclient.utils.network.OnlinePlayers;
import meteordevelopment.orbit.EventBus;
import meteordevelopment.orbit.EventHandler;
import meteordevelopment.orbit.IEventBus;
import net.fabricmc.api.ClientModInitializer;
Expand Down Expand Up @@ -58,7 +58,7 @@ public class MeteorClient implements ClientModInitializer {
public static MeteorAddon ADDON;

public static Minecraft mc;
public static final IEventBus EVENT_BUS = new EventBus();
public static final IEventBus EVENT_BUS = new MeteorEventBus();
public static final File FOLDER = FabricLoader.getInstance().getGameDir().resolve(MOD_ID).toFile();
public static final Logger LOG;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ protected void init() {
closed = false;

if (firstInit) {
firstInit = false;
clear();
initWidgets();
firstInit = false;
}

mc.textInputManager().startTextInput(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package meteordevelopment.meteorclient.gui.renderer;

import com.mojang.renderpearl.api.textures.FilterMode;
import it.unimi.dsi.fastutil.Stack;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import meteordevelopment.meteorclient.MeteorClient;
Expand Down Expand Up @@ -43,6 +44,8 @@ public class GuiRenderer {
public static GuiTexture FAVORITE_NO, FAVORITE_YES;
public static GuiTexture COPY, PASTE;

public static Texture EMPTY_SPAWN_EGG;

public GuiTheme theme;

private final Renderer2D r = new Renderer2D(false);
Expand Down Expand Up @@ -79,6 +82,8 @@ public static void init() {
PASTE = addTexture(MeteorClient.identifier("textures/icons/gui/paste.png"));

TEXTURE = TEXTURE_PACKER.pack();

EMPTY_SPAWN_EGG = Texture.readResource("/assets/meteor-client/textures/empty_spawn_egg.png", false, FilterMode.NEAREST);
}

public void begin(GuiGraphicsExtractor graphics) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@

package meteordevelopment.meteorclient.gui.screens.settings;

import com.mojang.renderpearl.api.textures.FilterMode;
import meteordevelopment.meteorclient.gui.GuiTheme;
import meteordevelopment.meteorclient.gui.WindowScreen;
import meteordevelopment.meteorclient.gui.renderer.GuiRenderer;
import meteordevelopment.meteorclient.gui.utils.Cell;
import meteordevelopment.meteorclient.gui.widgets.WWidget;
import meteordevelopment.meteorclient.gui.widgets.containers.WSection;
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList;
import meteordevelopment.meteorclient.gui.widgets.input.WTextBox;
import meteordevelopment.meteorclient.gui.widgets.pressable.WCheckbox;
import meteordevelopment.meteorclient.renderer.Texture;
import meteordevelopment.meteorclient.settings.EntityTypeListSetting;
import meteordevelopment.meteorclient.utils.Utils;
import meteordevelopment.meteorclient.utils.misc.Names;
Expand All @@ -32,7 +31,6 @@
import java.util.function.Consumer;

public class EntityTypeListSettingScreen extends WindowScreen {
private static Texture EMPTY_SPAWN_EGG_TEXTURE;

private final EntityTypeListSetting setting;

Expand Down Expand Up @@ -247,13 +245,7 @@ private void addEntityType(WTable table, WCheckbox tableCheckbox, EntityType<?>
}

if (stack != null) table.add(theme.item(stack));
else {
if (EMPTY_SPAWN_EGG_TEXTURE == null) {
EMPTY_SPAWN_EGG_TEXTURE = Texture.readResource("/assets/meteor-client/textures/empty_spawn_egg.png", false, FilterMode.NEAREST);
}

table.add(theme.texture(32, 32, 0, EMPTY_SPAWN_EGG_TEXTURE));
}
else table.add(theme.texture(32, 32, 0, GuiRenderer.EMPTY_SPAWN_EGG));

// Name

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.lwjgl.system.MemoryUtil;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

Expand Down Expand Up @@ -67,7 +68,7 @@ public void upload(ByteBuffer buffer) {

public static Texture readResource(String path, boolean flipY, FilterMode filter) {
try (var in = Texture.class.getResourceAsStream(path)) {
if (in == null) return null;
if (in == null) throw new IllegalStateException("Missing built-in texture: " + path);

var data = TextureUtil.readResource(in).rewind();

Expand All @@ -78,6 +79,7 @@ public static Texture readResource(String path, boolean flipY, FilterMode filter

STBImage.stbi_set_flip_vertically_on_load(flipY);
ByteBuffer image = STBImage.stbi_load_from_memory(data, width, height, comp, 4);
if (image == null) throw new IllegalStateException("Failed to decode built-in texture " + path + ": " + STBImage.stbi_failure_reason());

var texture = new Texture(width.get(0), height.get(0), GpuFormat.RGBA8_UNORM, filter, filter);
texture.upload(image);
Expand All @@ -87,8 +89,8 @@ public static Texture readResource(String path, boolean flipY, FilterMode filter

return texture;
}
} catch (IOException _) {
return null;
} catch (IOException e) {
throw new UncheckedIOException("Failed to read built-in texture: " + path, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class Modules extends System<Modules> {
private final Set<Module> active = new ReferenceOpenHashSet<>();
private @Nullable Module moduleToBind;
private boolean awaitingKeyRelease = false;
private boolean inGame, modulesSubscribed;

public Modules() {
super("modules");
Expand Down Expand Up @@ -323,6 +324,9 @@ private void onGameJoined(GameJoinedEvent event) {
module.onActivate();
}
}

inGame = true;
modulesSubscribed = true;
}
}

Expand All @@ -335,6 +339,29 @@ private void onGameLeft(GameLeftEvent event) {
module.onDeactivate();
}
}

inGame = false;
modulesSubscribed = false;
}
}

/**
* Module event handlers expect a world and player, so while either is missing (e.g. the world is still loading)
* their listeners are removed and added back once both exist. Called before each tick.
*/
public void updateModuleSubscriptions() {
synchronized (active) {
boolean canUpdate = Utils.canUpdate();
if (!inGame || canUpdate == modulesSubscribed) return;

for (Module module : active) {
if (module.runInMainMenu || !module.autoSubscribe) continue;

if (canUpdate) MeteorClient.EVENT_BUS.subscribe(module);
else MeteorClient.EVENT_BUS.unsubscribe(module);
}

modulesSubscribed = canUpdate;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.utils.misc;

import meteordevelopment.meteorclient.MeteorClient;
import meteordevelopment.meteorclient.systems.modules.Module;
import meteordevelopment.meteorclient.systems.modules.Modules;
import meteordevelopment.meteorclient.utils.player.ChatUtils;
import meteordevelopment.orbit.EventBus;
import meteordevelopment.orbit.ICancellable;
import org.jspecify.annotations.Nullable;

/**
* Disables and reports a module that throws from an event handler instead of crashing the game.
* Exceptions that don't come from a module are rethrown as usual.
*/
public class MeteorEventBus extends EventBus {
@Override
public <T> T post(T event) {
try {
return super.post(event);
} catch (RuntimeException e) {
if (!disableCrashedModule(e)) throw e;
return event;
}
}

@Override
public <T extends ICancellable> T post(T event) {
try {
return super.post(event);
} catch (RuntimeException e) {
if (!disableCrashedModule(e)) throw e;
return event;
}
}

private static boolean disableCrashedModule(RuntimeException e) {
Module module = findModule(e);
if (module == null) return false;

MeteorClient.LOG.error("Module {} threw an exception and was disabled", module.name, e);

if (module.isActive()) {
try {
module.toggle();
} catch (RuntimeException deactivateException) {
MeteorClient.LOG.error("Module {} also threw while being disabled", module.name, deactivateException);
}
}

ChatUtils.errorPrefix("Meteor", "(highlight)%s(default) crashed and was disabled, check the log for details.", module.title);
return true;
}

private static @Nullable Module findModule(Throwable e) {
Modules modules = Modules.get();
if (modules == null) return null;

for (StackTraceElement frame : e.getStackTrace()) {
String className = frame.getClassName();

for (Module module : modules.getAll()) {
String moduleClass = module.getClass().getName();
if (className.equals(moduleClass) || className.startsWith(moduleClass + "$")) return module;
}
}

return null;
}
}