diff --git a/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java b/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java index fbb9898355..ce0635a0e3 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java @@ -12,6 +12,7 @@ import meteordevelopment.meteorclient.systems.System; import meteordevelopment.meteorclient.systems.Systems; import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.misc.IconChanger; import meteordevelopment.meteorclient.utils.render.color.SettingColor; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; @@ -71,6 +72,15 @@ public class Config extends System { .build() ); + @SuppressWarnings("unused") + public final Setting customWindowIcon = sgVisual.add(new EnumSetting.Builder() + .name("custom-window-icon") + .description("The icon to use for the window.") + .defaultValue(IconChanger.WindowIcons.Default) + .onChanged(IconChanger::setIcon) + .build() + ); + public final Setting customWindowTitle = sgVisual.add(new BoolSetting.Builder() .name("custom-window-title") .description("Show custom text in the window title.") diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/IconChanger.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/IconChanger.java new file mode 100644 index 0000000000..0bcfb69263 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/IconChanger.java @@ -0,0 +1,113 @@ +/* + * 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 net.minecraft.SharedConstants; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.util.Icons; +import net.minecraft.resource.Resource; +import net.minecraft.util.Identifier; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.system.MemoryStack; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class IconChanger { + private IconChanger() { + } + + public enum WindowIcons { + Meteor( + MeteorClient.identifier("textures/icons/windowicon/meteor_16.png"), + MeteorClient.identifier("textures/icons/windowicon/meteor_32.png") + ), + Christmas( + MeteorClient.identifier("textures/icons/windowicon/christmas_16.png"), + MeteorClient.identifier("textures/icons/windowicon/christmas_32.png") + ), + Halloween( + MeteorClient.identifier("textures/icons/windowicon/halloween_16.png"), + MeteorClient.identifier("textures/icons/windowicon/halloween_32.png") + ), + Default(null, null); + + public final Identifier icon16; + public final Identifier icon32; + + WindowIcons(Identifier icon16, Identifier icon32) { + this.icon16 = icon16; + this.icon32 = icon32; + } + } + + public static void setIcon(WindowIcons icon) { + if (icon == WindowIcons.Default) { + resetToDefault(); + } else if (icon.icon16 == null || icon.icon32 == null) { + MeteorClient.LOG.warn("Icon paths cannot be null for custom icons"); + } else { + setCustomIcon(icon); + } + } + + private static void resetToDefault() { + try { + mc.getWindow().setIcon( + mc.getDefaultResourcePack(), + SharedConstants.getGameVersion().stable() ? Icons.RELEASE : Icons.SNAPSHOT + ); + } catch (IOException e) { + MeteorClient.LOG.warn("Failed to reset icon: {}", e.getMessage()); + } + } + + private static void setCustomIcon(WindowIcons windowIcons) { + try (MemoryStack stack = MemoryStack.stackPush()) { + GLFWImage.Buffer icons = GLFWImage.malloc(2, stack); + + loadIconSize(windowIcons.icon16, icons, 0, stack); + loadIconSize(windowIcons.icon32, icons, 1, stack); + + GLFW.glfwSetWindowIcon(mc.getWindow().getHandle(), icons); + } catch (Exception e) { + MeteorClient.LOG.warn("Failed to set icon: {}", e.getMessage()); + } + } + + private static void loadIconSize(Identifier iconPath, GLFWImage.Buffer icons, int index, MemoryStack stack) throws IOException { + Resource resource = mc.getResourceManager() + .getResource(iconPath) + .orElseThrow(() -> new IOException("Icon not found: " + iconPath)); + + try (NativeImage image = NativeImage.read(resource.getInputStream())) { + ByteBuffer pixelBuffer = imageToByteBuffer(image); + + GLFWImage glfwImage = GLFWImage.malloc(stack); + glfwImage.set(image.getWidth(), image.getHeight(), pixelBuffer); + icons.put(index, glfwImage); + } + } + + private static ByteBuffer imageToByteBuffer(NativeImage image) { + ByteBuffer buffer = ByteBuffer.allocateDirect(image.getWidth() * image.getHeight() * 4); + for (int y = 0; y < image.getHeight(); y++) { + for (int x = 0; x < image.getWidth(); x++) { + int pixel = image.getColorArgb(x, y); + buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red + buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green + buffer.put((byte) (pixel & 0xFF)); // Blue + buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha + } + } + buffer.flip(); + return buffer; + } +} diff --git a/src/main/resources/assets/meteor-client/textures/icons/windowicon/christmas_16.png b/src/main/resources/assets/meteor-client/textures/icons/windowicon/christmas_16.png new file mode 100644 index 0000000000..9974da263a Binary files /dev/null and b/src/main/resources/assets/meteor-client/textures/icons/windowicon/christmas_16.png differ diff --git a/src/main/resources/assets/meteor-client/textures/icons/windowicon/christmas_32.png b/src/main/resources/assets/meteor-client/textures/icons/windowicon/christmas_32.png new file mode 100644 index 0000000000..5644a68245 Binary files /dev/null and b/src/main/resources/assets/meteor-client/textures/icons/windowicon/christmas_32.png differ diff --git a/src/main/resources/assets/meteor-client/textures/icons/windowicon/halloween_16.png b/src/main/resources/assets/meteor-client/textures/icons/windowicon/halloween_16.png new file mode 100644 index 0000000000..2b4f33df02 Binary files /dev/null and b/src/main/resources/assets/meteor-client/textures/icons/windowicon/halloween_16.png differ diff --git a/src/main/resources/assets/meteor-client/textures/icons/windowicon/halloween_32.png b/src/main/resources/assets/meteor-client/textures/icons/windowicon/halloween_32.png new file mode 100644 index 0000000000..59b4e7da21 Binary files /dev/null and b/src/main/resources/assets/meteor-client/textures/icons/windowicon/halloween_32.png differ diff --git a/src/main/resources/assets/meteor-client/textures/icons/windowicon/meteor_16.png b/src/main/resources/assets/meteor-client/textures/icons/windowicon/meteor_16.png new file mode 100644 index 0000000000..6f9dc8f31c Binary files /dev/null and b/src/main/resources/assets/meteor-client/textures/icons/windowicon/meteor_16.png differ diff --git a/src/main/resources/assets/meteor-client/textures/icons/windowicon/meteor_32.png b/src/main/resources/assets/meteor-client/textures/icons/windowicon/meteor_32.png new file mode 100644 index 0000000000..0413bc1bb1 Binary files /dev/null and b/src/main/resources/assets/meteor-client/textures/icons/windowicon/meteor_32.png differ