diff --git a/1.16_combat-6/build.gradle.kts b/1.16_combat-6/build.gradle.kts index 3dac0cf7d..acdabf07b 100644 --- a/1.16_combat-6/build.gradle.kts +++ b/1.16_combat-6/build.gradle.kts @@ -73,6 +73,7 @@ tasks.processResources { tasks.runClient { classpath(sourceSets.getByName("test").runtimeClasspath) + jvmArgs("-XX:+AllowEnhancedClassRedefinition", "-XX:+IgnoreUnrecognizedVMOptions") } tasks.withType(JavaCompile::class).configureEach { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java index 0c6e37c7f..4a5930230 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java @@ -35,6 +35,7 @@ import io.github.axolotlclient.api.types.Channel; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.AlphabeticalComparator; +import lombok.Getter; import net.minecraft.client.gui.AbstractParentElement; import net.minecraft.client.gui.Drawable; import net.minecraft.client.gui.Element; @@ -50,6 +51,7 @@ import net.minecraft.util.math.MathHelper; import org.lwjgl.glfw.GLFW; +@SuppressWarnings("deprecation") public class ChatsSidebar extends Screen implements ContextMenuScreen { private static final int ANIM_STEP = 8; @@ -182,6 +184,7 @@ public List getButtons() { } private void close() { + //noinspection DataFlowIssue client.openScreen(parent); if (chatWidget != null) { chatWidget.remove(); @@ -219,9 +222,11 @@ private void addChat(Channel channel) { int w; if (channel.isDM()) { User chatUser = ((Channel.DM) channel).getReceiver(); + //noinspection DataFlowIssue w = Math.max(client.textRenderer.getWidth(chatUser.getStatus().getTitle() + ": " + chatUser.getStatus().getDescription()) + 5, client.textRenderer.getWidth(channel.getName())); } else { + //noinspection DataFlowIssue w = client.textRenderer.getWidth(channel.getName()); } sidebarWidth = Math.min(Math.max(width * 5 / 12, w + 5), width / 2); @@ -271,6 +276,7 @@ private class ListWidget extends AbstractParentElement implements Drawable, Elem private final int height; private final int entryHeight = 25; protected boolean hovered; + @Getter private int x; private int scrollAmount; private boolean visible; @@ -330,10 +336,6 @@ public boolean isMouseOver(double mouseX, double mouseY) { return hovered = visible && mouseX >= (double) this.x && mouseY >= (double) this.y && mouseX < (double) (this.x + this.width) && mouseY < (double) (this.y + this.height); } - public int getX() { - return x; - } - public void setX(int x) { this.x = x; elements.forEach(e -> e.x = x); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java index aecd95c8f..32b679ae7 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java @@ -51,13 +51,17 @@ public void init() { addButton(new ButtonWidget(width / 2 - 155, height - 50, 150, 20, ScreenTexts.CANCEL, button -> client.openScreen(parent))); - addButton(new ButtonWidget(width / 2 + 5, height - 50, 150, 20, + var done = addButton(new ButtonWidget(width / 2 + 5, height - 50, 150, 20, ScreenTexts.DONE, button -> { - if (!input.getText().isEmpty()) { + if (!input.getText().isBlank()) { consumer.accept(input.getText()); - client.openScreen(parent); } + client.openScreen(parent); })); + input.setChangedListener(s -> { + done.active = !s.isBlank(); + }); + done.active = false; } @Override diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java index fa5ae7b24..2a275a37d 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java @@ -33,6 +33,7 @@ import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; import net.minecraft.text.TranslatableText; import org.lwjgl.glfw.GLFW; @@ -47,7 +48,7 @@ public class ChatScreen extends Screen implements ContextMenuScreen { private TextFieldWidget input; public ChatScreen(Screen parent, Channel channel) { - super(new TranslatableText("api.screen.chat")); + super(new LiteralText(channel.getName())); this.channel = channel; this.parent = parent; } @@ -82,6 +83,7 @@ protected void init() { users.setUsers(channel.getAllUsers(), channel); addChild(users); + //noinspection DataFlowIssue addButton(input = new TextFieldWidget(client.textRenderer, width / 2 - 150, height - 50, 300, 20, new TranslatableText("api.chat.enterMessage")) { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java index b8f923d95..861d4e687 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java @@ -51,7 +51,7 @@ public Identifier getFabricId() { return new Identifier("axolotlclient", "bridge/resource_listener"); } }); - ClientPlayConnectionEvents.INIT.register((clientPlayNetworkHandler, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); + ClientPlayConnectionEvents.JOIN.register((clientPlayNetworkHandler, sender, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); ClientPlayConnectionEvents.DISCONNECT.register((clientPlayNetworkHandler, minecraftClient) -> Events.DISCONNECT.invoker().run()); } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java index eace10635..fbeca8d20 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java @@ -156,4 +156,9 @@ public MinecraftClientMixin(String string) { public AxoResourceManager br$getResourceManager() { return getResourceManager(); } + + @Override + public Object br$getScreen() { + return currentScreen; + } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java index 77709cf21..b3fbf9c25 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java @@ -57,7 +57,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(value = PlatformDispatch.class, remap = false) -public class PlatformDispatchMixin { +public abstract class PlatformDispatchMixin { @Unique private static void getRealTimeServerPing(ServerInfo server, MutableInt currentServerPing) { ThreadExecuter.scheduleTask(() -> { @@ -124,7 +124,7 @@ public ClientConnection getConnection() { final var minecraft = MinecraftClient.getInstance(); final var serverEntry = minecraft.getCurrentServerEntry(); - final var img = NativeImage.read(Objects.requireNonNull(serverEntry == null ? minecraft.getServer().getServerMetadata().getFavicon() : serverEntry.getIcon())); + final var img = NativeImage.read(Objects.requireNonNull(serverEntry == null ? minecraft.getServer().getServerMetadata().getFavicon().substring("data:image/png;base64,".length()) : serverEntry.getIcon())); final var icon = new NativeImageBackedTexture(img); final var iconId = new Identifier("axolotlclient", serverEntry == null ? "worlds/" + Hashing.sha1().hashUnencodedChars(((MinecraftServerAccessor) minecraft.getServer()).getStorageSource().getDirectoryName()) + "/icon" : @@ -137,7 +137,7 @@ class Impl implements AxoSprite.Dynamic, AxoSpriteImpl { @Override public void draw(MinecraftClient client, MatrixStack stack, int sX, int sY, int sW, int sH) { client.getTextureManager().bindTexture(iconId); - DrawUtil.drawTexture(stack, sX, sY, 0, 0, sW, sH, sW, sH); + DrawUtil.drawTexture(stack, sX, sY, 0, 0, sW, sH, sW, sH); } @Override diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java index 0ec60a178..833a962f6 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java @@ -32,7 +32,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(PlayerListEntry.class) -public class PlayerListEntryMixin implements AxoPlayerListEntry { +public abstract class PlayerListEntryMixin implements AxoPlayerListEntry { @Shadow @Final private GameProfile profile; diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java index 820f6388f..178f40b03 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(LivingEntity.class) -public class LivingEntityMixin implements AxoLivingEntity { +public abstract class LivingEntityMixin implements AxoLivingEntity { @Shadow @Final private Map activeStatusEffects; diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java index 2188dc7da..22fd3bc5d 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoStatusEffects.class, remap = false) -public class AxoStatusEffectsMixin { +public abstract class AxoStatusEffectsMixin { @Mutable @Shadow @Final diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java index 0b2fd78ef..17df440dd 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java @@ -69,7 +69,7 @@ @SuppressWarnings("OverwriteModifiers") @Mixin(value = PlatformImplInternal.class, remap = false) -public class PlatformImplInternalMixin { +public abstract class PlatformImplInternalMixin { /** * @author Flowey * @reason Implement bridge platform. @@ -147,9 +147,9 @@ public static int getCurrentFps() { * @reason Implement bridge platform. */ @Overwrite - public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name, String category) { + public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name) { int code = ((InputUtil.Key) Objects.requireNonNullElse(defaultKey, AxoKeys.KEY_UNKNOWN)).getCode(); - final var binding = new KeyBinding(name, code, category); + final var binding = new KeyBinding(name, code, "category.axolotlclient"); KeyBindingHelper.registerKeyBinding(binding); return binding; } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java index 1026dc5b2..08883ff6b 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoEnchants.class, remap = false) -public class AxoEnchantsMixin { +public abstract class AxoEnchantsMixin { @Mutable @Shadow @Final diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java index 3e8f7fa39..be2753ed2 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoItems.class, remap = false) -public class AxoItemsMixin { +public abstract class AxoItemsMixin { @Mutable @Shadow @Final diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java index e3b053e27..fc0b3ffea 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Enchantment.class) -public class EnchantmentMixin implements AxoEnchant { +public abstract class EnchantmentMixin implements AxoEnchant { } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java index 5e44604ed..eadcab05e 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Item.class) -public class ItemMixin implements AxoItem { +public abstract class ItemMixin implements AxoItem { @Override public boolean br$is(AxoItemClass itemClass) { return switch (itemClass) { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java index f34409d94..b1a06f61c 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoKeys.class, remap = false) -public class AxoKeysMixin { +public abstract class AxoKeysMixin { @Mutable @Shadow diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java index 54a47ccdf..adec275ae 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(GameOptions.class) -public class GameOptionsMixin implements AxoClientKeybinds{ +public abstract class GameOptionsMixin implements AxoClientKeybinds { @Shadow @Final public KeyBinding keyAttack; diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java index 53779b781..249ded443 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(InputUtil.Key.class) -public class KeyMixin implements AxoKey { +public abstract class KeyMixin implements AxoKey { } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java index f9e83f9ed..8c55504bf 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java @@ -36,7 +36,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoSprites.class, remap = false) -public class AxoSpritesMixin { +public abstract class AxoSpritesMixin { @Mutable @Shadow @Final diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java index 26e77d7a0..210e78b39 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java @@ -28,7 +28,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(Identifier.class) -public abstract class IdentifierMixin implements AxoIdentifier{ +public abstract class IdentifierMixin implements AxoIdentifier { @Shadow public abstract String getPath(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java index 50686e8e4..7b2883aeb 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java @@ -33,6 +33,7 @@ import io.github.axolotlclient.AxolotlClientConfig.api.ui.ConfigUI; import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import io.github.axolotlclient.AxolotlClientConfig.impl.options.*; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.RecreatableScreen; import io.github.axolotlclient.AxolotlClientConfigCommon; import io.github.axolotlclient.config.screen.CreditsScreen; import io.github.axolotlclient.config.screen.ProfilesScreen; @@ -43,6 +44,7 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.options.KeyBinding; import net.minecraft.client.texture.NativeImage; import net.minecraft.client.texture.NativeImageBackedTexture; @@ -155,7 +157,9 @@ public AxolotlClientConfig() { general.add(configStyle = new StringArrayOption("configStyle", themes, "configStyle." + ConfigUI.getInstance().getCurrentStyle().getName(), s -> { ConfigUI.getInstance().setStyle(s.split("\\.")[1]); - MinecraftClient.getInstance().openScreen(null); + + Screen newScreen = RecreatableScreen.tryRecreate(MinecraftClient.getInstance().currentScreen); + MinecraftClient.getInstance().openScreen(newScreen); })); AxolotlClient.getInstance().getConfigManager().load(); ConfigUI.getInstance().setStyle(configStyle.get().split("\\.")[1]); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java index 0e4103317..3393571b3 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java @@ -82,7 +82,7 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { renderBackground(matrices); creditsList.render(matrices, mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta); - drawCenteredText(matrices, textRenderer, getTitle(), width / 2, 33/2 - textRenderer.fontHeight / 2, -1); + drawCenteredText(matrices, textRenderer, getTitle(), width / 2, 33 / 2 - textRenderer.fontHeight / 2, -1); } @Override diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java index fb1c87483..8637de568 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java @@ -66,6 +66,7 @@ protected void init() { @Override public void onClose() { Profiles.getInstance().saveProfiles(); + //noinspection DataFlowIssue client.openScreen(parent); } @@ -114,14 +115,13 @@ public List children() { @Environment(EnvType.CLIENT) public class ProfileEntry extends Entry { + private static final Text EXPORT_BUTTON_TITLE = new TranslatableText("profiles.profile.export"); private static final Text CURRENT_TEXT = new TranslatableText("profiles.profile.current"); private static final Text LOAD_BUTTON_TITLE = new TranslatableText("profiles.profile.load"); private static final Text DUPLICATE_BUTTON_TITLE = new TranslatableText("profiles.profile.duplicate"); private static final Text REMOVE_BUTTON_TITLE = new TranslatableText("profiles.profile.remove"); private final TextFieldWidget profileName; - private final ButtonWidget loadButton; - private final ButtonWidget duplicateButton; - private final ButtonWidget removeButton; + private final ButtonWidget exportButton, loadButton, duplicateButton, removeButton; private final Profiles.Profile profile; ProfileEntry(Profiles.Profile profile) { @@ -129,6 +129,8 @@ public class ProfileEntry extends Entry { profileName = new TextFieldWidget(textRenderer, 0, 0, 150, 20, LiteralText.EMPTY); profileName.setText(profile.name()); profileName.setChangedListener(profile::setName); + exportButton = new ButtonWidget(0, 0, 50, 20, EXPORT_BUTTON_TITLE, btn -> + Profiles.getInstance().exportProfile(profile)); loadButton = new ButtonWidget(0, 0, 50, 20, LOAD_BUTTON_TITLE, btn -> Profiles.getInstance().switchTo(profile)); duplicateButton = new ButtonWidget(0, 0, 50, 20, DUPLICATE_BUTTON_TITLE, b -> { @@ -160,11 +162,15 @@ public void render(MatrixStack guiGraphics, int index, int top, int left, int wi boolean current = Profiles.getInstance().getCurrent() == profile; loadButton.setMessage(current ? CURRENT_TEXT : LOAD_BUTTON_TITLE); - loadButton.active = !current; + loadButton.active = removeButton.active = !current; i -= loadButton.getWidth(); this.loadButton.x = i; loadButton.y = j; this.loadButton.render(guiGraphics, mouseX, mouseY, partialTick); + i -= exportButton.getWidth(); + exportButton.x = i; + exportButton.y = j; + exportButton.render(guiGraphics, mouseX, mouseY, partialTick); profileName.setWidth(i - left - 4); profileName.x = left; profileName.y = j; @@ -179,7 +185,7 @@ public List children() { public class NewEntry extends Entry { - private final ButtonWidget addButton; + private final ButtonWidget addButton, importButton; public NewEntry() { this.addButton = new ButtonWidget(0, 0, 150, 20, new TranslatableText("profiles.profile.add"), button -> { @@ -188,20 +194,25 @@ public NewEntry() { Profiles.getInstance().saveProfiles(); setScrollAmount(Math.max(0, getMaxPosition() - (bottom - top - 4))); }); + this.importButton = new ButtonWidget(0, 0, 150, 20, new TranslatableText("profiles.profile.import"), btn -> + Profiles.getInstance().importProfiles().thenRun(ProfilesList.this::reload)); } @Override public void render(MatrixStack guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() / 2; + int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() + 2; int j = top - 2; this.addButton.x = i; addButton.y = j; this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); + this.importButton.x = addButton.x + addButton.getWidth() + 2; + this.importButton.y = j; + this.importButton.render(guiGraphics, mouseX, mouseY, partialTick); } @Override public List children() { - return List.of(addButton); + return List.of(addButton, importButton); } } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/AbstractInventoryScreenMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/AbstractInventoryScreenMixin.java index 58869d732..f3d6795e0 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/AbstractInventoryScreenMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/AbstractInventoryScreenMixin.java @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.At; @Mixin(AbstractInventoryScreen.class) -public class AbstractInventoryScreenMixin { +public abstract class AbstractInventoryScreenMixin { @WrapWithCondition(method = "applyStatusEffectOffset", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/screen/ingame/AbstractInventoryScreen;x:I")) private boolean noInventoryShift(AbstractInventoryScreen instance, int value) { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java index e4f165c12..853594dcb 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java @@ -37,7 +37,7 @@ public abstract class ClientPlayerEntityMixin { * @param sprintKey the sprint key that the user has bound * @return whether or not the user should try to sprint * @author DragonEggBedrockBreaking - * @license MPL-2.0 + *

License: MPL-2.0

*/ @Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/options/KeyBinding;isPressed()Z")) private boolean axolotlclient$alwaysPressed(KeyBinding sprintKey) { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ConfigVanillaButtonWidgetMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ConfigVanillaButtonWidgetMixin.java new file mode 100644 index 000000000..1832b6a56 --- /dev/null +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/ConfigVanillaButtonWidgetMixin.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.vanilla.widgets.VanillaButtonWidget; +import io.github.axolotlclient.modules.hud.util.DrawUtil; +import io.github.axolotlclient.util.ButtonWidgetTextures; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(VanillaButtonWidget.class) +public abstract class ConfigVanillaButtonWidgetMixin extends ButtonWidget { + @Shadow(remap = false) + public abstract int getX(); + + @Shadow(remap = false) + public abstract int getY(); + + private ConfigVanillaButtonWidgetMixin(int x, int y, int width, int height, Text message, PressAction action) { + super(x, y, width, height, message, action); + } + + @Redirect(method = "renderButton", at = @At(value = "INVOKE", target = "Lio/github/axolotlclient/AxolotlClientConfig/impl/ui/vanilla/widgets/VanillaButtonWidget;drawTexture(Lnet/minecraft/client/util/math/MatrixStack;IIIIII)V", ordinal = 0)) + private void drawTexture$1(VanillaButtonWidget instance, MatrixStack stack, int x, int y, int u, int v, int width, int height) { + + } + + @Redirect(method = "renderButton", at = @At(value = "INVOKE", target = "Lio/github/axolotlclient/AxolotlClientConfig/impl/ui/vanilla/widgets/VanillaButtonWidget;drawTexture(Lnet/minecraft/client/util/math/MatrixStack;IIIIII)V", ordinal = 1)) + private void drawTexture$2$replaceWithNineSlice(VanillaButtonWidget instance, MatrixStack stack, int x, int y, int u, int v, int width, int height) { + Identifier tex = ButtonWidgetTextures.get(getYImage(hovered)); + DrawUtil.blitSprite(tex, getX(), getY(), getWidth(), getHeight(), new DrawUtil.NineSlice(200, 20, 3)); + MinecraftClient.getInstance().getTextureManager().bindTexture(WIDGETS_LOCATION); + } +} diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java index f893fad52..829448181 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java @@ -22,10 +22,10 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.modules.freelook.Freelook; import io.github.axolotlclient.modules.hypixel.Skyblock; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import net.minecraft.entity.Entity; import net.minecraft.util.math.MathHelper; import org.spongepowered.asm.mixin.Mixin; @@ -55,7 +55,7 @@ public abstract class EntityMixin { float pitch = prevPitch + (float) (mouseDeltaY * .15); float yaw = prevYaw + (float) (mouseDeltaX * .15); pitch = MathHelper.clamp(pitch, -90.0F, 90.0F); - Events.PLAYER_DIRECTION_CHANGE.invoker().invoke(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); + Events.PLAYER_DIRECTION_CHANGE.invoker().accept(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); } @Shadow diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java index c32e77884..bf10493cd 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java @@ -22,6 +22,8 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.modules.hud.HudManager; +import io.github.axolotlclient.modules.hud.gui.hud.IconHud; import io.github.axolotlclient.modules.scrollableTooltips.ScrollableTooltips; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.util.math.MatrixStack; @@ -29,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -39,6 +42,7 @@ public abstract class HandledScreenMixin { @Shadow @Nullable protected Slot focusedSlot; + @Unique private Slot cachedSlot; @Inject(method = "drawMouseoverTooltip", at = @At("HEAD")) @@ -48,4 +52,12 @@ public abstract class HandledScreenMixin { ScrollableTooltips.getInstance().resetScroll(); } } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/util/math/MatrixStack;FII)V")) + private void renderIcon(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) { + var hud = (IconHud) HudManager.getInstance().get(IconHud.ID); + if (hud != null && hud.isEnabled()) { + hud.renderInGui(matrices, delta); + } + } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/InputUtilTypeMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/InputUtilTypeMixin.java index f90c190cd..5092b67d0 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/InputUtilTypeMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/InputUtilTypeMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(InputUtil.Type.class) -public class InputUtilTypeMixin { +public abstract class InputUtilTypeMixin { @Inject(method = "method_27450", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwGetKeyName(II)Ljava/lang/String;", remap = false), cancellable = true) private static void fixScancodeError(Integer i, String string, CallbackInfoReturnable cir) { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java index bf93ab2ff..6b625c1e3 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java @@ -22,16 +22,21 @@ package io.github.axolotlclient.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.util.OSUtil; import net.minecraft.client.main.Main; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(Main.class) public abstract class MinecraftClientMainMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) - private static String axolotlclient$noHeadless(String key, String value) { + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) + private static String axolotlclient$noHeadless(String key, String value, Operation original) { + if (OSUtil.getOS() != OSUtil.OperatingSystem.WINDOWS) { + return original.call(key, value); + } return ""; } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java index 9d48010eb..6ef7c5ee1 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java @@ -40,7 +40,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(SplashTextResourceSupplier.class) -public class SplashTextResourceSupplierMixin { +public abstract class SplashTextResourceSupplierMixin { @Unique private static final Identifier EXTRA_SPLASHES = new Identifier("axolotlclient", "texts/splashes.txt"); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java index a8b745206..5e2d38781 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java @@ -43,7 +43,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ @Mixin(WorldRenderer.class) diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java index 482d251ae..244f0302e 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java @@ -46,7 +46,7 @@ import org.spongepowered.asm.mixin.injection.invoke.arg.Args; @Mixin(MultiplayerScreen.class) -public class JoinMulitplayerScreenMixin extends Screen { +public abstract class JoinMulitplayerScreenMixin extends Screen { @Shadow @Final @@ -74,7 +74,7 @@ private void addFriendsMultiplayerScreenButtons(CallbackInfo ci) { @WrapOperation(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerServerListWidget;updateSize(IIII)V")) private void increaseHeaderSize(MultiplayerServerListWidget instance, int width, int height, int top, int bottom, Operation original) { if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - top += 32 - 60; + top += -32 + 60; } original.call(instance, width, height, top, bottom); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyBindAccessor.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/skins/PlayerSkinTextureAccessor.java similarity index 69% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyBindAccessor.java rename to 1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/skins/PlayerSkinTextureAccessor.java index bb020bda0..c14dc1a3d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyBindAccessor.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/mixin/skins/PlayerSkinTextureAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright © 2024 moehreag & Contributors + * Copyright © 2025 moehreag & Contributors * * This file is part of AxolotlClient. * @@ -20,19 +20,18 @@ * For more information, see the LICENSE file. */ -package io.github.axolotlclient.mixin; +package io.github.axolotlclient.mixin.skins; -import java.util.Map; - -import net.minecraft.client.KeyMapping; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.PlayerSkinTexture; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(KeyMapping.class) -public interface KeyBindAccessor { +@Mixin(PlayerSkinTexture.class) +public interface PlayerSkinTextureAccessor { - @Accessor("CATEGORY_SORT_ORDER") - static Map getOrderByCategories() { + @Invoker("remapTexture") + static NativeImage invokeRemapTexture(NativeImage img) { throw new UnsupportedOperationException(); } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java index 520ddb92b..bdc063580 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java @@ -26,6 +26,7 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import lombok.Getter; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; @@ -69,6 +70,7 @@ public static class Entry extends AlwaysSelectedEntryListWidget.Entry { private static final Identifier warningSign = new Identifier("axolotlclient", "textures/warning.png"); private final AccountsScreen screen; + @Getter private final Account account; private final MinecraftClient client; private long time; @@ -81,6 +83,7 @@ public Entry(AccountsScreen screen, Account account) { @Override public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + //noinspection deprecation GlStateManager.color4f(1, 1, 1, 1); if (Auth.getInstance().getCurrent().equals(account)) { client.getTextureManager().bindTexture(checkmark); @@ -113,8 +116,5 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { return false; } - public Account getAccount() { - return account; - } } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java index 3adb33a3d..081ae3749 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java @@ -22,6 +22,7 @@ package io.github.axolotlclient.modules.auth; +import io.github.axolotlclient.modules.auth.skin.SkinManagementScreen; import net.minecraft.client.gui.screen.ConfirmScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ScreenTexts; @@ -36,6 +37,7 @@ public class AccountsScreen extends Screen { private ButtonWidget loginButton; private ButtonWidget deleteButton; private ButtonWidget refreshButton; + private ButtonWidget skinsButton; public AccountsScreen(Screen currentScreen) { super(new TranslatableText("accounts")); @@ -77,10 +79,14 @@ public void init() { accountsListWidget.setAccounts(Auth.getInstance().getAccounts()); - addButton(loginButton = new ButtonWidget(this.width / 2 - 154, this.height - 52, 150, 20, new TranslatableText("auth.login"), + addButton(loginButton = new ButtonWidget(this.width / 2 - 154, this.height - 52, 100, 20, new TranslatableText("auth.login"), buttonWidget -> login())); - this.addButton(new ButtonWidget(this.width / 2 + 4, this.height - 52, 150, 20, new TranslatableText("auth.add"), + addButton(skinsButton = new ButtonWidget(this.width / 2 - 50, this.height - 52, 100, 20, new TranslatableText("skins.manage"), + btn -> client.openScreen(new SkinManagementScreen( + this, accountsListWidget.getSelected().getAccount())))); + + this.addButton(new ButtonWidget(this.width / 2 + 4 + 50, this.height - 52, 100, 20, new TranslatableText("auth.add"), button -> { if (!Auth.getInstance().allowOfflineAccounts()) { initMSAuth(); @@ -120,17 +126,14 @@ public void removed() { } private void initMSAuth() { - Auth.getInstance().getAuth().startDeviceAuth().thenRun(() -> client.execute(this::refresh)); + Auth.getInstance().getMsApi().startDeviceAuth().thenRun(() -> client.execute(this::refresh)); } private void refreshAccount() { refreshButton.active = false; AccountsListWidget.Entry entry = accountsListWidget.getSelected(); if (entry != null) { - entry.getAccount().refresh(Auth.getInstance().getAuth()).thenRun(() -> client.execute(() -> { - Auth.getInstance().save(); - refresh(); - })); + entry.getAccount().refresh(Auth.getInstance().getMsApi()); } } @@ -138,9 +141,10 @@ private void updateButtonActivationStates() { AccountsListWidget.Entry entry = accountsListWidget.getSelected(); if (client.world == null && entry != null) { loginButton.active = entry.getAccount().isExpired() || !entry.getAccount().equals(Auth.getInstance().getCurrent()); - deleteButton.active = refreshButton.active = true; + refreshButton.active = skinsButton.active = !entry.getAccount().isOffline(); + deleteButton.active = true; } else { - loginButton.active = deleteButton.active = refreshButton.active = false; + loginButton.active = deleteButton.active = refreshButton.active = skinsButton.active = false; } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/Auth.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/Auth.java index 766b121a3..0298c9de5 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/Auth.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/Auth.java @@ -23,24 +23,24 @@ package io.github.axolotlclient.modules.auth; import java.util.*; +import java.util.concurrent.CompletableFuture; import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftProfileTexture; import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.api.API; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.UUIDHelper; import io.github.axolotlclient.mixin.MinecraftClientAccessor; import io.github.axolotlclient.modules.Module; +import io.github.axolotlclient.modules.auth.skin.SkinManager; import io.github.axolotlclient.util.ThreadExecuter; import io.github.axolotlclient.util.notifications.Notifications; import io.github.axolotlclient.util.options.GenericOption; import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ConfirmScreen; -import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.DefaultSkinHelper; import net.minecraft.client.util.Session; import net.minecraft.text.TranslatableText; @@ -51,17 +51,20 @@ public class Auth extends Accounts implements Module { @Getter private final static Auth Instance = new Auth(); public final BooleanOption showButton = new BooleanOption("auth.showButton", false); + public final BooleanOption skinManagerAnimations = new BooleanOption("skins.manage.animations", true); private final MinecraftClient client = MinecraftClient.getInstance(); private final GenericOption viewAccounts = new GenericOption("viewAccounts", "clickToOpen", () -> client.openScreen(new AccountsScreen(client.currentScreen))); private final Map textures = new HashMap<>(); private final Set loadingTexture = new HashSet<>(); private final Map profileCache = new WeakHashMap<>(); + @Getter + private final SkinManager skinManager = new SkinManager(); @Override public void init() { load(); - this.auth = new MSAuth(AxolotlClient.LOGGER, this, () -> client.options.language); + this.msApi = new MSApi(this, () -> client.options.language); if (isContained(client.getSession().getUuid())) { current = getAccounts().stream().filter(account -> account.getUuid().equals(client.getSession().getUuid())).toList().get(0); current.setAuthToken(client.getSession().getAccessToken()); @@ -73,7 +76,6 @@ public void init() { current = new Account(client.getSession().getUsername(), client.getSession().getUuid(), client.getSession().getAccessToken()); } - OptionCategory category = OptionCategory.create("auth"); category.add(showButton, viewAccounts); AxolotlClient.config().general.add(category); } @@ -88,12 +90,10 @@ protected void login(Account account) { if (account.isExpired()) { Notifications.getInstance().addStatus(new TranslatableText("auth.notif.title"), new TranslatableText("auth.notif.refreshing", account.getName())); } - account.refresh(auth).thenAccept(res -> { - res.ifPresent(a -> { - if (!a.isExpired()) { - login(a); - } - }); + account.refresh(msApi).thenAccept(a -> { + if (!a.isExpired()) { + login(a); + } }).thenRun(this::save); } else { try { @@ -138,14 +138,18 @@ public void loadTextures(String uuid, String name) { } @Override - void showAccountsExpiredScreen(Account account) { - Screen current = client.currentScreen; + CompletableFuture showAccountsExpiredScreen(Account account) { + var screen = client.currentScreen; + var fut = new CompletableFuture(); client.execute(() -> client.openScreen(new ConfirmScreen((bl) -> { - client.openScreen(current); if (bl) { - auth.startDeviceAuth(); + msApi.startDeviceAuth().thenRun(() -> fut.complete(account)); + } else { + fut.cancel(true); } + client.openScreen(screen); }, new TranslatableText("auth"), new TranslatableText("auth.accountExpiredNotice", account.getName())))); + return fut; } @Override diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java new file mode 100644 index 000000000..d1195a321 --- /dev/null +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import net.minecraft.util.Util; + +public class LoadingScreen extends Screen { + private final Text description; + + public LoadingScreen(Text title, Text description) { + super(title); + this.description = description; + } + + @Override + public void render(MatrixStack graphics, int mouseX, int mouseY, float delta) { + renderBackground(graphics); + drawCenteredText(graphics, textRenderer, getTitle(), width / 2, 33 / 2 - textRenderer.fontHeight / 2, -1); + int centerX = width / 2; + int centerY = height / 2; + var text = description; + textRenderer.draw(graphics, text, centerX - textRenderer.getWidth(text) / 2f, centerY - 9, -1); + String string = switch ((int) (Util.getMeasuringTimeMs() / 300L % 4L)) { + case 1, 3 -> "o O o"; + case 2 -> "o o O"; + default -> "O o o"; + }; + textRenderer.draw(graphics, string, centerX - textRenderer.getWidth(string) / 2f, centerY + 9, 0xFF808080); + } +} diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java new file mode 100644 index 000000000..c5376dc4e --- /dev/null +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java @@ -0,0 +1,880 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.mojang.blaze3d.systems.RenderSystem; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Colors; +import io.github.axolotlclient.api.SimpleTextInputScreen; +import io.github.axolotlclient.api.util.UUIDHelper; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import io.github.axolotlclient.modules.hud.util.DrawUtil; +import io.github.axolotlclient.util.ButtonWidgetTextures; +import io.github.axolotlclient.util.ClientColors; +import io.github.axolotlclient.util.Watcher; +import io.github.axolotlclient.util.notifications.Notifications; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.Drawable; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.ParentElement; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ScreenTexts; +import net.minecraft.client.gui.widget.AbstractButtonWidget; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SkinManagementScreen extends Screen { + private static final Path SKINS_DIR = FabricLoader.getInstance().getGameDir().resolve("skins"); + private static final int LIST_SKIN_WIDTH = 75; + private static final int LIST_SKIN_HEIGHT = 110; + private static final Text TEXT_EQUIPPING = new TranslatableText("skins.manage.equipping"); + private final Screen parent; + private final Account account; + private MSApi.MCProfile cachedProfile; + private SkinListWidget skinList; + private SkinListWidget capesList; + private boolean capesTab; + private SkinWidget current; + private final Watcher skinDirWatcher; + private final List drawables = new ArrayList<>(); + private final CompletableFuture loadingFuture; + private Text tooltip; + + public SkinManagementScreen(Screen parent, Account account) { + super(new TranslatableText("skins.manage")); + this.parent = parent; + this.account = account; + skinDirWatcher = Watcher.createSelfTicking(SKINS_DIR, () -> { + AxolotlClientCommon.getInstance().getLogger().info("Reloading screen as local files changed!"); + loadSkinsList(); + }); + loadingFuture = (account.needsRefresh() ? account.refresh(Auth.getInstance().getMsApi()) + : CompletableFuture.completedFuture(null)) + .thenComposeAsync(unused -> Auth.getInstance().getMsApi().getProfile(account)); + } + + @Override + public void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + + var back = addDrawableChild(new ButtonWidget(width / 2 - 75, height - headerHeight / 2 - 10, 150, 20, ScreenTexts.BACK, btn -> onClose())); + + var loadingPlaceholder = new AbstractButtonWidget(0, headerHeight, width, contentHeight, new TranslatableText("skins.loading")) { + @Override + public void renderButton(MatrixStack graphics, int mouseX, int mouseY, float delta) { + int centerX = this.x + this.getWidth() / 2; + int centerY = this.y + this.getHeight() / 2; + Text text = this.getMessage(); + textRenderer.draw(graphics, text, centerX - textRenderer.getWidth(text) / 2f, centerY - 9, -1); + String string = switch ((int) (Util.getMeasuringTimeMs() / 300L % 4L)) { + case 1, 3 -> "o O o"; + case 2 -> "o o O"; + default -> "O o o"; + }; + textRenderer.draw(graphics, string, centerX - textRenderer.getWidth(string) / 2f, centerY + 9, 0xFF808080); + } + + @Override + protected MutableText getNarrationMessage() { + return LiteralText.EMPTY.copy(); + } + }; + loadingPlaceholder.active = false; + addDrawableChild(loadingPlaceholder); + addDrawableChild(back); + + skinList = new SkinListWidget(client, width / 2, contentHeight - 24, headerHeight + 24, LIST_SKIN_HEIGHT + 34); + capesList = new SkinListWidget(client, width / 2, contentHeight - 24, headerHeight + 24, skinList.getEntryContentsHeight() + 24); + skinList.setLeftPos(width / 2); + capesList.setLeftPos(width / 2); + var currentHeight = Math.min((width / 2f) * 120 / 85, contentHeight); + var currentWidth = currentHeight * 85 / 120; + current = new SkinWidget((int) currentWidth, (int) currentHeight, null, account); + current.setPosition((int) (width / 4f - currentWidth / 2), (int) (height / 2f - currentHeight / 2)); + + if (!capesTab) { + capesList.visible = capesList.active = false; + } else { + skinList.visible = skinList.active = false; + } + List navBar = new ArrayList<>(); + var skinsTab = new ButtonWidget(Math.max(width * 3 / 4 - 102, width / 2 + 2), headerHeight, Math.min(100, width / 4 - 2), 20, new TranslatableText("skins.nav.skins"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = true; + capesList.visible = capesList.active = false; + capesTab = false; + }); + navBar.add(skinsTab); + var capesTab = new ButtonWidget(width * 3 / 4 + 2, headerHeight, Math.min(100, width / 4 - 2), 20, new TranslatableText("skins.nav.capes"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = false; + capesList.visible = capesList.active = true; + this.capesTab = true; + }); + navBar.add(capesTab); + var importButton = new SpriteButton(new TranslatableText("skins.manage.import.local"), btn -> { + btn.active = false; + SkinImportUtil.openImportSkinDialog().thenAccept(this::filesDragged).thenRun(() -> btn.active = true); + }, new Identifier("axolotlclient", "textures/gui/sprites/folder.png")); + var downloadButton = new SpriteButton(new TranslatableText("skins.manage.import.online"), btn -> { + btn.active = false; + promptForSkinDownload(); + }, new Identifier("axolotlclient", "textures/gui/sprites/download.png")); + downloadButton.x = importButton.x - 2 - 11; + downloadButton.y = capesTab.y - 13; + if (width - (capesTab.x + capesTab.getWidth()) > 28) { + importButton.x = width - importButton.getWidth() - 2; + downloadButton.x = importButton.x - downloadButton.getWidth() - 2; + importButton.y = capesTab.y + capesTab.getHeight() - 11; + downloadButton.y = importButton.y; + } else { + importButton.x = capesTab.x + capesTab.getWidth() - 11; + importButton.y = capesTab.y - 13; + downloadButton.x = importButton.x - 2 - 11; + downloadButton.y = importButton.y; + } + skinsTab.active = this.capesTab; + capesTab.active = !this.capesTab; + Runnable addWidgets = () -> { + clear(); + addDrawableChild(current); + addDrawableChild(skinsTab); + addDrawableChild(capesTab); + addDrawableChild(downloadButton); + addDrawableChild(importButton); + addDrawableChild(skinList); + addDrawableChild(capesList); + addDrawableChild(back); + }; + if (cachedProfile != null) { + initDisplay(); + addWidgets.run(); + return; + } + loadingFuture.thenAcceptAsync(profile -> { + cachedProfile = profile; + initDisplay(); + addWidgets.run(); + }).exceptionally(t -> { + if (t.getCause() instanceof CancellationException) { + client.openScreen(parent); + return null; + } + AxolotlClientCommon.getInstance().getLogger().error("Failed to load skins!", t); + var error = new TranslatableText("skins.error.failed_to_load"); + var errorDesc = new TranslatableText("skins.error.failed_to_load_desc"); + clear(); + addDrawableChild(back); + class TextWidget extends AbstractButtonWidget { + + public TextWidget(int x, int y, int width, int height, Text message, TextRenderer textRenderer) { + super(x, y, width, height, message); + active = false; + } + + @Override + public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) { + drawCenteredText(matrices, textRenderer, getMessage(), x + getWidth() / 2, y + getHeight() / 2 - textRenderer.fontHeight / 2, -1); + } + } + addDrawableChild(new TextWidget(width / 2 - textRenderer.getWidth(error) / 2, height / 2 - textRenderer.fontHeight - 2, textRenderer.getWidth(error), textRenderer.fontHeight, error, textRenderer)); + addDrawableChild(new TextWidget(width / 2 - textRenderer.getWidth(errorDesc) / 2, height / 2 + 1, textRenderer.getWidth(errorDesc), textRenderer.fontHeight, errorDesc, textRenderer)); + return null; + }); + } + + private void promptForSkinDownload() { + client.openScreen(new SimpleTextInputScreen(this, new TranslatableText("skins.manage.import.online"), new TranslatableText("skins.manage.import.online.input"), s -> + UUIDHelper.ensureUuidOpt(s).thenAccept(o -> { + if (o.isPresent()) { + AxolotlClientCommon.getInstance().getLogger().info("Downloading skin of {} ({})", s, o.get()); + Auth.getInstance().getMsApi().getTextures(o.get()) + .exceptionally(th -> { + AxolotlClientCommon.getInstance().getLogger().info("Failed to download skin of {} ({})", s, o.get(), th); + return null; + }).thenAccept(t -> { + if (t == null) { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_download", s); + return; + } + try { + var bytes = t.skin().join(); + var out = ensureNonexistent(SKINS_DIR.resolve(t.skinKey())); + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, t.classicModel(), "name", t.name(), "uuid", t.id(), "download_time", Instant.now())); + Files.write(out, bytes); + client.execute(this::loadSkinsList); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.downloaded", t.name()); + AxolotlClientCommon.getInstance().getLogger().info("Downloaded skin of {} ({})", t.name(), o.get()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to write skin file", e); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_save", t.name()); + } + }); + } else { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.not_found", s); + } + }))); + } + + private T addDrawableChild(T child) { + drawables.add(child); + return addChild(child); + } + + private void clear() { + children.clear(); + buttons.clear(); + drawables.clear(); + } + + @Override + public void render(MatrixStack graphics, int mouseX, int mouseY, float delta) { + tooltip = null; + renderBackground(graphics); + drawables.forEach(d -> d.render(graphics, mouseX, mouseY, delta)); + drawCenteredText(graphics, textRenderer, getTitle(), width / 2, 33 / 2 - textRenderer.fontHeight / 2, -1); + if (tooltip != null) { + renderTooltip(graphics, tooltip, mouseX, mouseY + 20); + } + } + + private void initDisplay() { + loadSkinsList(); + loadCapesList(); + } + + private void refreshCurrentList() { + if (capesTab) { + var scroll = capesList.getScrollAmount(); + loadCapesList(); + capesList.setScrollAmount(scroll); + } else { + var scroll = skinList.getScrollAmount(); + loadSkinsList(); + skinList.setScrollAmount(scroll); + } + } + + private void loadCapesList() { + List rows = new ArrayList<>(); + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + var capes = profile.capes(); + var deselectCape = createWidgetForCape(current.getSkin(), null); + var activeCape = capes.stream().filter(Cape::active).findFirst(); + current.setCape(activeCape.orElse(null)); + deselectCape.noCape(activeCape.isEmpty()); + for (int i = 0; i < capes.size() + 1; i += columns) { + Entry widget; + if (i == 0) { + widget = createEntry(capesList.getEntryContentsHeight(), deselectCape, new TranslatableText("skins.capes.no_cape")); + } else { + var cape = capes.get(i - 1); + widget = createEntryForCape(current.getSkin(), cape, capesList.getEntryContentsHeight()); + } + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < capes.size() + 1 - c)) continue; + var cape2 = capes.get(i + c - 1); + Entry widget2 = createEntryForCape(current.getSkin(), cape2, capesList.getEntryContentsHeight()); + + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + client.execute(() -> capesList.replaceEntries(rows)); + } + + private void loadSkinsList() { + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + List skins = new ArrayList<>(profile.skins()); + var hashes = skins.stream().map(Asset::sha256).collect(Collectors.toSet()); + var defaultSkin = Skin.getDefaultSkin(account); + var local = new ArrayList<>(loadLocalSkins()); + var localHashes = local.stream().collect(Collectors.toMap(Asset::sha256, Function.identity(), (skin, skin2) -> skin)); + local.removeIf(s -> !localHashes.containsValue(s)); + skins.replaceAll(s -> { + if (s instanceof MSApi.MCProfile.OnlineSkin online) { + if (localHashes.containsKey(s.sha256()) && localHashes.get(s.sha256()) instanceof Skin.LocalSkin file) { + local.remove(localHashes.remove(s.sha256())); + return new Skin.Shared(file, online); + } + } + return s; + }); + skins.addAll(local); + if (!hashes.contains(defaultSkin.sha256())) { + skins.add(defaultSkin); + } + populateSkinList(skins, columns); + } + + private List loadLocalSkins() { + try { + Files.createDirectories(SKINS_DIR); + try (Stream skins = Files.list(SKINS_DIR)) { + return skins.filter(Files::isRegularFile).sorted(Comparator.comparingLong(p -> { + try { + return Files.getLastModifiedTime(p).toMillis(); + } catch (IOException e) { + return 0L; + } + }).reversed()).map(Auth.getInstance().getSkinManager()::read).filter(Objects::nonNull).toList(); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to read skins dir!", e); + } + return Collections.emptyList(); + } + + private void populateSkinList(List skins, int columns) { + int entryHeight = skinList.getEntryContentsHeight(); + List rows = new ArrayList<>(); + for (int i = 0; i < skins.size(); i += columns) { + var s = skins.get(i); + if (s != null && s.active()) { + current.setSkin(s); + } + var widget = createEntryForSkin(s, entryHeight); + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < skins.size() - c)) continue; + var s2 = skins.get(i + c); + if (s2 != null && s2.active()) { + current.setSkin(s2); + } + var widget2 = createEntryForSkin(s2, entryHeight); + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + client.execute(() -> skinList.replaceEntries(rows)); + } + + private Path ensureNonexistent(Path p) { + if (Files.exists(p)) { + int counter = 0; + do { + counter++; + p = p.resolveSibling(p.getFileName().toString() + "_" + counter); + } while (Files.exists(p)); + } + return p; + } + + @Override + public void filesDragged(List packs) { + if (packs.isEmpty()) return; + + CompletableFuture[] futs = new CompletableFuture[packs.size()]; + for (int i = 0; i < packs.size(); i++) { + Path p = packs.get(i); + futs[i] = CompletableFuture.runAsync(() -> { + try { + var target = ensureNonexistent(SKINS_DIR.resolve(p.getFileName())); + var skin = Auth.getInstance().getSkinManager().read(p, false); + if (skin != null) { + Files.write(target, skin.image()); + } else { + AxolotlClientCommon.getInstance().getLogger().info("Skipping dragged file {} because it does not seem to be a valid skin!", p); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.not_copied", p.getFileName()); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to copy skin file: ", e); + } + }, client); + } + CompletableFuture.allOf(futs).thenRun(this::loadSkinsList); + } + + private @NotNull Entry createEntryForSkin(Skin skin, int entryHeight) { + return createEntry(entryHeight, new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, skin, account)); + } + + private @NotNull Entry createEntryForCape(Skin currentSkin, Cape cape, int entryHeight) { + return createEntry(entryHeight, createWidgetForCape(currentSkin, cape), new LiteralText(cape.alias())); + } + + private SkinWidget createWidgetForCape(Skin currentSkin, Cape cape) { + SkinWidget widget2 = new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, currentSkin, cape, account); + widget2.setRotationY(210); + return widget2; + } + + @Override + public void resize(MinecraftClient client, int width, int height) { + Auth.getInstance().getSkinManager().releaseAll(); + super.resize(client, width, height); + } + + @Override + public void removed() { + Auth.getInstance().getSkinManager().releaseAll(); + Watcher.close(skinDirWatcher); + } + + @Override + public void onClose() { + client.openScreen(parent); + } + + private SkinListWidget getCurrentList() { + return capesTab ? capesList : skinList; + } + + private class SkinListWidget extends ElementListWidget { + public boolean active = true, visible = true; + + public SkinListWidget(MinecraftClient minecraft, int width, int height, int y, int entryHeight) { + super(minecraft, width, SkinManagementScreen.this.height, y, y + height, entryHeight); + setRenderHeader(false, 0); + //setRenderBackground(false); + } + + @Override + protected int getScrollbarPositionX() { + return right - 8; + } + + @Override + public int getRowLeft() { + return left + 3; + } + + @Override + public int getRowWidth() { + if (!(getMaxScroll() > 0)) { + return width - 4; + } + return width - 14; + } + + private int getMaxScroll() { + return Math.max(0, this.getMaxPosition() - (this.bottom - this.top - 4)); + } + + public int getEntryContentsHeight() { + return itemHeight - 4; + } + + @Override + public void replaceEntries(Collection newEntries) { + super.replaceEntries(newEntries); + } + + @Override + public void centerScrollOn(Row entry) { + super.centerScrollOn(entry); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amountY) { + if (!visible) return false; + return super.mouseScrolled(mouseX, mouseY, amountY); + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + return active && visible && super.isMouseOver(mouseX, mouseY); + } + + @Override + public void render(MatrixStack graphics, int mouseX, int mouseY, float delta) { + if (!visible) return; + super.render(graphics, mouseX, mouseY, delta); + } + } + + private class Row extends ElementListWidget.Entry { + private final List widgets; + + public Row(List entries) { + this.widgets = entries; + } + + @Override + public void render(MatrixStack guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + int x = left; + if (widgets.isEmpty()) return; + int count = widgets.size(); + int padding = ((width - 5 * (count - 1)) / count); + for (var w : widgets) { + w.x = x; + w.y = top; + w.setWidth(padding); + w.render(guiGraphics, mouseX, mouseY, partialTick); + x += w.getWidth() + 5; + } + } + + @Override + public @NotNull List children() { + return widgets; + } + + @Override + public void setFocused(@Nullable Element focused) { + super.setFocused(focused); + if (focused != null) { + getCurrentList().centerScrollOn(this); + } + } + } + + Entry createEntry(int height, SkinWidget widget) { + return createEntry(height, widget, null); + } + + Entry createEntry(int height, SkinWidget widget, Text label) { + return new Entry(height, widget, label); + } + + private class Entry extends AbstractButtonWidget implements ParentElement { + private final SkinWidget skinWidget; + private final @Nullable AbstractButtonWidget label; + private final List actionButtons = new ArrayList<>(); + private final AbstractButtonWidget equipButton; + private boolean equipping; + private long equippingStart; + @Nullable + private Element focused; + private boolean dragging; + + public Entry(int height, SkinWidget widget, @Nullable Text label) { + super(0, 0, widget.getWidth(), height, LiteralText.EMPTY); + widget.setWidth(getWidth() - 4); + var asset = widget.getFocusedAsset(); + if (asset instanceof Skin skin) { + var wideSprite = new Identifier("axolotlclient", "textures/gui/sprites/wide.png"); + var slimSprite = new Identifier("axolotlclient", "textures/gui/sprites/slim.png"); + var slimText = new TranslatableText("skins.manage.variant.classic"); + var wideText = new TranslatableText("skins.manage.variant.slim"); + actionButtons.add(new SpriteButton(skin.classicVariant() ? wideText : slimText, btn -> { + var self = (SpriteButton) btn; + skin.classicVariant(!skin.classicVariant()); + self.sprite = skin.classicVariant() ? slimSprite : wideSprite; + self.setMessage(skin.classicVariant() ? wideText : slimText); + }, skin.classicVariant() ? slimSprite : wideSprite)); + } + if (asset != null) { + if (asset instanceof Asset.Local local) { + this.actionButtons.add(new SpriteButton(new TranslatableText("skins.manage.delete"), btn -> { + btn.active = false; + client.openScreen(new ConfirmScreen(confirmed -> { + client.openScreen(new LoadingScreen(getTitle(), new TranslatableText("menu.working"))); + if (confirmed) { + try { + Files.delete(local.file()); + Skin.LocalSkin.deleteMetadata(local.file()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to delete: ", e); + } + } + client.openScreen(SkinManagementScreen.this); + btn.active = true; + }, new TranslatableText("skins.manage.delete.confirm"), (Text) (asset.active() ? + new TranslatableText("skins.manage.delete.confirm.desc_active") : + new TranslatableText("skins.manage.delete.confirm.desc") + ).br$color(Colors.RED.toInt()))); + }, new Identifier("axolotlclient", "textures/gui/sprites/delete.png"))); + } + if (asset instanceof Asset.Online online && online.supportsDownload() && !(asset instanceof Asset.Local)) { + this.actionButtons.add(new SpriteButton(new TranslatableText("skins.manage.download"), btn -> { + btn.active = false; + download(asset).thenRun(() -> { + refreshCurrentList(); + btn.active = true; + }); + }, new Identifier("axolotlclient", "textures/gui/sprites/download.png"))); + } + } + if (label != null) { + this.label = new AbstractButtonWidget(0, 0, widget.getWidth(), 16, label) { + @Override + public void renderButton(MatrixStack guiGraphics, int mouseX, int mouseY, float partialTick) { + DrawUtil.drawScrollableText(guiGraphics, textRenderer, getMessage(), x + 2, y, x + width - 2, y + height, -1); + } + }; + this.label.active = false; + } else { + this.label = null; + } + this.equipButton = new ButtonWidget(0, 0, widget.getWidth(), 20, new TranslatableText( + widget.isEquipped() ? "skins.manage.equipped" : "skins.manage.equip"), + btn -> { + equippingStart = Util.getMeasuringTimeMs(); + equipping = true; + btn.setMessage(TEXT_EQUIPPING); + btn.active = false; + Consumer> consumer = f -> f.thenAcceptAsync(p -> { + cachedProfile = p; + if (client.currentScreen == SkinManagementScreen.this) { + refreshCurrentList(); + } else { + client.execute(() -> client.openScreen(SkinManagementScreen.this)); + } + }).exceptionally(t -> { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to equip asset!", t); + equipping = false; + return null; + }); + if (asset instanceof Skin && !(current.getSkin() instanceof Skin.Local)) { + client.openScreen(new ConfirmScreen(confirmed -> { + client.openScreen(new LoadingScreen(getTitle(), TEXT_EQUIPPING)); + if (confirmed) { + consumer.accept(download(current.getSkin()).thenCompose(a -> widget.equip())); + } else { + consumer.accept(widget.equip()); + } + }, new TranslatableText("skins.manage.equip.confirm"), new TranslatableText("skins.manage.equip.download_current"))); + } else { + consumer.accept(widget.equip()); + } + }); + this.equipButton.active = !widget.isEquipped(); + this.skinWidget = widget; + } + + private @NotNull CompletableFuture download(Asset asset) { + return CompletableFuture.runAsync(() -> { + try { + var out = SKINS_DIR.resolve(asset.sha256()); + Files.createDirectories(out.getParent()); + Files.write(out, asset.image()); + if (asset instanceof Skin skin) { + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, skin.classicVariant())); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to download: ", e); + } + }); + } + + @Override + public final boolean isDragging() { + return this.dragging; + } + + @Override + public final void setDragging(boolean dragging) { + this.dragging = dragging; + } + + @Nullable + @Override + public Element getFocused() { + return this.focused; + } + + @Override + public void setFocused(@Nullable Element child) { + this.focused = child; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return ParentElement.super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return ParentElement.super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + return ParentElement.super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean isFocused() { + return getFocused() != null; + } + + @Override + public void setFocused(boolean focused) { + + } + + @Override + public @NotNull List children() { + return Stream.concat(actionButtons.stream(), Stream.of(skinWidget, label, equipButton)).filter(Objects::nonNull).toList(); + } + + private float applyEasing(float x) { + return x * x * x; + } + + @Override + public void renderButton(MatrixStack guiGraphics, int mouseX, int mouseY, float partialTick) { + int y = this.y + 4; + int x = this.x + 2; + skinWidget.setPosition(x, y); + skinWidget.setWidth(getWidth() - 4); + if (skinWidget.isEquipped() || equipping) { + long prog; + if (Auth.getInstance().skinManagerAnimations.get()) { + if (equipping) prog = (Util.getMeasuringTimeMs() - equippingStart) / 20 % 100; + else prog = Math.abs((Util.getMeasuringTimeMs() / 30 % 200) - 100); + } else prog = 100; + var percent = (prog / 100f); + float gradientWidth; + if (equipping) { + gradientWidth = percent * Math.min(getWidth() / 3f, getHeight() / 3f); + } else { + gradientWidth = Math.min(getWidth() / 15f, getHeight() / 6f) + applyEasing(percent) * Math.min(getWidth() * 2 / 15f, getHeight() / 6f); + } + GradientHoleRectangleRenderState.render(guiGraphics, this.x + 2, this.y + 2, this.x + getWidth() - 2, + skinWidget.getY() + skinWidget.getHeight() + 2, + gradientWidth, + equipping ? 0xFFFF0088 : ClientColors.SELECTOR_GREEN.toInt(), 0); + } + skinWidget.render(guiGraphics, mouseX, mouseY, partialTick); + int actionButtonY = this.y + 2; + for (var button : actionButtons) { + button.x = skinWidget.getX() + skinWidget.getWidth() - button.getWidth(); + button.y = actionButtonY; + if (isHovered() || button.isHovered()) { + button.render(guiGraphics, mouseX, mouseY, partialTick); + } + actionButtonY += button.getHeight() + 2; + } + if (label != null) { + label.x = x; + label.y = skinWidget.getY() + skinWidget.getHeight() + 6; + label.render(guiGraphics, mouseX, mouseY, partialTick); + label.setWidth(getWidth() - 4); + equipButton.x = x; + equipButton.y = label.y + label.getHeight() + 2; + } else { + equipButton.x = x; + equipButton.y = skinWidget.getY() + skinWidget.getHeight() + 4; + } + equipButton.setWidth(getWidth() - 4); + equipButton.render(guiGraphics, mouseX, mouseY, partialTick); + + if (isHovered()) { + guiGraphics.br$outlineRect(this.x, this.y, getWidth(), getHeight(), -1); + } + } + + private static class GradientHoleRectangleRenderState { + + public static void render(MatrixStack graphics, int x0, int y0, int x1, int y1, float gradientWidth, int col1, int col2) { + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.disableAlphaTest(); + RenderSystem.defaultBlendFunc(); + RenderSystem.shadeModel(7425); + var tessellator = Tessellator.getInstance(); + var vertexConsumer = tessellator.getBuffer(); + float z = 0; + //top + var pose = graphics.peek().getModel(); + vertexConsumer.begin(7, VertexFormats.POSITION_COLOR); + vertexConsumer.vertex(pose, x0, y0, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y0 + gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y0 + gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x1, y0, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + //left + vertexConsumer.vertex(pose, x0, y1, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y1 - gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y0 + gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x0, y0, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + //bottom + vertexConsumer.vertex(pose, x1, y1, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y1 - gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y1 - gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x0, y1, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + //right + vertexConsumer.vertex(pose, x1, y0, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y0 + gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y1 - gradientWidth, z).color(col2 >> 16 & 255, col2 >> 8 & 255, col2 & 255, col2 >> 24 & 255).next(); + vertexConsumer.vertex(pose, x1, y1, z).color(col1 >> 16 & 255, col1 >> 8 & 255, col1 & 255, col1 >> 24 & 255).next(); + tessellator.draw(); + RenderSystem.shadeModel(7424); + RenderSystem.disableBlend(); + RenderSystem.enableAlphaTest(); + RenderSystem.enableTexture(); + } + } + } + + private class SpriteButton extends ButtonWidget { + private Identifier sprite; + + public SpriteButton(Text message, PressAction onPress, Identifier sprite) { + super(0, 0, 11, 11, message, onPress); + this.sprite = sprite; + } + + @Override + public void renderButton(MatrixStack graphics, int mouseX, int mouseY, float delta) { + Identifier tex = ButtonWidgetTextures.get(getYImage(hovered)); + DrawUtil.blitSprite(tex, x, y, width, height, new DrawUtil.NineSlice(200, 20, 3)); + client.getTextureManager().bindTexture(sprite); + drawTexture(graphics, x + 2, y + 2, 0, 0, 7, 7, 7, 7); + if (this.isHovered()) { + tooltip = getMessage(); + } + } + } +} diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java new file mode 100644 index 000000000..c9bffe1a6 --- /dev/null +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import com.google.common.hash.Hashing; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.mixin.skins.PlayerSkinTextureAccessor; +import io.github.axolotlclient.util.ClientColors; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.util.Identifier; + +public class SkinManager { + + private final Set loadedTextures = new ConcurrentSkipListSet<>(Comparator.comparing(Object::toString)); + + public Skin read(Path p) { + return read(p, true); + } + + @SuppressWarnings("UnstableApiUsage") + public Skin read(Path p, boolean fix) { + boolean slim; + String sha256; + try { + var in = Files.readAllBytes(p); + sha256 = Hashing.sha256().hashBytes(in).toString(); + try (var stream = new ByteArrayInputStream(in)) { + try (var img = NativeImage.read(stream)) { + int width = img.getWidth(); + int height = img.getHeight(); + if (width != 64) return null; + if (height == 32) { + if (fix) { + try (var img2 = PlayerSkinTextureAccessor.invokeRemapTexture(img)) { + img2.writeFile(p); + } + } + slim = false; + } else if (height != 64) { + return null; + } else { + slim = ClientColors.ARGB.alpha(img.getPixelColor(50, 16)) == 0; + } + var metadata = Skin.LocalSkin.readMetadata(p); + if (metadata != null && metadata.containsKey(Skin.LocalSkin.CLASSIC_METADATA_KEY)) { + slim = !(boolean) metadata.get(Skin.LocalSkin.CLASSIC_METADATA_KEY); + } + } + } + return new Skin.LocalSkin(!slim, p, in, sha256); + } catch (Exception e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to probe skin: ", e); + } + return null; + } + + public AxoIdentifier loadSkin(Skin skin) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "skins/" + skin.sha256()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try (var stream = new ByteArrayInputStream(skin.image())) { + var tex = new NativeImageBackedTexture(NativeImage.read(stream)); + tex.upload(); + MinecraftClient.getInstance().getTextureManager().registerTexture((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public AxoIdentifier loadCape(Cape cape) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "capes/" + cape.id()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try (var stream = new ByteArrayInputStream(cape.image())) { + var tex = new NativeImageBackedTexture(NativeImage.read(stream)); + MinecraftClient.getInstance().getTextureManager().registerTexture((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public void releaseAll() { + loadedTextures.forEach(id -> MinecraftClient.getInstance().getTextureManager().destroyTexture((Identifier) id)); + loadedTextures.clear(); + } +} diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java new file mode 100644 index 000000000..aa18c8668 --- /dev/null +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java @@ -0,0 +1,116 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.function.Consumer; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.*; +import net.minecraft.client.render.entity.model.PlayerEntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +public class SkinRenderer { + private static PlayerEntityModel classicModel, slimModel; + + private SkinRenderer() { + } + + public static void render(MatrixStack graphics, boolean classicVariant, + Identifier skinTexture, + @Nullable Identifier cape, + float rotationX, + float rotationY, + float pivotY, + int x0, + int y0, + int x1, + int y1, + float scale) { + if (classicModel == null && classicVariant) { + classicModel = new PlayerEntityModel<>(0, false); + classicModel.child = false; + } + if (slimModel == null && !classicVariant) { + slimModel = new PlayerEntityModel<>(0, true); + slimModel.child = false; + } + + int width = x1 - x0; + DiffuseLighting.disable(); + graphics.push(); + graphics.translate(x0 + width / 2.0F, (float) (y1), 100.0F); + graphics.scale(scale, scale, scale); + graphics.translate(0.0F, -0.0625F, 0.0F); + graphics.translate(0, pivotY, 0); + graphics.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(rotationX)); + graphics.translate(0, -pivotY, 0); + graphics.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(rotationY)); + graphics.push(); + graphics.scale(1.0F, 1.0F, -1.0F); + graphics.translate(0.0F, -1.5F, 0.0F); + var model = classicVariant ? classicModel : slimModel; + var tessellator = Tessellator.getInstance(); + RenderSystem.enableDepthTest(); + RenderSystem.enableBlend(); + RenderSystem.enableTexture(); + MinecraftClient.getInstance().getTextureManager().bindTexture(skinTexture); + var consumer = VertexConsumerProvider.immediate(tessellator.getBuffer()).getBuffer(model.getLayer(skinTexture)); + Consumer renderModelPart = m -> m.render(graphics, consumer, 15728880, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); + renderModelPart.accept(model.head); + renderModelPart.accept(model.torso); + renderModelPart.accept(model.rightArm); + renderModelPart.accept(model.leftArm); + renderModelPart.accept(model.rightLeg); + renderModelPart.accept(model.leftLeg); + renderModelPart.accept(model.helmet); + renderModelPart.accept(model.leftPantLeg); + renderModelPart.accept(model.rightPantLeg); + renderModelPart.accept(model.leftSleeve); + graphics.translate(0, 0, -0.62f); + renderModelPart.accept(model.rightSleeve); + graphics.translate(0, 0, 0.62f); + renderModelPart.accept(model.jacket); + tessellator.draw(); + if (cape != null) { + graphics.push(); + MinecraftClient.getInstance().getTextureManager().bindTexture(cape); + graphics.translate(0.0F, 0.0F, 0.125F); + graphics.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(6.0F)); + graphics.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(180.0F)); + model.renderCape(graphics, VertexConsumerProvider.immediate(tessellator.getBuffer()).getBuffer(RenderLayer.getEntitySolid(cape)), 15728880, OverlayTexture.DEFAULT_UV); + tessellator.draw(); + graphics.pop(); + } + graphics.pop(); + + graphics.pop(); + RenderSystem.disableBlend(); + RenderSystem.disableDepthTest(); + DiffuseLighting.enableGuiDepthLighting(); + } +} diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java new file mode 100644 index 000000000..822d87941 --- /dev/null +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java @@ -0,0 +1,144 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.concurrent.CompletableFuture; + +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.gui.widget.AbstractButtonWidget; +import net.minecraft.client.sound.SoundManager; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.MutableText; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; + +public class SkinWidget extends AbstractButtonWidget { + private static final float MODEL_HEIGHT = 2.125F; + private static final float FIT_SCALE = 0.97F; + private static final float ROTATION_SENSITIVITY = 2.5F; + private static final float DEFAULT_ROTATION_X = -5.0F; + private static final float DEFAULT_ROTATION_Y = 30.0F; + private static final float ROTATION_X_LIMIT = 50.0F; + private float rotationX = DEFAULT_ROTATION_X; + @Setter + private float rotationY = DEFAULT_ROTATION_Y; + @Getter + @Setter + private Skin skin; + @Getter + @Setter + private Cape cape; + private final Account owner; + private boolean noCape, noCapeActive; + + public SkinWidget(int width, int height, Skin skin, @Nullable Cape cape, Account owner) { + super(0, 0, width, height, LiteralText.EMPTY); + this.skin = skin; + this.cape = cape; + this.owner = owner; + } + + public SkinWidget(int width, int height, Skin skin, Account owner) { + this(width, height, skin, null, owner); + } + + public void noCape(boolean noCapeActive) { + noCape = true; + this.noCapeActive = noCapeActive; + } + + @Override + public void renderButton(MatrixStack guiGraphics, int mouseX, int mouseY, float partialTick) { + float scale = FIT_SCALE * this.getHeight() / MODEL_HEIGHT; + float pivotY = -1.0625F; + + SkinManager skinManager = Auth.getInstance().getSkinManager(); + AxoIdentifier skinRl = skinManager.loadSkin(skin); + boolean classic = skin.classicVariant(); + var capeRl = cape == null ? null : skinManager.loadCape(cape); + + SkinRenderer.render(guiGraphics, classic, (Identifier) skinRl, (Identifier) capeRl, this.rotationX, this.rotationY, pivotY, this.getX(), this.getY(), this.getX() + getWidth(), this.getY() + getHeight(), scale); + } + + public int getY() { + return y; + } + + public int getX() { + return x; + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) { + this.rotationX = MathHelper.clamp(this.rotationX - (float) dragY * ROTATION_SENSITIVITY, -ROTATION_X_LIMIT, ROTATION_X_LIMIT); + this.rotationY += (float) dragX * ROTATION_SENSITIVITY; + } + + @Override + public void playDownSound(SoundManager handler) { + } + + @Override + protected MutableText getNarrationMessage() { + return LiteralText.EMPTY.copy(); + } + + @Override + public boolean changeFocus(boolean lookForwards) { + return false; + } + + public boolean isEquipped() { + return noCape ? noCapeActive : (cape != null ? cape.active() : skin != null && skin.active()); + } + + public CompletableFuture equip() { + var msApi = Auth.getInstance().getMsApi(); + if (noCape) { + return msApi.hideCape(owner); + } + if (cape != null) { + return cape.equip(msApi, owner); + } + if (skin != null) { + return skin.equip(msApi, owner); + } + return msApi.resetSkin(owner); + } + + public Asset getFocusedAsset() { + return noCape ? null : cape != null ? cape : skin; + } + + public void setPosition(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java index 03c34e5cf..d9a0a56dd 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java @@ -32,6 +32,7 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.FloatOption; import io.github.axolotlclient.mixin.ShaderEffectAccessor; import io.github.axolotlclient.modules.AbstractModule; +import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gl.ShaderEffect; import net.minecraft.client.gl.Uniform; @@ -43,6 +44,7 @@ public class MotionBlur extends AbstractModule { + @Getter private static final MotionBlur Instance = new MotionBlur(); public final BooleanOption enabled = new BooleanOption("enabled", false); public final FloatOption strength = new FloatOption("strength", 50F, 1F, 99F); @@ -60,10 +62,6 @@ private static float getBlur() { return MotionBlur.getInstance().strength.get() / 100F; } - public static MotionBlur getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled, strength, inGuis); @@ -140,7 +138,7 @@ public String getResourcePackName() { } @Override - public void close() throws IOException { + public void close() { } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java index aa7ffc8f0..ab5986139 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java @@ -46,7 +46,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudEditScreen extends Screen { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java index db60ef06d..9c0a90113 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java @@ -26,9 +26,9 @@ import io.github.axolotlclient.modules.hud.gui.hud.KeystrokeHud; import io.github.axolotlclient.modules.hud.gui.hud.PackDisplayHud; import io.github.axolotlclient.modules.hud.gui.hud.PlayerHud; -import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import io.github.axolotlclient.modules.hud.gui.hud.simple.ComboHud; import io.github.axolotlclient.modules.hud.gui.hud.simple.ReachHud; +import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import lombok.Getter; import net.minecraft.client.MinecraftClient; @@ -36,7 +36,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudManager extends HudManagerCommon { @Getter @@ -67,7 +67,7 @@ protected void addExtraHud() { public void render(AxoRenderContext context, float delta) { final var mc = ((MinecraftClient) client); mc.getProfiler().push("Hud render"); - if(!(mc.currentScreen instanceof HudEditScreen)) { + if (!(mc.currentScreen instanceof HudEditScreen)) { super.render(context, delta); } mc.getProfiler().pop(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java index 496e65984..b0752e23f 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java @@ -38,9 +38,9 @@ import io.github.axolotlclient.config.profiles.ProfileAware; import io.github.axolotlclient.mixin.KeyBindAccessor; import io.github.axolotlclient.modules.hud.ClickInputTracker; +import io.github.axolotlclient.modules.hud.gui.entry.TextHudEntry; import io.github.axolotlclient.modules.hud.gui.keystrokes.KeystrokePositioningScreen; import io.github.axolotlclient.modules.hud.gui.keystrokes.KeystrokesScreen; -import io.github.axolotlclient.modules.hud.gui.entry.TextHudEntry; import io.github.axolotlclient.modules.hud.gui.layout.Justification; import io.github.axolotlclient.modules.hud.util.DrawPosition; import io.github.axolotlclient.modules.hud.util.Rectangle; @@ -68,7 +68,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class KeystrokeHud extends TextHudEntry implements ProfileAware { @@ -475,6 +475,7 @@ public boolean isLabelEditable() { } public void saveKeystrokes() { + if (keystrokes == null) return; try { var path = AxolotlClientCommon.resolveProfileConfigFile(KEYSTROKE_SAVE_FILE_NAME); Files.createDirectories(path.getParent()); @@ -493,7 +494,11 @@ public void loadKeystrokes() { var loaded = entries.stream().map(e -> (Map) e) .map(KeystrokeHud.this::deserializeKey) .toList(); - keystrokes.clear(); + if (keystrokes == null) { + keystrokes = new ArrayList<>(); + } else { + keystrokes.clear(); + } keystrokes.addAll(loaded); } else { saveKeystrokes(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java index e90fbb3bd..1b040e0cc 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java @@ -23,9 +23,9 @@ package io.github.axolotlclient.modules.hud.gui.hud; import com.mojang.blaze3d.systems.RenderSystem; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.render.AxoRenderContext; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; @@ -42,7 +42,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @SuppressWarnings("deprecation") @@ -58,7 +58,7 @@ public PlayerHud() { } public void onPlayerDirectionChange(PlayerDirectionChangeEvent event) { - yawOffset += (event.getYaw() - event.getPrevYaw()) / 2; + yawOffset += (event.yaw() - event.prevYaw()) / 2; } @Override @@ -159,6 +159,7 @@ protected void renderPlayer(AxoRenderContext ctx, boolean placeholder, double x, private boolean isPerformingAction() { // inspired by tr7zw's mod ClientPlayerEntity player = MinecraftClient.getInstance().player; + //noinspection DataFlowIssue return player.isSneaking() || player.isSprinting() || player.isFallFlying() || player.abilities.flying || player.isSubmergedInWater() || player.isInSwimmingPose() || player.hasVehicle() || player.isUsingItem() || player.handSwinging || player.hurtTime > 0 || player.isOnFire(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java index d253f9bba..d0e811f92 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java @@ -40,7 +40,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ActionBarHud extends TextHudEntry { @@ -117,6 +117,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(timeShown); options.add(customTextColor); return options; diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java index 905832c13..7a54da534 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java @@ -52,7 +52,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class BossBarHud extends TextHudEntry implements DynamicallyPositionable { @@ -153,6 +153,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(text); options.add(bar); options.add(anchor); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java index 5cc60c2ac..0c88bbf6a 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java @@ -65,7 +65,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CrosshairHud extends AbstractHudEntry implements DynamicallyPositionable { @@ -121,6 +121,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(type); options.add(customTextureGraphics); options.add(showInF5); @@ -150,6 +151,7 @@ public double getDefaultY() { return 0.5; } + @SuppressWarnings("deprecation") @Override public void render(AxoRenderContext context, float delta) { MatrixStack matrices = (MatrixStack) context; @@ -226,6 +228,7 @@ public void render(AxoRenderContext context, float delta) { // Draw attack indicator x = (int) ((client.getWindow().getScaledWidth() / getScale()) / 2 - 8); y = (int) ((client.getWindow().getScaledHeight() / getScale()) / 2 - 7 + 16); + //noinspection DataFlowIssue ItemStack itemStack = this.client.player.getStackInHand(Hand.OFF_HAND); boolean bl = this.client.options.field_26808 == class_5512.field_26811; if (bl && itemStack.getItem() == Items.SHIELD && this.client.player.method_31233(itemStack)) { @@ -236,6 +239,7 @@ public void render(AxoRenderContext context, float delta) { float f = this.client.player.getAttackCooldownProgress(0.0F); boolean bl2 = false; if (this.client.targetedEntity != null && this.client.targetedEntity instanceof LivingEntity && f >= 2.0F) { + //noinspection DataFlowIssue bl2 = ((EntityHitResult) this.client.crosshairTarget).method_31252() <= this.client.player.method_31239(0.0F); bl2 &= this.client.targetedEntity.isAlive(); } @@ -252,6 +256,7 @@ public void render(AxoRenderContext context, float delta) { } } if (((type.get().equals(Crosshair.TEXTURE) || type.get().equals(Crosshair.CUSTOM)) ? customAttackIndicator.get() : true) && indicator == AttackIndicator.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackCooldownProgress(0.0F) / 2; if (progress != 1.0F) { RenderUtil.drawRectangle(matrices, getRawX() + (getWidth() / 2) - 6, getRawY() + (getHeight() / 2) + 9, @@ -268,11 +273,13 @@ public Color getColor() { HitResult hit = client.crosshairTarget; if (hit == null || hit.getType() == null) { return defaultColor.get(); - } else if (hit.getType() == HitResult.Type.ENTITY && ((EntityHitResult) this.client.crosshairTarget).method_31252() <= this.client.player.method_31239(0.0F)) { + } else //noinspection DataFlowIssue + if (hit.getType() == HitResult.Type.ENTITY && ((EntityHitResult) this.client.crosshairTarget).method_31252() <= this.client.player.method_31239(0.0F)) { return entityColor.get(); } else if (hit.getType() == HitResult.Type.BLOCK) { BlockPos blockPos = ((BlockHitResult) hit).getBlockPos(); World world = this.client.world; + //noinspection DataFlowIssue if (world.getBlockState(blockPos).createScreenHandlerFactory(world, blockPos) != null || world.getBlockState(blockPos).getBlock() instanceof AbstractChestBlock) { return containerColor.get(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java index 3d53b392c..31eaf4c0b 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java @@ -138,6 +138,7 @@ public AnchorPoint getAnchor() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(anchor); options.add(showCCount); options.add(showECount); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java index 3702ea449..372e35fe2 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java @@ -52,6 +52,7 @@ public class HotbarHUD extends TextHudEntry { public HotbarHUD() { super(182, 22, false); + supportsScaling = false; } @Override @@ -62,7 +63,6 @@ public void renderComponent(AxoRenderContext context, float delta) { ? (PlayerEntity) MinecraftClient.getInstance().cameraEntity : null; if (playerEntity != null) { - //scale(matrices); DrawPosition pos = getPos(); RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); @@ -72,7 +72,6 @@ public void renderComponent(AxoRenderContext context, float delta) { Arm arm = playerEntity.getMainArm().getOpposite(); matrices.br$pushMatrix(); - matrices.br$translateMatrix(0, -90, 0); drawTexture(matrices, pos.x, pos.y, 0, 0, 182, 22, 256, 256); drawTexture(matrices, pos.x - 1 + playerEntity.inventory.selectedSlot * 20, pos.y - 1, 0, 22, 24, 22, 256, 256); @@ -155,6 +154,7 @@ public boolean overridesF3() { public List> getConfigurationOptions() { List> list = new ArrayList<>(); list.add(enabled); + list.add(hide); return list; } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java index 120db20a6..a071ba326 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java @@ -57,7 +57,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ScoreboardHud extends TextHudEntry implements DynamicallyPositionable { @@ -105,8 +105,10 @@ public void render(AxoRenderContext matrices, float delta) { @Override public void renderComponent(AxoRenderContext matrices, float delta) { + //noinspection DataFlowIssue Scoreboard scoreboard = this.client.world.getScoreboard(); ScoreboardObjective scoreboardObjective = null; + //noinspection DataFlowIssue Team team = scoreboard.getPlayerTeam(this.client.player.getEntityName()); if (team != null) { int t = team.getColor().getColorIndex(); @@ -240,8 +242,8 @@ private void renderScoreboardSidebar(MatrixStack matrices, ScoreboardObjective o @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); - options.add(options.indexOf(super.backgroundColor), backgroundColor); - options.remove(super.backgroundColor); + options.set(options.indexOf(super.backgroundColor), backgroundColor); + options.add(hide); options.add(topColor); options.add(scores); options.add(scoreColor); @@ -261,4 +263,14 @@ public Identifier getId() { public AnchorPoint getAnchor() { return anchor.get(); } + + @Override + public double getDefaultX() { + return 1.0; + } + + @Override + public double getDefaultY() { + return 0.5; + } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java index df840cecb..b157d7c32 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class SnappingHelper { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java index 55263bfd9..0e02b680b 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java @@ -40,7 +40,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class DrawUtil extends DrawableHelper { @@ -384,6 +384,7 @@ private static void innerBlit( int g = color >> 8 & 255; int b = color & 255; int a = color >> 24 & 255; + //noinspection deprecation GlStateManager.color4f(r, g, b, a); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferBuilder = tessellator.getBuffer(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java index f27dbabce..43a866618 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java @@ -22,10 +22,6 @@ package io.github.axolotlclient.modules.hud.util; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import io.github.axolotlclient.util.ClientColors; @@ -41,124 +37,18 @@ import net.minecraft.client.texture.SpriteAtlasTexture; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; -import net.minecraft.util.Util; import net.minecraft.util.math.MathHelper; /** * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ +@SuppressWarnings("deprecation") @UtilityClass public class ItemUtil { - - public static ArrayList removeOld(List list, int time) { - ArrayList stored = new ArrayList<>(); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.getPassedTime() <= time) { - stored.add(storage); - } - } - return stored; - } - - public static List untimedToTimed(List list) { - ArrayList timed = new ArrayList<>(); - for (ItemStorage stack : list) { - timed.add(stack.timed()); - } - return timed; - } - - public static Optional getTimedItemFromItem(ItemStack item, - List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.stack.isItemEqualIgnoreDamage(compare)) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - public static int getTotal(MinecraftClient client, ItemStack stack) { - List item = ItemUtil.getItems(client); - if (item == null || item.isEmpty()) { - return 0; - } - List items = ItemUtil.storageFromItem(item); - Optional stor = ItemUtil.getItemFromItem(stack, items); - return stor.map(itemStorage -> itemStorage.times).orElse(0); - } - - public static List getItems(MinecraftClient client) { - ArrayList items = new ArrayList<>(); - if (client.player == null) { - return null; - } - items.addAll(client.player.inventory.armor); - items.addAll(client.player.inventory.offHand); - items.addAll(client.player.inventory.main); - return items; - } - - public static List storageFromItem(List items) { - ArrayList storage = new ArrayList<>(); - for (ItemStack item : items) { - if (item.isEmpty()) { - continue; - } - Optional s = getItemFromItem(item, storage); - if (s.isPresent()) { - ItemUtil.ItemStorage store = s.get(); - store.incrementTimes(item.getCount()); - } else { - storage.add(new ItemUtil.ItemStorage(item, item.getCount())); - } - } - return storage; - } - - public static Optional getItemFromItem(ItemStack item, List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.ItemStorage storage : list) { - if (storage.stack.isItemEqualIgnoreDamage(compare)) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - /** - * Compares two ItemStorage Lists. - * If list1.get(1) is 10, and list2 is 5, it will return 5. - * Will return nothing if negative... - * - * @param list1 one to be based off of - * @param list2 one to compare to - * @return the compared list - */ - public static List compare(List list1, List list2) { - ArrayList list = new ArrayList<>(); - for (ItemStorage current : list1) { - Optional optional = getItemFromItem(current.stack, list2); - if (optional.isPresent()) { - ItemStorage other = optional.get(); - if (current.times - other.times <= 0) { - continue; - } - list.add(new ItemStorage(other.stack.copy(), current.times - other.times)); - } else { - list.add(current.copy()); - } - } - return list; - } - public void renderGuiItemModel(float scale, ItemStack stack, float x, float y) { DiffuseLighting.disable(); MinecraftClient client = MinecraftClient.getInstance(); @@ -166,6 +56,7 @@ public void renderGuiItemModel(float scale, ItemStack stack, float x, float y) { RenderSystem.pushMatrix(); RenderSystem.scalef(scale, scale, 1); client.getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE); + //noinspection DataFlowIssue client.getTextureManager().getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).setFilter(false, false); RenderSystem.enableRescaleNormal(); RenderSystem.enableAlphaTest(); @@ -243,53 +134,4 @@ public static void renderGuiItemOverlay(MatrixStack matrices, TextRenderer rende RenderSystem.enableDepthTest(); } } - - public static class ItemStorage { - - public final ItemStack stack; - public int times; - - public ItemStorage(ItemStack stack, int times) { - ItemStack copy = stack.copy(); - copy.setCount(1); - this.stack = copy; - this.times = times; - } - - public void incrementTimes(int num) { - times = times + num; - } - - public ItemStorage copy() { - return new ItemStorage(stack.copy(), times); - } - - public TimedItemStorage timed() { - return new TimedItemStorage(stack, times); - } - } - - public static class TimedItemStorage extends ItemStorage { - - public float start; - - public TimedItemStorage(ItemStack stack, int times) { - super(stack, times); - this.start = Util.getMeasuringTimeMs(); - } - - public float getPassedTime() { - return Util.getMeasuringTimeMs() - start; - } - - @Override - public void incrementTimes(int num) { - super.incrementTimes(num); - refresh(); - } - - public void refresh() { - start = Util.getMeasuringTimeMs(); - } - } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java index b55b8def0..2ce5c0816 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java @@ -35,9 +35,10 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ +@SuppressWarnings("deprecation") @UtilityClass public class RenderUtil { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/particles/Particles.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/particles/Particles.java index 993d473d2..154537f0e 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/particles/Particles.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/particles/Particles.java @@ -35,6 +35,7 @@ import io.github.axolotlclient.mixin.ParticleAccessor; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.ClientColors; +import lombok.Getter; import net.minecraft.client.particle.Particle; import net.minecraft.particle.ParticleType; import net.minecraft.particle.ParticleTypes; @@ -43,6 +44,7 @@ public class Particles extends AbstractModule { + @Getter private static final Particles Instance = new Particles(); public final HashMap, HashMap>> particleOptions = new HashMap<>(); @@ -51,10 +53,6 @@ public class Particles extends AbstractModule { private final OptionCategory cat = OptionCategory.create("particles"); private final BooleanOption enabled = new BooleanOption("enabled", false); - public static Particles getInstance() { - return Instance; - } - @Override public void init() { cat.add(enabled); @@ -64,8 +62,9 @@ public void init() { } private void addParticleOptions() { - for (ParticleType type : Registry.PARTICLE_TYPE.stream().sorted(new AlphabeticalComparator()).collect(Collectors.toList())) { + for (ParticleType type : Registry.PARTICLE_TYPE.stream().sorted(new AlphabeticalComparator()).toList()) { if (Registry.PARTICLE_TYPE.getId(type) != null) { + //noinspection DataFlowIssue OptionCategory category = OptionCategory.create( Arrays.stream(Registry.PARTICLE_TYPE.getId(type).getPath().split("_")) .map(StringUtils::capitalize).collect(Collectors.joining(" "))); @@ -146,6 +145,7 @@ public int compare(ParticleType s1, ParticleType s2) { private String getName(ParticleType type) { if (Registry.PARTICLE_TYPE.getId(type) != null) { + //noinspection DataFlowIssue return Registry.PARTICLE_TYPE.getId(type).getPath(); } return ""; diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java index 4d51d7ab1..81f4400e9 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java @@ -52,7 +52,7 @@ public void render(MatrixStack graphics, int mouseX, int mouseY, float delta) { @Override protected void init() { - var urlBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 2 - 10, 200, 20, new TranslatableText("urlBox")); + var urlBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 2 - 10, 200, 20, new TranslatableText("pasteURL")); urlBox.setSuggestion(I18n.translate("pasteURL")); urlBox.setChangedListener(s -> { if (s.isEmpty()) { @@ -68,6 +68,7 @@ protected void init() { if (url.isEmpty()) { return; } + //noinspection DataFlowIssue client.openScreen(ImageScreen.create(this, ImageShare.getInstance().downloadImage(url), true)); }) { @Override @@ -76,6 +77,7 @@ public void renderButton(MatrixStack graphics, int mouseX, int mouseY, float del setMessage(LiteralText.EMPTY); super.renderButton(graphics, mouseX, mouseY, delta); setMessage(message); + //noinspection DataFlowIssue client.getTextureManager().bindTexture(SPRITE); drawTexture(graphics, x, y, 0, 0, getWidth(), getHeight(), getWidth(), getHeight()); } @@ -89,6 +91,7 @@ public void renderButton(MatrixStack graphics, int mouseX, int mouseY, float del @Override public void onClose() { + //noinspection DataFlowIssue client.openScreen(parent); } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java index afb76d8a1..37acaf409 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java @@ -27,10 +27,12 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; import io.github.axolotlclient.modules.AbstractModule; +import lombok.Getter; import net.minecraft.client.gui.screen.Screen; public class ScrollableTooltips extends AbstractModule { + @Getter private static final ScrollableTooltips Instance = new ScrollableTooltips(); public final BooleanOption enabled = new BooleanOption("enabled", false); public final BooleanOption enableShiftHorizontalScroll = new BooleanOption("shiftHorizontalScroll", true); @@ -40,10 +42,6 @@ public class ScrollableTooltips extends AbstractModule { public int tooltipOffsetX; public int tooltipOffsetY; - public static ScrollableTooltips getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java index 45f627df8..63b4627ba 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java @@ -40,9 +40,10 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: GPL-3.0

**/ +@SuppressWarnings("deprecation") public class FSBSkyboxInstance extends SkyboxInstance { public FSBSkyboxInstance(JsonObject json) { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java index 38104198c..4499a0398 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java @@ -46,7 +46,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ public class SkyResourceManager extends AbstractModule implements SimpleSynchronousResourceReloadListener { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java index 2cc370dec..95e44bf3e 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java @@ -48,11 +48,12 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ // TODO fix rotation & blending issues with shooting stars, implement more missing features like worlds, weather, biomes... +@SuppressWarnings("deprecation") public abstract class SkyboxInstance { protected final Identifier MOON_PHASES = new Identifier("textures/environment/moon_phases.png"); @@ -145,33 +146,26 @@ protected int parseBlend(String str) { if (str == null) { return 1; } else { - switch (str.toLowerCase(Locale.ENGLISH).trim()) { - case "alpha": - return 0; - case "add": - return 1; - case "subtract": - return 2; - case "multiply": - return 3; - case "dodge": - return 4; - case "burn": - return 5; - case "screen": - return 6; - case "overlay": - return 7; - case "replace": - return 8; - default: + return switch (str.toLowerCase(Locale.ENGLISH).trim()) { + case "alpha" -> 0; + case "add" -> 1; + case "subtract" -> 2; + case "multiply" -> 3; + case "dodge" -> 4; + case "burn" -> 5; + case "screen" -> 6; + case "overlay" -> 7; + case "replace" -> 8; + default -> { AxolotlClient.LOGGER.warn("Unknown blend: " + str); - return 1; - } + yield 1; + } + }; } } public void render(MatrixStack matrices, float tickDelta) { + //noinspection DataFlowIssue float brightness = MinecraftClient.getInstance().world.getRainGradient(tickDelta); matrices.push(); setupBlend(brightness); @@ -255,6 +249,7 @@ protected void setupRotate(MatrixStack matrices, float delta, float brightness) matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(rotationAxis[1])); matrices.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(rotationAxis[2])); matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(-90.0F)); + //noinspection DataFlowIssue matrices.multiply(Vector3f.NEGATIVE_X.getDegreesQuaternion( MinecraftClient.getInstance().world.getSkyAngle(delta) * 360F * rotationSpeed)); matrices.multiply(Vector3f.NEGATIVE_Z.getDegreesQuaternion(rotationAxis[0])); @@ -285,6 +280,7 @@ protected void renderDecorations(MatrixStack matrices, float delta) { GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO); matrices.push(); + //noinspection DataFlowIssue float i = 1.0F - MinecraftClient.getInstance().world.getRainGradient(delta); RenderSystem.color4f(1.0F, 1.0F, 1.0F, i); matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(-90.0F)); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java index 0f3956644..16c533e8a 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java @@ -32,7 +32,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ public class SkyboxManager { @@ -54,10 +54,9 @@ public void addSkybox(SkyboxInstance skybox) { public void renderSkyboxes(MatrixStack matrices, float tickDelta) { this.skyboxes.stream().filter(this.renderPredicate).forEach(this.active_skies::add); + //noinspection ComparatorMethodParameterNotUsed this.active_skies.sort((skybox1, skybox2) -> skybox1.alpha >= skybox2.alpha ? 0 : 1); - this.active_skies.forEach(skyboxInstance -> { - skyboxInstance.render(matrices, tickDelta); - }); + this.active_skies.forEach(skyboxInstance -> skyboxInstance.render(matrices, tickDelta)); this.active_skies.removeIf((skybox) -> skybox.getAlpha() <= MINIMUM_ALPHA); } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java index c493a2775..9301cd01d 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java @@ -29,12 +29,14 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.options.ForceableBooleanOption; +import lombok.Getter; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; public class TntTime extends AbstractModule { + @Getter private static final TntTime Instance = new TntTime(); public final ForceableBooleanOption enabled = new ForceableBooleanOption("enabled", false); private final OptionCategory category = OptionCategory.create("tnttime"); @@ -42,10 +44,6 @@ public class TntTime extends AbstractModule { private DecimalFormat format; private int decimals; - public static TntTime getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled, decimalPlaces); @@ -58,9 +56,7 @@ public void tick() { StringBuilder string = new StringBuilder("#0"); if (decimalPlaces.get() > 0) { string.append("."); - for (int i = 0; i < decimalPlaces.get(); i++) { - string.append("0"); - } + string.append("0".repeat(Math.max(0, decimalPlaces.get()))); } format = new DecimalFormat(string.toString()); decimals = decimalPlaces.get(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java index fbc682e6f..ea26bbba1 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java @@ -28,6 +28,7 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.FloatOption; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.Util; +import lombok.Getter; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.MinecraftClient; @@ -47,6 +48,7 @@ public class Zoom extends AbstractModule { public static final BooleanOption zoomScrolling = new BooleanOption("zoomScrolling", false); public static final BooleanOption decreaseSensitivity = new BooleanOption("decreaseSensitivity", true); public static final BooleanOption smoothCamera = new BooleanOption("smoothCamera", false); + @Getter private static final Zoom Instance = new Zoom(); public static boolean active; private static Double originalSensitivity; @@ -58,10 +60,6 @@ public class Zoom extends AbstractModule { private static double lastReturnedFov; public final OptionCategory zoom = OptionCategory.create("zoom"); - public static Zoom getInstance() { - return Instance; - } - public static double getFov(double current, float tickDelta) { double result = current * (zoomSpeed.get() == 10 ? targetFactor : Util.lerp(lastAnimatedFactor, animatedFactor, tickDelta)); @@ -174,6 +172,6 @@ public void init() { public void tick() { lastAnimatedFactor = animatedFactor; - animatedFactor += (targetFactor - animatedFactor) * (zoomSpeed.get() / 10F); + animatedFactor += (float) ((targetFactor - animatedFactor) * (zoomSpeed.get() / 10F)); } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/LoggerImpl.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/util/LoggerImpl.java index b8218f227..6c25a8952 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/LoggerImpl.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/util/LoggerImpl.java @@ -33,19 +33,23 @@ public class LoggerImpl implements Logger { private static final String prefix = FabricLoader.getInstance().isDevelopmentEnvironment() ? "" : "(AxolotlClient) "; public void info(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + msg, args); } public void warn(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.warn(prefix + msg, args); } public void error(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.error(prefix + msg, args); } public void debug(String msg, Object... args) { if (AxolotlClient.config().debugLogOutput.get()) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + "[DEBUG] " + msg, args); } } diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/Util.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/util/Util.java index 199f478e6..355549775 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/Util.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/util/Util.java @@ -46,7 +46,7 @@ import net.minecraft.util.Identifier; public class Util { - public static Color GlColor = new Color(); + public static final Color GlColor = new Color(); public static String lastgame; public static String game; @@ -79,7 +79,7 @@ else if (MinecraftClient.getInstance().getCurrentServerEntry() != null game = "Playing " + sidebar.get(0); } - if (!Objects.equals(lastgame, game) && game.equals("")) + if (!Objects.equals(lastgame, game) && game.isEmpty()) game = lastgame; else lastgame = game; @@ -163,10 +163,6 @@ public static Text formatFromCodes(String formattedString) { return text; } - public static void sendChatMessage(String msg) { - MinecraftClient.getInstance().player.sendChatMessage(msg); - } - public static void addMessageToChatHud(Text msg) { MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(msg); } @@ -175,6 +171,7 @@ public static Identifier getTexture(GraphicsOption option) { return getTexture(option.get(), option.getName()); } + @SuppressWarnings("DataFlowIssue") public static Identifier getTexture(Graphics graphics, String name) { Identifier id = new Identifier("axolotlclient", "graphics_" + name.toLowerCase(Locale.ROOT)); try { diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/Events.java b/1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/Events.java index 36fde99c0..e44a3069c 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/Events.java +++ b/1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/Events.java @@ -24,7 +24,8 @@ import java.util.Arrays; -import io.github.axolotlclient.util.events.impl.*; +import io.github.axolotlclient.util.events.impl.KeyBindChangeEvent; +import io.github.axolotlclient.util.events.impl.MouseInputEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.MinecraftClient; @@ -33,7 +34,6 @@ public class Events { public static final Event> MOUSE_INPUT = createEvent(); public static final Event> KEYBIND_CHANGE = createEvent(); - public static final Event> PLAYER_DIRECTION_CHANGE = createEvent(); public static final Event> GAME_LOAD_EVENT = createEvent(); private static Event> createEvent() { diff --git a/1.16_combat-6/src/main/resources/axolotlclient.mixins.json b/1.16_combat-6/src/main/resources/axolotlclient.mixins.json index f9da4cbef..bb9947a9d 100644 --- a/1.16_combat-6/src/main/resources/axolotlclient.mixins.json +++ b/1.16_combat-6/src/main/resources/axolotlclient.mixins.json @@ -17,6 +17,7 @@ "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerMixin", "ClientWorldMixin", + "ConfigVanillaButtonWidgetMixin", "DebugHudMixin", "DownloadingTerrainScreenMixin", "EmitterParticleMixin", @@ -62,6 +63,7 @@ "WorldRendererAccessor", "WorldRendererMixin", "api.JoinMulitplayerScreenMixin", + "skins.PlayerSkinTextureAccessor", "translation.LanguageMixin" ], "injectors": { diff --git a/1.20/build.gradle.kts b/1.20/build.gradle.kts index 852d41d34..12b50c933 100644 --- a/1.20/build.gradle.kts +++ b/1.20/build.gradle.kts @@ -47,7 +47,6 @@ dependencies { api("org.lwjgl:lwjgl-nanovg:3.3.2") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.2:natives-linux") - runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.2:natives-linux-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.2:natives-windows") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.2:natives-windows-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.2:natives-macos") @@ -87,6 +86,7 @@ java { tasks.runClient { classpath(sourceSets.getByName("test").runtimeClasspath) + jvmArgs("-XX:+AllowEnhancedClassRedefinition", "-XX:+IgnoreUnrecognizedVMOptions") } // Configure the maven publication diff --git a/1.20/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java b/1.20/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java index 8fad0c6bb..e855858f7 100644 --- a/1.20/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java +++ b/1.20/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java @@ -33,6 +33,7 @@ import io.github.axolotlclient.api.types.Channel; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.AlphabeticalComparator; +import lombok.Getter; import net.minecraft.client.gui.*; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; @@ -74,6 +75,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { graphics.getMatrices().translate(0, 0, 1000); graphics.fill(sidebarAnimX, 0, sidebarWidth + sidebarAnimX, height, 0x99000000); + //noinspection DataFlowIssue graphics.drawShadowedText(client.textRenderer, Text.translatable("api.chats"), 10 + sidebarAnimX, 10, -1); if (hasChat) { @@ -161,6 +163,7 @@ public List getButtons() { } private void close() { + //noinspection DataFlowIssue client.setScreen(parent); if (chatWidget != null) { chatWidget.remove(); @@ -198,9 +201,11 @@ private void addChat(Channel channel) { int w; if (channel.isDM()) { User chatUser = ((Channel.DM) channel).getReceiver(); + //noinspection DataFlowIssue w = Math.max(client.textRenderer.getWidth(chatUser.getStatus().getTitle() + ": " + chatUser.getStatus().getDescription()) + 5, client.textRenderer.getWidth(channel.getName())); } else { + //noinspection DataFlowIssue w = client.textRenderer.getWidth(channel.getName()); } sidebarWidth = Math.min(Math.max(width * 5 / 12, w + 5), width / 2); @@ -250,6 +255,7 @@ private class ListWidget extends AbstractParentElement implements Drawable, Elem private final int height; private final int entryHeight = 25; protected boolean hovered; + @Getter private int x; private int scrollAmount; private boolean visible; @@ -309,10 +315,6 @@ public boolean isMouseOver(double mouseX, double mouseY) { return hovered = visible && mouseX >= (double) this.x && mouseY >= (double) this.y && mouseX < (double) (this.x + this.width) && mouseY < (double) (this.y + this.height); } - public int getX() { - return x; - } - public void setX(int x) { this.x = x; elements.forEach(e -> e.setX(x)); diff --git a/1.20/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java b/1.20/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java index ebf2034f6..b73720dbd 100644 --- a/1.20/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java @@ -51,12 +51,21 @@ public void init() { addDrawableChild(new ButtonWidget.Builder(CommonTexts.CANCEL, button -> client.setScreen(parent)) .positionAndSize(width / 2 - 155, height - 50, 150, 20).build()); - addDrawableChild(new ButtonWidget.Builder(CommonTexts.DONE, button -> { - if (!input.getText().isEmpty()) { + var done = addDrawableChild(new ButtonWidget.Builder(CommonTexts.DONE, button -> { + if (!input.getText().isBlank()) { consumer.accept(input.getText()); - client.setScreen(parent); } + client.setScreen(parent); }).positionAndSize(width / 2 + 5, height - 50, 150, 20).build()); + input.setChangedListener(s -> { + done.active = !s.isBlank(); + }); + done.active = false; + } + + @Override + public void tick() { + input.tick(); } @Override diff --git a/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java b/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java index 51613d3b8..e504cffc7 100644 --- a/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java @@ -46,7 +46,7 @@ public class ChatScreen extends Screen implements ContextMenuScreen { private TextFieldWidget input; public ChatScreen(Screen parent, Channel channel) { - super(Text.translatable("api.screen.chat")); + super(Text.literal(channel.getName())); this.channel = channel; this.parent = parent; } @@ -73,6 +73,7 @@ protected void init() { users.setUsers(channel.getAllUsers(), channel); addDrawableChild(users); + //noinspection DataFlowIssue addDrawableChild(input = new TextFieldWidget(client.textRenderer, width / 2 - 150, height - 50, 300, 20, Text.translatable("api.chat.enterMessage")) { diff --git a/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java b/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java index 07d9c70a2..b21dac773 100644 --- a/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java +++ b/1.20/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java @@ -172,7 +172,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { if (!origin.sender().equals(API.getInstance().getSelf())) { builder.entry(Text.translatable("api.friends.chat"), buttonWidget -> ChannelRequest.getOrCreateDM(origin.sender()) - .whenCompleteAsync((channel, throwable) -> client.execute(() -> client.setScreen(new ChatScreen(screen.getParent(), channel))))) + .whenCompleteAsync((channel, throwable) -> client.execute(() -> client.setScreen(new ChatScreen(screen.getParent(), channel))))) .spacer(); } builder.entry(Text.translatable("api.chat.report.message"), buttonWidget -> { diff --git a/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java b/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java index 935f10e0b..e4c7e04b0 100644 --- a/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java @@ -60,7 +60,7 @@ public FriendsMultiplayerScreen(Screen lastScreen) { @Override protected void init() { if (this.initialized) { - this.serverSelectionList.updateSize(this.width, this.height, 60, this.height-64); + this.serverSelectionList.updateSize(this.width, this.height, 60, this.height - 64); } else { this.serverSelectionList = new FriendsMultiplayerSelectionList(this, this.client, this.width, this.height - 64 - 60, 60, 36); } diff --git a/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java b/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java index 636441d65..bbfe4ae99 100644 --- a/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java +++ b/1.20/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java @@ -40,22 +40,22 @@ public static Status.Activity.ServerInfo getServerInfo(String levelName, ServerM return new Status.Activity.ServerInfo(levelName, null, null, null, null); } return new Status.Activity.ServerInfo(levelName, status.description().getString(), - new Status.Activity.ServerInfo.Favicon(status.favicon().map(ServerMetadata.Favicon::iconBytes).orElse(null)), - status.players().map(p -> - new Status.Activity.ServerInfo.Players(p.max(), p.online(), - p.sample().stream().map(prof -> new Status.Activity.ServerInfo.Players.Player(prof.getName(), UUIDHelper.toUndashed(prof.getId()))).toList()) - ).orElse(null), - status.version().map(v -> new Status.Activity.ServerInfo.Version(v.name(), v.protocol())).orElse(null)); + new Status.Activity.ServerInfo.Favicon(status.favicon().map(ServerMetadata.Favicon::iconBytes).orElse(null)), + status.players().map(p -> + new Status.Activity.ServerInfo.Players(p.max(), p.online(), + p.sample().stream().map(prof -> new Status.Activity.ServerInfo.Players.Player(prof.getName(), UUIDHelper.toUndashed(prof.getId()))).toList()) + ).orElse(null), + status.version().map(v -> new Status.Activity.ServerInfo.Version(v.name(), v.protocol())).orElse(null)); } public static ServerMetadata getServerStatus(Status.Activity.ServerInfo info) { return new ServerMetadata(Text.of(info.levelName()), - Optional.ofNullable(info.players()).map(p -> new ServerMetadata.Players(p.max(), - p.online(), - p.sample().stream().map(prof -> new GameProfile(UUIDHelper.fromUndashed(prof.uuid()), prof.name())).toList())), - Optional.ofNullable(info.version()).map(v -> new ServerMetadata.Version(v.name(), v.protocol())), - Optional.ofNullable(info.icon()).map(f -> new ServerMetadata.Favicon(f.iconBytes())), - false); + Optional.ofNullable(info.players()).map(p -> new ServerMetadata.Players(p.max(), + p.online(), + p.sample().stream().map(prof -> new GameProfile(UUIDHelper.fromUndashed(prof.uuid()), prof.name())).toList())), + Optional.ofNullable(info.version()).map(v -> new ServerMetadata.Version(v.name(), v.protocol())), + Optional.ofNullable(info.icon()).map(f -> new ServerMetadata.Favicon(f.iconBytes())), + false); } public static ServerInfo getServerData(String username, Status.Activity.E4mcMetadata metadata) { diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java b/1.20/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java index d6e5cb1c5..9117bab7a 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java @@ -52,7 +52,7 @@ public Identifier getFabricId() { return new Identifier("axolotlclient", "bridge/resource_listener"); } }); - ClientPlayConnectionEvents.INIT.register((clientPlayNetworkHandler, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); + ClientPlayConnectionEvents.JOIN.register((clientPlayNetworkHandler, sender, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); ClientPlayConnectionEvents.DISCONNECT.register((clientPlayNetworkHandler, minecraftClient) -> Events.DISCONNECT.invoker().run()); ClientCommandRegistrationCallback.EVENT.register((commandDispatcher, commandBuildContext) -> diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java index 6a812703e..14afe85a0 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java @@ -89,9 +89,10 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient { public abstract ResourceManager getResourceManager(); @Override - public@Nullable AxoPlayer br$getPlayer() { + public @Nullable AxoPlayer br$getPlayer() { return player; } + @Override public AxoWorld br$getWorld() { @@ -146,7 +147,7 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient { @Override public void br$reinitScreen() { if (currentScreen != null) { - currentScreen.init((MinecraftClient) (Object)this, currentScreen.width, currentScreen.height); + currentScreen.init((MinecraftClient) (Object) this, currentScreen.width, currentScreen.height); } } @@ -154,4 +155,9 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient { public AxoResourceManager br$getResourceManager() { return getResourceManager(); } + + @Override + public Object br$getScreen() { + return currentScreen; + } } diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java index a7f88e3a5..a99d5840d 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java @@ -56,7 +56,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(value = PlatformDispatch.class, remap = false) -public class PlatformDispatchMixin { +public abstract class PlatformDispatchMixin { @Unique private static void getRealTimeServerPing(ServerInfo server, MutableInt currentServerPing) { ThreadExecuter.scheduleTask(() -> { @@ -93,6 +93,7 @@ public boolean isConnected() { return clientConnection.isOpen(); } }; + clientConnection.setPacketListener(listener); clientConnection.send(new HandshakeC2SPacket(address.getAddress(), address.getPort(), NetworkState.STATUS)); clientConnection.send(new MetadataQueryC2SPacket()); diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java index 0ec60a178..833a962f6 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java @@ -32,7 +32,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(PlayerListEntry.class) -public class PlayerListEntryMixin implements AxoPlayerListEntry { +public abstract class PlayerListEntryMixin implements AxoPlayerListEntry { @Shadow @Final private GameProfile profile; diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java index 820f6388f..178f40b03 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(LivingEntity.class) -public class LivingEntityMixin implements AxoLivingEntity { +public abstract class LivingEntityMixin implements AxoLivingEntity { @Shadow @Final private Map activeStatusEffects; diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java index 2188dc7da..22fd3bc5d 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoStatusEffects.class, remap = false) -public class AxoStatusEffectsMixin { +public abstract class AxoStatusEffectsMixin { @Mutable @Shadow @Final diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java index c4a16fa65..9ab515b48 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java @@ -67,7 +67,7 @@ @SuppressWarnings("OverwriteModifiers") @Mixin(value = PlatformImplInternal.class, remap = false) -public class PlatformImplInternalMixin { +public abstract class PlatformImplInternalMixin { /** * @author Flowey * @reason Implement bridge platform. @@ -145,9 +145,9 @@ public static int getCurrentFps() { * @reason Implement bridge platform. */ @Overwrite - public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name, String category) { + public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name) { int code = ((InputUtil.Key) Objects.requireNonNullElse(defaultKey, AxoKeys.KEY_UNKNOWN)).getKeyCode(); - final var binding = new KeyBind(name, code, category); + final var binding = new KeyBind(name, code, "category.axolotlclient"); KeyBinds.getInstance().register(binding); return binding; } diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java index 1026dc5b2..08883ff6b 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoEnchants.class, remap = false) -public class AxoEnchantsMixin { +public abstract class AxoEnchantsMixin { @Mutable @Shadow @Final diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java index 3e8f7fa39..be2753ed2 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoItems.class, remap = false) -public class AxoItemsMixin { +public abstract class AxoItemsMixin { @Mutable @Shadow @Final diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java index e3b053e27..fc0b3ffea 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Enchantment.class) -public class EnchantmentMixin implements AxoEnchant { +public abstract class EnchantmentMixin implements AxoEnchant { } diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java index 5e44604ed..eadcab05e 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Item.class) -public class ItemMixin implements AxoItem { +public abstract class ItemMixin implements AxoItem { @Override public boolean br$is(AxoItemClass itemClass) { return switch (itemClass) { diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java index 476ff861e..45822b799 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoKeys.class, remap = false) -public class AxoKeysMixin { +public abstract class AxoKeysMixin { @Mutable @Shadow diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java index b1d447da2..782cc5c68 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(GameOptions.class) -public class GameOptionsMixin implements AxoClientKeybinds { +public abstract class GameOptionsMixin implements AxoClientKeybinds { @Shadow @Final public KeyBind sprintKey; diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java index 458cb6b4d..4cd07679f 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(InputUtil.Key.class) -public class KeyMixin implements AxoKey { +public abstract class KeyMixin implements AxoKey { } diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java index f9e83f9ed..8c55504bf 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java @@ -36,7 +36,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoSprites.class, remap = false) -public class AxoSpritesMixin { +public abstract class AxoSpritesMixin { @Mutable @Shadow @Final diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java index ef46da1cc..b44e75eaf 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java @@ -90,7 +90,7 @@ public abstract void drawItemInSlot(TextRenderer textRenderer, ItemStack stack, // scissor @Override public void br$pushScissor(int x, int y, int w, int h) { - enableScissor(x, y, x+w, y+h); + enableScissor(x, y, x + w, y + h); } @Override @@ -133,7 +133,7 @@ public abstract void drawItemInSlot(TextRenderer textRenderer, ItemStack stack, @Override public void br$fillRect(int x, int y, int width, int height, int color) { - fill(x, y, x+width, y+height, color); + fill(x, y, x + width, y + height, color); } @Override diff --git a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java index 26e77d7a0..210e78b39 100644 --- a/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java @@ -28,7 +28,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(Identifier.class) -public abstract class IdentifierMixin implements AxoIdentifier{ +public abstract class IdentifierMixin implements AxoIdentifier { @Shadow public abstract String getPath(); diff --git a/1.20/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java b/1.20/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java index 340945ab4..67032ba6f 100644 --- a/1.20/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java +++ b/1.20/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java @@ -34,6 +34,7 @@ import io.github.axolotlclient.AxolotlClientConfig.api.ui.ConfigUI; import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import io.github.axolotlclient.AxolotlClientConfig.impl.options.*; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.RecreatableScreen; import io.github.axolotlclient.AxolotlClientConfigCommon; import io.github.axolotlclient.config.screen.CreditsScreen; import io.github.axolotlclient.config.screen.ProfilesScreen; @@ -43,6 +44,7 @@ import io.github.axolotlclient.util.options.GenericOption; import lombok.Getter; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.option.KeyBind; import net.minecraft.client.texture.NativeImageBackedTexture; @@ -66,28 +68,26 @@ public class AxolotlClientConfig extends AxolotlClientConfigCommon { public final BooleanOption lowShield = new BooleanOption("lowShield", false); public final ColorOption hitColor = new ColorOption("hitColor", new Color(255, 0, 0, 77), value -> { - try { // needed because apparently someone created a bug that makes this be called when the config is loaded. Will be fixed with the next release. - NativeImageBackedTexture texture = ((OverlayTextureAccessor) MinecraftClient.getInstance().gameRenderer.getOverlayTexture()).axolotlclient$getTexture(); - NativeImage nativeImage = texture.getImage(); - if (nativeImage != null) { - int color = 255 - value.getAlpha(); - color = (color << 8) + value.getBlue(); - color = (color << 8) + value.getGreen(); - color = (color << 8) + value.getRed(); - - for (int i = 0; i < 8; ++i) { - for (int j = 0; j < 8; ++j) { - nativeImage.setPixelColor(j, i, color); - } + //noinspection resource + NativeImageBackedTexture texture = ((OverlayTextureAccessor) MinecraftClient.getInstance().gameRenderer.getOverlayTexture()).axolotlclient$getTexture(); + NativeImage nativeImage = texture.getImage(); + if (nativeImage != null) { + int color = 255 - value.getAlpha(); + color = (color << 8) + value.getBlue(); + color = (color << 8) + value.getGreen(); + color = (color << 8) + value.getRed(); + + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + nativeImage.setPixelColor(j, i, color); } - - RenderSystem.activeTexture(33985); - texture.bindTexture(); - nativeImage.upload(0, 0, 0, 0, 0, - nativeImage.getWidth(), nativeImage.getHeight(), false, true, false, false); - RenderSystem.activeTexture(33984); } - } catch (Exception ignored) { + + RenderSystem.activeTexture(33985); + texture.bindTexture(); + nativeImage.upload(0, 0, 0, 0, 0, + nativeImage.getWidth(), nativeImage.getHeight(), false, true, false, false); + RenderSystem.activeTexture(33984); } }); public final BooleanOption minimalViewBob = new BooleanOption("minimalViewBob", false); @@ -154,7 +154,9 @@ public AxolotlClientConfig() { general.add(configStyle = new StringArrayOption("configStyle", themes, "configStyle." + ConfigUI.getInstance().getCurrentStyle().getName(), s -> { ConfigUI.getInstance().setStyle(s.split("\\.")[1]); - MinecraftClient.getInstance().setScreen(null); + + Screen newScreen = RecreatableScreen.tryRecreate(MinecraftClient.getInstance().currentScreen); + MinecraftClient.getInstance().setScreen(newScreen); })); AxolotlClient.getInstance().getConfigManager().load(); ConfigUI.getInstance().setStyle(configStyle.get().split("\\.")[1]); diff --git a/1.20/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java b/1.20/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java index be2b91ca3..ca0af7780 100644 --- a/1.20/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java @@ -41,7 +41,6 @@ public class ProfilesScreen extends Screen { - private ProfilesList profilesList; private final Screen parent; public ProfilesScreen(Screen parent) { @@ -59,7 +58,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { @Override protected void init() { - profilesList = addDrawableChild(new ProfilesList(client, width, height, 33, height - 33, 25)); + addDrawableChild(new ProfilesList(client, width, height, 33, height - 33, 25)); addDrawableChild(ButtonWidget.builder(CommonTexts.BACK, btn -> closeScreen()) .positionAndSize(width / 2 - 75, height - 33 / 2 - 10, 150, 20).build()); @@ -68,6 +67,7 @@ protected void init() { @Override public void closeScreen() { Profiles.getInstance().saveProfiles(); + //noinspection DataFlowIssue client.setScreen(parent); } @@ -129,14 +129,13 @@ public List children() { @Environment(EnvType.CLIENT) public class ProfileEntry extends Entry { + private static final Text EXPORT_BUTTON_TITLE = Text.translatable("profiles.profile.export"); private static final Text CURRENT_TEXT = Text.translatable("profiles.profile.current"); private static final Text LOAD_BUTTON_TITLE = Text.translatable("profiles.profile.load"); private static final Text DUPLICATE_BUTTON_TITLE = Text.translatable("profiles.profile.duplicate"); private static final Text REMOVE_BUTTON_TITLE = Text.translatable("profiles.profile.remove"); private final TextFieldWidget profileName; - private final ButtonWidget loadButton; - private final ButtonWidget duplicateButton; - private final ButtonWidget removeButton; + private final ButtonWidget exportButton, loadButton, duplicateButton, removeButton; private final Profiles.Profile profile; ProfileEntry(Profiles.Profile profile) { @@ -144,6 +143,8 @@ public class ProfileEntry extends Entry { profileName = new TextFieldWidget(textRenderer, 0, 0, 150, 20, Text.empty()); profileName.setText(profile.name()); profileName.setChangedListener(profile::setName); + exportButton = ButtonWidget.builder(EXPORT_BUTTON_TITLE, btn -> Profiles.getInstance().exportProfile(profile)) + .positionAndSize(0, 0, 50, 20).build(); loadButton = ButtonWidget.builder(LOAD_BUTTON_TITLE, btn -> Profiles.getInstance().switchTo(profile)).positionAndSize(0, 0, 50, 20).build(); duplicateButton = ButtonWidget.builder(DUPLICATE_BUTTON_TITLE, b -> { @@ -174,10 +175,13 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi boolean current = Profiles.getInstance().getCurrent() == profile; loadButton.setMessage(current ? CURRENT_TEXT : LOAD_BUTTON_TITLE); - loadButton.active = !current; + loadButton.active = removeButton.active = !current; i -= loadButton.getWidth(); this.loadButton.setPosition(i, j); this.loadButton.render(guiGraphics, mouseX, mouseY, partialTick); + i -= exportButton.getWidth(); + exportButton.setPosition(i, j); + exportButton.render(guiGraphics, mouseX, mouseY, partialTick); profileName.setWidth(i - left - 4); profileName.setPosition(left, j); profileName.render(guiGraphics, mouseX, mouseY, partialTick); @@ -185,18 +189,18 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi @Override public List children() { - return List.of(profileName, this.loadButton, duplicateButton, removeButton); + return List.of(profileName, exportButton, this.loadButton, duplicateButton, removeButton); } @Override public List selectableChildren() { - return List.of(profileName, this.loadButton, duplicateButton, removeButton); + return List.of(profileName, exportButton, this.loadButton, duplicateButton, removeButton); } } public class NewEntry extends Entry { - private final ButtonWidget addButton; + private final ButtonWidget addButton, importButton; public NewEntry() { this.addButton = ButtonWidget.builder(Text.translatable("profiles.profile.add"), button -> { @@ -206,6 +210,8 @@ public NewEntry() { setScrollAmount(getMaxScroll()); }).positionAndSize(0, 0, 150, 20) .build(); + this.importButton = ButtonWidget.builder(Text.translatable("profiles.profile.import"), btn -> + Profiles.getInstance().importProfiles().thenRun(ProfilesList.this::reload)).build(); } @Override @@ -215,15 +221,17 @@ public List selectableChildren() { @Override public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() / 2; + int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() + 2; int j = top - 2; this.addButton.setPosition(i, j); this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); + this.importButton.setPosition(addButton.getX() + addButton.getWidth() + 2, j); + this.importButton.render(guiGraphics, mouseX, mouseY, partialTick); } @Override public List children() { - return List.of(addButton); + return List.of(addButton, importButton); } } } diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java index 948c55f26..bd46a2ca0 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java @@ -49,9 +49,9 @@ public abstract class CameraMixin { private void axolotlclient$perspectiveUpdatePitchYaw(BlockView area, Entity focusedEntity, boolean thirdPerson, boolean inverseView, float tickDelta, CallbackInfo ci) { this.pitch = Freelook.getInstance().pitch(pitch) - * (inverseView && Freelook.getInstance().enabled.get() && Freelook.getInstance().isActive() ? -1 : 1); + ;//* (inverseView && Freelook.getInstance().enabled.get() && Freelook.getInstance().isActive() ? -1 : 1); this.yaw = Freelook.getInstance().yaw(yaw) - + (inverseView && Freelook.getInstance().enabled.get() && Freelook.getInstance().isActive() ? 180 : 0); + ;//+ (inverseView && Freelook.getInstance().enabled.get() && Freelook.getInstance().isActive() ? 180 : 0); } @ModifyArgs(method = "update", at = @At(value = "INVOKE", target = "net/minecraft/client/render/Camera.setRotation(FF)V", ordinal = 0)) diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java index bb84de949..b9b77a927 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java @@ -22,10 +22,10 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.modules.freelook.Freelook; import io.github.axolotlclient.modules.hypixel.Skyblock; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import net.minecraft.entity.Entity; import net.minecraft.util.math.MathHelper; import org.spongepowered.asm.mixin.Mixin; @@ -55,7 +55,7 @@ public abstract class EntityMixin { float pitch = prevPitch + (float) (mouseDeltaY * .15); float yaw = prevYaw + (float) (mouseDeltaX * .15); pitch = MathHelper.clamp(pitch, -90.0F, 90.0F); - Events.PLAYER_DIRECTION_CHANGE.invoker().invoke(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); + Events.PLAYER_DIRECTION_CHANGE.invoker().accept(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); } @Shadow diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java index 523006347..8ca62204f 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameOptions.class) -public class GameOptionsMixin { +public abstract class GameOptionsMixin { @Mutable @Shadow diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java index e9e5deb8c..f42c4f5f3 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; @Mixin(GuiGraphics.class) -public class GuiGraphicsMixin { +public abstract class GuiGraphicsMixin { @ModifyVariable(method = "drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;IILnet/minecraft/client/gui/tooltip/TooltipPositioner;)V", at = @At("STORE"), index = 11) diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java index d09f25ef4..7bda0cbd0 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java @@ -22,6 +22,8 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.modules.hud.HudManager; +import io.github.axolotlclient.modules.hud.gui.hud.IconHud; import io.github.axolotlclient.modules.scrollableTooltips.ScrollableTooltips; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screen.ingame.HandledScreen; @@ -29,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -39,6 +42,7 @@ public abstract class HandledScreenMixin { @Shadow @Nullable protected Slot focusedSlot; + @Unique private Slot cachedSlot; @Inject(method = "drawMouseoverTooltip", at = @At("HEAD")) @@ -48,4 +52,12 @@ public abstract class HandledScreenMixin { ScrollableTooltips.getInstance().resetScroll(); } } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/gui/GuiGraphics;FII)V")) + private void renderIcon(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) { + var hud = (IconHud) HudManager.getInstance().get(IconHud.ID); + if (hud != null && hud.isEnabled()) { + hud.renderInGui(guiGraphics, partialTick); + } + } } diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java index e1292723a..98fcb51b0 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java @@ -168,7 +168,7 @@ public abstract class InGameHudMixin { @Redirect(method = "renderExperienceBar", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/hud/InGameHud;scaledHeight:I")) public int axolotlclient$moveXPBarHeight(InGameHud instance) { HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud != null &&hud.isEnabled()) { + if (HudManager.getInstance().hudsEnabled() && hud != null && hud.isEnabled()) { return hud.getY() + 22; } return scaledHeight; @@ -177,7 +177,7 @@ public abstract class InGameHudMixin { @Redirect(method = "renderExperienceBar", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/hud/InGameHud;scaledWidth:I")) public int axolotlclient$moveXPBarWidth(InGameHud instance) { HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud != null &&hud.isEnabled()) { + if (HudManager.getInstance().hudsEnabled() && hud != null && hud.isEnabled()) { return hud.getX() * 2 + hud.getWidth(); } return scaledWidth; @@ -186,7 +186,7 @@ public abstract class InGameHudMixin { @Redirect(method = "renderStatusBars", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/hud/InGameHud;scaledHeight:I")) public int axolotlclient$moveStatusBarsHeight(InGameHud instance) { HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud != null &&hud.isEnabled()) { + if (HudManager.getInstance().hudsEnabled() && hud != null && hud.isEnabled()) { return hud.getY() + 22; } return scaledHeight; @@ -195,7 +195,7 @@ public abstract class InGameHudMixin { @Redirect(method = "renderStatusBars", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/hud/InGameHud;scaledWidth:I")) public int axolotlclient$moveStatusBarsWidth(InGameHud instance) { HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud != null &&hud.isEnabled()) { + if (HudManager.getInstance().hudsEnabled() && hud != null && hud.isEnabled()) { return hud.getX() * 2 + hud.getWidth(); } return scaledWidth; diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java index bf93ab2ff..6b625c1e3 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java @@ -22,16 +22,21 @@ package io.github.axolotlclient.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.util.OSUtil; import net.minecraft.client.main.Main; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(Main.class) public abstract class MinecraftClientMainMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) - private static String axolotlclient$noHeadless(String key, String value) { + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) + private static String axolotlclient$noHeadless(String key, String value, Operation original) { + if (OSUtil.getOS() != OSUtil.OperatingSystem.WINDOWS) { + return original.call(key, value); + } return ""; } } diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java index d86811bd6..9cd8ed1b1 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java @@ -38,7 +38,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(SplashTextResourceSupplier.class) -public class SplashTextResourceSupplierMixin { +public abstract class SplashTextResourceSupplierMixin { @Unique private static final Identifier EXTRA_SPLASHES = new Identifier("axolotlclient", "texts/splashes.txt"); diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java index 856658b6c..abc917168 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java @@ -45,7 +45,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ @Mixin(WorldRenderer.class) diff --git a/1.20/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java b/1.20/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java index 85cf93de4..ec9f373a6 100644 --- a/1.20/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java +++ b/1.20/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java @@ -40,12 +40,10 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.ModifyArgs; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; @Mixin(MultiplayerScreen.class) -public class JoinMulitplayerScreenMixin extends Screen { +public abstract class JoinMulitplayerScreenMixin extends Screen { @Shadow @Final @@ -65,7 +63,7 @@ private void addFriendsMultiplayerScreenButtons(CallbackInfo ci) { }).position(this.width / 2 - 102, 32).width(100).build()).active = false; ButtonWidget friendsCountButton = addDrawableChild(ButtonWidget.builder(Text.translatable("api.servers.friends", "..."), button -> { client.setScreen(new FriendsMultiplayerScreen(this.parent)); - }).positionAndSize(width/2+2, 32, 100, 20).build()); + }).positionAndSize(width / 2 + 2, 32, 100, 20).build()); FriendRequest.getInstance().getOnlineFriendCount().thenAccept(count -> friendsCountButton.setMessage(Text.translatable("api.servers.friends", count))); } } @@ -73,16 +71,18 @@ private void addFriendsMultiplayerScreenButtons(CallbackInfo ci) { @WrapOperation(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerServerListWidget;updateSize(IIII)V")) private void increaseHeaderSize(MultiplayerServerListWidget instance, int width, int height, int top, int bottom, Operation original) { if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - top += 32 - 60; + top -= 32; + top += 60; } original.call(instance, width, height, top, bottom); } - @ModifyArgs(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerServerListWidget;(Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;Lnet/minecraft/client/MinecraftClient;IIIII)V")) - private void increaseHeaderSize$2(Args args) { + @ModifyArg(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerServerListWidget;(Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;Lnet/minecraft/client/MinecraftClient;IIIII)V"), index = 4) + private int increaseHeaderSize$2(int par3) { if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - args.set(4, ((Integer)args.get(4)) - 32 + 60); + par3 = par3 - 32 + 60; } + return par3; } @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawCenteredShadowedText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;III)V"), index = 3) diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java index 000f2e6ec..6ea605fd1 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java @@ -25,6 +25,7 @@ import java.util.List; import com.mojang.blaze3d.systems.RenderSystem; +import lombok.Getter; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; @@ -70,6 +71,7 @@ public static class Entry extends AlwaysSelectedEntryListWidget.Entry login()).positionAndSize(this.width / 2 - 154, this.height - 52, 150, 20).build()); + buttonWidget -> login()).positionAndSize(this.width / 2 - 154, this.height - 52, 100, 20).build()); + + addDrawableChild(skinsButton = ButtonWidget.builder(Text.translatable("skins.manage"), + btn -> client.setScreen(new SkinManagementScreen( + this, accountsListWidget.getSelectedOrNull().getAccount()))) + .positionAndSize(this.width / 2 - 50, this.height - 52, 100, 20).build()); this.addDrawableChild(ButtonWidget.builder(Text.translatable("auth.add"), button -> { @@ -99,7 +106,7 @@ public void init() { }, Text.translatable("auth.add.choose"), Text.empty(), Text.translatable("auth.add.offline"), Text.translatable("auth.add.ms"))); } }) - .positionAndSize(this.width / 2 + 4, this.height - 52, 150, 20).build()); + .positionAndSize(this.width / 2 + 4 + 50, this.height - 52, 100, 20).build()); this.deleteButton = this.addDrawableChild(ButtonWidget.builder(Text.translatable("selectServer.delete"), button -> { AccountsListWidget.Entry entry = this.accountsListWidget.getSelectedOrNull(); @@ -125,17 +132,14 @@ public void init() { } private void initMSAuth() { - Auth.getInstance().getAuth().startDeviceAuth().thenRun(() -> client.execute(this::refresh)); + Auth.getInstance().getMsApi().startDeviceAuth().thenRun(() -> client.execute(this::refresh)); } private void refreshAccount() { refreshButton.active = false; AccountsListWidget.Entry entry = accountsListWidget.getSelectedOrNull(); if (entry != null) { - entry.getAccount().refresh(Auth.getInstance().getAuth()).thenRun(() -> client.execute(() -> { - Auth.getInstance().save(); - refresh(); - })); + entry.getAccount().refresh(Auth.getInstance().getMsApi()); } } @@ -143,9 +147,10 @@ private void updateButtonActivationStates() { AccountsListWidget.Entry entry = accountsListWidget.getSelectedOrNull(); if (client.world == null && entry != null) { loginButton.active = entry.getAccount().isExpired() || !entry.getAccount().equals(Auth.getInstance().getCurrent()); - deleteButton.active = refreshButton.active = true; + refreshButton.active = skinsButton.active = !entry.getAccount().isOffline(); + deleteButton.active = true; } else { - loginButton.active = deleteButton.active = refreshButton.active = false; + loginButton.active = deleteButton.active = refreshButton.active = skinsButton.active = false; } } diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/Auth.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/Auth.java index cb5343e47..1463f261f 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/auth/Auth.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/Auth.java @@ -23,18 +23,19 @@ package io.github.axolotlclient.modules.auth; import java.util.*; +import java.util.concurrent.CompletableFuture; import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.minecraft.UserApiService; import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.api.API; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.UUIDHelper; import io.github.axolotlclient.mixin.MinecraftClientAccessor; import io.github.axolotlclient.modules.Module; +import io.github.axolotlclient.modules.auth.skin.SkinManager; import io.github.axolotlclient.util.ThreadExecuter; import io.github.axolotlclient.util.notifications.Notifications; import io.github.axolotlclient.util.options.GenericOption; @@ -56,16 +57,20 @@ public class Auth extends Accounts implements Module { @Getter private final static Auth Instance = new Auth(); public final BooleanOption showButton = new BooleanOption("auth.showButton", false); + public final BooleanOption skinManagerAnimations = new BooleanOption("skins.manage.animations", true); private final MinecraftClient client = MinecraftClient.getInstance(); private final GenericOption viewAccounts = new GenericOption("viewAccounts", "clickToOpen", () -> client.setScreen(new AccountsScreen(client.currentScreen))); private final Set loadingTexture = new HashSet<>(); private final Map textures = new HashMap<>(); + @Getter + private final SkinManager skinManager = new SkinManager(); @Override public void init() { load(); - this.auth = new MSAuth(AxolotlClient.LOGGER, this, () -> client.options.language); + this.msApi = new MSApi(this, () -> client.options.language); if (isContained(client.getSession().getSessionId())) { + //noinspection DataFlowIssue current = getAccounts().stream().filter(account -> account.getUuid() .equals(UUIDHelper.toUndashed(client.getSession().getPlayerUuid()))).toList().get(0); current.setAuthToken(client.getSession().getAccessToken()); @@ -74,11 +79,11 @@ public void init() { current.refresh(auth).thenRun(this::save); }*/ } else { + //noinspection DataFlowIssue current = new Account(client.getSession().getUsername(), UUIDHelper.toUndashed(client.getSession().getPlayerUuid()), client.getSession().getAccessToken()); } - OptionCategory category = OptionCategory.create("auth"); - category.add(showButton, viewAccounts); + category.add(showButton, viewAccounts, skinManagerAnimations); AxolotlClient.config().general.add(category); } @@ -92,11 +97,11 @@ protected void login(Account account) { if (account.isExpired()) { Notifications.getInstance().addStatus(Text.translatable("auth.notif.title"), Text.translatable("auth.notif.refreshing", account.getName())); } - account.refresh(auth).thenAccept(res -> res.ifPresent(a -> { + account.refresh(msApi).thenAccept(a -> { if (!a.isExpired()) { login(a); } - })).thenRun(this::save); + }).thenRun(this::save); } else { try { API.getInstance().shutdown(); @@ -115,7 +120,7 @@ protected void login(Account account) { ((MinecraftClientAccessor) client).axolotlclient$setChatReportingContext(ChatReportingContext.create(ReportEnvironment.createLocal(), service)); save(); current = account; - Notifications.getInstance().addStatus(Text.translatable("auth.notif.title"), Text.translatable("auth.notif.login.successful", (Object) current.getName())); + Notifications.getInstance().addStatus(Text.translatable("auth.notif.title"), Text.translatable("auth.notif.login.successful", current.getName())); API.getInstance().startup(account); } catch (Exception e) { Notifications.getInstance().addStatus(Text.translatable("auth.notif.title"), Text.translatable("auth.notif.login.failed")); @@ -124,14 +129,18 @@ protected void login(Account account) { } @Override - void showAccountsExpiredScreen(Account account) { + CompletableFuture showAccountsExpiredScreen(Account account) { Screen current = client.currentScreen; + var fut = new CompletableFuture(); client.execute(() -> client.setScreen(new ConfirmScreen((bl) -> { - client.setScreen(current); if (bl) { - auth.startDeviceAuth(); + msApi.startDeviceAuth().thenRun(() -> fut.complete(account)); + } else { + fut.cancel(true); } + client.setScreen(current); }, Text.translatable("auth"), Text.translatable("auth.accountExpiredNotice", account.getName())))); + return fut; } @Override diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java new file mode 100644 index 000000000..fd4308760 --- /dev/null +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java @@ -0,0 +1,67 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screen.LoadingDisplay; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.TextWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Util; + +public class LoadingScreen extends Screen { + private final Text description; + + public LoadingScreen(Text title, Text description) { + super(title); + this.description = description; + } + + @Override + protected void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + var titleWidget = new TextWidget(width / 2 - textRenderer.getWidth(getTitle()) / 2, headerHeight / 2 - textRenderer.fontHeight / 2, textRenderer.getWidth(getTitle()), textRenderer.fontHeight, getTitle(), textRenderer); + addDrawableChild(titleWidget); + + var loadingPlaceholder = new ClickableWidget(0, headerHeight, width, contentHeight, description) { + @Override + protected void drawWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + int centerX = this.getX() + this.getWidth() / 2; + int centerY = this.getY() + this.getHeight() / 2; + Text text = this.getMessage(); + graphics.drawText(textRenderer, text, centerX - textRenderer.getWidth(text) / 2, centerY - 9, -1, false); + String string = LoadingDisplay.get(Util.getMeasuringTimeMs()); + graphics.drawText(textRenderer, string, centerX - textRenderer.getWidth(string) / 2, centerY + 9, 0xFF808080, false); + } + + @Override + protected void updateNarration(NarrationMessageBuilder builder) { + + } + }; + addDrawableChild(loadingPlaceholder); + } +} diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java new file mode 100644 index 000000000..14870d316 --- /dev/null +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java @@ -0,0 +1,863 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Colors; +import io.github.axolotlclient.api.SimpleTextInputScreen; +import io.github.axolotlclient.api.util.UUIDHelper; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import io.github.axolotlclient.util.ClientColors; +import io.github.axolotlclient.util.Watcher; +import io.github.axolotlclient.util.notifications.Notifications; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.*; +import net.minecraft.client.gui.navigation.GuiNavigationEvent; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.LoadingDisplay; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.*; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.text.CommonTexts; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SkinManagementScreen extends Screen { + private static final Path SKINS_DIR = FabricLoader.getInstance().getGameDir().resolve("skins"); + private static final int LIST_SKIN_WIDTH = 75; + private static final int LIST_SKIN_HEIGHT = 110; + private static final Text TEXT_EQUIPPING = Text.translatable("skins.manage.equipping"); + private final Screen parent; + private final Account account; + private MSApi.MCProfile cachedProfile; + private SkinListWidget skinList; + private SkinListWidget capesList; + private boolean capesTab; + private SkinWidget current; + private final Watcher skinDirWatcher; + private final CompletableFuture loadingFuture; + + public SkinManagementScreen(Screen parent, Account account) { + super(Text.translatable("skins.manage")); + this.parent = parent; + this.account = account; + skinDirWatcher = Watcher.createSelfTicking(SKINS_DIR, () -> { + AxolotlClientCommon.getInstance().getLogger().info("Reloading screen as local files changed!"); + loadSkinsList(); + }); + loadingFuture = (account.needsRefresh() ? account.refresh(Auth.getInstance().getMsApi()) + : CompletableFuture.completedFuture(null)) + .thenComposeAsync(unused -> Auth.getInstance().getMsApi().getProfile(account)); + } + + @Override + protected void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + + var titleWidget = new TextWidget(0, headerHeight / 2 - textRenderer.fontHeight / 2, width, textRenderer.fontHeight, getTitle(), textRenderer); + addDrawableChild(titleWidget); + + var back = addDrawableChild(ButtonWidget.builder(CommonTexts.BACK, btn -> closeScreen()) + .positionAndSize(width / 2 - 75, height - headerHeight / 2 - 10, 150, 20).build()); + + var loadingPlaceholder = new ClickableWidget(0, headerHeight, width, contentHeight, Text.translatable("skins.loading")) { + @Override + protected void drawWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + int centerX = this.getX() + this.getWidth() / 2; + int centerY = this.getY() + this.getHeight() / 2; + Text text = this.getMessage(); + graphics.drawText(textRenderer, text, centerX - textRenderer.getWidth(text) / 2, centerY - 9, -1, false); + String string = LoadingDisplay.get(Util.getMeasuringTimeMs()); + graphics.drawText(textRenderer, string, centerX - textRenderer.getWidth(string) / 2, centerY + 9, 0xFF808080, false); + } + + @Override + protected void updateNarration(NarrationMessageBuilder builder) { + + } + }; + loadingPlaceholder.active = false; + addDrawableChild(loadingPlaceholder); + addDrawableChild(back); + + skinList = new SkinListWidget(client, width / 2, contentHeight - 24, headerHeight + 24, LIST_SKIN_HEIGHT + 34); + capesList = new SkinListWidget(client, width / 2, contentHeight - 24, headerHeight + 24, skinList.getEntryContentsHeight() + 24); + skinList.setLeftPos(width / 2); + capesList.setLeftPos(width / 2); + var currentHeight = Math.min((width / 2f) * 120 / 85, contentHeight); + var currentWidth = currentHeight * 85 / 120; + current = new SkinWidget((int) currentWidth, (int) currentHeight, null, account); + current.setPosition((int) (width / 4f - currentWidth / 2), (int) (height / 2f - currentHeight / 2)); + + if (!capesTab) { + capesList.visible = capesList.active = false; + } else { + skinList.visible = skinList.active = false; + } + List navBar = new ArrayList<>(); + var skinsTab = ButtonWidget.builder(Text.translatable("skins.nav.skins"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = true; + capesList.visible = capesList.active = false; + capesTab = false; + }).position(Math.max(width * 3 / 4 - 102, width / 2 + 2), headerHeight).width(Math.min(100, width / 4 - 2)).build(); + navBar.add(skinsTab); + var capesTab = ButtonWidget.builder(Text.translatable("skins.nav.capes"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = false; + capesList.visible = capesList.active = true; + this.capesTab = true; + }).position(width * 3 / 4 + 2, headerHeight).width(Math.min(100, width / 4 - 2)).build(); + navBar.add(capesTab); + var importButton = new SpriteButton(Text.translatable("skins.manage.import.local"), btn -> { + btn.active = false; + SkinImportUtil.openImportSkinDialog().thenAccept(this::filesDragged).thenRun(() -> btn.active = true); + }, new Identifier("axolotlclient", "textures/gui/sprites/folder.png")); + var downloadButton = new SpriteButton(Text.translatable("skins.manage.import.online"), btn -> { + btn.active = false; + promptForSkinDownload(); + }, new Identifier("axolotlclient", "textures/gui/sprites/download.png")); + if (width - (capesTab.getX() + capesTab.getWidth()) > 28) { + importButton.setX(width - importButton.getWidth() - 2); + downloadButton.setX(importButton.getX() - downloadButton.getWidth() - 2); + importButton.setY(capesTab.getY() + capesTab.getHeight() - 11); + downloadButton.setY(importButton.getY()); + } else { + importButton.setX(capesTab.getX() + capesTab.getWidth() - 11); + importButton.setY(capesTab.getY() - 13); + downloadButton.setX(importButton.getX() - 2 - 11); + downloadButton.setY(importButton.getY()); + } + skinsTab.active = this.capesTab; + capesTab.active = !this.capesTab; + Runnable addWidgets = () -> { + clearChildren(); + addDrawableChild(titleWidget); + addDrawableChild(current); + addDrawableChild(skinsTab); + addDrawableChild(capesTab); + addDrawableChild(downloadButton); + addDrawableChild(importButton); + addDrawableChild(skinList); + addDrawableChild(capesList); + addDrawableChild(back); + }; + if (cachedProfile != null) { + initDisplay(); + addWidgets.run(); + return; + } + loadingFuture.thenAcceptAsync(profile -> { + cachedProfile = profile; + initDisplay(); + addWidgets.run(); + }).exceptionally(t -> { + if (t.getCause() instanceof CancellationException) { + client.setScreen(parent); + return null; + } + AxolotlClientCommon.getInstance().getLogger().error("Failed to load skins!", t); + var error = Text.translatable("skins.error.failed_to_load"); + var errorDesc = Text.translatable("skins.error.failed_to_load_desc"); + clearChildren(); + addDrawableChild(titleWidget); + addDrawableChild(new TextWidget(width / 2 - textRenderer.getWidth(error) / 2, height / 2 - textRenderer.fontHeight - 2, textRenderer.getWidth(error), textRenderer.fontHeight, error, textRenderer)); + addDrawableChild(new TextWidget(width / 2 - textRenderer.getWidth(errorDesc) / 2, height / 2 + 1, textRenderer.getWidth(errorDesc), textRenderer.fontHeight, errorDesc, textRenderer)); + addDrawableChild(back); + return null; + }); + } + + private void promptForSkinDownload() { + client.setScreen(new SimpleTextInputScreen(this, Text.translatable("skins.manage.import.online"), Text.translatable("skins.manage.import.online.input"), s -> + UUIDHelper.ensureUuidOpt(s).thenAccept(o -> { + if (o.isPresent()) { + AxolotlClientCommon.getInstance().getLogger().info("Downloading skin of {} ({})", s, o.get()); + Auth.getInstance().getMsApi().getTextures(o.get()) + .exceptionally(th -> { + AxolotlClientCommon.getInstance().getLogger().info("Failed to download skin of {} ({})", s, o.get(), th); + return null; + }).thenAccept(t -> { + if (t == null) { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_download", s); + return; + } + try { + var bytes = t.skin().join(); + var out = ensureNonexistent(SKINS_DIR.resolve(t.skinKey())); + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, t.classicModel(), "name", t.name(), "uuid", t.id(), "download_time", Instant.now())); + Files.write(out, bytes); + client.execute(this::loadSkinsList); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.downloaded", t.name()); + AxolotlClientCommon.getInstance().getLogger().info("Downloaded skin of {} ({})", t.name(), o.get()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to write skin file", e); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_save", t.name()); + } + }); + } else { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.not_found", s); + } + }))); + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + renderBackground(graphics); + super.render(graphics, mouseX, mouseY, delta); + } + + private void initDisplay() { + loadSkinsList(); + loadCapesList(); + } + + private void refreshCurrentList() { + if (capesTab) { + var scroll = capesList.getScrollAmount(); + loadCapesList(); + capesList.setScrollAmount(scroll); + } else { + var scroll = skinList.getScrollAmount(); + loadSkinsList(); + skinList.setScrollAmount(scroll); + } + } + + private void loadCapesList() { + List rows = new ArrayList<>(); + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + var capes = profile.capes(); + var deselectCape = createWidgetForCape(current.getSkin(), null); + var activeCape = capes.stream().filter(Cape::active).findFirst(); + current.setCape(activeCape.orElse(null)); + deselectCape.noCape(activeCape.isEmpty()); + for (int i = 0; i < capes.size() + 1; i += columns) { + Entry widget; + if (i == 0) { + widget = createEntry(capesList.getEntryContentsHeight(), deselectCape, Text.translatable("skins.capes.no_cape")); + } else { + var cape = capes.get(i - 1); + widget = createEntryForCape(current.getSkin(), cape, capesList.getEntryContentsHeight()); + } + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < capes.size() + 1 - c)) continue; + var cape2 = capes.get(i + c - 1); + Entry widget2 = createEntryForCape(current.getSkin(), cape2, capesList.getEntryContentsHeight()); + + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + client.execute(() -> capesList.replaceEntries(rows)); + } + + private void loadSkinsList() { + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + List skins = new ArrayList<>(profile.skins()); + var hashes = skins.stream().map(Asset::sha256).collect(Collectors.toSet()); + var defaultSkin = Skin.getDefaultSkin(account); + var local = new ArrayList<>(loadLocalSkins()); + var localHashes = local.stream().collect(Collectors.toMap(Asset::sha256, Function.identity(), (skin, skin2) -> skin)); + local.removeIf(s -> !localHashes.containsValue(s)); + skins.replaceAll(s -> { + if (s instanceof MSApi.MCProfile.OnlineSkin online) { + if (localHashes.containsKey(s.sha256()) && localHashes.get(s.sha256()) instanceof Skin.LocalSkin file) { + local.remove(localHashes.remove(s.sha256())); + return new Skin.Shared(file, online); + } + } + return s; + }); + skins.addAll(local); + if (!hashes.contains(defaultSkin.sha256())) { + skins.add(defaultSkin); + } + populateSkinList(skins, columns); + } + + private List loadLocalSkins() { + try { + Files.createDirectories(SKINS_DIR); + try (Stream skins = Files.list(SKINS_DIR)) { + return skins.filter(Files::isRegularFile).sorted(Comparator.comparingLong(p -> { + try { + return Files.getLastModifiedTime(p).toMillis(); + } catch (IOException e) { + return 0L; + } + }).reversed()).map(Auth.getInstance().getSkinManager()::read).filter(Objects::nonNull).toList(); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to read skins dir!", e); + } + return Collections.emptyList(); + } + + private void populateSkinList(List skins, int columns) { + int entryHeight = skinList.getEntryContentsHeight(); + List rows = new ArrayList<>(); + for (int i = 0; i < skins.size(); i += columns) { + var s = skins.get(i); + if (s != null && s.active()) { + current.setSkin(s); + } + var widget = createEntryForSkin(s, entryHeight); + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < skins.size() - c)) continue; + var s2 = skins.get(i + c); + if (s2 != null && s2.active()) { + current.setSkin(s2); + } + var widget2 = createEntryForSkin(s2, entryHeight); + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + client.execute(() -> skinList.replaceEntries(rows)); + } + + private Path ensureNonexistent(Path p) { + if (Files.exists(p)) { + int counter = 0; + do { + counter++; + p = p.resolveSibling(p.getFileName().toString() + "_" + counter); + } while (Files.exists(p)); + } + return p; + } + + @Override + public void filesDragged(List packs) { + if (packs.isEmpty()) return; + + CompletableFuture[] futs = new CompletableFuture[packs.size()]; + for (int i = 0; i < packs.size(); i++) { + Path p = packs.get(i); + futs[i] = CompletableFuture.runAsync(() -> { + try { + var target = ensureNonexistent(SKINS_DIR.resolve(p.getFileName())); + var skin = Auth.getInstance().getSkinManager().read(p, false); + if (skin != null) { + Files.write(target, skin.image()); + } else { + AxolotlClientCommon.getInstance().getLogger().info("Skipping dragged file {} because it does not seem to be a valid skin!", p); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.not_copied", p.getFileName()); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to copy skin file: ", e); + } + }, client); + } + CompletableFuture.allOf(futs).thenRun(this::loadSkinsList); + } + + private @NotNull Entry createEntryForSkin(Skin skin, int entryHeight) { + return createEntry(entryHeight, new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, skin, account)); + } + + private @NotNull Entry createEntryForCape(Skin currentSkin, Cape cape, int entryHeight) { + return createEntry(entryHeight, createWidgetForCape(currentSkin, cape), Text.literal(cape.alias())); + } + + private SkinWidget createWidgetForCape(Skin currentSkin, Cape cape) { + SkinWidget widget2 = new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, currentSkin, cape, account); + widget2.setRotationY(210); + return widget2; + } + + @Override + protected void clearAndInit() { + Auth.getInstance().getSkinManager().releaseAll(); + super.clearAndInit(); + } + + @Override + public void removed() { + Auth.getInstance().getSkinManager().releaseAll(); + Watcher.close(skinDirWatcher); + } + + @Override + public void closeScreen() { + client.setScreen(parent); + } + + private SkinListWidget getCurrentList() { + return capesTab ? capesList : skinList; + } + + private class SkinListWidget extends ElementListWidget { + public boolean active = true, visible = true; + + public SkinListWidget(MinecraftClient minecraft, int width, int height, int y, int entryHeight) { + super(minecraft, width, SkinManagementScreen.this.height, y, y + height, entryHeight); + setRenderHeader(false, 0); + } + + @Override + protected int getScrollbarPositionX() { + return right - 8; + } + + @Override + public int getRowLeft() { + return left + 3; + } + + @Override + public int getRowWidth() { + if (!(getMaxScroll() > 0)) { + return width - 4; + } + return width - 14; + } + + public int getEntryContentsHeight() { + return itemHeight - 4; + } + + @Override + public @Nullable ElementPath nextFocusPath(GuiNavigationEvent event) { + if (!active || !visible) return null; + return super.nextFocusPath(event); + } + + @Override + public void replaceEntries(Collection newEntries) { + super.replaceEntries(newEntries); + } + + @Override + public void centerScrollOn(Row entry) { + super.centerScrollOn(entry); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amountY) { + if (!visible) return false; + return super.mouseScrolled(mouseX, mouseY, amountY); + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + return active && visible && super.isMouseOver(mouseX, mouseY); + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + if (!visible) return; + super.render(graphics, mouseX, mouseY, delta); + } + } + + private class Row extends ElementListWidget.Entry { + private final List widgets; + + public Row(List entries) { + this.widgets = entries; + } + + @Override + public @NotNull List selectableChildren() { + return widgets; + } + + @Override + public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + int x = left; + if (widgets.isEmpty()) return; + int count = widgets.size(); + int padding = ((width - 5 * (count - 1)) / count); + for (var w : widgets) { + w.setPosition(x, top); + w.setWidth(padding); + w.render(guiGraphics, mouseX, mouseY, partialTick); + x += w.getWidth() + 5; + } + } + + @Override + public @NotNull List children() { + return widgets; + } + + @Override + public void setFocusedChild(@Nullable Element focused) { + super.setFocusedChild(focused); + if (focused != null) { + getCurrentList().centerScrollOn(this); + } + } + } + + Entry createEntry(int height, SkinWidget widget) { + return createEntry(height, widget, null); + } + + Entry createEntry(int height, SkinWidget widget, Text label) { + return new Entry(height, widget, label); + } + + private class Entry extends ClickableWidget implements ParentElement { + private final SkinWidget skinWidget; + private final @Nullable ClickableWidget label; + private final List actionButtons = new ArrayList<>(); + private final ClickableWidget equipButton; + private boolean equipping; + private long equippingStart; + @Nullable + private Element focused; + private boolean dragging; + + public Entry(int height, SkinWidget widget, @Nullable Text label) { + super(0, 0, widget.getWidth(), height, Text.empty()); + widget.setWidth(getWidth() - 4); + var asset = widget.getFocusedAsset(); + if (asset != null) { + if (asset instanceof Skin skin) { + var wideSprite = new Identifier("axolotlclient", "textures/gui/sprites/wide.png"); + var slimSprite = new Identifier("axolotlclient", "textures/gui/sprites/slim.png"); + var slimText = Text.translatable("skins.manage.variant.classic"); + var wideText = Text.translatable("skins.manage.variant.slim"); + actionButtons.add(new SpriteButton(skin.classicVariant() ? wideText : slimText, btn -> { + var self = (SpriteButton) btn; + skin.classicVariant(!skin.classicVariant()); + self.sprite = skin.classicVariant() ? slimSprite : wideSprite; + self.setMessage(skin.classicVariant() ? wideText : slimText); + }, skin.classicVariant() ? slimSprite : wideSprite)); + } + if (asset instanceof Asset.Local local) { + this.actionButtons.add(new SpriteButton(Text.translatable("skins.manage.delete"), btn -> { + btn.active = false; + client.setScreen(new ConfirmScreen(confirmed -> { + client.setScreen(new LoadingScreen(getTitle(), Text.translatable("menu.working"))); + if (confirmed) { + try { + Files.delete(local.file()); + Skin.LocalSkin.deleteMetadata(local.file()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to delete: ", e); + } + } + client.setScreen(SkinManagementScreen.this); + btn.active = true; + }, Text.translatable("skins.manage.delete.confirm"), (Text) (asset.active() ? + Text.translatable("skins.manage.delete.confirm.desc_active") : + Text.translatable("skins.manage.delete.confirm.desc") + ).br$color(Colors.RED.toInt()))); + }, new Identifier("axolotlclient", "textures/gui/sprites/delete.png"))); + } + if (asset instanceof Asset.Online online && online.supportsDownload() && !(asset instanceof Asset.Local)) { + this.actionButtons.add(new SpriteButton(Text.translatable("skins.manage.download"), btn -> { + btn.active = false; + download(asset).thenRun(() -> { + refreshCurrentList(); + btn.active = true; + }); + }, new Identifier("axolotlclient", "textures/gui/sprites/download.png"))); + } + } + if (label != null) { + this.label = new AbstractTextWidget(0, 0, widget.getWidth(), 16, label, textRenderer) { + @Override + protected void drawWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + drawScrollingText(guiGraphics, textRenderer, 2, -1); + } + }; + this.label.active = false; + } else { + this.label = null; + } + this.equipButton = ButtonWidget.builder(Text.translatable( + widget.isEquipped() ? "skins.manage.equipped" : "skins.manage.equip"), + btn -> { + equippingStart = Util.getMeasuringTimeMs(); + equipping = true; + btn.setMessage(TEXT_EQUIPPING); + btn.active = false; + Consumer> consumer = f -> f.thenAcceptAsync(p -> { + cachedProfile = p; + if (client.currentScreen == SkinManagementScreen.this) { + refreshCurrentList(); + } else { + client.execute(() -> client.setScreen(SkinManagementScreen.this)); + } + }).exceptionally(t -> { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to equip asset!", t); + equipping = false; + return null; + }); + if (asset instanceof Skin && !(current.getSkin() instanceof Skin.Local)) { + client.setScreen(new ConfirmScreen(confirmed -> { + client.setScreen(new LoadingScreen(getTitle(), TEXT_EQUIPPING)); + if (confirmed) { + consumer.accept(download(current.getSkin()).thenCompose(a -> widget.equip())); + } else { + consumer.accept(widget.equip()); + } + }, Text.translatable("skins.manage.equip.confirm"), Text.translatable("skins.manage.equip.download_current"))); + } else { + consumer.accept(widget.equip()); + } + }).width(widget.getWidth()).build(); + this.equipButton.active = !widget.isEquipped(); + this.skinWidget = widget; + } + + private @NotNull CompletableFuture download(Asset asset) { + return CompletableFuture.runAsync(() -> { + try { + var out = SKINS_DIR.resolve(asset.sha256()); + Files.createDirectories(out.getParent()); + Files.write(out, asset.image()); + if (asset instanceof Skin skin) { + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, skin.classicVariant())); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to download: ", e); + } + }); + } + + @Override + public final boolean isDragging() { + return this.dragging; + } + + @Override + public final void setDragging(boolean dragging) { + this.dragging = dragging; + } + + @Nullable + @Override + public Element getFocused() { + return this.focused; + } + + @Override + public void setFocusedChild(@Nullable Element child) { + if (this.focused != null) { + this.focused.setFocused(false); + } + + if (child != null) { + child.setFocused(true); + } + + this.focused = child; + } + + @Nullable + @Override + public ElementPath nextFocusPath(GuiNavigationEvent event) { + return ParentElement.super.nextFocusPath(event); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return ParentElement.super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return ParentElement.super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + return ParentElement.super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean isFocused() { + return ParentElement.super.isFocused(); + } + + @Override + public void setFocused(boolean focused) { + ParentElement.super.setFocused(focused); + } + + @Override + public @NotNull List children() { + return Stream.concat(actionButtons.stream(), Stream.of(skinWidget, label, equipButton)).filter(Objects::nonNull).toList(); + } + + private float applyEasing(float x) { + return x * x * x; + } + + @Override + protected void drawWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + int y = getY() + 4; + int x = getX() + 2; + skinWidget.setPosition(x, y); + skinWidget.setWidth(getWidth() - 4); + if (skinWidget.isEquipped() || equipping) { + long prog; + if (Auth.getInstance().skinManagerAnimations.get()) { + if (equipping) prog = (Util.getMeasuringTimeMs() - equippingStart) / 20 % 100; + else prog = Math.abs((Util.getMeasuringTimeMs() / 30 % 200) - 100); + } else prog = 100; + var percent = (prog / 100f); + float gradientWidth; + if (equipping) { + gradientWidth = percent * Math.min(getWidth() / 3f, getHeight() / 3f); + } else { + gradientWidth = Math.min(getWidth() / 15f, getHeight() / 6f) + applyEasing(percent) * Math.min(getWidth() * 2 / 15f, getHeight() / 6f); + } + GradientHoleRectangleRenderState.render(guiGraphics, getX() + 2, getY() + 2, getX() + getWidth() - 2, + skinWidget.getY() + skinWidget.getHeight() + 2, + gradientWidth, + equipping ? 0xFFFF0088 : ClientColors.SELECTOR_GREEN.toInt(), 0); + } + skinWidget.render(guiGraphics, mouseX, mouseY, partialTick); + int actionButtonY = getY() + 2; + for (var button : actionButtons) { + button.setPosition(skinWidget.getX() + skinWidget.getWidth() - button.getWidth(), actionButtonY); + if (isHovered() || button.isHoveredOrFocused()) { + button.render(guiGraphics, mouseX, mouseY, partialTick); + } + actionButtonY += button.getHeight() + 2; + } + if (label != null) { + label.setPosition(x, skinWidget.getY() + skinWidget.getHeight() + 6); + label.render(guiGraphics, mouseX, mouseY, partialTick); + label.setWidth(getWidth() - 4); + equipButton.setPosition(x, label.getY() + label.getHeight() + 2); + } else { + equipButton.setPosition(x, skinWidget.getY() + skinWidget.getHeight() + 4); + } + equipButton.setWidth(getWidth() - 4); + equipButton.render(guiGraphics, mouseX, mouseY, partialTick); + + if (isHovered()) { + guiGraphics.br$outlineRect(getX(), getY(), getWidth(), getHeight(), -1); + } + } + + @Override + protected void updateNarration(NarrationMessageBuilder narrationElementOutput) { + skinWidget.appendNarrations(narrationElementOutput); + actionButtons.forEach(w -> w.appendNarrations(narrationElementOutput)); + if (label != null) { + label.appendNarrations(narrationElementOutput); + } + equipButton.appendNarrations(narrationElementOutput); + } + + private static class GradientHoleRectangleRenderState { + + public static void render(GuiGraphics graphics, int x0, int y0, int x1, int y1, float gradientWidth, int col1, int col2) { + var vertexConsumer = graphics.getVertexConsumers().getBuffer(RenderLayer.getGui()); + float z = 0; + //top + var pose = graphics.getMatrices().peek().getModel(); + vertexConsumer.vertex(pose, x0, y0, z).color(col1).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y0 + gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y0 + gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x1, y0, z).color(col1).next(); + //left + vertexConsumer.vertex(pose, x0, y1, z).color(col1).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y1 - gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y0 + gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x0, y0, z).color(col1).next(); + //bottom + vertexConsumer.vertex(pose, x1, y1, z).color(col1).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y1 - gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x0 + gradientWidth, y1 - gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x0, y1, z).color(col1).next(); + //right + vertexConsumer.vertex(pose, x1, y0, z).color(col1).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y0 + gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x1 - gradientWidth, y1 - gradientWidth, z).color(col2).next(); + vertexConsumer.vertex(pose, x1, y1, z).color(col1).next(); + } + } + + } + + private static class SpriteButton extends ButtonWidget { + private Identifier sprite; + + public SpriteButton(Text message, PressAction onPress, Identifier sprite) { + super(0, 0, 11, 11, message, onPress, DEFAULT_NARRATION); + this.sprite = sprite; + setTooltip(Tooltip.create(message, Text.empty())); + } + + @Override + public void setMessage(Text message) { + super.setMessage(message); + setTooltip(Tooltip.create(message, Text.empty())); + } + + @Override + protected void drawWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + super.drawWidget(graphics, mouseX, mouseY, delta); + graphics.drawTexture(sprite, getX() + 2, getY() + 2, 0, 0, 7, 7, 7, 7); + } + + @Override + public void drawScrollableText(GuiGraphics graphics, TextRenderer renderer, int color) { + + } + } +} diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java new file mode 100644 index 000000000..6f3844c34 --- /dev/null +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java @@ -0,0 +1,178 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import com.google.common.hash.Hashing; +import com.mojang.blaze3d.texture.NativeImage; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.util.ClientColors; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.util.Identifier; + +public class SkinManager { + + private final Set loadedTextures = new ConcurrentSkipListSet<>(Comparator.comparing(Object::toString)); + + public Skin read(Path p) { + return read(p, true); + } + + public Skin read(Path p, boolean fix) { + boolean slim; + String sha256; + try { + var in = Files.readAllBytes(p); + sha256 = Hashing.sha256().hashBytes(in).toString(); + try (var img = NativeImage.read(in)) { + int width = img.getWidth(); + int height = img.getHeight(); + if (width != 64) return null; + if (height == 32) { + if (fix) { + try (var img2 = remapTexture(img)) { + img2.writeFile(p); + } + } + slim = false; + } else if (height != 64) { + return null; + } else { + slim = ClientColors.ARGB.alpha(img.getPixelColor(50, 16)) == 0; + } + var metadata = Skin.LocalSkin.readMetadata(p); + if (metadata != null && metadata.containsKey(Skin.LocalSkin.CLASSIC_METADATA_KEY)) { + slim = !(boolean) metadata.get(Skin.LocalSkin.CLASSIC_METADATA_KEY); + } + } + return new Skin.LocalSkin(!slim, p, in, sha256); + } catch (Exception e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to probe skin: {}", p, e); + } + return null; + } + + private static NativeImage remapTexture(NativeImage skinImage) { + boolean legacySkin = skinImage.getHeight() == 32; + if (legacySkin) { + NativeImage nativeImage = new NativeImage(64, 64, true); + nativeImage.copyFrom(skinImage); + skinImage.close(); + skinImage = nativeImage; + nativeImage.fillRect(0, 32, 64, 32, 0); + nativeImage.copyRectangle(4, 16, 16, 32, 4, 4, true, false); + nativeImage.copyRectangle(8, 16, 16, 32, 4, 4, true, false); + nativeImage.copyRectangle(0, 20, 24, 32, 4, 12, true, false); + nativeImage.copyRectangle(4, 20, 16, 32, 4, 12, true, false); + nativeImage.copyRectangle(8, 20, 8, 32, 4, 12, true, false); + nativeImage.copyRectangle(12, 20, 16, 32, 4, 12, true, false); + nativeImage.copyRectangle(44, 16, -8, 32, 4, 4, true, false); + nativeImage.copyRectangle(48, 16, -8, 32, 4, 4, true, false); + nativeImage.copyRectangle(40, 20, 0, 32, 4, 12, true, false); + nativeImage.copyRectangle(44, 20, -8, 32, 4, 12, true, false); + nativeImage.copyRectangle(48, 20, -16, 32, 4, 12, true, false); + nativeImage.copyRectangle(52, 20, -8, 32, 4, 12, true, false); + } + + stripAlpha(skinImage, 0, 0, 32, 16); + if (legacySkin) { + stripColor(skinImage, 32, 0, 64, 32); + } + + stripAlpha(skinImage, 0, 16, 64, 32); + stripAlpha(skinImage, 16, 48, 48, 64); + return skinImage; + } + + @SuppressWarnings("SameParameterValue") + private static void stripColor(NativeImage image, int x1, int y1, int x2, int y2) { + for (int x = x1; x < x2; x++) { + for (int y = y1; y < y2; y++) { + int k = image.getPixelColor(x, y); + if ((k >> 24 & 0xFF) < 128) { + return; + } + } + } + + for (int x = x1; x < x2; x++) { + for (int y = y1; y < y2; y++) { + image.setPixelColor(x, y, image.getPixelColor(x, y) & 16777215); + } + } + } + + private static void stripAlpha(NativeImage image, int x1, int y1, int x2, int y2) { + for (int x = x1; x < x2; x++) { + for (int y = y1; y < y2; y++) { + image.setPixelColor(x, y, image.getPixelColor(x, y) | 0xFF000000); + } + } + } + + public AxoIdentifier loadSkin(Skin skin) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "skins/" + skin.sha256()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try { + var tex = new NativeImageBackedTexture(NativeImage.read(skin.image())); + MinecraftClient.getInstance().getTextureManager().registerTexture((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public AxoIdentifier loadCape(Cape cape) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "capes/" + cape.id()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try { + var tex = new NativeImageBackedTexture(NativeImage.read(cape.image())); + MinecraftClient.getInstance().getTextureManager().registerTexture((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public void releaseAll() { + loadedTextures.forEach(id -> MinecraftClient.getInstance().getTextureManager().destroyTexture((Identifier) id)); + loadedTextures.clear(); + } +} diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java new file mode 100644 index 000000000..4ffe9fd88 --- /dev/null +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java @@ -0,0 +1,90 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import com.mojang.blaze3d.lighting.DiffuseLighting; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.render.LightmapTextureManager; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.entity.model.EntityModelLayers; +import net.minecraft.client.render.entity.model.PlayerEntityModel; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Axis; +import org.jetbrains.annotations.Nullable; + +public class SkinRenderer { + private static PlayerEntityModel classicModel, slimModel; + private static final MinecraftClient minecraft = MinecraftClient.getInstance(); + + private SkinRenderer() { + } + + public static void render(GuiGraphics graphics, boolean classicVariant, + Identifier skinTexture, + @Nullable Identifier cape, + float rotationX, + float rotationY, + float pivotY, + int x0, + int y0, + int x1, + int y1, + float scale) { + if (classicModel == null && classicVariant) { + classicModel = new PlayerEntityModel<>(minecraft.getEntityModelLoader().getModelPart(EntityModelLayers.PLAYER), false); + classicModel.child = false; + } + if (slimModel == null && !classicVariant) { + slimModel = new PlayerEntityModel<>(minecraft.getEntityModelLoader().getModelPart(EntityModelLayers.PLAYER_SLIM), true); + slimModel.child = false; + } + + int width = x1 - x0; + DiffuseLighting.setupInventoryEntityLighting(); + graphics.getMatrices().push(); + graphics.getMatrices().translate(x0 + width / 2.0F, (float) (y1), 100.0F); + graphics.getMatrices().scale(scale, scale, scale); + graphics.getMatrices().translate(0.0F, -0.0625F, 0.0F); + graphics.getMatrices().rotateAround(Axis.X_POSITIVE.rotationDegrees(rotationX), 0.0F, pivotY, 0.0F); + graphics.getMatrices().multiply(Axis.Y_POSITIVE.rotationDegrees(rotationY)); + graphics.draw(); + graphics.getMatrices().push(); + graphics.getMatrices().scale(1.0F, 1.0F, -1.0F); + graphics.getMatrices().translate(0.0F, -1.5F, 0.0F); + var model = classicVariant ? classicModel : slimModel; + RenderLayer renderLayer = RenderLayer.getEntityAlpha(skinTexture); + model.render(graphics.getMatrices(), graphics.getVertexConsumers().getBuffer(renderLayer), LightmapTextureManager.MAX_LIGHT_COORDINATE, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); + if (cape != null) { + graphics.getMatrices().translate(0.0F, 0.0F, 0.125F); + graphics.getMatrices().multiply(Axis.X_POSITIVE.rotationDegrees(6.0F)); + graphics.getMatrices().multiply(Axis.Y_POSITIVE.rotationDegrees(180.0F)); + model.renderCape(graphics.getMatrices(), graphics.getVertexConsumers().getBuffer(RenderLayer.getEntityAlpha(cape)), LightmapTextureManager.MAX_LIGHT_COORDINATE, OverlayTexture.DEFAULT_UV); + } + graphics.getMatrices().pop(); + graphics.draw(); + graphics.getMatrices().pop(); + DiffuseLighting.setup3DGuiLighting(); + } +} diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java new file mode 100644 index 000000000..5f6116c15 --- /dev/null +++ b/1.20/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java @@ -0,0 +1,133 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.concurrent.CompletableFuture; + +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.gui.ElementPath; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.GuiNavigationEvent; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.sound.SoundManager; +import net.minecraft.text.CommonTexts; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; + +public class SkinWidget extends ClickableWidget { + private static final float MODEL_HEIGHT = 2.125F; + private static final float FIT_SCALE = 0.97F; + private static final float ROTATION_SENSITIVITY = 2.5F; + private static final float DEFAULT_ROTATION_X = -5.0F; + private static final float DEFAULT_ROTATION_Y = 30.0F; + private static final float ROTATION_X_LIMIT = 50.0F; + private float rotationX = DEFAULT_ROTATION_X; + @Setter + private float rotationY = DEFAULT_ROTATION_Y; + @Getter + @Setter + private Skin skin; + @Getter + @Setter + private Cape cape; + private final Account owner; + private boolean noCape, noCapeActive; + + public SkinWidget(int width, int height, Skin skin, @Nullable Cape cape, Account owner) { + super(0, 0, width, height, CommonTexts.EMPTY); + this.skin = skin; + this.cape = cape; + this.owner = owner; + } + + public SkinWidget(int width, int height, Skin skin, Account owner) { + this(width, height, skin, null, owner); + } + + public void noCape(boolean noCapeActive) { + noCape = true; + this.noCapeActive = noCapeActive; + } + + @Override + protected void drawWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + float scale = FIT_SCALE * this.getHeight() / MODEL_HEIGHT; + float pivotY = -1.0625F; + + SkinManager skinManager = Auth.getInstance().getSkinManager(); + AxoIdentifier skinRl = skinManager.loadSkin(skin); + boolean classic = skin.classicVariant(); + var capeRl = cape == null ? null : skinManager.loadCape(cape); + + SkinRenderer.render(guiGraphics, classic, (Identifier) skinRl, (Identifier) capeRl, this.rotationX, this.rotationY, pivotY, this.getX(), this.getY(), this.getX() + getWidth(), this.getY() + getHeight(), scale); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) { + this.rotationX = MathHelper.clamp(this.rotationX - (float) dragY * ROTATION_SENSITIVITY, -ROTATION_X_LIMIT, ROTATION_X_LIMIT); + this.rotationY += (float) dragX * ROTATION_SENSITIVITY; + } + + @Override + public void playDownSound(SoundManager handler) { + } + + @Override + protected void updateNarration(NarrationMessageBuilder builder) { + + } + + @Override + public @Nullable ElementPath nextFocusPath(GuiNavigationEvent event) { + return null; + } + + public boolean isEquipped() { + return noCape ? noCapeActive : (cape != null ? cape.active() : skin != null && skin.active()); + } + + public CompletableFuture equip() { + var msApi = Auth.getInstance().getMsApi(); + if (noCape) { + return msApi.hideCape(owner); + } + if (cape != null) { + return cape.equip(msApi, owner); + } + if (skin != null) { + return skin.equip(msApi, owner); + } + return msApi.resetSkin(owner); + } + + public Asset getFocusedAsset() { + return noCape ? null : cape != null ? cape : skin; + } +} diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java b/1.20/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java index 5e369ad8b..f69234118 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java @@ -32,6 +32,7 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.FloatOption; import io.github.axolotlclient.mixin.ShaderEffectAccessor; import io.github.axolotlclient.modules.AbstractModule; +import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gl.ShaderEffect; import net.minecraft.resource.Resource; @@ -40,6 +41,7 @@ public class MotionBlur extends AbstractModule { + @Getter private static final MotionBlur Instance = new MotionBlur(); public final BooleanOption enabled = new BooleanOption("enabled", false); public final FloatOption strength = new FloatOption("strength", 50F, 1F, 99F); @@ -57,10 +59,6 @@ private static float getBlur() { return MotionBlur.getInstance().strength.get() / 100F; } - public static MotionBlur getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled, strength, inGuis); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java b/1.20/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java index 1b06ca24b..640c8238c 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java @@ -123,7 +123,7 @@ private void start(Perspective perspective, WrappedValue active) { } private void setPerspective(Perspective perspective) { - MinecraftClient.getInstance().options.setPerspective(perspective); + client.options.setPerspective(perspective); } public boolean consumeRotation(double dx, double dy) { diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java index 0959e1411..b963650d8 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java @@ -46,7 +46,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudEditScreen extends Screen { @@ -125,19 +125,20 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { if (entry.isPresent()) { var bounds = entry.get().getTrueBounds(); if (mode == ModificationMode.NONE && bounds.isMouseOver(mouseX, mouseY)) { + var supportsScaling = entry.get().supportsScaling(); var xBound = Math.max(0, mouseX - bounds.x()); var yBound = Math.max(0, mouseY - bounds.y()); var tolerance = GRAB_TOLERANCE; - if (xBound < tolerance && yBound < tolerance) { + if (supportsScaling && xBound < tolerance && yBound < tolerance) { // top-left setCursor(NWSE_RESIZE_CURSOR); - } else if (Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-right setCursor(NWSE_RESIZE_CURSOR); - } else if (xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-left setCursor(NESW_RESIZE_CURSOR); - } else if (yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { + } else if (supportsScaling && yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { // top-right setCursor(NESW_RESIZE_CURSOR); } else { diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java index b970b7b1d..61c11002e 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java @@ -34,7 +34,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudManager extends HudManagerCommon { @Getter @@ -62,7 +62,7 @@ protected void addExtraHud() { public void render(AxoRenderContext context, float delta) { final var mc = ((MinecraftClient) client); mc.getProfiler().push("Hud render"); - if(!(mc.currentScreen instanceof HudEditScreen)) { + if (!(mc.currentScreen instanceof HudEditScreen)) { super.render(context, delta); } mc.getProfiler().pop(); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java index ee3d8dc4a..05d8d319d 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java @@ -70,7 +70,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class KeystrokeHud extends TextHudEntry implements ProfileAware { @@ -480,6 +480,7 @@ public boolean isLabelEditable() { } public void saveKeystrokes() { + if (keystrokes == null) return; try { var path = AxolotlClientCommon.resolveProfileConfigFile(KEYSTROKE_SAVE_FILE_NAME); Files.createDirectories(path.getParent()); @@ -498,7 +499,11 @@ public void loadKeystrokes() { var loaded = entries.stream().map(e -> (Map) e) .map(KeystrokeHud.this::deserializeKey) .toList(); - keystrokes.clear(); + if (keystrokes == null) { + keystrokes = new ArrayList<>(); + } else { + keystrokes.clear(); + } keystrokes.addAll(loaded); } else { saveKeystrokes(); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java index 80e2ce3d4..e77e65bc2 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java @@ -22,19 +22,15 @@ package io.github.axolotlclient.modules.hud.gui.hud; -import com.mojang.blaze3d.lighting.DiffuseLighting; -import com.mojang.blaze3d.systems.RenderSystem; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.render.AxoRenderContext; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import lombok.Getter; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; -import net.minecraft.util.math.Axis; import net.minecraft.util.math.MathHelper; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -43,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class PlayerHud extends PlayerHudCommon { @@ -58,7 +54,7 @@ public PlayerHud() { } public void onPlayerDirectionChange(PlayerDirectionChangeEvent event) { - yawOffset += (event.getYaw() - event.getPrevYaw()) / 2; + yawOffset += (event.yaw() - event.prevYaw()) / 2; } @Override @@ -81,8 +77,7 @@ public void tick() { float pitch = k * (-90.0F - client.player.getPitch()) + 90; float height = client.player.getHeight(); // sin = opposite / hypotenuse - float offset = (float) (Math.sin(Math.toRadians(pitch)) * height) * 50; - yOffset = 35 - offset; + yOffset = (float) (Math.sin(Math.toRadians(pitch)) * height); if (pitch < 0) { yOffset -= (float) (((1 / (1 + Math.exp(-pitch / 4))) - .5) * 20); } @@ -112,56 +107,34 @@ protected void renderPlayer(AxoRenderContext ctx, boolean placeholder, double x, float lerpY = (lastYOffset + ((yOffset - lastYOffset) * delta)); - MatrixStack matrixStack = RenderSystem.getModelViewStack(); - matrixStack.push(); - matrixStack.translate(x, y - lerpY, 1050); - matrixStack.scale(1, 1, -1); - - RenderSystem.applyModelViewMatrix(); - MatrixStack nextStack = new MatrixStack(); - nextStack.translate(0, 0, 1000); float scale = getScale() * 40; - nextStack.scale(scale, scale, scale); - Quaternionf quaternion = Axis.Z_POSITIVE.rotationDegrees(180.0F); + Quaternionf quaternion = new Quaternionf().rotateZ((float) Math.PI); - nextStack.multiply(quaternion); // Rotate to whatever is wanted. Also make sure to offset the yaw float deltaYaw = client.player.getYaw(delta); if (dynamicRotation.get()) { deltaYaw -= (lastYawOffset + ((yawOffset - lastYawOffset) * delta)); } - nextStack.multiply(new Quaternionf().fromAxisAngleDeg(new Vector3f(0, 1, 0), deltaYaw - 180 + rotation.get().floatValue())); - - // Save these to set them back later - float pastYaw = client.player.getYaw(); - float pastPrevYaw = client.player.prevYaw; - - DiffuseLighting.setupInventoryEntityLighting(); - EntityRenderDispatcher renderer = client.getEntityRenderDispatcher(); - renderer.setRotation(quaternion); - renderer.setRenderShadows(false); - VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders() - .getEntityVertexConsumers(); + Quaternionf quaternionf2 = new Quaternionf().fromAxisAngleDeg(new Vector3f(0, 1, 0), deltaYaw - 180 + rotation.get().floatValue()); + quaternion.mul(quaternionf2); currentlyRendering = true; - renderer.render(client.player, 0, 0, 0, 0, delta, nextStack, immediate, 0xF000F0); - immediate.draw(); + InventoryScreen.drawEntity((GuiGraphics) ctx, + (int) (x + getTrueWidth() / 2f), + (int) (y + getTrueHeight() * client.player.getHeight() / 2f - lerpY), + (int) scale, + quaternion, + quaternionf2, + client.player); currentlyRendering = false; - renderer.setRenderShadows(true); - matrixStack.pop(); - - client.player.setYaw(pastYaw); - client.player.prevYaw = pastPrevYaw; - - RenderSystem.applyModelViewMatrix(); - DiffuseLighting.setup3DGuiLighting(); } private boolean isPerformingAction() { // inspired by tr7zw's mod ClientPlayerEntity player = MinecraftClient.getInstance().player; + //noinspection DataFlowIssue return player.isSneaking() || player.isSprinting() || player.isFallFlying() || player.getAbilities().flying || player.isSubmergedInWater() || player.isInSwimmingPose() || player.hasVehicle() || player.isUsingItem() || player.handSwinging || player.hurtTime > 0 || player.isOnFire(); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java index 02c235dd2..f84e5d742 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java @@ -40,7 +40,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ActionBarHud extends TextHudEntry { @@ -106,6 +106,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(timeShown); options.add(customTextColor); return options; diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java index 7ea700dab..f4be818fb 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java @@ -50,7 +50,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class BossBarHud extends TextHudEntry implements DynamicallyPositionable { @@ -146,6 +146,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(text); options.add(bar); options.add(anchor); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java index dce6dfa79..db80f173d 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java @@ -62,7 +62,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CrosshairHud extends AbstractHudEntry implements DynamicallyPositionable { @@ -116,6 +116,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(type); options.add(customTextureGraphics); options.add(showInF5); @@ -219,6 +220,7 @@ public void render(AxoRenderContext context, float delta) { // Draw attack indicator if (!customAttackIndicator.get() && indicator == AttackIndicator.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackCooldownProgress(0.0F); // Whether a cross should be displayed under the indicator @@ -242,6 +244,7 @@ public void render(AxoRenderContext context, float delta) { } } if (((type.get().equals(Crosshair.TEXTURE) || type.get().equals(Crosshair.CUSTOM)) ? customAttackIndicator.get() : true) && indicator == AttackIndicator.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackCooldownProgress(0.0F); if (progress != 1.0F) { RenderUtil.drawRectangle(graphics, getRawX() + (getWidth() / 2) - 6, getRawY() + (getHeight() / 2) + 9, @@ -264,6 +267,7 @@ public Color getColor() { } else if (hit.getType() == HitResult.Type.BLOCK) { BlockPos blockPos = ((BlockHitResult) hit).getBlockPos(); World world = this.client.world; + //noinspection DataFlowIssue if (world.getBlockState(blockPos).createScreenHandlerFactory(world, blockPos) != null || world.getBlockState(blockPos).getBlock() instanceof AbstractChestBlock) { return containerColor.get(); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java index 36bd9a1d5..c919cd7cc 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java @@ -133,6 +133,7 @@ public AnchorPoint getAnchor() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(anchor); options.add(showCCount); options.add(showECount); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java index 470584deb..7d45339a1 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java @@ -49,6 +49,7 @@ public class HotbarHUD extends TextHudEntry { public HotbarHUD() { super(182, 22, false); + supportsScaling = false; } @Override @@ -155,6 +156,7 @@ public boolean overridesF3() { public List> getConfigurationOptions() { List> list = new ArrayList<>(); list.add(enabled); + list.add(hide); return list; } } diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java index 200bb8714..0dc34ce39 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java @@ -56,7 +56,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ScoreboardHud extends TextHudEntry implements DynamicallyPositionable { @@ -104,8 +104,10 @@ public void render(AxoRenderContext graphics, float delta) { @Override public void renderComponent(AxoRenderContext graphics, float delta) { + //noinspection DataFlowIssue Scoreboard scoreboard = this.client.world.getScoreboard(); ScoreboardObjective scoreboardObjective = null; + //noinspection DataFlowIssue Team team = scoreboard.getPlayerTeam(this.client.player.getEntityName()); if (team != null) { int t = team.getColor().getColorIndex(); @@ -230,8 +232,8 @@ private void renderScoreboardSidebar(GuiGraphics graphics, ScoreboardObjective o @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); - options.add(options.indexOf(super.backgroundColor), backgroundColor); - options.remove(super.backgroundColor); + options.set(options.indexOf(super.backgroundColor), backgroundColor); + options.add(hide); options.add(topColor); options.add(scores); options.add(scoreColor); @@ -249,6 +251,16 @@ public Identifier getId() { @Override public AnchorPoint getAnchor() { - return (anchor.get()); + return anchor.get(); + } + + @Override + public double getDefaultX() { + return 1.0; + } + + @Override + public double getDefaultY() { + return 0.5; } } diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java index 9113ec6da..834db3e9c 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class SnappingHelper { diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java index a4631b6b6..df6597a0f 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java @@ -36,7 +36,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class DrawUtil { diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java deleted file mode 100644 index d642ca6c4..000000000 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.modules.hud.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import lombok.experimental.UtilityClass; -import net.minecraft.client.MinecraftClient; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Util; - -/** - * This implementation of Hud modules is based on KronHUD. - * Github Link. - * - * @license GPL-3.0 - */ - -@UtilityClass -public class ItemUtil { - - public static ArrayList removeOld(List list, int time) { - ArrayList stored = new ArrayList<>(); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.getPassedTime() <= time) { - stored.add(storage); - } - } - return stored; - } - - public static List untimedToTimed(List list) { - ArrayList timed = new ArrayList<>(); - for (ItemStorage stack : list) { - timed.add(stack.timed()); - } - return timed; - } - - public static Optional getTimedItemFromItem(ItemStack item, - List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.stack.isOf(compare.getItem())) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - public static int getTotal(MinecraftClient client, ItemStack stack) { - List item = ItemUtil.getItems(client); - if (item == null || item.isEmpty()) { - return 0; - } - List items = ItemUtil.storageFromItem(item); - Optional stor = ItemUtil.getItemFromItem(stack, items); - return stor.map(itemStorage -> itemStorage.times).orElse(0); - } - - public static List getItems(MinecraftClient client) { - ArrayList items = new ArrayList<>(); - if (client.player == null) { - return null; - } - items.addAll(client.player.getInventory().armor); - items.addAll(client.player.getInventory().offHand); - items.addAll(client.player.getInventory().main); - return items; - } - - public static List storageFromItem(List items) { - ArrayList storage = new ArrayList<>(); - for (ItemStack item : items) { - if (item.isEmpty()) { - continue; - } - Optional s = getItemFromItem(item, storage); - if (s.isPresent()) { - ItemUtil.ItemStorage store = s.get(); - store.incrementTimes(item.getCount()); - } else { - storage.add(new ItemUtil.ItemStorage(item, item.getCount())); - } - } - return storage; - } - - public static Optional getItemFromItem(ItemStack item, List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.ItemStorage storage : list) { - if (storage.stack.isOf(compare.getItem())) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - /** - * Compares two ItemStorage Lists. - * If list1.get(1) is 10, and list2 is 5, it will return 5. - * Will return nothing if negative... - * - * @param list1 one to be based off of - * @param list2 one to compare to - * @return the compared list - */ - public static List compare(List list1, List list2) { - ArrayList list = new ArrayList<>(); - for (ItemStorage current : list1) { - Optional optional = getItemFromItem(current.stack, list2); - if (optional.isPresent()) { - ItemStorage other = optional.get(); - if (current.times - other.times <= 0) { - continue; - } - list.add(new ItemStorage(other.stack.copy(), current.times - other.times)); - } else { - list.add(current.copy()); - } - } - return list; - } - - public static class ItemStorage { - - public final ItemStack stack; - public int times; - - public ItemStorage(ItemStack stack, int times) { - ItemStack copy = stack.copy(); - copy.setCount(1); - this.stack = copy; - this.times = times; - } - - public void incrementTimes(int num) { - times = times + num; - } - - public ItemStorage copy() { - return new ItemStorage(stack.copy(), times); - } - - public TimedItemStorage timed() { - return new TimedItemStorage(stack, times); - } - } - - public static class TimedItemStorage extends ItemStorage { - - public float start; - - public TimedItemStorage(ItemStack stack, int times) { - super(stack, times); - this.start = Util.getMeasuringTimeMs(); - } - - public float getPassedTime() { - return Util.getMeasuringTimeMs() - start; - } - - @Override - public void incrementTimes(int num) { - super.incrementTimes(num); - refresh(); - } - - public void refresh() { - start = Util.getMeasuringTimeMs(); - } - } -} diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java b/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java index 71df579a9..55b08b0d1 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java @@ -37,7 +37,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @UtilityClass diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/particles/Particles.java b/1.20/src/main/java/io/github/axolotlclient/modules/particles/Particles.java index e102cacb3..a1f46eea2 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/particles/Particles.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/particles/Particles.java @@ -35,6 +35,7 @@ import io.github.axolotlclient.mixin.ParticleAccessor; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.ClientColors; +import lombok.Getter; import net.minecraft.client.particle.Particle; import net.minecraft.particle.ParticleType; import net.minecraft.particle.ParticleTypes; @@ -43,6 +44,7 @@ public class Particles extends AbstractModule { + @Getter private static final Particles Instance = new Particles(); public final HashMap, HashMap>> particleOptions = new HashMap<>(); @@ -51,10 +53,6 @@ public class Particles extends AbstractModule { private final OptionCategory cat = OptionCategory.create("particles"); private final BooleanOption enabled = new BooleanOption("enabled", false); - public static Particles getInstance() { - return Instance; - } - @Override public void init() { cat.add(enabled); @@ -66,6 +64,7 @@ public void init() { private void addParticleOptions() { for (ParticleType type : Registries.PARTICLE_TYPE.stream().sorted(new AlphabeticalComparator()).toList()) { if (Registries.PARTICLE_TYPE.getId(type) != null) { + //noinspection DataFlowIssue OptionCategory category = OptionCategory.create( Arrays.stream(Registries.PARTICLE_TYPE.getId(type).getPath().split("_")) .map(StringUtils::capitalize).collect(Collectors.joining(" "))); @@ -145,6 +144,7 @@ public int compare(ParticleType s1, ParticleType s2) { private String getName(ParticleType type) { if (Registries.PARTICLE_TYPE.getId(type) != null) { + //noinspection DataFlowIssue return Registries.PARTICLE_TYPE.getId(type).getPath(); } return ""; diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java b/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java index 9ecd96f09..55d1d29d5 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java @@ -53,7 +53,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { @Override protected void init() { - var urlBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 2 - 10, 200, 20, Text.translatable("urlBox")); + var urlBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 2 - 10, 200, 20, Text.translatable("pasteURL")); urlBox.setSuggestion(I18n.translate("pasteURL")); urlBox.setChangedListener(s -> { if (s.isEmpty()) { @@ -69,6 +69,7 @@ protected void init() { if (url.isEmpty()) { return; } + //noinspection DataFlowIssue client.setScreen(ImageScreen.create(this, ImageShare.getInstance().downloadImage(url), true)); }, Supplier::get) { @Override @@ -90,6 +91,7 @@ public void drawScrollableText(GuiGraphics graphics, TextRenderer renderer, int @Override public void closeScreen() { + //noinspection DataFlowIssue client.setScreen(parent); } } diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java b/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java index 9b88f618b..cbf337a26 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java @@ -87,10 +87,10 @@ public void closeScreen() { private void drawHorizontalGradient(GuiGraphics guiGraphics, int x1, int y1, int y2, int x2) { VertexConsumer consumer = client.getBufferBuilders().getEntityVertexConsumers().getBuffer(RenderLayer.getGui()); Matrix4f matrix4f = guiGraphics.getMatrices().peek().getModel(); - consumer.vertex(matrix4f, x1, y1, 0).color(LoadingImageScreen.bgColor); - consumer.vertex(matrix4f, x1, y2, 0).color(LoadingImageScreen.bgColor); - consumer.vertex(matrix4f, x2, y2, 0).color(LoadingImageScreen.accent); - consumer.vertex(matrix4f, x2, y1, 0).color(LoadingImageScreen.accent); + consumer.vertex(matrix4f, x1, y1, 0).color(LoadingImageScreen.bgColor).next(); + consumer.vertex(matrix4f, x1, y2, 0).color(LoadingImageScreen.bgColor).next(); + consumer.vertex(matrix4f, x2, y2, 0).color(LoadingImageScreen.accent).next(); + consumer.vertex(matrix4f, x2, y1, 0).color(LoadingImageScreen.accent).next(); } private double easeInOutCubic(double x) { diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java b/1.20/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java index 2d094a77f..19f315047 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java @@ -27,10 +27,12 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; import io.github.axolotlclient.modules.AbstractModule; +import lombok.Getter; import net.minecraft.client.gui.screen.Screen; public class ScrollableTooltips extends AbstractModule { + @Getter private static final ScrollableTooltips Instance = new ScrollableTooltips(); public final BooleanOption enabled = new BooleanOption("enabled", false); public final BooleanOption enableShiftHorizontalScroll = new BooleanOption("shiftHorizontalScroll", true); @@ -40,10 +42,6 @@ public class ScrollableTooltips extends AbstractModule { public int tooltipOffsetX; public int tooltipOffsetY; - public static ScrollableTooltips getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java b/1.20/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java index 95947b29b..f9594e511 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java @@ -36,7 +36,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: GPL-3.0

**/ public class FSBSkyboxInstance extends SkyboxInstance { diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java b/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java index 21b78fc7c..6a7ab2971 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java @@ -33,10 +33,12 @@ import io.github.axolotlclient.AxolotlClient; import io.github.axolotlclient.modules.AbstractCommonModule; import lombok.Getter; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; import net.minecraft.client.MinecraftClient; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; @@ -44,7 +46,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ public class SkyResourceManager extends AbstractCommonModule implements SimpleSynchronousResourceReloadListener { @@ -54,6 +56,11 @@ public class SkyResourceManager extends AbstractCommonModule implements SimpleSy @Getter private final static SkyResourceManager Instance = new SkyResourceManager(); + @Override + public void init() { + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(this); + } + private static JsonObject loadMCPSky(String loader, Identifier id, Resource resource) { JsonObject object = new JsonObject(); String line; diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java b/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java index 6afc513e4..0f1c60205 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java @@ -46,7 +46,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ // TODO fix rotation & blending issues with shooting stars, implement more missing features like worlds, weather, biomes... @@ -180,6 +180,7 @@ protected int parseBlend(String str) { } public void render(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, Runnable runnable) { + //noinspection DataFlowIssue float brightness = MinecraftClient.getInstance().world.getRainGradient(tickDelta); matrices.push(); RenderSystem.setShader(GameRenderer::getPositionTexShader); @@ -248,6 +249,7 @@ protected void setupRotate(MatrixStack matrices, float delta, float brightness) matrices.multiply(Axis.Y_POSITIVE.rotationDegrees(rotationAxis[1])); matrices.multiply(Axis.Z_POSITIVE.rotationDegrees(rotationAxis[2])); matrices.multiply(Axis.Y_POSITIVE.rotationDegrees(-90.0F)); + //noinspection DataFlowIssue matrices.multiply(Axis.X_NEGATIVE.rotationDegrees( MinecraftClient.getInstance().world.getSkyAngle(delta) * 360F * rotationSpeed)); matrices.multiply(Axis.Z_NEGATIVE.rotationDegrees(rotationAxis[0])); @@ -277,6 +279,7 @@ protected void renderDecorations(MatrixStack matrices, Matrix4f projectionMatrix GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); matrices.push(); + //noinspection DataFlowIssue float i = 1.0F - MinecraftClient.getInstance().world.getRainGradient(delta); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, i); matrices.multiply(Axis.Y_POSITIVE.rotationDegrees(-90.0F)); @@ -319,7 +322,9 @@ protected void renderDecorations(MatrixStack matrices, Matrix4f projectionMatrix if (u > 0.0F) { RenderSystem.setShaderColor(u, u, u, u); BackgroundRenderer.clearFog(); + //noinspection resource worldRendererAccessor.axolotlclient$getStarsBuffer().bind(); + //noinspection resource worldRendererAccessor.axolotlclient$getStarsBuffer().draw(matrices.peek().getModel(), projectionMatrix, GameRenderer.getPositionShader()); VertexBuffer.unbind(); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java b/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java index 23f4643d2..84b0a7bfa 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java @@ -33,7 +33,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ public class SkyboxManager { @@ -55,10 +55,9 @@ public void addSkybox(SkyboxInstance skybox) { public void renderSkyboxes(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, Runnable runnable) { this.skyboxes.stream().filter(this.renderPredicate).forEach(this.active_skies::add); + //noinspection ComparatorMethodParameterNotUsed this.active_skies.sort((skybox1, skybox2) -> skybox1.alpha >= skybox2.alpha ? 0 : 1); - this.active_skies.forEach(skyboxInstance -> { - skyboxInstance.render(matrices, projectionMatrix, tickDelta, runnable); - }); + this.active_skies.forEach(skyboxInstance -> skyboxInstance.render(matrices, projectionMatrix, tickDelta, runnable)); this.active_skies.removeIf((skybox) -> skybox.getAlpha() <= MINIMUM_ALPHA); } diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java b/1.20/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java index 805a5ab99..9301cd01d 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java @@ -29,12 +29,14 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.options.ForceableBooleanOption; +import lombok.Getter; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; public class TntTime extends AbstractModule { + @Getter private static final TntTime Instance = new TntTime(); public final ForceableBooleanOption enabled = new ForceableBooleanOption("enabled", false); private final OptionCategory category = OptionCategory.create("tnttime"); @@ -42,10 +44,6 @@ public class TntTime extends AbstractModule { private DecimalFormat format; private int decimals; - public static TntTime getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled, decimalPlaces); diff --git a/1.20/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java b/1.20/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java index 769fdb605..832c03cc2 100644 --- a/1.20/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java +++ b/1.20/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java @@ -30,6 +30,7 @@ import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.Util; import io.github.axolotlclient.util.keybinds.KeyBinds; +import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.option.KeyBind; @@ -46,6 +47,7 @@ public class Zoom extends AbstractModule { public static final BooleanOption zoomScrolling = new BooleanOption("zoomScrolling", false); public static final BooleanOption decreaseSensitivity = new BooleanOption("decreaseSensitivity", true); public static final BooleanOption smoothCamera = new BooleanOption("smoothCamera", false); + @Getter private static final Zoom Instance = new Zoom(); public static boolean active; private static Double originalSensitivity; @@ -57,10 +59,6 @@ public class Zoom extends AbstractModule { private static double lastReturnedFov; public final OptionCategory zoom = OptionCategory.create("zoom"); - public static Zoom getInstance() { - return Instance; - } - public static double getFov(double current, float tickDelta) { double result = current * (zoomSpeed.get() == 10 ? targetFactor : Util.lerp(lastAnimatedFactor, animatedFactor, tickDelta)); @@ -165,6 +163,6 @@ public void init() { public void tick() { lastAnimatedFactor = animatedFactor; - animatedFactor += (targetFactor - animatedFactor) * (zoomSpeed.get() / 10F); + animatedFactor += (float) ((targetFactor - animatedFactor) * (zoomSpeed.get() / 10F)); } } diff --git a/1.20/src/main/java/io/github/axolotlclient/util/LoggerImpl.java b/1.20/src/main/java/io/github/axolotlclient/util/LoggerImpl.java index b9f07252d..8e5d9bc12 100644 --- a/1.20/src/main/java/io/github/axolotlclient/util/LoggerImpl.java +++ b/1.20/src/main/java/io/github/axolotlclient/util/LoggerImpl.java @@ -33,19 +33,23 @@ public class LoggerImpl implements Logger { private static final String prefix = FabricLoader.getInstance().isDevelopmentEnvironment() ? "" : "(AxolotlClient) "; public void info(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + msg, args); } public void warn(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.warn(prefix + msg, args); } public void error(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.error(prefix + msg, args); } public void debug(String msg, Object... args) { if (AxolotlClient.config().debugLogOutput.get()) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + "[DEBUG] " + msg, args); } } diff --git a/1.20/src/main/java/io/github/axolotlclient/util/events/Events.java b/1.20/src/main/java/io/github/axolotlclient/util/events/Events.java index 8178444be..8ff71720c 100644 --- a/1.20/src/main/java/io/github/axolotlclient/util/events/Events.java +++ b/1.20/src/main/java/io/github/axolotlclient/util/events/Events.java @@ -24,7 +24,8 @@ import java.util.Arrays; -import io.github.axolotlclient.util.events.impl.*; +import io.github.axolotlclient.util.events.impl.KeyBindChangeEvent; +import io.github.axolotlclient.util.events.impl.MouseInputEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.MinecraftClient; @@ -33,7 +34,6 @@ public class Events { public static final Event> MOUSE_INPUT = createEvent(); public static final Event> KEYBIND_CHANGE = createEvent(); - public static final Event> PLAYER_DIRECTION_CHANGE = createEvent(); public static final Event> GAME_LOAD_EVENT = createEvent(); private static Event> createEvent() { diff --git a/1.20/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java b/1.20/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java index 2fdae0ff4..1a181ed67 100644 --- a/1.20/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java +++ b/1.20/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java @@ -61,7 +61,7 @@ public void init() { int buttonX = gridX + maxGridWidth + 10; int buttonY = gridY + 60; - var back = (ButtonWidget) children().get(children().size()-1); + var back = (ButtonWidget) children().get(children().size() - 1); remove(back); addDrawableChild(ButtonWidget.builder(Text.translatable("graphics.copy_text"), btn -> client.keyboard.setClipboard(Base64.getEncoder().encodeToString(graphics.getPixelData()))) diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/EntityRendererMixin.java b/1.21.7/src/main/java/io/github/axolotlclient/mixin/EntityRendererMixin.java deleted file mode 100644 index 31b8dae37..000000000 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/EntityRendererMixin.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.mixin; - -import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.blaze3d.vertex.PoseStack; -import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.api.requests.UserRequest; -import io.github.axolotlclient.modules.hypixel.LevelHead; -import io.github.axolotlclient.modules.hypixel.NickHider; -import io.github.axolotlclient.modules.hypixel.bedwars.BedwarsMod; -import io.github.axolotlclient.util.ClientColors; -import io.github.axolotlclient.util.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.renderer.*; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.client.renderer.entity.state.EntityRenderState; -import net.minecraft.client.renderer.entity.state.PlayerRenderState; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.scores.PlayerTeam; -import org.joml.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(EntityRenderer.class) -public abstract class EntityRendererMixin { - - @Unique - private static final RenderType TEXTURED_TYPE = RenderType.create("textured_quads", 1536, RenderPipelines.GUI_TEXTURED, - RenderType.CompositeState.builder().setTextureState(new RenderStateShard.TextureStateShard(AxolotlClient.badgeIcon, false)).createCompositeState(false)); - - @Inject(method = "renderNameTag", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V", ordinal = 0)) - public void axolotlclient$addBadges(S entityRenderState, Component text, PoseStack matrices, MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - if (entityRenderState instanceof PlayerRenderState state && text.equals(entityRenderState.nameTag)) { - if (!state.isDiscrete) { - if (AxolotlClient.config().showBadges.get()) { - Player entity = (Player) Minecraft.getInstance().level.getEntity(state.id); - if (entity != null && UserRequest.getOnline(entity.getStringUUID())) { - assert Minecraft.getInstance().player != null; - int x = getNameOffset(entity); - - if (AxolotlClient.config().customBadge.get()) { - Component badgeText = Util.formatFromCodes(AxolotlClient.config().badgeText.get()); - Minecraft.getInstance().font.drawInBatch(badgeText, x + 6, 0, -1, AxolotlClient.config().useShadows.get(), matrices.last().pose(), vertexConsumers, Font.DisplayMode.NORMAL, 0, 15728880); - } else { - - var builder = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(TEXTURED_TYPE); - Matrix4f matrix4f = matrices.last().pose(); - builder.addVertex(matrix4f, x, 0, 0).setUv(0, 0).setColor(-1); - builder.addVertex(matrix4f, x, 8, 0).setUv(0, 1).setColor(-1); - builder.addVertex(matrix4f, x + 8, 8, 0).setUv(1, 1).setColor(-1); - builder.addVertex(matrix4f, x + 8, 0, 0).setUv(1, 0).setColor(-1); - Minecraft.getInstance().renderBuffers().bufferSource().endBatch(); - } - } - } - } - } - } - - @Unique - private int getNameOffset(Player entity) { - int x; - int playerNameWidth = Minecraft.getInstance().font.width(PlayerTeam.formatNameForTeam(entity.getTeam(), entity.getName()).getString()) / 2; - if (AxolotlClient.config().customBadge.get()) { - return -(playerNameWidth + 4 + Minecraft.getInstance().font.width(AxolotlClient.config().badgeText.get())); - } - if (entity == Minecraft.getInstance().player) { - if (NickHider.getInstance().hideOwnName.get()) { - int hiddenNameSelfWidth = Minecraft.getInstance().font.width(NickHider.getInstance().hiddenNameSelf.get()) / 2; - if (AxolotlClient.config().customBadge.get()) { - x = -(hiddenNameSelfWidth + 4 + Minecraft.getInstance().font.width(AxolotlClient.config().badgeText.get())); - } else { - x = -(hiddenNameSelfWidth + 10); - } - return x; - } - } else { - if (NickHider.getInstance().hideOtherNames.get()) { - int hiddenNameOtherWidth = Minecraft.getInstance().font.width(NickHider.getInstance().hiddenNameOthers.get()) / 2; - if (AxolotlClient.config().customBadge.get()) { - x = -(hiddenNameOtherWidth + 4 + Minecraft.getInstance().font.width(AxolotlClient.config().badgeText.get())); - } else { - x = -(hiddenNameOtherWidth + 10); - } - return x; - } - } - return -playerNameWidth - 10; - } - - @ModifyArg(method = "renderNameTag", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V"), index = 8) - public int axolotlclient$bgColor(int color) { - if (AxolotlClient.config().nametagBackground.get()) { - return color; - } else { - return 0; - } - } - - @ModifyArg(method = "renderNameTag", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V", ordinal = 1), index = 4) - public boolean axolotlclient$enableShadows(boolean shadow) { - return AxolotlClient.config().useShadows.get(); - } - - @Inject(method = "renderNameTag", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V", ordinal = 1)) - public void axolotlclient$addLevel(S entityRenderState, Component c, PoseStack matrices, MultiBufferSource vertexConsumers, int light, CallbackInfo ci, @Local(ordinal = 2) int bgColor) { - if (entityRenderState instanceof PlayerRenderState state && c.equals(entityRenderState.nameTag)) { - if (Minecraft.getInstance().getCurrentServer() != null && Minecraft.getInstance().getCurrentServer().ip.contains("hypixel.net")) { - AbstractClientPlayer entity = (AbstractClientPlayer) Minecraft.getInstance().level.getEntity(state.id); - if (entity != null) { - Font textRenderer = Minecraft.getInstance().font; - if (BedwarsMod.getInstance().isEnabled() && BedwarsMod.getInstance().inGame() && BedwarsMod.getInstance().bedwarsLevelHead.get()) { - String text = BedwarsMod.getInstance().getGame().get().getLevelHead(entity); - if (text != null) { - float x = -textRenderer.width(text) / 2F; - float y = c.getString().contains("deadmau5") ? -20 : -10; - - if (LevelHead.getInstance().background.get()) { - y -= 2; - } - - Matrix4f matrix4f = matrices.last().pose(); - textRenderer.drawInBatch(text, x, y, ClientColors.ARGB.color(0x20, LevelHead.getInstance().textColor.get().toInt()), false, matrix4f, vertexConsumers, Font.DisplayMode.SEE_THROUGH, LevelHead.getInstance().background.get() ? bgColor : 0, light); - textRenderer.drawInBatch(text, x, y, LevelHead.getInstance().textColor.get().toInt(), AxolotlClient.config().useShadows.get(), matrix4f, vertexConsumers, Font.DisplayMode.NORMAL, 0, LightTexture.lightCoordsWithEmission(light, 2)); - } - } else if (LevelHead.getInstance().enabled.get()) { - String text = LevelHead.getInstance().getDisplayString(entity.getStringUUID()); - - float x = -textRenderer.width(text) / 2F; - float y = c.getString().contains("deadmau5") ? -20 : -10; - - if (LevelHead.getInstance().background.get()) { - y -= 2; - } - - Matrix4f matrix4f = matrices.last().pose(); - textRenderer.drawInBatch(text, x, y, ClientColors.ARGB.color(0x20, LevelHead.getInstance().textColor.get().toInt()), false, matrix4f, vertexConsumers, Font.DisplayMode.SEE_THROUGH, LevelHead.getInstance().background.get() ? bgColor : 0, light); - textRenderer.drawInBatch(text, x, y, LevelHead.getInstance().textColor.get().toInt(), AxolotlClient.config().useShadows.get(), matrix4f, vertexConsumers, Font.DisplayMode.NORMAL, 0, LightTexture.lightCoordsWithEmission(light, 2)); - } - } - } - } - } -} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ParticleManagerMixin.java b/1.21.7/src/main/java/io/github/axolotlclient/mixin/ParticleManagerMixin.java deleted file mode 100644 index 86766f4d2..000000000 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ParticleManagerMixin.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.mixin; - -import java.util.List; -import java.util.Queue; - -import com.llamalad7.mixinextras.sugar.Local; -import io.github.axolotlclient.modules.particles.Particles; -import net.minecraft.client.Camera; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.particle.ParticleEngine; -import net.minecraft.client.particle.ParticleRenderType; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.core.particles.ParticleType; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(ParticleEngine.class) -public abstract class ParticleManagerMixin { - - @Unique - private ParticleType cachedType; - - @Inject( - method = "makeParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)Lnet/minecraft/client/particle/Particle;", - at = @At(value = "HEAD"), cancellable = true) - private void axolotlclient$afterCreation(ParticleOptions parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ, CallbackInfoReturnable cir) { - cachedType = parameters.getType(); - - if (!Particles.getInstance().getShowParticle(cachedType)) { - cir.setReturnValue(null); - cir.cancel(); - } - } - - @Inject(method = "add(Lnet/minecraft/client/particle/Particle;)V", at = @At(value = "HEAD")) - private void axolotlclient$afterCreation(Particle particle, CallbackInfo ci) { - if (cachedType != null) { - Particles.getInstance().particleMap.put(particle, cachedType); - cachedType = null; - } - } - - @Inject(method = "tickParticleList", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/particle/ParticleEngine;tickParticle(Lnet/minecraft/client/particle/Particle;)V")) - private void axolotlclient$removeParticlesWhenRemoved(CallbackInfo ci, @Local Particle particle) { - if (!particle.isAlive()) { - Particles.getInstance().particleMap.remove(particle); - } - } - - @Inject(method = "tick", at = @At(value = "INVOKE", target = "Ljava/util/Queue;removeAll(Ljava/util/Collection;)Z")) - private void axolotlclient$removeEmitterParticlesWhenRemoved(CallbackInfo ci, @Local List collection) { - collection.forEach(particle -> Particles.getInstance().particleMap.remove(particle)); - } - - @Inject(method = "renderParticleType", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/particle/Particle;render(Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/client/Camera;F)V")) - private static void axolotlclient$applyOptions(Camera camera, float f, MultiBufferSource.BufferSource bufferSource, ParticleRenderType particleRenderType, Queue queue, CallbackInfo ci, @Local Particle particle) { - if (Particles.getInstance().particleMap.containsKey(particle)) { - Particles.getInstance().applyOptions(particle); - } - } -} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerEntityRendererMixin.java b/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerEntityRendererMixin.java deleted file mode 100644 index 7af04e430..000000000 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerEntityRendererMixin.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.mixin; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.blaze3d.vertex.PoseStack; -import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.modules.hypixel.NickHider; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.entity.player.PlayerRenderer; -import net.minecraft.client.renderer.entity.state.EntityRenderState; -import net.minecraft.client.renderer.entity.state.PlayerRenderState; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; - -@Mixin(PlayerRenderer.class) -public abstract class PlayerEntityRendererMixin { - - @WrapOperation(method = "renderNameTag(Lnet/minecraft/client/renderer/entity/state/PlayerRenderState;Lnet/minecraft/network/chat/Component;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/LivingEntityRenderer;renderNameTag(Lnet/minecraft/client/renderer/entity/state/EntityRenderState;Lnet/minecraft/network/chat/Component;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V")) - private void axolotlclient$modifiyName(PlayerRenderer instance, EntityRenderState entityRenderState, Component component, PoseStack poseStack, MultiBufferSource source, int i, Operation original, @Local(argsOnly = true) PlayerRenderState state) { - if (AxolotlClient.config() != null) { - Level level = Minecraft.getInstance().level; - Entity player = level.getEntity(state.id); - boolean self = player.getUUID() == Minecraft.getInstance().player.getUUID(); - if (self && NickHider.getInstance().hideOwnName.get()) { - component = (Component) NickHider.getInstance().editComponent(component, player.getName().getString(), NickHider.getInstance().hiddenNameSelf.get()); - } else if (!self && NickHider.getInstance().hideOtherNames.get()) { - component = (Component) NickHider.getInstance().editComponent(component, player.getName().getString(), NickHider.getInstance().hiddenNameOthers.get()); - } - } - original.call(instance, entityRenderState, component, poseStack, source, i); - } -} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java b/1.21.7/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java deleted file mode 100644 index ba20bca81..000000000 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright © 2025 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.mixin.api; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import io.github.axolotlclient.api.API; -import io.github.axolotlclient.api.multiplayer.FriendsMultiplayerScreen; -import io.github.axolotlclient.api.requests.FriendRequest; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; -import net.minecraft.client.gui.screens.multiplayer.ServerSelectionList; -import net.minecraft.network.chat.Component; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.ModifyArgs; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; - -@Mixin(JoinMultiplayerScreen.class) -public class JoinMulitplayerScreenMixin extends Screen { - - @Shadow - @Final - private Screen lastScreen; - @Unique - private static final boolean WORLD_HOST_INSTALLED = FabricLoader.getInstance().isModLoaded("world-host"); - - protected JoinMulitplayerScreenMixin(Component title) { - super(title); - } - - @Inject(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen;addRenderableWidget(Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;", ordinal = 1)) - private void addFriendsMultiplayerScreenButtons(CallbackInfo ci) { - if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - addRenderableWidget(Button.builder(Component.translatable("api.servers"), button -> { - - }).pos(this.width / 2 - 102, 32).width(100).build()).active = false; - Button friendsCountButton = addRenderableWidget(Button.builder(Component.translatable("api.servers.friends", "..."), button -> { - minecraft.setScreen(new FriendsMultiplayerScreen(this.lastScreen)); - }).bounds(width/2+2, 32, 100, 20).build()); - FriendRequest.getInstance().getOnlineFriendCount().thenAccept(count -> friendsCountButton.setMessage(Component.translatable("api.servers.friends", count))); - } - } - - @WrapOperation(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList;setRectangle(IIII)V")) - private void increaseHeaderSize(ServerSelectionList instance, int width, int height, int x, int y, Operation original) { - if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - height += 32 - 60; - y += -32 + 60; - } - original.call(instance, width, height, x, y); - } - - @ModifyArgs(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList;(Lnet/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen;Lnet/minecraft/client/Minecraft;IIII)V")) - private void increaseHeaderSize$2(Args args) { - if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - args.set(3, ((Integer)args.get(3)) + 32 - 60); - args.set(4, ((Integer)args.get(4)) - 32 + 60); - } - } - - @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawCenteredString(Lnet/minecraft/client/gui/Font;Lnet/minecraft/network/chat/Component;III)V"), index = 3) - private int shiftTitle(int par3) { - if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - return 15; - } - return par3; - } -} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java b/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java deleted file mode 100644 index b3d14b2de..000000000 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.modules.hud.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import lombok.experimental.UtilityClass; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.world.item.ItemStack; - -/** - * This implementation of Hud modules is based on KronHUD. - * Github Link. - * - * @license GPL-3.0 - */ - -@UtilityClass -public class ItemUtil { - - public static ArrayList removeOld(List list, int time) { - ArrayList stored = new ArrayList<>(); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.getPassedTime() <= time) { - stored.add(storage); - } - } - return stored; - } - - public static List untimedToTimed(List list) { - ArrayList timed = new ArrayList<>(); - for (ItemStorage stack : list) { - timed.add(stack.timed()); - } - return timed; - } - - public static Optional getTimedItemFromItem(ItemStack item, List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.stack.is(compare.getItem())) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - public static int getTotal(Minecraft client, ItemStack stack) { - List item = ItemUtil.getItems(client); - if (item == null || item.isEmpty()) { - return 0; - } - List items = ItemUtil.storageFromItem(item); - Optional stor = ItemUtil.getItemFromItem(stack, items); - return stor.map(itemStorage -> itemStorage.times).orElse(0); - } - - public static List getItems(Minecraft client) { - ArrayList items = new ArrayList<>(); - if (client.player == null) { - return null; - } - client.player.getInventory().iterator().forEachRemaining(items::add); - return items; - } - - public static List storageFromItem(List items) { - ArrayList storage = new ArrayList<>(); - for (ItemStack item : items) { - if (item.isEmpty()) { - continue; - } - Optional s = getItemFromItem(item, storage); - if (s.isPresent()) { - ItemUtil.ItemStorage store = s.get(); - store.incrementTimes(item.getCount()); - } else { - storage.add(new ItemUtil.ItemStorage(item, item.getCount())); - } - } - return storage; - } - - public static Optional getItemFromItem(ItemStack item, List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.ItemStorage storage : list) { - if (storage.stack.is(compare.getItem())) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - /** - * Compares two ItemStorage Lists. - * If list1.get(1) is 10, and list2 is 5, it will return 5. - * Will return nothing if negative... - * - * @param list1 one to be based off of - * @param list2 one to compare to - * @return the compared list - */ - public static List compare(List list1, List list2) { - ArrayList list = new ArrayList<>(); - for (ItemStorage current : list1) { - Optional optional = getItemFromItem(current.stack, list2); - if (optional.isPresent()) { - ItemStorage other = optional.get(); - if (current.times - other.times <= 0) { - continue; - } - list.add(new ItemStorage(other.stack.copy(), current.times - other.times)); - } else { - list.add(current.copy()); - } - } - return list; - } - - public static class ItemStorage { - - public final ItemStack stack; - public int times; - - public ItemStorage(ItemStack stack, int times) { - ItemStack copy = stack.copy(); - copy.setCount(1); - this.stack = copy; - this.times = times; - } - - public void incrementTimes(int num) { - times = times + num; - } - - public ItemStorage copy() { - return new ItemStorage(stack.copy(), times); - } - - public TimedItemStorage timed() { - return new TimedItemStorage(stack, times); - } - } - - public static class TimedItemStorage extends ItemStorage { - - public float start; - - public TimedItemStorage(ItemStack stack, int times) { - super(stack, times); - this.start = Util.getMillis(); - } - - public float getPassedTime() { - return Util.getMillis() - start; - } - - @Override - public void incrementTimes(int num) { - super.incrementTimes(num); - refresh(); - } - - public void refresh() { - start = Util.getMillis(); - } - } -} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java b/1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java deleted file mode 100644 index ff61807e0..000000000 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.util.events.impl; - -import lombok.Data; - -@Data -public class MouseInputEvent { - - private final long window; - private final int button, action, mods; -} diff --git a/1.21/build.gradle.kts b/1.21/build.gradle.kts index 271d5ac54..ef23181e0 100644 --- a/1.21/build.gradle.kts +++ b/1.21/build.gradle.kts @@ -42,7 +42,6 @@ dependencies { api("org.lwjgl:lwjgl-nanovg:3.3.3") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-linux") - runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-linux-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-windows") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-windows-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-macos") @@ -89,6 +88,7 @@ java { tasks.runClient { classpath(sourceSets.getByName("test").runtimeClasspath) + jvmArgs("-XX:+AllowEnhancedClassRedefinition", "-XX:+IgnoreUnrecognizedVMOptions") } // Configure the maven publication diff --git a/1.21/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java b/1.21/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java index 03af791b7..1e994726f 100644 --- a/1.21/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java +++ b/1.21/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java @@ -33,6 +33,7 @@ import io.github.axolotlclient.api.types.Channel; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.AlphabeticalComparator; +import lombok.Getter; import net.minecraft.client.gui.*; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; @@ -75,6 +76,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { graphics.getMatrices().translate(0, 0, 1000); graphics.fill(sidebarAnimX, 0, sidebarWidth + sidebarAnimX, height, 0x99000000); + //noinspection DataFlowIssue graphics.drawShadowedText(client.textRenderer, Text.translatable("api.chats"), 10 + sidebarAnimX, 10, -1); if (hasChat) { @@ -166,6 +168,7 @@ public List getButtons() { } private void close() { + //noinspection DataFlowIssue client.setScreen(parent); if (chatWidget != null) { chatWidget.remove(); @@ -203,9 +206,11 @@ private void addChat(Channel channel) { int w; if (channel.isDM()) { User chatUser = ((Channel.DM) channel).getReceiver(); + //noinspection DataFlowIssue w = Math.max(client.textRenderer.getWidth(I18n.translate(chatUser.getStatus().getTitle()) + ":" + I18n.translate(chatUser.getStatus().getDescription())), client.textRenderer.getWidth(channel.getName())); } else { + //noinspection DataFlowIssue w = client.textRenderer.getWidth(channel.getName()); } sidebarWidth = Math.min(Math.max(width * 5 / 12, w + 5), width / 2); @@ -255,6 +260,7 @@ private class ListWidget extends AbstractParentElement implements Drawable, Elem private final int height; private final int entryHeight = 25; protected boolean hovered; + @Getter private int x; private int scrollAmount; private boolean visible; @@ -314,10 +320,6 @@ public boolean isMouseOver(double mouseX, double mouseY) { return hovered = visible && mouseX >= (double) this.x && mouseY >= (double) this.y && mouseX < (double) (this.x + this.width) && mouseY < (double) (this.y + this.height); } - public int getX() { - return x; - } - public void setX(int x) { this.x = x; elements.forEach(e -> e.setX(x)); diff --git a/1.21/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java b/1.21/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java index 9927e15e6..811f61765 100644 --- a/1.21/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java @@ -51,12 +51,16 @@ public void init() { addDrawableSelectableElement(new ButtonWidget.Builder(CommonTexts.CANCEL, button -> client.setScreen(parent)) .positionAndSize(width / 2 - 155, height - 50, 150, 20).build()); - addDrawableSelectableElement(new ButtonWidget.Builder(CommonTexts.DONE, button -> { - if (!input.getText().isEmpty()) { + var done = addDrawableSelectableElement(new ButtonWidget.Builder(CommonTexts.DONE, button -> { + if (!input.getText().isBlank()) { consumer.accept(input.getText()); - client.setScreen(parent); } + client.setScreen(parent); }).positionAndSize(width / 2 + 5, height - 50, 150, 20).build()); + input.setChangedListener(s -> { + done.active = !s.isBlank(); + }); + done.active = false; } @Override diff --git a/1.21/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java b/1.21/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java index a5ebffe35..bfe6150ae 100644 --- a/1.21/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java @@ -46,7 +46,7 @@ public class ChatScreen extends Screen implements ContextMenuScreen { private TextFieldWidget input; public ChatScreen(Screen parent, Channel channel) { - super(Text.translatable("api.screen.chat")); + super(Text.literal(channel.getName())); this.channel = channel; this.parent = parent; } @@ -70,6 +70,7 @@ protected void init() { users.setUsers(channel.getAllUsers(), channel); addDrawableSelectableElement(users); + //noinspection DataFlowIssue addDrawableSelectableElement(input = new TextFieldWidget(client.textRenderer, width / 2 - 150, height - 50, 300, 20, Text.translatable("api.chat.enterMessage")) { diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java b/1.21/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java index 8b7c1b3bf..06d0f14ab 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java @@ -52,7 +52,7 @@ public Identifier getFabricId() { return Identifier.of("axolotlclient", "bridge/resource_listener"); } }); - ClientPlayConnectionEvents.INIT.register((clientPlayNetworkHandler, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); + ClientPlayConnectionEvents.JOIN.register((clientPlayNetworkHandler, sender, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); ClientPlayConnectionEvents.DISCONNECT.register((clientPlayNetworkHandler, minecraftClient) -> Events.DISCONNECT.invoker().run()); ClientCommandRegistrationCallback.EVENT.register((commandDispatcher, commandBuildContext) -> diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java index de94a10e9..81920386b 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java @@ -51,7 +51,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(MinecraftClient.class) -public abstract class MinecraftClientMixin implements AxoMinecraftClient{ +public abstract class MinecraftClientMixin implements AxoMinecraftClient { @Final @Shadow public TextRenderer textRenderer; @@ -89,9 +89,10 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient{ public abstract ResourceManager getResourceManager(); @Override - public@Nullable AxoPlayer br$getPlayer() { + public @Nullable AxoPlayer br$getPlayer() { return player; } + @Override public AxoWorld br$getWorld() { @@ -145,7 +146,7 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient{ @Override public void br$reinitScreen() { if (currentScreen != null) { - currentScreen.init((MinecraftClient) (Object)this, currentScreen.width, currentScreen.height); + currentScreen.init((MinecraftClient) (Object) this, currentScreen.width, currentScreen.height); } } @@ -153,4 +154,9 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient{ public AxoResourceManager br$getResourceManager() { return getResourceManager(); } + + @Override + public Object br$getScreen() { + return currentScreen; + } } diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java index c0fddb78d..00fd4251f 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java @@ -57,7 +57,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(value = PlatformDispatch.class, remap = false) -public class PlatformDispatchMixin { +public abstract class PlatformDispatchMixin { @Unique private static void getRealTimeServerPing(ServerInfo server, MutableInt currentServerPing) { ThreadExecuter.scheduleTask(() -> { diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java index 0ec60a178..833a962f6 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java @@ -32,7 +32,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(PlayerListEntry.class) -public class PlayerListEntryMixin implements AxoPlayerListEntry { +public abstract class PlayerListEntryMixin implements AxoPlayerListEntry { @Shadow @Final private GameProfile profile; diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java index ecaebe598..cf2ed1665 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoStatusEffects.class, remap = false) -public class AxoStatusEffectsMixin { +public abstract class AxoStatusEffectsMixin { @Mutable @Shadow @Final diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java index e57524b6a..e2efcd272 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java @@ -68,24 +68,24 @@ @SuppressWarnings("OverwriteModifiers") @Mixin(value = PlatformImplInternal.class, remap = false) -public class PlatformImplInternalMixin { - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static @Nullable AxoWindow getWindow() { - return MinecraftClient.getInstance().getWindow(); - } +public abstract class PlatformImplInternalMixin { + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static @Nullable AxoWindow getWindow() { + return MinecraftClient.getInstance().getWindow(); + } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static AxoMinecraftClient getMinecraftClientInstance() { - return MinecraftClient.getInstance(); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static AxoMinecraftClient getMinecraftClientInstance() { + return MinecraftClient.getInstance(); + } /** * @author moehreag @@ -96,71 +96,71 @@ public static AxoProfiler getProfiler() { return MinecraftClient.getInstance().getProfiler(); } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static String getTranslatedString(String nameKey, Object[] args) { - return I18n.translate(nameKey, args); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static String getTranslatedString(String nameKey, Object[] args) { + return I18n.translate(nameKey, args); + } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static AxoItemStack createItemStack(AxoItem item, int count) { - return new ItemStack((Item) item, count); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static AxoItemStack createItemStack(AxoItem item, int count) { + return new ItemStack((Item) item, count); + } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static long getMeasuringTimeMs() { - return Util.getMeasuringTimeMs(); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static long getMeasuringTimeMs() { + return Util.getMeasuringTimeMs(); + } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static AxolotlClientConfigCommon getConfig() { - return AxolotlClient.config(); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static AxolotlClientConfigCommon getConfig() { + return AxolotlClient.config(); + } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static int getCurrentFps() { - return MinecraftClientAccessor.axolotlclient$getCurrentFps(); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static int getCurrentFps() { + return MinecraftClientAccessor.axolotlclient$getCurrentFps(); + } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name, String category) { + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name) { int code = ((InputUtil.Key) Objects.requireNonNullElse(defaultKey, AxoKeys.KEY_UNKNOWN)).getKeyCode(); - final var binding = new KeyBind(name, code, category); + final var binding = new KeyBind(name, code, "category.axolotlclient"); KeyBinds.getInstance().register(binding); return binding; } - /** - * @author Flowey - * @reason Implement bridge platform. - */ - @Overwrite - public static AxoIdentifier createIdentifier(String ns, String path) { - return Identifier.of(ns, path); - } + /** + * @author Flowey + * @reason Implement bridge platform. + */ + @Overwrite + public static AxoIdentifier createIdentifier(String ns, String path) { + return Identifier.of(ns, path); + } /** * @author Flowey diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java index dcca6ed2c..77f10806a 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoEnchants.class, remap = false) -public class AxoEnchantsMixin { +public abstract class AxoEnchantsMixin { @Mutable @Shadow @Final diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java index 3e8f7fa39..be2753ed2 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoItems.class, remap = false) -public class AxoItemsMixin { +public abstract class AxoItemsMixin { @Mutable @Shadow @Final diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java index e3b053e27..fc0b3ffea 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Enchantment.class) -public class EnchantmentMixin implements AxoEnchant { +public abstract class EnchantmentMixin implements AxoEnchant { } diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java index 5e44604ed..eadcab05e 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Item.class) -public class ItemMixin implements AxoItem { +public abstract class ItemMixin implements AxoItem { @Override public boolean br$is(AxoItemClass itemClass) { return switch (itemClass) { diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java index 9daaf9c49..e376b9615 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoKeys.class, remap = false) -public class AxoKeysMixin { +public abstract class AxoKeysMixin { @Mutable @Shadow diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java index b1d447da2..782cc5c68 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(GameOptions.class) -public class GameOptionsMixin implements AxoClientKeybinds { +public abstract class GameOptionsMixin implements AxoClientKeybinds { @Shadow @Final public KeyBind sprintKey; diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java index 458cb6b4d..4cd07679f 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(InputUtil.Key.class) -public class KeyMixin implements AxoKey { +public abstract class KeyMixin implements AxoKey { } diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java index ea73abbe8..71ac7b3bf 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java @@ -36,7 +36,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoSprites.class, remap = false) -public class AxoSpritesMixin { +public abstract class AxoSpritesMixin { @Mutable @Shadow @Final diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java index ef46da1cc..b44e75eaf 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java @@ -90,7 +90,7 @@ public abstract void drawItemInSlot(TextRenderer textRenderer, ItemStack stack, // scissor @Override public void br$pushScissor(int x, int y, int w, int h) { - enableScissor(x, y, x+w, y+h); + enableScissor(x, y, x + w, y + h); } @Override @@ -133,7 +133,7 @@ public abstract void drawItemInSlot(TextRenderer textRenderer, ItemStack stack, @Override public void br$fillRect(int x, int y, int width, int height, int color) { - fill(x, y, x+width, y+height, color); + fill(x, y, x + width, y + height, color); } @Override diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java index 26e77d7a0..210e78b39 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java @@ -28,7 +28,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(Identifier.class) -public abstract class IdentifierMixin implements AxoIdentifier{ +public abstract class IdentifierMixin implements AxoIdentifier { @Shadow public abstract String getPath(); diff --git a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableTextMixin.java b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableTextMixin.java index ff8243c88..c765328de 100644 --- a/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableTextMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableTextMixin.java @@ -34,7 +34,7 @@ public abstract class MutableTextMixin implements Text, AxoText.Mutable { public abstract MutableText append(Text text); @Override - public Mutable br$append(AxoText child) { + public Mutable br$append(AxoText child) { return append((Text) child); } diff --git a/1.21/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java b/1.21/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java index 99f6d6703..ca8e6539f 100644 --- a/1.21/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java +++ b/1.21/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java @@ -34,6 +34,7 @@ import io.github.axolotlclient.AxolotlClientConfig.api.ui.ConfigUI; import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import io.github.axolotlclient.AxolotlClientConfig.impl.options.*; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.RecreatableScreen; import io.github.axolotlclient.AxolotlClientConfigCommon; import io.github.axolotlclient.config.screen.CreditsScreen; import io.github.axolotlclient.config.screen.ProfilesScreen; @@ -43,6 +44,7 @@ import io.github.axolotlclient.util.options.GenericOption; import lombok.Getter; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.option.KeyBind; import net.minecraft.client.texture.NativeImageBackedTexture; @@ -66,28 +68,26 @@ public class AxolotlClientConfig extends AxolotlClientConfigCommon { public final BooleanOption lowShield = new BooleanOption("lowShield", false); public final ColorOption hitColor = new ColorOption("hitColor", new Color(255, 0, 0, 77), value -> { - try { // needed because apparently someone created a bug that makes this be called when the config is loaded. Will be fixed with the next release. - NativeImageBackedTexture texture = ((OverlayTextureAccessor) MinecraftClient.getInstance().gameRenderer.getOverlayTexture()).axolotlclient$getTexture(); - NativeImage nativeImage = texture.getImage(); - if (nativeImage != null) { - int color = 255 - value.getAlpha(); - color = (color << 8) + value.getBlue(); - color = (color << 8) + value.getGreen(); - color = (color << 8) + value.getRed(); - - for (int i = 0; i < 8; ++i) { - for (int j = 0; j < 8; ++j) { - nativeImage.setPixelColor(j, i, color); - } + //noinspection resource + NativeImageBackedTexture texture = ((OverlayTextureAccessor) MinecraftClient.getInstance().gameRenderer.getOverlayTexture()).axolotlclient$getTexture(); + NativeImage nativeImage = texture.getImage(); + if (nativeImage != null) { + int color = 255 - value.getAlpha(); + color = (color << 8) + value.getBlue(); + color = (color << 8) + value.getGreen(); + color = (color << 8) + value.getRed(); + + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + nativeImage.setPixelColor(j, i, color); } - - RenderSystem.activeTexture(33985); - texture.bindTexture(); - nativeImage.upload(0, 0, 0, 0, 0, - nativeImage.getWidth(), nativeImage.getHeight(), false, true, false, false); - RenderSystem.activeTexture(33984); } - } catch (Exception ignored) { + + RenderSystem.activeTexture(33985); + texture.bindTexture(); + nativeImage.upload(0, 0, 0, 0, 0, + nativeImage.getWidth(), nativeImage.getHeight(), false, true, false, false); + RenderSystem.activeTexture(33984); } }); public final BooleanOption minimalViewBob = new BooleanOption("minimalViewBob", false); @@ -153,7 +153,9 @@ public AxolotlClientConfig() { general.add(configStyle = new StringArrayOption("configStyle", themes, "configStyle." + ConfigUI.getInstance().getCurrentStyle().getName(), s -> { ConfigUI.getInstance().setStyle(s.split("\\.")[1]); - MinecraftClient.getInstance().setScreen(null); + + Screen newScreen = RecreatableScreen.tryRecreate(MinecraftClient.getInstance().currentScreen); + MinecraftClient.getInstance().setScreen(newScreen); })); AxolotlClient.getInstance().getConfigManager().load(); ConfigUI.getInstance().setStyle(configStyle.get().split("\\.")[1]); diff --git a/1.21/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java b/1.21/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java index e1793476b..10e50f738 100644 --- a/1.21/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java @@ -250,6 +250,7 @@ public void tick() { private class SpacerTitle extends Entry { private final String name; + public SpacerTitle(String name) { this.name = name; } diff --git a/1.21/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java b/1.21/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java index 7606b0984..3c313c1c9 100644 --- a/1.21/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java @@ -78,6 +78,7 @@ protected void repositionElements() { @Override public void closeScreen() { Profiles.getInstance().saveProfiles(); + //noinspection DataFlowIssue client.setScreen(parent); } @@ -134,14 +135,13 @@ public List children() { @Environment(EnvType.CLIENT) public class ProfileEntry extends Entry { + private static final Text EXPORT_BUTTON_TITLE = Text.translatable("profiles.profile.export"); private static final Text CURRENT_TEXT = Text.translatable("profiles.profile.current"); private static final Text LOAD_BUTTON_TITLE = Text.translatable("profiles.profile.load"); private static final Text DUPLICATE_BUTTON_TITLE = Text.translatable("profiles.profile.duplicate"); private static final Text REMOVE_BUTTON_TITLE = Text.translatable("profiles.profile.remove"); private final TextFieldWidget profileName; - private final ButtonWidget loadButton; - private final ButtonWidget duplicateButton; - private final ButtonWidget removeButton; + private final ButtonWidget exportButton, loadButton, duplicateButton, removeButton; private final Profiles.Profile profile; ProfileEntry(Profiles.Profile profile) { @@ -149,6 +149,8 @@ public class ProfileEntry extends Entry { profileName = new TextFieldWidget(textRenderer, 0, 0, 150, 20, Text.empty()); profileName.setText(profile.name()); profileName.setChangedListener(profile::setName); + exportButton = ButtonWidget.builder(EXPORT_BUTTON_TITLE, btn -> Profiles.getInstance().exportProfile(profile)) + .positionAndSize(0, 0, 50, 20).build(); loadButton = ButtonWidget.builder(LOAD_BUTTON_TITLE, btn -> Profiles.getInstance().switchTo(profile)).positionAndSize(0, 0, 50, 20).build(); duplicateButton = ButtonWidget.builder(DUPLICATE_BUTTON_TITLE, b -> { @@ -179,10 +181,13 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi boolean current = Profiles.getInstance().getCurrent() == profile; loadButton.setMessage(current ? CURRENT_TEXT : LOAD_BUTTON_TITLE); - loadButton.active = !current; + loadButton.active = removeButton.active = !current; i -= loadButton.getWidth(); this.loadButton.setPosition(i, j); this.loadButton.render(guiGraphics, mouseX, mouseY, partialTick); + i -= exportButton.getWidth(); + exportButton.setPosition(i, j); + exportButton.render(guiGraphics, mouseX, mouseY, partialTick); profileName.setWidth(i - left - 4); profileName.setPosition(left, j); profileName.render(guiGraphics, mouseX, mouseY, partialTick); @@ -190,18 +195,18 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi @Override public List children() { - return List.of(profileName, this.loadButton, duplicateButton, removeButton); + return List.of(profileName, exportButton, this.loadButton, duplicateButton, removeButton); } @Override public List selectableChildren() { - return List.of(profileName, this.loadButton, duplicateButton, removeButton); + return List.of(profileName, exportButton, this.loadButton, duplicateButton, removeButton); } } public class NewEntry extends Entry { - private final ButtonWidget addButton; + private final ButtonWidget addButton, importButton; public NewEntry() { this.addButton = ButtonWidget.builder(Text.translatable("profiles.profile.add"), button -> { @@ -211,6 +216,8 @@ public NewEntry() { setScrollAmount(getMaxScroll()); }).positionAndSize(0, 0, 150, 20) .build(); + this.importButton = ButtonWidget.builder(Text.translatable("profiles.profile.import"), btn -> + Profiles.getInstance().importProfiles().thenRun(ProfilesList.this::reload)).build(); } @Override @@ -220,15 +227,17 @@ public List selectableChildren() { @Override public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() / 2; + int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() + 2; int j = top - 2; this.addButton.setPosition(i, j); this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); + this.importButton.setPosition(addButton.getXEnd() + 2, j); + this.importButton.render(guiGraphics, mouseX, mouseY, partialTick); } @Override public List children() { - return List.of(addButton); + return List.of(addButton, importButton); } } } diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java index a77f1ed75..08fc4bfb1 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java @@ -22,10 +22,10 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.modules.freelook.Freelook; import io.github.axolotlclient.modules.hypixel.Skyblock; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import net.minecraft.entity.Entity; import net.minecraft.util.math.MathHelper; import org.spongepowered.asm.mixin.Mixin; @@ -55,7 +55,7 @@ public abstract class EntityMixin { float pitch = prevPitch + (float) (mouseDeltaY * .15); float yaw = prevYaw + (float) (mouseDeltaX * .15); pitch = MathHelper.clamp(pitch, -90.0F, 90.0F); - Events.PLAYER_DIRECTION_CHANGE.invoker().invoke(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); + Events.PLAYER_DIRECTION_CHANGE.invoker().accept(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); } @Shadow diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java index 523006347..8ca62204f 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameOptions.class) -public class GameOptionsMixin { +public abstract class GameOptionsMixin { @Mutable @Shadow diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java index e9e5deb8c..f42c4f5f3 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; @Mixin(GuiGraphics.class) -public class GuiGraphicsMixin { +public abstract class GuiGraphicsMixin { @ModifyVariable(method = "drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;IILnet/minecraft/client/gui/tooltip/TooltipPositioner;)V", at = @At("STORE"), index = 11) diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java index be4314342..8652275ed 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java @@ -22,6 +22,8 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.modules.hud.HudManager; +import io.github.axolotlclient.modules.hud.gui.hud.IconHud; import io.github.axolotlclient.modules.scrollableTooltips.ScrollableTooltips; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screen.ingame.HandledScreen; @@ -29,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -39,6 +42,7 @@ public abstract class HandledScreenMixin { @Shadow @Nullable protected Slot focusedSlot; + @Unique private Slot cachedSlot; @Inject(method = "drawMouseoverTooltip", at = @At("HEAD")) @@ -48,4 +52,12 @@ public abstract class HandledScreenMixin { ScrollableTooltips.getInstance().resetScroll(); } } + + @Inject(method = "renderBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/gui/GuiGraphics;FII)V")) + private void renderIcon(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) { + var hud = (IconHud) HudManager.getInstance().get(IconHud.ID); + if (hud != null && hud.isEnabled()) { + hud.renderInGui(guiGraphics, partialTick); + } + } } diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java index f55e7c9c7..5f9746684 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java @@ -24,6 +24,7 @@ import com.llamalad7.mixinextras.expression.Expression; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; @@ -46,17 +47,13 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.scoreboard.ScoreboardObjective; -import net.minecraft.text.StringVisitable; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArgs; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; @Mixin(InGameHud.class) public abstract class InGameHudMixin { @@ -134,91 +131,16 @@ private void onHudRender(GuiGraphics graphics, DeltaTracker tracker, CallbackInf } } - @Inject(method = "renderHotbar", at = @At("HEAD"), cancellable = true) - public void axolotlclient$customHotbar(GuiGraphics graphics, DeltaTracker tracker, CallbackInfo ci) { - if (!HudManager.getInstance().hudsEnabled()) return; - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (hud.isEnabled()) { - ci.cancel(); - } - } - - @ModifyArgs(method = "renderHeldItemTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawTextWithBackground(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIII)I")) - public void axolotlclient$setItemNamePos(Args args) { - if (!HudManager.getInstance().hudsEnabled()) return; - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (hud.isEnabled()) { - args.set(2, hud.getX() + (int) ((hud.getWidth() * hud.getScale()) - - MinecraftClient.getInstance().textRenderer.getWidth((StringVisitable) args.get(1))) / 2); - args.set(3, hud.getY() - 36 - + (!MinecraftClient.getInstance().interactionManager.hasStatusBars() ? 14 : 0)); - } - } - - @ModifyArgs(method = "renderMountJumpBar", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V")) - public void axolotlclient$moveHorseHealth(Args args) { - if (!HudManager.getInstance().hudsEnabled()) return; - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (hud.isEnabled()) { - args.set(1, hud.getX()); - args.set(2, hud.getY() - 7); - } - } - - @ModifyArgs(method = "renderExperienceBar", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawGuiTexture(Lnet/minecraft/util/Identifier;IIIIIIII)V")) - public void axolotlclient$moveXPBar(Args args) { - if (!HudManager.getInstance().hudsEnabled()) return; - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (hud.isEnabled()) { - args.set(1, hud.getX()); - args.set(2, hud.getY() - 7); - } - } - - @WrapOperation(method = "renderExperienceBar", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;getScaledWindowHeight()I")) - public int axolotlclient$moveXPBarHeight(GuiGraphics instance, Operation original) { - if (!HudManager.getInstance().hudsEnabled()) return original.call(instance); - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (hud.isEnabled()) { - return hud.getY() + 22; - } - return original.call(instance); - } - - @Redirect(method = "renderExperienceLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;getScaledWindowHeight()I")) - public int axolotlclient$moveXPLevelHeight(GuiGraphics instance) { - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud.isEnabled()) { - return hud.getY() + 22; - } - return instance.getScaledWindowHeight(); - } - - @Redirect(method = "renderExperienceLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;getScaledWindowWidth()I")) - public int axolotlclient$moveXPLevelWidth(GuiGraphics instance) { - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud.isEnabled()) { - return hud.getX() * 2 + hud.getWidth(); - } - return instance.getScaledWindowWidth(); - } - - @Redirect(method = "renderStatusBars", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;getScaledWindowHeight()I")) - public int axolotlclient$moveStatusBarsHeight(GuiGraphics instance) { - HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud.isEnabled()) { - return hud.getY() + 22; - } - return instance.getScaledWindowHeight(); - } - - @Redirect(method = "renderStatusBars", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;getScaledWindowWidth()I")) - public int axolotlclient$moveStatusBarsWidth(GuiGraphics instance) { + @WrapMethod(method = "renderHotbar") + public void axolotlclient$customHotbar(GuiGraphics graphics, DeltaTracker tracker, Operation original) { HotbarHUD hud = (HotbarHUD) HudManager.getInstance().get(HotbarHUD.ID); - if (HudManager.getInstance().hudsEnabled() && hud.isEnabled()) { - return hud.getX() * 2 + hud.getWidth(); + graphics.getMatrices().push(); + if (hud.isEnabled() && !hud.isHidden()) { + graphics.getMatrices().translate(-graphics.getScaledWindowWidth() / 2f + 182 / 2f, -graphics.getScaledWindowHeight() + 22, 0); + graphics.getMatrices().translate(hud.getX(), hud.getY(), 0); } - return instance.getScaledWindowWidth(); + original.call(graphics, tracker); + graphics.getMatrices().pop(); } @Inject( diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java index 9ac435873..219269181 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java @@ -22,16 +22,21 @@ package io.github.axolotlclient.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.util.OSUtil; import net.minecraft.client.main.Main; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(Main.class) public abstract class MinecraftClientMainMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) - private static String axolotlclient$noHeadless(String key, String value) { + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) + private static String axolotlclient$noHeadless(String key, String value, Operation original) { + if (OSUtil.getOS() != OSUtil.OperatingSystem.WINDOWS) { + return original.call(key, value); + } return ""; } } diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java index ecaa28fd4..9da262388 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java @@ -36,7 +36,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ @Mixin(WorldRenderer.class) diff --git a/1.21/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java b/1.21/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java index 0b57c9885..3172fb142 100644 --- a/1.21/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java +++ b/1.21/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java @@ -45,7 +45,7 @@ import org.spongepowered.asm.mixin.injection.invoke.arg.Args; @Mixin(SelectServerScreen.class) -public class JoinMulitplayerScreenMixin extends Screen { +public abstract class JoinMulitplayerScreenMixin extends Screen { @Shadow @Final @@ -65,7 +65,7 @@ private void addFriendsMultiplayerScreenButtons(CallbackInfo ci) { }).position(this.width / 2 - 102, 32).width(100).build()).active = false; ButtonWidget friendsCountButton = addDrawableSelectableElement(ButtonWidget.builder(Text.translatable("api.servers.friends", "..."), button -> { client.setScreen(new FriendsMultiplayerScreen(this.parent)); - }).positionAndSize(width/2+2, 32, 100, 20).build()); + }).positionAndSize(width / 2 + 2, 32, 100, 20).build()); FriendRequest.getInstance().getOnlineFriendCount().thenAccept(count -> friendsCountButton.setMessage(Text.translatable("api.servers.friends", count))); } } @@ -82,8 +82,8 @@ private void increaseHeaderSize(ServerEntryListWidget instance, int width, int h @ModifyArgs(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/list/multiplayer/ServerEntryListWidget;(Lnet/minecraft/client/gui/screen/multiplayer/SelectServerScreen;Lnet/minecraft/client/MinecraftClient;IIII)V")) private void increaseHeaderSize$2(Args args) { if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { - args.set(3, ((Integer)args.get(3)) + 32 - 60); - args.set(4, ((Integer)args.get(4)) - 32 + 60); + args.set(3, ((Integer) args.get(3)) + 32 - 60); + args.set(4, ((Integer) args.get(4)) - 32 + 60); } } diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java index 42eb856e6..14fdb334e 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java @@ -25,6 +25,7 @@ import java.util.List; import com.mojang.blaze3d.systems.RenderSystem; +import lombok.Getter; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; @@ -70,6 +71,7 @@ public static class Entry extends AlwaysSelectedEntryListWidget.Entry login()).positionAndSize(this.width / 2 - 154, this.height - 52, 150, 20).build()); + addDrawableSelectableElement(loginButton = ButtonWidget.builder(Text.translatable("auth.login"), + buttonWidget -> login()).positionAndSize(this.width / 2 - 154, this.height - 52, 100, 20).build()); + + addDrawableSelectableElement(skinsButton = ButtonWidget.builder(Text.translatable("skins.manage"), + btn -> client.setScreen(new SkinManagementScreen( + this, accountsListWidget.getSelectedOrNull().getAccount()))) + .positionAndSize(this.width / 2 - 50, this.height - 52, 100, 20).build()); this.addDrawableSelectableElement(ButtonWidget.builder(Text.translatable("auth.add"), button -> { @@ -94,7 +101,7 @@ public void init() { }, Text.translatable("auth.add.choose"), Text.empty(), Text.translatable("auth.add.offline"), Text.translatable("auth.add.ms"))); } }) - .positionAndSize(this.width / 2 + 4, this.height - 52, 150, 20).build()); + .positionAndSize(this.width / 2 + 4 + 50, this.height - 52, 100, 20).build()); this.deleteButton = this.addDrawableSelectableElement(ButtonWidget.builder(Text.translatable("selectServer.delete"), button -> { AccountsListWidget.Entry entry = this.accountsListWidget.getSelectedOrNull(); @@ -120,17 +127,14 @@ public void init() { } private void initMSAuth() { - Auth.getInstance().getAuth().startDeviceAuth().thenRun(() -> client.execute(this::refresh)); + Auth.getInstance().getMsApi().startDeviceAuth().thenRun(() -> client.execute(this::refresh)); } private void refreshAccount() { refreshButton.active = false; AccountsListWidget.Entry entry = accountsListWidget.getSelectedOrNull(); if (entry != null) { - entry.getAccount().refresh(Auth.getInstance().getAuth()).thenRun(() -> client.execute(() -> { - Auth.getInstance().save(); - refresh(); - })); + entry.getAccount().refresh(Auth.getInstance().getMsApi()); } } @@ -138,9 +142,10 @@ private void updateButtonActivationStates() { AccountsListWidget.Entry entry = accountsListWidget.getSelectedOrNull(); if (client.world == null && entry != null) { loginButton.active = entry.getAccount().isExpired() || !entry.getAccount().equals(Auth.getInstance().getCurrent()); - deleteButton.active = refreshButton.active = true; + refreshButton.active = skinsButton.active = !entry.getAccount().isOffline(); + deleteButton.active = true; } else { - loginButton.active = deleteButton.active = refreshButton.active = false; + loginButton.active = deleteButton.active = refreshButton.active = skinsButton.active = false; } } diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java index 9da89256e..528f8e8df 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java @@ -43,7 +43,6 @@ public AddOfflineScreen(Screen parent) { @Override public void render(GuiGraphics graphics, int i, int j, float f) { - renderBackground(graphics, i, j, f); super.render(graphics, i, j, f); graphics.drawShadowedText(textRenderer, Text.translatable("auth.add.offline.name"), (int) (width / 2F - 100), (int) (height / 2f - 20), -1); graphics.drawCenteredShadowedText(this.textRenderer, this.title, this.width / 2, 20, 16777215); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/Auth.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/Auth.java index 521e99c3c..7922c7dd0 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/auth/Auth.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/Auth.java @@ -23,17 +23,18 @@ package io.github.axolotlclient.modules.auth; import java.util.*; +import java.util.concurrent.CompletableFuture; import com.mojang.authlib.minecraft.UserApiService; import com.mojang.authlib.yggdrasil.ProfileResult; import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.api.API; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.UUIDHelper; import io.github.axolotlclient.mixin.MinecraftClientAccessor; import io.github.axolotlclient.modules.Module; +import io.github.axolotlclient.modules.auth.skin.SkinManager; import io.github.axolotlclient.util.ThreadExecuter; import io.github.axolotlclient.util.notifications.Notifications; import io.github.axolotlclient.util.options.GenericOption; @@ -55,15 +56,18 @@ public class Auth extends Accounts implements Module { @Getter private final static Auth Instance = new Auth(); public final BooleanOption showButton = new BooleanOption("auth.showButton", false); + public final BooleanOption skinManagerAnimations = new BooleanOption("skins.manage.animations", true); private final MinecraftClient client = MinecraftClient.getInstance(); private final GenericOption viewAccounts = new GenericOption("viewAccounts", "clickToOpen", () -> client.setScreen(new AccountsScreen(client.currentScreen))); private final Set loadingTexture = new HashSet<>(); private final Map textures = new WeakHashMap<>(); + @Getter + private final SkinManager skinManager = new SkinManager(); @Override public void init() { load(); - this.auth = new MSAuth(AxolotlClient.LOGGER, this, () -> client.options.language); + this.msApi = new MSApi(this, () -> client.options.language); if (isContained(client.getSession().getSessionId())) { current = getAccounts().stream().filter(account -> account.getUuid() .equals(UUIDHelper.toUndashed(client.getSession().getPlayerUuid()))).toList().getFirst(); @@ -76,7 +80,6 @@ public void init() { current = new Account(client.getSession().getUsername(), UUIDHelper.toUndashed(client.getSession().getPlayerUuid()), client.getSession().getAccessToken()); } - OptionCategory category = OptionCategory.create("auth"); category.add(showButton, viewAccounts); AxolotlClient.config().general.add(category); } @@ -91,11 +94,11 @@ protected void login(Account account) { if (account.isExpired()) { Notifications.getInstance().addStatus(Text.translatable("auth.notif.title"), Text.translatable("auth.notif.refreshing", account.getName())); } - account.refresh(auth).thenAccept(res -> res.ifPresent(a -> { + account.refresh(msApi).thenAccept(a -> { if (!a.isExpired()) { login(a); } - })).thenRun(this::save); + }).thenRun(this::save); } else { try { API.getInstance().shutdown(); @@ -124,14 +127,18 @@ protected void login(Account account) { } @Override - void showAccountsExpiredScreen(Account account) { + CompletableFuture showAccountsExpiredScreen(Account account) { Screen current = client.currentScreen; + var fut = new CompletableFuture(); client.execute(() -> client.setScreen(new ConfirmScreen((bl) -> { - client.setScreen(current); if (bl) { - auth.startDeviceAuth(); + msApi.startDeviceAuth().thenRun(() -> fut.complete(account)); + } else { + fut.cancel(true); } + client.setScreen(current); }, Text.translatable("auth"), Text.translatable("auth.accountExpiredNotice", account.getName())))); + return fut; } @Override diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java new file mode 100644 index 000000000..da4fa292a --- /dev/null +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java @@ -0,0 +1,50 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.LoadingTextWidget; +import net.minecraft.client.gui.widget.text.TextWidget; +import net.minecraft.text.Text; + +public class LoadingScreen extends Screen { + private final Text description; + + public LoadingScreen(Text title, Text description) { + super(title); + this.description = description; + } + + @Override + protected void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + var titleWidget = new TextWidget(width / 2 - textRenderer.getWidth(getTitle()) / 2, headerHeight / 2 - textRenderer.fontHeight / 2, textRenderer.getWidth(getTitle()), textRenderer.fontHeight, getTitle(), textRenderer); + addDrawableSelectableElement(titleWidget); + + var loadingPlaceholder = new LoadingTextWidget(textRenderer, description); + loadingPlaceholder.setDimensionsAndPosition(width, contentHeight, 0, + headerHeight); + addDrawableSelectableElement(loadingPlaceholder); + } +} diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java new file mode 100644 index 000000000..57c8ceb3e --- /dev/null +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java @@ -0,0 +1,780 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Colors; +import io.github.axolotlclient.api.SimpleTextInputScreen; +import io.github.axolotlclient.api.util.UUIDHelper; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import io.github.axolotlclient.util.ClientColors; +import io.github.axolotlclient.util.Watcher; +import io.github.axolotlclient.util.notifications.Notifications; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.ElementPath; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.navigation.GuiNavigationEvent; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.DraggingWidget; +import net.minecraft.client.gui.widget.LoadingTextWidget; +import net.minecraft.client.gui.widget.button.ButtonWidget; +import net.minecraft.client.gui.widget.button.SpriteButtonWidget; +import net.minecraft.client.gui.widget.list.ElementListWidget; +import net.minecraft.client.gui.widget.text.AbstractTextWidget; +import net.minecraft.client.gui.widget.text.TextWidget; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.text.CommonTexts; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SkinManagementScreen extends Screen { + private static final Path SKINS_DIR = FabricLoader.getInstance().getGameDir().resolve("skins"); + private static final int LIST_SKIN_WIDTH = 75; + private static final int LIST_SKIN_HEIGHT = 110; + private static final Text TEXT_EQUIPPING = Text.translatable("skins.manage.equipping"); + private final Screen parent; + private final Account account; + private MSApi.MCProfile cachedProfile; + private SkinListWidget skinList; + private SkinListWidget capesList; + private boolean capesTab; + private SkinWidget current; + private final Watcher skinDirWatcher; + private final CompletableFuture loadingFuture; + + public SkinManagementScreen(Screen parent, Account account) { + super(Text.translatable("skins.manage")); + this.parent = parent; + this.account = account; + skinDirWatcher = Watcher.createSelfTicking(SKINS_DIR, () -> { + AxolotlClientCommon.getInstance().getLogger().info("Reloading screen as local files changed!"); + loadSkinsList(); + }); + loadingFuture = (account.needsRefresh() ? account.refresh(Auth.getInstance().getMsApi()) + : CompletableFuture.completedFuture(null)) + .thenComposeAsync(unused -> Auth.getInstance().getMsApi().getProfile(account)); + } + + @Override + protected void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + + var titleWidget = new TextWidget(0, headerHeight / 2 - textRenderer.fontHeight / 2, width, textRenderer.fontHeight, getTitle(), textRenderer); + addDrawableSelectableElement(titleWidget); + + var back = ButtonWidget.builder(CommonTexts.BACK, btn -> closeScreen()) + .positionAndSize(width / 2 - 75, height - headerHeight / 2 - 10, 150, 20).build(); + + var loadingPlaceholder = new LoadingTextWidget(textRenderer, Text.translatable("skins.loading")); + loadingPlaceholder.setDimensionsAndPosition(width, contentHeight, 0, headerHeight); + addDrawableSelectableElement(loadingPlaceholder); + addDrawableSelectableElement(back); + + skinList = new SkinListWidget(client, width / 2, contentHeight - 24, headerHeight + 24, LIST_SKIN_HEIGHT + 34); + capesList = new SkinListWidget(client, width / 2, contentHeight - 24, headerHeight + 24, skinList.getEntryContentsHeight() + 24); + skinList.setX(width / 2); + capesList.setX(width / 2); + var currentHeight = Math.min((width / 2f) * 120 / 85, contentHeight); + var currentWidth = currentHeight * 85 / 120; + current = new SkinWidget((int) currentWidth, (int) currentHeight, null, account); + current.setPosition((int) (width / 4f - currentWidth / 2), (int) (height / 2f - currentHeight / 2)); + + if (!capesTab) { + capesList.visible = capesList.active = false; + } else { + skinList.visible = skinList.active = false; + } + List navBar = new ArrayList<>(); + var skinsTab = ButtonWidget.builder(Text.translatable("skins.nav.skins"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = true; + capesList.visible = capesList.active = false; + capesTab = false; + }).position(Math.max(width * 3 / 4 - 102, width / 2 + 2), headerHeight).width(Math.min(100, width / 4 - 2)).build(); + navBar.add(skinsTab); + var capesTab = ButtonWidget.builder(Text.translatable("skins.nav.capes"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = false; + capesList.visible = capesList.active = true; + this.capesTab = true; + }).position(width * 3 / 4 + 2, headerHeight).width(Math.min(100, width / 4 - 2)).build(); + navBar.add(capesTab); + var importButton = SpriteButtonWidget.builder(Text.translatable("skins.manage.import.local"), btn -> { + btn.active = false; + SkinImportUtil.openImportSkinDialog().thenAccept(this::filesDragged).thenRun(() -> btn.active = true); + }, true).sprite(Identifier.of("axolotlclient", "folder"), 7, 7).dimensions(11, 11).build(); + importButton.setTooltip(Tooltip.create(importButton.getMessage())); + var downloadButton = SpriteButtonWidget.builder(Text.translatable("skins.manage.import.online"), btn -> { + btn.active = false; + promptForSkinDownload(); + }, true).sprite(Identifier.of("axolotlclient", "download"), 7, 7).dimensions(11, 11).build(); + downloadButton.setTooltip(Tooltip.create(downloadButton.getMessage())); + if (width - (capesTab.getX() + capesTab.getWidth()) > 28) { + importButton.setX(width - importButton.getWidth() - 2); + downloadButton.setX(importButton.getX() - downloadButton.getWidth() - 2); + importButton.setY(capesTab.getY() + capesTab.getHeight() - 11); + downloadButton.setY(importButton.getY()); + } else { + importButton.setX(capesTab.getX() + capesTab.getWidth() - 11); + importButton.setY(capesTab.getY() - 13); + downloadButton.setX(importButton.getX() - 2 - 11); + downloadButton.setY(importButton.getY()); + } + skinsTab.active = this.capesTab; + capesTab.active = !this.capesTab; + Runnable addWidgets = () -> { + clearChildren(); + addDrawableSelectableElement(titleWidget); + addDrawableSelectableElement(current); + addDrawableSelectableElement(skinsTab); + addDrawableSelectableElement(capesTab); + addDrawableSelectableElement(downloadButton); + addDrawableSelectableElement(importButton); + addDrawableSelectableElement(skinList); + addDrawableSelectableElement(capesList); + addDrawableSelectableElement(back); + }; + if (cachedProfile != null) { + initDisplay(); + addWidgets.run(); + return; + } + loadingFuture.thenAcceptAsync(profile -> { + cachedProfile = profile; + initDisplay(); + addWidgets.run(); + }).exceptionally(t -> { + if (t.getCause() instanceof CancellationException) { + client.setScreen(parent); + return null; + } + AxolotlClientCommon.getInstance().getLogger().error("Failed to load skins!", t); + var error = Text.translatable("skins.error.failed_to_load"); + var errorDesc = Text.translatable("skins.error.failed_to_load_desc"); + clearChildren(); + addDrawableSelectableElement(titleWidget); + addDrawableSelectableElement(new TextWidget(width / 2 - textRenderer.getWidth(error) / 2, height / 2 - textRenderer.fontHeight - 2, textRenderer.getWidth(error), textRenderer.fontHeight, error, textRenderer)); + addDrawableSelectableElement(new TextWidget(width / 2 - textRenderer.getWidth(errorDesc) / 2, height / 2 + 1, textRenderer.getWidth(errorDesc), textRenderer.fontHeight, errorDesc, textRenderer)); + addDrawableSelectableElement(back); + return null; + }); + } + + private void promptForSkinDownload() { + client.setScreen(new SimpleTextInputScreen(this, Text.translatable("skins.manage.import.online"), Text.translatable("skins.manage.import.online.input"), s -> + UUIDHelper.ensureUuidOpt(s).thenAccept(o -> { + if (o.isPresent()) { + AxolotlClientCommon.getInstance().getLogger().info("Downloading skin of {} ({})", s, o.get()); + Auth.getInstance().getMsApi().getTextures(o.get()) + .exceptionally(th -> { + AxolotlClientCommon.getInstance().getLogger().info("Failed to download skin of {} ({})", s, o.get(), th); + return null; + }).thenAccept(t -> { + if (t == null) { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_download", s); + return; + } + try { + var bytes = t.skin().join(); + var out = ensureNonexistent(SKINS_DIR.resolve(t.skinKey())); + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, t.classicModel(), "name", t.name(), "uuid", t.id(), "download_time", Instant.now())); + Files.write(out, bytes); + client.execute(this::loadSkinsList); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.downloaded", t.name()); + AxolotlClientCommon.getInstance().getLogger().info("Downloaded skin of {} ({})", t.name(), o.get()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to write skin file", e); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_save", t.name()); + } + }); + } else { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.not_found", s); + } + }))); + } + + private void initDisplay() { + loadSkinsList(); + loadCapesList(); + } + + private void refreshCurrentList() { + if (capesTab) { + var scroll = capesList.getScrollAmount(); + loadCapesList(); + capesList.setScrollAmount(scroll); + } else { + var scroll = skinList.getScrollAmount(); + loadSkinsList(); + skinList.setScrollAmount(scroll); + } + } + + private void loadCapesList() { + List rows = new ArrayList<>(); + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + var capes = profile.capes(); + var deselectCape = createWidgetForCape(current.getSkin(), null); + var activeCape = capes.stream().filter(Cape::active).findFirst(); + current.setCape(activeCape.orElse(null)); + deselectCape.noCape(activeCape.isEmpty()); + for (int i = 0; i < capes.size() + 1; i += columns) { + Entry widget; + if (i == 0) { + widget = createEntry(capesList.getEntryContentsHeight(), deselectCape, Text.translatable("skins.capes.no_cape")); + } else { + var cape = capes.get(i - 1); + widget = createEntryForCape(current.getSkin(), cape, capesList.getEntryContentsHeight()); + } + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < capes.size() + 1 - c)) continue; + var cape2 = capes.get(i + c - 1); + Entry widget2 = createEntryForCape(current.getSkin(), cape2, capesList.getEntryContentsHeight()); + + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + client.execute(() -> capesList.replaceEntries(rows)); + } + + private void loadSkinsList() { + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + List skins = new ArrayList<>(profile.skins()); + var hashes = skins.stream().map(Asset::sha256).collect(Collectors.toSet()); + var defaultSkin = Skin.getDefaultSkin(account); + var local = new ArrayList<>(loadLocalSkins()); + var localHashes = local.stream().collect(Collectors.toMap(Asset::sha256, Function.identity(), (skin, skin2) -> skin)); + local.removeIf(s -> !localHashes.containsValue(s)); + skins.replaceAll(s -> { + if (s instanceof MSApi.MCProfile.OnlineSkin online) { + if (localHashes.containsKey(s.sha256()) && localHashes.get(s.sha256()) instanceof Skin.LocalSkin file) { + local.remove(localHashes.remove(s.sha256())); + return new Skin.Shared(file, online); + } + } + return s; + }); + + skins.addAll(local); + if (!hashes.contains(defaultSkin.sha256())) { + skins.add(defaultSkin); + } + populateSkinList(skins, columns); + } + + private List loadLocalSkins() { + try { + Files.createDirectories(SKINS_DIR); + try (Stream skins = Files.list(SKINS_DIR)) { + return skins.filter(Files::isRegularFile).sorted(Comparator.comparingLong(p -> { + try { + return Files.getLastModifiedTime(p).toMillis(); + } catch (IOException e) { + return 0L; + } + }).reversed()).map(Auth.getInstance().getSkinManager()::read).filter(Objects::nonNull).toList(); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to read skins dir!", e); + } + return Collections.emptyList(); + } + + private void populateSkinList(List skins, int columns) { + int entryHeight = skinList.getEntryContentsHeight(); + List rows = new ArrayList<>(); + for (int i = 0; i < skins.size(); i += columns) { + var s = skins.get(i); + if (s != null && s.active()) { + current.setSkin(s); + } + var widget = createEntryForSkin(s, entryHeight); + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < skins.size() - c)) continue; + var s2 = skins.get(i + c); + if (s2 != null && s2.active()) { + current.setSkin(s2); + } + var widget2 = createEntryForSkin(s2, entryHeight); + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + client.execute(() -> skinList.replaceEntries(rows)); + } + + private Path ensureNonexistent(Path p) { + if (Files.exists(p)) { + int counter = 0; + do { + counter++; + p = p.resolveSibling(p.getFileName().toString() + "_" + counter); + } while (Files.exists(p)); + } + return p; + } + + @Override + public void filesDragged(List packs) { + if (packs.isEmpty()) return; + + CompletableFuture[] futs = new CompletableFuture[packs.size()]; + for (int i = 0; i < packs.size(); i++) { + Path p = packs.get(i); + futs[i] = CompletableFuture.runAsync(() -> { + try { + var target = ensureNonexistent(SKINS_DIR.resolve(p.getFileName())); + var skin = Auth.getInstance().getSkinManager().read(p, false); + if (skin != null) { + Files.write(target, skin.image()); + } else { + AxolotlClientCommon.getInstance().getLogger().info("Skipping dragged file {} because it does not seem to be a valid skin!", p); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.not_copied", p.getFileName()); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to copy skin file: ", e); + } + }, client); + } + CompletableFuture.allOf(futs).thenRun(this::loadSkinsList); + } + + private @NotNull Entry createEntryForSkin(Skin skin, int entryHeight) { + return createEntry(entryHeight, new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, skin, account)); + } + + private @NotNull Entry createEntryForCape(Skin currentSkin, Cape cape, int entryHeight) { + return createEntry(entryHeight, createWidgetForCape(currentSkin, cape), Text.literal(cape.alias())); + } + + private SkinWidget createWidgetForCape(Skin currentSkin, Cape cape) { + SkinWidget widget2 = new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, currentSkin, cape, account); + widget2.setRotationY(210); + return widget2; + } + + @Override + protected void clearChildren() { + super.clearChildren(); + Auth.getInstance().getSkinManager().releaseAll(); + } + + @Override + public void removed() { + Auth.getInstance().getSkinManager().releaseAll(); + Watcher.close(skinDirWatcher); + } + + @Override + public void closeScreen() { + client.setScreen(parent); + } + + private SkinListWidget getCurrentList() { + return capesTab ? capesList : skinList; + } + + private class SkinListWidget extends ElementListWidget { + public SkinListWidget(MinecraftClient minecraft, int width, int height, int y, int entryHeight) { + super(minecraft, width, height, y, entryHeight); + } + + @Override + protected int getScrollbarPositionX() { + return getXEnd() - 8; + } + + @Override + public int getRowLeft() { + return getX() + 3; + } + + @Override + public int getRowWidth() { + if (!canScroll()) { + return getWidth() - 4; + } + return getWidth() - 14; + } + + public int getEntryContentsHeight() { + return itemHeight - 4; + } + + @Override + public @Nullable ElementPath nextFocusPath(GuiNavigationEvent event) { + if (!active || !visible) return null; + return super.nextFocusPath(event); + } + + @Override + public void replaceEntries(Collection newEntries) { + super.replaceEntries(newEntries); + } + + @Override + public void centerScrollOn(Row entry) { + super.centerScrollOn(entry); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amountX, double amountY) { + if (!visible) return false; + return super.mouseScrolled(mouseX, mouseY, amountX, amountY); + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + return active && visible && super.isMouseOver(mouseX, mouseY); + } + } + + private class Row extends ElementListWidget.Entry { + private final List widgets; + + public Row(List entries) { + this.widgets = entries; + } + + @Override + public @NotNull List selectableChildren() { + return widgets; + } + + @Override + public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + int x = left; + if (widgets.isEmpty()) return; + int count = widgets.size(); + int padding = ((width - 5 * (count - 1)) / count); + for (var w : widgets) { + w.setPosition(x, top); + w.setWidth(padding); + w.render(guiGraphics, mouseX, mouseY, partialTick); + x += w.getWidth() + 5; + } + } + + @Override + public @NotNull List children() { + return widgets; + } + + @Override + public void setFocusedChild(@Nullable Element focused) { + super.setFocusedChild(focused); + if (focused != null) { + getCurrentList().centerScrollOn(this); + } + } + } + + Entry createEntry(int height, SkinWidget widget) { + return createEntry(height, widget, null); + } + + Entry createEntry(int height, SkinWidget widget, Text label) { + return new Entry(height, widget, label); + } + + private class Entry extends DraggingWidget { + private final SkinWidget skinWidget; + private final @Nullable ClickableWidget label; + private final List actionButtons = new ArrayList<>(); + private final ClickableWidget equipButton; + private boolean equipping; + private long equippingStart; + + public Entry(int height, SkinWidget widget, @Nullable Text label) { + super(0, 0, widget.getWidth(), height, Text.empty()); + widget.setWidth(getWidth() - 4); + var asset = widget.getFocusedAsset(); + if (asset != null) { + class SpriteButton extends ButtonWidget { + private Identifier sprite; + + public SpriteButton(Text message, PressAction onPress, Identifier sprite) { + super(0, 0, 11, 11, message, onPress, DEFAULT_NARRATION); + this.sprite = sprite; + setTooltip(Tooltip.create(message, Text.empty())); + } + + @Override + public void setMessage(Text message) { + super.setMessage(message); + setTooltip(Tooltip.create(message, Text.empty())); + } + + @Override + protected void drawWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + super.drawWidget(graphics, mouseX, mouseY, delta); + graphics.drawGuiTexture(sprite, this.getX() + 2, this.getY() + 2, 7, 7); + } + + @Override + public void drawScrollableText(GuiGraphics graphics, TextRenderer renderer, int color) { + + } + } + if (asset instanceof Skin skin) { + var wideSprite = Identifier.of("axolotlclient", "wide"); + var slimSprite = Identifier.of("axolotlclient", "slim"); + var slimText = Text.translatable("skins.manage.variant.classic"); + var wideText = Text.translatable("skins.manage.variant.slim"); + actionButtons.add(new SpriteButton(skin.classicVariant() ? wideText : slimText, btn -> { + var self = (SpriteButton) btn; + skin.classicVariant(!skin.classicVariant()); + self.sprite = skin.classicVariant() ? slimSprite : wideSprite; + self.setMessage(skin.classicVariant() ? wideText : slimText); + }, skin.classicVariant() ? slimSprite : wideSprite)); + } + if (asset instanceof Asset.Local local) { + this.actionButtons.add(new SpriteButton(Text.translatable("skins.manage.delete"), btn -> { + btn.active = false; + client.setScreen(new ConfirmScreen(confirmed -> { + client.setScreen(new LoadingScreen(getTitle(), Text.translatable("menu.working"))); + if (confirmed) { + try { + Files.delete(local.file()); + Skin.LocalSkin.deleteMetadata(local.file()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to delete: ", e); + } + } + client.setScreen(SkinManagementScreen.this); + btn.active = true; + }, Text.translatable("skins.manage.delete.confirm"), (Text) (asset.active() ? + Text.translatable("skins.manage.delete.confirm.desc_active") : + Text.translatable("skins.manage.delete.confirm.desc") + ).br$color(Colors.RED.toInt()))); + }, Identifier.of("axolotlclient", "delete"))); + } + if (asset instanceof Asset.Online online && online.supportsDownload() && !(asset instanceof Asset.Local)) { + this.actionButtons.add(new SpriteButton(Text.translatable("skins.manage.download"), btn -> { + btn.active = false; + download(asset).thenRun(() -> { + refreshCurrentList(); + btn.active = true; + }); + }, Identifier.of("axolotlclient", "download"))); + } + } + if (label != null) { + this.label = new AbstractTextWidget(0, 0, widget.getWidth(), 16, label, textRenderer) { + @Override + protected void drawWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + drawScrollingText(guiGraphics, textRenderer, 2, -1); + } + }; + this.label.active = false; + } else { + this.label = null; + } + this.equipButton = ButtonWidget.builder(Text.translatable( + widget.isEquipped() ? "skins.manage.equipped" : "skins.manage.equip"), + btn -> { + equippingStart = Util.getMeasuringTimeMs(); + equipping = true; + btn.setMessage(TEXT_EQUIPPING); + btn.active = false; + Consumer> consumer = f -> f.thenAcceptAsync(p -> { + cachedProfile = p; + if (client.currentScreen == SkinManagementScreen.this) { + refreshCurrentList(); + } else { + client.execute(() -> client.setScreen(SkinManagementScreen.this)); + } + }).exceptionally(t -> { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to equip asset!", t); + equipping = false; + return null; + }); + if (asset instanceof Skin && !(current.getSkin() instanceof Skin.Local)) { + client.setScreen(new ConfirmScreen(confirmed -> { + client.setScreen(new LoadingScreen(getTitle(), TEXT_EQUIPPING)); + if (confirmed) { + consumer.accept(download(current.getSkin()).thenCompose(a -> widget.equip())); + } else { + consumer.accept(widget.equip()); + } + }, Text.translatable("skins.manage.equip.confirm"), Text.translatable("skins.manage.equip.download_current"))); + } else { + consumer.accept(widget.equip()); + } + }).width(widget.getWidth()).build(); + this.equipButton.active = !widget.isEquipped(); + this.skinWidget = widget; + } + + private @NotNull CompletableFuture download(Asset asset) { + return CompletableFuture.runAsync(() -> { + try { + var out = SKINS_DIR.resolve(asset.sha256()); + Files.createDirectories(out.getParent()); + Files.write(out, asset.image()); + if (asset instanceof Skin skin) { + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, skin.classicVariant())); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to download: ", e); + } + }); + } + + @Override + public @NotNull List children() { + return Stream.concat(actionButtons.stream(), Stream.of(skinWidget, label, equipButton)).filter(Objects::nonNull).toList(); + } + + private float applyEasing(float x) { + return x * x * x; + } + + @Override + protected void drawWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + int y = getY() + 4; + int x = getX() + 2; + skinWidget.setPosition(x, y); + skinWidget.setWidth(getWidth() - 4); + if (skinWidget.isEquipped() || equipping) { + long prog; + if (Auth.getInstance().skinManagerAnimations.get()) { + if (equipping) prog = (Util.getMeasuringTimeMs() - equippingStart) / 20 % 100; + else prog = Math.abs((Util.getMeasuringTimeMs() / 30 % 200) - 100); + } else prog = 100; + var percent = (prog / 100f); + float gradientWidth; + if (equipping) { + gradientWidth = percent * Math.min(getWidth() / 3f, getHeight() / 3f); + } else { + gradientWidth = Math.min(getWidth() / 15f, getHeight() / 6f) + applyEasing(percent) * Math.min(getWidth() * 2 / 15f, getHeight() / 6f); + } + GradientHoleRectangleRenderState.render(guiGraphics, getX() + 2, getY() + 2, getXEnd() - 2, + skinWidget.getYEnd() + 2, + gradientWidth, + equipping ? 0xFFFF0088 : ClientColors.SELECTOR_GREEN.toInt(), 0); + } + skinWidget.render(guiGraphics, mouseX, mouseY, partialTick); + int actionButtonY = getY() + 2; + for (var button : actionButtons) { + button.setPosition(skinWidget.getXEnd() - button.getWidth(), actionButtonY); + if (isHovered() || button.isHoveredOrFocused()) { + button.render(guiGraphics, mouseX, mouseY, partialTick); + } + actionButtonY += button.getHeight() + 2; + } + if (label != null) { + label.setPosition(x, skinWidget.getYEnd() + 6); + label.render(guiGraphics, mouseX, mouseY, partialTick); + label.setWidth(getWidth() - 4); + equipButton.setPosition(x, label.getYEnd() + 2); + } else { + equipButton.setPosition(x, skinWidget.getYEnd() + 4); + } + equipButton.setWidth(getWidth() - 4); + equipButton.render(guiGraphics, mouseX, mouseY, partialTick); + + if (isHovered()) { + guiGraphics.br$outlineRect(getX(), getY(), getWidth(), getHeight(), -1); + } + } + + @Override + protected void updateNarration(NarrationMessageBuilder narrationElementOutput) { + skinWidget.appendNarrations(narrationElementOutput); + actionButtons.forEach(w -> w.appendNarrations(narrationElementOutput)); + if (label != null) { + label.appendNarrations(narrationElementOutput); + } + equipButton.appendNarrations(narrationElementOutput); + } + + private static class GradientHoleRectangleRenderState { + + public static void render(GuiGraphics graphics, int x0, int y0, int x1, int y1, float gradientWidth, int col1, int col2) { + var vertexConsumer = graphics.getVertexConsumers().getBuffer(RenderLayer.getGui()); + float z = 0; + //top + var pose = graphics.getMatrices().peek().getModel(); + vertexConsumer.xyz(pose, x0, y0, z).color(col1); + vertexConsumer.xyz(pose, x0 + gradientWidth, y0 + gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x1 - gradientWidth, y0 + gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x1, y0, z).color(col1); + //left + vertexConsumer.xyz(pose, x0, y1, z).color(col1); + vertexConsumer.xyz(pose, x0 + gradientWidth, y1 - gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x0 + gradientWidth, y0 + gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x0, y0, z).color(col1); + //bottom + vertexConsumer.xyz(pose, x1, y1, z).color(col1); + vertexConsumer.xyz(pose, x1 - gradientWidth, y1 - gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x0 + gradientWidth, y1 - gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x0, y1, z).color(col1); + //right + vertexConsumer.xyz(pose, x1, y0, z).color(col1); + vertexConsumer.xyz(pose, x1 - gradientWidth, y0 + gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x1 - gradientWidth, y1 - gradientWidth, z).color(col2); + vertexConsumer.xyz(pose, x1, y1, z).color(col1); + } + } + } +} diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java new file mode 100644 index 000000000..4b0357f7e --- /dev/null +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java @@ -0,0 +1,178 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import com.google.common.hash.Hashing; +import com.mojang.blaze3d.texture.NativeImage; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.util.ClientColors; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.util.Identifier; + +public class SkinManager { + + private final Set loadedTextures = new ConcurrentSkipListSet<>(Comparator.comparing(Object::toString)); + + public Skin read(Path p) { + return read(p, true); + } + + public Skin read(Path p, boolean fix) { + boolean slim; + String sha256; + try { + var in = Files.readAllBytes(p); + sha256 = Hashing.sha256().hashBytes(in).toString(); + try (var img = NativeImage.read(in)) { + int width = img.getWidth(); + int height = img.getHeight(); + if (width != 64) return null; + if (height == 32) { + if (fix) { + try (var img2 = remapTexture(img)) { + img2.writeFile(p); + } + } + slim = false; + } else if (height != 64) { + return null; + } else { + slim = ClientColors.ARGB.alpha(img.getPixelColor(50, 16)) == 0; + } + var metadata = Skin.LocalSkin.readMetadata(p); + if (metadata != null && metadata.containsKey(Skin.LocalSkin.CLASSIC_METADATA_KEY)) { + slim = !(boolean) metadata.get(Skin.LocalSkin.CLASSIC_METADATA_KEY); + } + } + return new Skin.LocalSkin(!slim, p, in, sha256); + } catch (Exception e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to probe skin: ", e); + } + return null; + } + + private static NativeImage remapTexture(NativeImage skinImage) { + boolean legacySkin = skinImage.getHeight() == 32; + if (legacySkin) { + NativeImage nativeImage = new NativeImage(64, 64, true); + nativeImage.copyFrom(skinImage); + skinImage.close(); + skinImage = nativeImage; + nativeImage.fillRect(0, 32, 64, 32, 0); + nativeImage.copyRectangle(4, 16, 16, 32, 4, 4, true, false); + nativeImage.copyRectangle(8, 16, 16, 32, 4, 4, true, false); + nativeImage.copyRectangle(0, 20, 24, 32, 4, 12, true, false); + nativeImage.copyRectangle(4, 20, 16, 32, 4, 12, true, false); + nativeImage.copyRectangle(8, 20, 8, 32, 4, 12, true, false); + nativeImage.copyRectangle(12, 20, 16, 32, 4, 12, true, false); + nativeImage.copyRectangle(44, 16, -8, 32, 4, 4, true, false); + nativeImage.copyRectangle(48, 16, -8, 32, 4, 4, true, false); + nativeImage.copyRectangle(40, 20, 0, 32, 4, 12, true, false); + nativeImage.copyRectangle(44, 20, -8, 32, 4, 12, true, false); + nativeImage.copyRectangle(48, 20, -16, 32, 4, 12, true, false); + nativeImage.copyRectangle(52, 20, -8, 32, 4, 12, true, false); + } + + stripAlpha(skinImage, 0, 0, 32, 16); + if (legacySkin) { + stripColor(skinImage, 32, 0, 64, 32); + } + + stripAlpha(skinImage, 0, 16, 64, 32); + stripAlpha(skinImage, 16, 48, 48, 64); + return skinImage; + } + + @SuppressWarnings("SameParameterValue") + private static void stripColor(NativeImage image, int x1, int y1, int x2, int y2) { + for (int x = x1; x < x2; x++) { + for (int y = y1; y < y2; y++) { + int k = image.getPixelColor(x, y); + if ((k >> 24 & 0xFF) < 128) { + return; + } + } + } + + for (int x = x1; x < x2; x++) { + for (int y = y1; y < y2; y++) { + image.setPixelColor(x, y, image.getPixelColor(x, y) & 16777215); + } + } + } + + private static void stripAlpha(NativeImage image, int x1, int y1, int x2, int y2) { + for (int x = x1; x < x2; x++) { + for (int y = y1; y < y2; y++) { + image.setPixelColor(x, y, image.getPixelColor(x, y) | 0xFF000000); + } + } + } + + public AxoIdentifier loadSkin(Skin skin) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "skins/" + skin.sha256()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try { + var tex = new NativeImageBackedTexture(NativeImage.read(skin.image())); + MinecraftClient.getInstance().getTextureManager().registerTexture((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public AxoIdentifier loadCape(Cape cape) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "capes/" + cape.id()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try { + var tex = new NativeImageBackedTexture(NativeImage.read(cape.image())); + MinecraftClient.getInstance().getTextureManager().registerTexture((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public void releaseAll() { + loadedTextures.forEach(id -> MinecraftClient.getInstance().getTextureManager().destroyTexture((Identifier) id)); + loadedTextures.clear(); + } +} diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java new file mode 100644 index 000000000..2f12705c8 --- /dev/null +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java @@ -0,0 +1,89 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import com.mojang.blaze3d.lighting.DiffuseLighting; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.entity.model.EntityModelLayers; +import net.minecraft.client.render.entity.model.PlayerEntityModel; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Axis; +import org.jetbrains.annotations.Nullable; + +public class SkinRenderer { + private static PlayerEntityModel classicModel, slimModel; + private static final MinecraftClient minecraft = MinecraftClient.getInstance(); + + private SkinRenderer() { + } + + public static void render(GuiGraphics graphics, boolean classicVariant, + Identifier skinTexture, + @Nullable Identifier cape, + float rotationX, + float rotationY, + float pivotY, + int x0, + int y0, + int x1, + int y1, + float scale) { + if (classicModel == null && classicVariant) { + classicModel = new PlayerEntityModel<>(minecraft.getEntityModelLoader().getModelPart(EntityModelLayers.PLAYER), false); + classicModel.child = false; + } + if (slimModel == null && !classicVariant) { + slimModel = new PlayerEntityModel<>(minecraft.getEntityModelLoader().getModelPart(EntityModelLayers.PLAYER_SLIM), true); + slimModel.child = false; + } + + int width = x1 - x0; + graphics.getMatrices().push(); + graphics.getMatrices().translate(x0 + width / 2.0F, (float) (y1), 100.0F); + graphics.getMatrices().scale(scale, scale, scale); + graphics.getMatrices().translate(0.0F, -0.0625F, 0.0F); + graphics.getMatrices().rotateAround(Axis.X_POSITIVE.rotationDegrees(rotationX), 0.0F, pivotY, 0.0F); + graphics.getMatrices().rotate(Axis.Y_POSITIVE.rotationDegrees(rotationY)); + graphics.draw(); + DiffuseLighting.setupInventoryShaderLighting(Axis.X_POSITIVE.rotationDegrees(rotationX)); + graphics.getMatrices().push(); + graphics.getMatrices().scale(1.0F, 1.0F, -1.0F); + graphics.getMatrices().translate(0.0F, -1.5F, 0.0F); + var model = classicVariant ? classicModel : slimModel; + RenderLayer renderLayer = model.getLayer(skinTexture); + model.method_60879(graphics.getMatrices(), graphics.getVertexConsumers().getBuffer(renderLayer), 15728880, OverlayTexture.DEFAULT_UV); + if (cape != null) { + graphics.getMatrices().translate(0.0F, 0.0F, 0.125F); + graphics.getMatrices().rotate(Axis.X_POSITIVE.rotationDegrees(6.0F)); + graphics.getMatrices().rotate(Axis.Y_POSITIVE.rotationDegrees(180.0F)); + model.renderCape(graphics.getMatrices(), graphics.getVertexConsumers().getBuffer(RenderLayer.getEntitySolid(cape)), 15728880, OverlayTexture.DEFAULT_UV); + } + graphics.getMatrices().pop(); + graphics.draw(); + DiffuseLighting.setup3DGuiLighting(); + graphics.getMatrices().pop(); + } +} diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java new file mode 100644 index 000000000..a9cd345c3 --- /dev/null +++ b/1.21/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java @@ -0,0 +1,134 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.concurrent.CompletableFuture; + +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.gui.ElementPath; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.GuiNavigationEvent; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.sound.SoundManager; +import net.minecraft.text.CommonTexts; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; + +public class SkinWidget extends ClickableWidget { + private static final float MODEL_HEIGHT = 2.125F; + private static final float FIT_SCALE = 0.97F; + private static final float ROTATION_SENSITIVITY = 2.5F; + private static final float DEFAULT_ROTATION_X = -5.0F; + private static final float DEFAULT_ROTATION_Y = 30.0F; + private static final float ROTATION_X_LIMIT = 50.0F; + private float rotationX = DEFAULT_ROTATION_X; + @Setter + private float rotationY = DEFAULT_ROTATION_Y; + @Getter + @Setter + private Skin skin; + @Getter + @Setter + private Cape cape; + private final Account owner; + private boolean noCape, noCapeActive; + + public SkinWidget(int width, int height, Skin skin, @Nullable Cape cape, Account owner) { + super(0, 0, width, height, CommonTexts.EMPTY); + this.skin = skin; + this.cape = cape; + this.owner = owner; + } + + public SkinWidget(int width, int height, Skin skin, Account owner) { + this(width, height, skin, null, owner); + } + + public void noCape(boolean noCapeActive) { + noCape = true; + this.noCapeActive = noCapeActive; + } + + @Override + protected void drawWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + + float scale = FIT_SCALE * this.getHeight() / MODEL_HEIGHT; + float pivotY = -1.0625F; + + SkinManager skinManager = Auth.getInstance().getSkinManager(); + AxoIdentifier skinRl = skinManager.loadSkin(skin); + boolean classic = skin.classicVariant(); + var capeRl = cape == null ? null : skinManager.loadCape(cape); + + SkinRenderer.render(guiGraphics, classic, (Identifier) skinRl, (Identifier) capeRl, this.rotationX, this.rotationY, pivotY, this.getX(), this.getY(), this.getXEnd(), this.getYEnd(), scale); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) { + this.rotationX = MathHelper.clamp(this.rotationX - (float) dragY * ROTATION_SENSITIVITY, -ROTATION_X_LIMIT, ROTATION_X_LIMIT); + this.rotationY += (float) dragX * ROTATION_SENSITIVITY; + } + + @Override + public void playDownSound(SoundManager handler) { + } + + @Override + protected void updateNarration(NarrationMessageBuilder builder) { + + } + + @Override + public @Nullable ElementPath nextFocusPath(GuiNavigationEvent event) { + return null; + } + + public boolean isEquipped() { + return noCape ? noCapeActive : (cape != null ? cape.active() : skin != null && skin.active()); + } + + public CompletableFuture equip() { + var msApi = Auth.getInstance().getMsApi(); + if (noCape) { + return msApi.hideCape(owner); + } + if (cape != null) { + return cape.equip(msApi, owner); + } + if (skin != null) { + return skin.equip(msApi, owner); + } + return msApi.resetSkin(owner); + } + + public Asset getFocusedAsset() { + return noCape ? null : cape != null ? cape : skin; + } +} diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java b/1.21/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java index 11959e0cf..b45caac98 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java @@ -32,6 +32,7 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.FloatOption; import io.github.axolotlclient.mixin.ShaderEffectAccessor; import io.github.axolotlclient.modules.AbstractModule; +import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gl.ShaderEffect; import net.minecraft.resource.Resource; @@ -40,6 +41,7 @@ public class MotionBlur extends AbstractModule { + @Getter private static final MotionBlur Instance = new MotionBlur(); public final BooleanOption enabled = new BooleanOption("enabled", false); public final FloatOption strength = new FloatOption("strength", 50F, 1F, 99F); @@ -57,10 +59,6 @@ private static float getBlur() { return MotionBlur.getInstance().strength.get() / 100F; } - public static MotionBlur getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled, strength, inGuis); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java index 0ea711b2d..a0dd2580a 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java @@ -46,7 +46,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudEditScreen extends Screen { @@ -124,19 +124,20 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { if (entry.isPresent()) { var bounds = entry.get().getTrueBounds(); if (mode == ModificationMode.NONE && bounds.isMouseOver(mouseX, mouseY)) { + var supportsScaling = entry.get().supportsScaling(); var xBound = Math.max(0, mouseX - bounds.x()); var yBound = Math.max(0, mouseY - bounds.y()); var tolerance = GRAB_TOLERANCE; - if (xBound < tolerance && yBound < tolerance) { + if (supportsScaling && xBound < tolerance && yBound < tolerance) { // top-left setCursor(NWSE_RESIZE_CURSOR); - } else if (Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-right setCursor(NWSE_RESIZE_CURSOR); - } else if (xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-left setCursor(NESW_RESIZE_CURSOR); - } else if (yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { + } else if (supportsScaling && yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { // top-right setCursor(NESW_RESIZE_CURSOR); } else { diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java index 19e4c60dc..7c75d3f2c 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java @@ -26,9 +26,9 @@ import io.github.axolotlclient.modules.hud.gui.hud.KeystrokeHud; import io.github.axolotlclient.modules.hud.gui.hud.PackDisplayHud; import io.github.axolotlclient.modules.hud.gui.hud.PlayerHud; -import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import io.github.axolotlclient.modules.hud.gui.hud.simple.ComboHud; import io.github.axolotlclient.modules.hud.gui.hud.simple.ReachHud; +import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import lombok.Getter; import net.minecraft.client.MinecraftClient; @@ -36,7 +36,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudManager extends HudManagerCommon { @Getter @@ -67,7 +67,7 @@ protected void addExtraHud() { public void render(AxoRenderContext context, float delta) { final var mc = ((MinecraftClient) client); mc.getProfiler().push("Hud render"); - if(!(mc.currentScreen instanceof HudEditScreen)) { + if (!(mc.currentScreen instanceof HudEditScreen)) { super.render(context, delta); } mc.getProfiler().pop(); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java index 6d8342165..c5860b214 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java @@ -68,7 +68,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class KeystrokeHud extends TextHudEntry implements ProfileAware { @@ -477,6 +477,7 @@ public boolean isLabelEditable() { } public void saveKeystrokes() { + if (keystrokes == null) return; try { var path = AxolotlClientCommon.resolveProfileConfigFile(KEYSTROKE_SAVE_FILE_NAME); Files.createDirectories(path.getParent()); @@ -495,7 +496,11 @@ public void loadKeystrokes() { var loaded = entries.stream().map(e -> (Map) e) .map(KeystrokeHud.this::deserializeKey) .toList(); - keystrokes.clear(); + if (keystrokes == null) { + keystrokes = new ArrayList<>(); + } else { + keystrokes.clear(); + } keystrokes.addAll(loaded); } else { saveKeystrokes(); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java index 527c0b56f..8fa6d160c 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java @@ -22,9 +22,9 @@ package io.github.axolotlclient.modules.hud.gui.hud; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.render.AxoRenderContext; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.GuiGraphics; @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class PlayerHud extends PlayerHudCommon { @@ -52,7 +52,7 @@ public PlayerHud() { } public void onPlayerDirectionChange(PlayerDirectionChangeEvent event) { - yawOffset += (event.getYaw() - event.getPrevYaw()) / 2; + yawOffset += (event.yaw() - event.prevYaw()) / 2; } @Override @@ -133,6 +133,7 @@ protected void renderPlayer(AxoRenderContext ctx, boolean placeholder, double x, private boolean isPerformingAction() { // inspired by tr7zw's mod ClientPlayerEntity player = MinecraftClient.getInstance().player; + //noinspection DataFlowIssue return player.isSneaking() || player.isSprinting() || player.isFallFlying() || player.getAbilities().flying || player.isSubmergedInWater() || player.isInSwimmingPose() || player.hasVehicle() || player.isUsingItem() || player.handSwinging || player.hurtTime > 0 || player.isOnFire(); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java index 6f763a82d..3b7182fbc 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java @@ -40,7 +40,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ActionBarHud extends TextHudEntry { @@ -103,6 +103,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(timeShown); options.add(customTextColor); return options; diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java index 3fe29426e..5b92db663 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java @@ -50,7 +50,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class BossBarHud extends TextHudEntry implements DynamicallyPositionable { @@ -146,6 +146,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(text); options.add(bar); options.add(anchor); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java index 13c3564b3..9d36254c2 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java @@ -60,7 +60,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CrosshairHud extends AbstractHudEntry implements DynamicallyPositionable { @@ -118,6 +118,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(type); options.add(customTextureGraphics); options.add(showInF5); @@ -222,6 +223,7 @@ public void render(AxoRenderContext context, float delta) { // Draw attack indicator if (!customAttackIndicator.get() && indicator == AttackIndicator.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackCooldownProgress(0.0F); // Whether a cross should be displayed under the indicator @@ -245,6 +247,7 @@ public void render(AxoRenderContext context, float delta) { } } if (((type.get().equals(Crosshair.TEXTURE) || type.get().equals(Crosshair.CUSTOM)) ? customAttackIndicator.get() : true) && indicator == AttackIndicator.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackCooldownProgress(0.0F); if (progress != 1.0F) { RenderUtil.drawRectangle(graphics, getRawX() + (getWidth() / 2) - 6, getRawY() + (getHeight() / 2) + 9, @@ -267,6 +270,7 @@ public Color getColor() { } else if (hit.getType() == HitResult.Type.BLOCK) { BlockPos blockPos = ((BlockHitResult) hit).getBlockPos(); World world = this.client.world; + //noinspection DataFlowIssue if (world.getBlockState(blockPos).createScreenHandlerFactory(world, blockPos) != null || world.getBlockState(blockPos).getBlock() instanceof AbstractChestBlock) { return containerColor.get(); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java index 201ad3521..04a9501cd 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java @@ -137,6 +137,7 @@ public AnchorPoint getAnchor() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(anchor); options.add(showCCount); options.add(showECount); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java index 864b87c14..f5cbdd124 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java @@ -25,114 +25,27 @@ import java.util.ArrayList; import java.util.List; -import com.mojang.blaze3d.systems.RenderSystem; import io.github.axolotlclient.AxolotlClientConfig.api.options.Option; import io.github.axolotlclient.bridge.render.AxoRenderContext; import io.github.axolotlclient.modules.hud.gui.entry.TextHudEntry; import io.github.axolotlclient.modules.hud.util.DrawPosition; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.option.AttackIndicator; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Arm; import net.minecraft.util.Identifier; import static io.github.axolotlclient.modules.hud.util.DrawUtil.drawCenteredString; public class HotbarHUD extends TextHudEntry { - public static final Identifier ICONS_TEXTURE = Identifier.ofDefault("textures/gui/icons.png"); public static final Identifier ID = Identifier.of("axolotlclient", "hotbarhud"); - private static final Identifier WIDGETS_TEXTURE = Identifier.ofDefault("textures/gui/widgets.png"); - - private final MinecraftClient client = (MinecraftClient) super.client; public HotbarHUD() { super(182, 22, false); + supportsScaling = false; } @Override public void renderComponent(AxoRenderContext context, float delta) { - final var graphics = (GuiGraphics) context; - - graphics.getMatrices().push(); - PlayerEntity playerEntity = MinecraftClient.getInstance().cameraEntity instanceof PlayerEntity - ? (PlayerEntity) MinecraftClient.getInstance().cameraEntity - : null; - if (playerEntity != null) { - ItemStack itemStack = playerEntity.getOffHandStack(); - Arm arm = playerEntity.getMainArm().getOpposite(); - DrawPosition pos = getPos(); - int i = pos.x() + getWidth() / 2; - graphics.getMatrices().push(); - graphics.getMatrices().translate(0.0F, 0.0F, -90.0F); - graphics.drawTexture(WIDGETS_TEXTURE, i - 91, pos.y(), 0, 0, 182, 22); - graphics.drawTexture(WIDGETS_TEXTURE, i - 91 - 1 + playerEntity.getInventory().selectedSlot * 20, pos.y() - 1, 0, 22, 24, 22); - if (!itemStack.isEmpty()) { - if (arm == Arm.LEFT) { - graphics.drawTexture(WIDGETS_TEXTURE, i - 91 - 29, pos.y() - 1, 24, 22, 29, 24); - } else { - graphics.drawTexture(WIDGETS_TEXTURE, i + 91, pos.y() - 1, 53, 22, 29, 24); - } - } - - graphics.getMatrices().pop(); - int l = 1; - - for (int m = 0; m < 9; ++m) { - int n = i - 90 + m * 20 + 2; - int o = pos.y() + 6 - 3; - this.renderHotbarItem(graphics, n, o, delta, playerEntity, playerEntity.getInventory().main.get(m), l++); - } - - if (!itemStack.isEmpty()) { - int m = pos.y() + 6 - 3; - if (arm == Arm.LEFT) { - this.renderHotbarItem(graphics, i - 91 - 26, m, delta, playerEntity, itemStack, l++); - } else { - this.renderHotbarItem(graphics, i + 91 + 10, m, delta, playerEntity, itemStack, l++); - } - } - - RenderSystem.enableBlend(); - if (this.client.options.getAttackIndicator().get() == AttackIndicator.HOTBAR) { - float f = this.client.player.getAttackCooldownProgress(0.0F); - if (f < 1.0F) { - int n = pos.y() + 2; - int o = i + 91 + 6; - if (arm == Arm.RIGHT) { - o = i - 91 - 22; - } - - int p = (int) (f * 19.0F); - graphics.drawTexture(ICONS_TEXTURE, o, n, 0, 94, 18, 18); - graphics.drawTexture(ICONS_TEXTURE, o, n + 18 - p, 18, 112 - p, 18, p); - } - } - - RenderSystem.disableBlend(); - } - graphics.getMatrices().pop(); - } - - private void renderHotbarItem(GuiGraphics graphics, int x, int y, float tickDelta, PlayerEntity player, ItemStack stack, int seed) { - if (!stack.isEmpty()) { - float f = (float) stack.getCooldown() - tickDelta; - if (f > 0.0F) { - float g = 1.0F + f / 5.0F; - graphics.getMatrices().push(); - graphics.getMatrices().translate((float) (x + 8), (float) (y + 12), 0.0F); - graphics.getMatrices().scale(1.0F / g, (g + 1.0F) / 2.0F, 1.0F); - graphics.getMatrices().translate((float) (-(x + 8)), (float) (-(y + 12)), 0.0F); - } - - graphics.drawItem(player, stack, x, y, seed); - if (f > 0.0F) { - graphics.getMatrices().pop(); - } - - graphics.drawItemInSlot(this.client.textRenderer, stack, x, y); - } + // this is just a matrix translate in InGameHudMixin } @Override @@ -159,6 +72,7 @@ public boolean overridesF3() { public List> getConfigurationOptions() { List> list = new ArrayList<>(); list.add(enabled); + list.add(hide); return list; } } diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java index 8a7f557af..d61f5cb29 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java @@ -52,7 +52,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ScoreboardHud extends TextHudEntry implements DynamicallyPositionable { @@ -101,8 +101,10 @@ public void render(AxoRenderContext context, float delta) { @Override public void renderComponent(AxoRenderContext context, float delta) { final var graphics = (GuiGraphics) context; + //noinspection DataFlowIssue Scoreboard scoreboard = this.client.world.getScoreboard(); ScoreboardObjective scoreboardObjective = null; + //noinspection DataFlowIssue Team team = scoreboard.getPlayerTeam(this.client.player.getProfileName()); if (team != null) { int t = team.getColor().getColorIndex(); @@ -207,8 +209,8 @@ record DisplayEntry(Text name, Text score, int scoreWidth) { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); - options.add(options.indexOf(super.backgroundColor), backgroundColor); - options.remove(super.backgroundColor); + options.set(options.indexOf(super.backgroundColor), backgroundColor); + options.add(hide); options.add(topColor); options.add(scores); options.add(scoreColor); @@ -226,6 +228,16 @@ public Identifier getId() { @Override public AnchorPoint getAnchor() { - return (anchor.get()); + return anchor.get(); + } + + @Override + public double getDefaultX() { + return 1.0; + } + + @Override + public double getDefaultY() { + return 0.5; } } diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java index 5e5181ccf..793cbf4b4 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java @@ -35,7 +35,7 @@ public class AddSpecialKeystrokeScreen extends Screen { private final Screen lastScreen; public final KeystrokeHud hud; private SpecialKeystrokeSelectionList keyBindsList; - public HeaderFooterLayoutWidget layout = new HeaderFooterLayoutWidget(this); + public final HeaderFooterLayoutWidget layout = new HeaderFooterLayoutWidget(this); public AddSpecialKeystrokeScreen(Screen lastScreen, KeystrokeHud hud) { super(TITLE); @@ -62,6 +62,7 @@ protected void repositionElements() { @Override public void closeScreen() { + //noinspection DataFlowIssue client.setScreen(lastScreen); } } diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java index d84cc6f5a..3e601c7ee 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java @@ -35,7 +35,7 @@ public class KeyBindSelectionScreen extends Screen { private final Screen lastScreen; public final KeystrokeHud.Keystroke stroke; private KeyBindSelectionList keyBindsList; - public HeaderFooterLayoutWidget layout = new HeaderFooterLayoutWidget(this); + public final HeaderFooterLayoutWidget layout = new HeaderFooterLayoutWidget(this); public KeyBindSelectionScreen(Screen lastScreen, KeystrokeHud.Keystroke stroke) { super(TITLE); @@ -46,9 +46,7 @@ public KeyBindSelectionScreen(Screen lastScreen, KeystrokeHud.Keystroke stroke) @Override public void init() { layout.addToHeader(getTitle(), textRenderer); - this.keyBindsList = this.layout.addToContents(new KeyBindSelectionList(this, this.client, key -> { - stroke.setKey(key); - })); + this.keyBindsList = this.layout.addToContents(new KeyBindSelectionList(this, this.client, stroke::setKey)); LinearLayoutWidget linearLayout = this.layout.addToFooter(LinearLayoutWidget.createHorizontal().setSpacing(8)); linearLayout.add(ButtonWidget.builder(CommonTexts.DONE, button -> this.closeScreen()).build()); @@ -64,6 +62,7 @@ protected void repositionElements() { @Override public void closeScreen() { + //noinspection DataFlowIssue client.setScreen(lastScreen); } } diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java index 9113ec6da..834db3e9c 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class SnappingHelper { diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java index e3754c35c..ba5d88034 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java @@ -31,7 +31,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class DrawUtil { diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java deleted file mode 100644 index d642ca6c4..000000000 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.modules.hud.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import lombok.experimental.UtilityClass; -import net.minecraft.client.MinecraftClient; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Util; - -/** - * This implementation of Hud modules is based on KronHUD. - * Github Link. - * - * @license GPL-3.0 - */ - -@UtilityClass -public class ItemUtil { - - public static ArrayList removeOld(List list, int time) { - ArrayList stored = new ArrayList<>(); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.getPassedTime() <= time) { - stored.add(storage); - } - } - return stored; - } - - public static List untimedToTimed(List list) { - ArrayList timed = new ArrayList<>(); - for (ItemStorage stack : list) { - timed.add(stack.timed()); - } - return timed; - } - - public static Optional getTimedItemFromItem(ItemStack item, - List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.stack.isOf(compare.getItem())) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - public static int getTotal(MinecraftClient client, ItemStack stack) { - List item = ItemUtil.getItems(client); - if (item == null || item.isEmpty()) { - return 0; - } - List items = ItemUtil.storageFromItem(item); - Optional stor = ItemUtil.getItemFromItem(stack, items); - return stor.map(itemStorage -> itemStorage.times).orElse(0); - } - - public static List getItems(MinecraftClient client) { - ArrayList items = new ArrayList<>(); - if (client.player == null) { - return null; - } - items.addAll(client.player.getInventory().armor); - items.addAll(client.player.getInventory().offHand); - items.addAll(client.player.getInventory().main); - return items; - } - - public static List storageFromItem(List items) { - ArrayList storage = new ArrayList<>(); - for (ItemStack item : items) { - if (item.isEmpty()) { - continue; - } - Optional s = getItemFromItem(item, storage); - if (s.isPresent()) { - ItemUtil.ItemStorage store = s.get(); - store.incrementTimes(item.getCount()); - } else { - storage.add(new ItemUtil.ItemStorage(item, item.getCount())); - } - } - return storage; - } - - public static Optional getItemFromItem(ItemStack item, List list) { - ItemStack compare = item.copy(); - compare.setCount(1); - for (ItemUtil.ItemStorage storage : list) { - if (storage.stack.isOf(compare.getItem())) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - /** - * Compares two ItemStorage Lists. - * If list1.get(1) is 10, and list2 is 5, it will return 5. - * Will return nothing if negative... - * - * @param list1 one to be based off of - * @param list2 one to compare to - * @return the compared list - */ - public static List compare(List list1, List list2) { - ArrayList list = new ArrayList<>(); - for (ItemStorage current : list1) { - Optional optional = getItemFromItem(current.stack, list2); - if (optional.isPresent()) { - ItemStorage other = optional.get(); - if (current.times - other.times <= 0) { - continue; - } - list.add(new ItemStorage(other.stack.copy(), current.times - other.times)); - } else { - list.add(current.copy()); - } - } - return list; - } - - public static class ItemStorage { - - public final ItemStack stack; - public int times; - - public ItemStorage(ItemStack stack, int times) { - ItemStack copy = stack.copy(); - copy.setCount(1); - this.stack = copy; - this.times = times; - } - - public void incrementTimes(int num) { - times = times + num; - } - - public ItemStorage copy() { - return new ItemStorage(stack.copy(), times); - } - - public TimedItemStorage timed() { - return new TimedItemStorage(stack, times); - } - } - - public static class TimedItemStorage extends ItemStorage { - - public float start; - - public TimedItemStorage(ItemStack stack, int times) { - super(stack, times); - this.start = Util.getMeasuringTimeMs(); - } - - public float getPassedTime() { - return Util.getMeasuringTimeMs() - start; - } - - @Override - public void incrementTimes(int num) { - super.incrementTimes(num); - refresh(); - } - - public void refresh() { - start = Util.getMeasuringTimeMs(); - } - } -} diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java b/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java index 56854bbe7..e654dd686 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java @@ -37,7 +37,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @UtilityClass diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/particles/Particles.java b/1.21/src/main/java/io/github/axolotlclient/modules/particles/Particles.java index e102cacb3..a1f46eea2 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/particles/Particles.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/particles/Particles.java @@ -35,6 +35,7 @@ import io.github.axolotlclient.mixin.ParticleAccessor; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.ClientColors; +import lombok.Getter; import net.minecraft.client.particle.Particle; import net.minecraft.particle.ParticleType; import net.minecraft.particle.ParticleTypes; @@ -43,6 +44,7 @@ public class Particles extends AbstractModule { + @Getter private static final Particles Instance = new Particles(); public final HashMap, HashMap>> particleOptions = new HashMap<>(); @@ -51,10 +53,6 @@ public class Particles extends AbstractModule { private final OptionCategory cat = OptionCategory.create("particles"); private final BooleanOption enabled = new BooleanOption("enabled", false); - public static Particles getInstance() { - return Instance; - } - @Override public void init() { cat.add(enabled); @@ -66,6 +64,7 @@ public void init() { private void addParticleOptions() { for (ParticleType type : Registries.PARTICLE_TYPE.stream().sorted(new AlphabeticalComparator()).toList()) { if (Registries.PARTICLE_TYPE.getId(type) != null) { + //noinspection DataFlowIssue OptionCategory category = OptionCategory.create( Arrays.stream(Registries.PARTICLE_TYPE.getId(type).getPath().split("_")) .map(StringUtils::capitalize).collect(Collectors.joining(" "))); @@ -145,6 +144,7 @@ public int compare(ParticleType s1, ParticleType s2) { private String getName(ParticleType type) { if (Registries.PARTICLE_TYPE.getId(type) != null) { + //noinspection DataFlowIssue return Registries.PARTICLE_TYPE.getId(type).getPath(); } return ""; diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java b/1.21/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java index dcfc78a31..22df6a231 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java @@ -41,6 +41,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; +@SuppressWarnings("DataFlowIssue") public class DownloadImageScreen extends Screen { private static final Identifier SPRITE = Identifier.of("axolotlclient", "go"); @@ -56,7 +57,7 @@ protected void init() { var hFL = new ImprovedHeaderAndFooterLayout(this); hFL.addTitleHeader(getTitle(), textRenderer); - var urlBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 2 - 10, 200, 20, Text.translatable("urlBox")); + var urlBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 2 - 10, 200, 20, Text.translatable("pasteURL")); urlBox.setSuggestion(I18n.translate("pasteURL")); urlBox.setChangedListener(s -> { if (s.isEmpty()) { diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java b/1.21/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java index 2d094a77f..19f315047 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java @@ -27,10 +27,12 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; import io.github.axolotlclient.modules.AbstractModule; +import lombok.Getter; import net.minecraft.client.gui.screen.Screen; public class ScrollableTooltips extends AbstractModule { + @Getter private static final ScrollableTooltips Instance = new ScrollableTooltips(); public final BooleanOption enabled = new BooleanOption("enabled", false); public final BooleanOption enableShiftHorizontalScroll = new BooleanOption("shiftHorizontalScroll", true); @@ -40,10 +42,6 @@ public class ScrollableTooltips extends AbstractModule { public int tooltipOffsetX; public int tooltipOffsetY; - public static ScrollableTooltips getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java b/1.21/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java index 805a5ab99..9301cd01d 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java @@ -29,12 +29,14 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.options.ForceableBooleanOption; +import lombok.Getter; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; public class TntTime extends AbstractModule { + @Getter private static final TntTime Instance = new TntTime(); public final ForceableBooleanOption enabled = new ForceableBooleanOption("enabled", false); private final OptionCategory category = OptionCategory.create("tnttime"); @@ -42,10 +44,6 @@ public class TntTime extends AbstractModule { private DecimalFormat format; private int decimals; - public static TntTime getInstance() { - return Instance; - } - @Override public void init() { category.add(enabled, decimalPlaces); diff --git a/1.21/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java b/1.21/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java index 769fdb605..832c03cc2 100644 --- a/1.21/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java +++ b/1.21/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java @@ -30,6 +30,7 @@ import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.Util; import io.github.axolotlclient.util.keybinds.KeyBinds; +import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.option.KeyBind; @@ -46,6 +47,7 @@ public class Zoom extends AbstractModule { public static final BooleanOption zoomScrolling = new BooleanOption("zoomScrolling", false); public static final BooleanOption decreaseSensitivity = new BooleanOption("decreaseSensitivity", true); public static final BooleanOption smoothCamera = new BooleanOption("smoothCamera", false); + @Getter private static final Zoom Instance = new Zoom(); public static boolean active; private static Double originalSensitivity; @@ -57,10 +59,6 @@ public class Zoom extends AbstractModule { private static double lastReturnedFov; public final OptionCategory zoom = OptionCategory.create("zoom"); - public static Zoom getInstance() { - return Instance; - } - public static double getFov(double current, float tickDelta) { double result = current * (zoomSpeed.get() == 10 ? targetFactor : Util.lerp(lastAnimatedFactor, animatedFactor, tickDelta)); @@ -165,6 +163,6 @@ public void init() { public void tick() { lastAnimatedFactor = animatedFactor; - animatedFactor += (targetFactor - animatedFactor) * (zoomSpeed.get() / 10F); + animatedFactor += (float) ((targetFactor - animatedFactor) * (zoomSpeed.get() / 10F)); } } diff --git a/1.21/src/main/java/io/github/axolotlclient/util/LoggerImpl.java b/1.21/src/main/java/io/github/axolotlclient/util/LoggerImpl.java index 5eb4b1aaa..2aec0a520 100644 --- a/1.21/src/main/java/io/github/axolotlclient/util/LoggerImpl.java +++ b/1.21/src/main/java/io/github/axolotlclient/util/LoggerImpl.java @@ -33,19 +33,23 @@ public class LoggerImpl implements Logger { private static final String prefix = FabricLoader.getInstance().isDevelopmentEnvironment() ? "" : "(AxolotlClient) "; public void info(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + msg, args); } public void warn(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.warn(prefix + msg, args); } public void error(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.error(prefix + msg, args); } public void debug(String msg, Object... args) { if (AxolotlClient.config().debugLogOutput.get()) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + "[DEBUG] " + msg, args); } } diff --git a/1.21/src/main/java/io/github/axolotlclient/util/events/Events.java b/1.21/src/main/java/io/github/axolotlclient/util/events/Events.java index 729e9a9df..3884a4eae 100644 --- a/1.21/src/main/java/io/github/axolotlclient/util/events/Events.java +++ b/1.21/src/main/java/io/github/axolotlclient/util/events/Events.java @@ -26,7 +26,6 @@ import io.github.axolotlclient.util.events.impl.KeyBindChangeEvent; import io.github.axolotlclient.util.events.impl.MouseInputEvent; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.MinecraftClient; @@ -35,7 +34,6 @@ public class Events { public static final Event> MOUSE_INPUT = createEvent(); public static final Event> KEYBIND_CHANGE = createEvent(); - public static final Event> PLAYER_DIRECTION_CHANGE = createEvent(); public static final Event> GAME_LOAD_EVENT = createEvent(); private static Event> createEvent() { diff --git a/1.8.9/build.gradle.kts b/1.8.9/build.gradle.kts index e3045c94e..f28a3c463 100644 --- a/1.8.9/build.gradle.kts +++ b/1.8.9/build.gradle.kts @@ -42,10 +42,9 @@ dependencies { modApi(include("io.github.moehreag:search-in-resources:1.0.6+1.8.9")!!) - val lwjglVersion = "3.3.5" + val lwjglVersion = "3.3.6" api("org.lwjgl:lwjgl-nanovg:$lwjglVersion") runtimeOnly("org.lwjgl:lwjgl-nanovg:${lwjglVersion}:natives-linux") - runtimeOnly("org.lwjgl:lwjgl-nanovg:${lwjglVersion}:natives-linux-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:${lwjglVersion}:natives-windows") runtimeOnly("org.lwjgl:lwjgl-nanovg:${lwjglVersion}:natives-windows-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:${lwjglVersion}:natives-macos") @@ -59,15 +58,14 @@ dependencies { localRuntime("org.slf4j:slf4j-jdk14:1.7.36") compileOnly("org.lwjgl:lwjgl-glfw:${lwjglVersion}") + compileOnly("org.lwjgl:lwjgl-sdl:3.4.0-SNAPSHOT") - modCompileOnly("io.github.moehreag:legacy-lwjgl3:${project.property("legacy_lwgjl3")}") - modLocalRuntime("io.github.moehreag:legacy-lwjgl3:${project.property("legacy_lwgjl3")}:all-remapped") + modImplementation("io.github.moehreag:legacy-lwjgl3:${project.property("legacy_lwgjl3")}") include(implementation("org.lwjgl", "lwjgl-tinyfd", lwjglVersion)) include(runtimeOnly("org.lwjgl", "lwjgl-tinyfd", lwjglVersion, classifier = "natives-linux")) include(runtimeOnly("org.lwjgl", "lwjgl-tinyfd", lwjglVersion, classifier = "natives-windows")) include(runtimeOnly("org.lwjgl", "lwjgl-tinyfd", lwjglVersion, classifier = "natives-macos")) - include(runtimeOnly("org.lwjgl", "lwjgl-tinyfd", lwjglVersion, classifier = "natives-linux-arm64")) include(runtimeOnly("org.lwjgl", "lwjgl-tinyfd", lwjglVersion, classifier = "natives-windows-arm64")) include(runtimeOnly("org.lwjgl", "lwjgl-tinyfd", lwjglVersion, classifier = "natives-macos-arm64")) @@ -79,6 +77,7 @@ dependencies { } configurations.configureEach { + exclude("org.lwjgl.lwjgl") resolutionStrategy { dependencySubstitution { substitute(module("io.netty:netty-all:4.0.23.Final")).using(module("io.netty:netty-all:4.0.56.Final")) @@ -102,6 +101,7 @@ tasks.runClient { jvmArgs("-Dorg.lwjgl.glfw.libname=$glfwPath") } classpath(sourceSets.getByName("test").runtimeClasspath) + jvmArgs("-XX:+AllowEnhancedClassRedefinition", "-XX:+IgnoreUnrecognizedVMOptions") } tasks.withType(JavaCompile::class).configureEach { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java index 8c82cb2b8..0b95e1fb6 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java @@ -36,6 +36,7 @@ public class SimpleTextInputScreen extends Screen { private final String title; private final Consumer consumer; private TextFieldWidget input; + private ButtonWidget done; public SimpleTextInputScreen(Screen parent, String title, String inputLabel, Consumer consumer) { super(); @@ -50,12 +51,14 @@ public void init() { input = new TextFieldWidget(3, textRenderer, width / 2 - 100, height / 2 - 10, 200, 20); buttons.add(new ButtonWidget(0, width / 2 - 155, height - 50, 150, 20, I18n.translate("gui.cancel"))); - buttons.add(new ButtonWidget(1, width / 2 + 5, height - 50, 150, 20, I18n.translate("gui.done"))); + buttons.add(done = new ButtonWidget(1, width / 2 + 5, height - 50, 150, 20, I18n.translate("gui.done"))); + done.active = false; } @Override public void tick() { input.tick(); + done.active = !input.getText().isBlank(); } @Override @@ -86,10 +89,10 @@ protected void buttonClicked(ButtonWidget buttonWidget) { minecraft.openScreen(parent); break; case 1: - if (!input.getText().isEmpty()) { + if (!input.getText().isBlank()) { consumer.accept(input.getText()); - minecraft.openScreen(parent); } + minecraft.openScreen(parent); break; } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java index d5c69e4ba..41575391a 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java @@ -45,7 +45,6 @@ public class ChatScreen extends Screen implements ContextMenuScreen { private ChatListWidget chatListWidget; private ChatUserListWidget users; private TextFieldWidget input; - private final String title = I18n.translate("api.screen.chat"); public ChatScreen(Screen parent, Channel channel) { super(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/AxoRenderContextImpl.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/AxoRenderContextImpl.java index fd5dea09d..491532b2d 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/AxoRenderContextImpl.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/AxoRenderContextImpl.java @@ -142,7 +142,7 @@ public static AxoRenderContext getInstance() { public void br$renderGuiItemModel(AxoItemStack stack, int x, int y) { final var vanilla = Bridge.unwrapStack(stack); - if(vanilla != null) { + if (vanilla != null) { ItemUtil.renderGuiItemModel(vanilla, x, y); } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java index a4f107c30..9c1c18cdc 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java @@ -80,7 +80,7 @@ public static void init() { ClientConnectionEvents.DISCONNECT.register(mc -> Events.DISCONNECT.invoker().run()); } - public static void postInit() { + public static void postInit() { Events.COMMAND_REGISTER.invoker().accept(CommandsImpl.getInstance()); - } + } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java index fcdeef69c..01466aa16 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java @@ -158,4 +158,9 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient { public void execute(@NotNull Runnable command) { this.submit(command); } + + @Override + public Object br$getScreen() { + return screen; + } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java index b3d541c49..d4092fe8e 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java @@ -54,7 +54,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(value = PlatformDispatch.class, remap = false) -public class PlatformDispatchMixin { +public abstract class PlatformDispatchMixin { @Unique private static void getRealTimeServerPing(String address, int port, MutableInt currentServerPing) { ThreadExecuter.scheduleTask(() -> { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerInfoMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerInfoMixin.java index 160624dfe..8a59feac3 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerInfoMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerInfoMixin.java @@ -32,7 +32,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(PlayerInfo.class) -public class PlayerInfoMixin implements AxoPlayerListEntry { +public abstract class PlayerInfoMixin implements AxoPlayerListEntry { @Shadow @Final private GameProfile profile; diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java index 3ebd6ff70..ba5ac972a 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(LivingEntity.class) -public class LivingEntityMixin implements AxoLivingEntity { +public abstract class LivingEntityMixin implements AxoLivingEntity { @Shadow @Final private Map statusEffects; diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java index 537ab6c43..0842488d7 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoStatusEffects.class, remap = false) -public class AxoStatusEffectsMixin { +public abstract class AxoStatusEffectsMixin { @Mutable @Shadow @Final diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java index 9cccb41b5..70d09a55b 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java @@ -36,6 +36,7 @@ public abstract class StatusEffectMixin implements AxoStatusEffect { @Unique private static final Identifier INVENTORY_TEXTURE = new Identifier("textures/gui/container/inventory.png"); + @Shadow public abstract int getIconIndex(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java index 6e897729e..d9a129b86 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java @@ -70,7 +70,7 @@ @SuppressWarnings("OverwriteModifiers") @Mixin(value = PlatformImplInternal.class, remap = false) -public class PlatformImplInternalMixin { +public abstract class PlatformImplInternalMixin { /** * @author Flowey * @reason Implement bridge platform. @@ -139,9 +139,9 @@ public static int getCurrentFps() { * @reason Implement bridge platform. */ @Overwrite - public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name, String category) { + public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name) { final var id = ((AxoKeyImpl) Objects.requireNonNullElse(defaultKey, AxoKeys.KEY_UNKNOWN)).id(); - final var binding = new KeyBinding(name, id, category); + final var binding = new KeyBinding(name, id, "category.axolotlclient"); Bridge.addKeybind(binding); return binding; } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java index 091d5ac81..34154b127 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoEnchants.class, remap = false) -public class AxoEnchantsMixin { +public abstract class AxoEnchantsMixin { @Mutable @Shadow @Final diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java index ea1f2d1e6..a6cdb8bff 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java @@ -37,7 +37,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoItems.class, remap = false) -public class AxoItemsMixin { +public abstract class AxoItemsMixin { @Mutable @Shadow @Final diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java index e3b053e27..fc0b3ffea 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Enchantment.class) -public class EnchantmentMixin implements AxoEnchant { +public abstract class EnchantmentMixin implements AxoEnchant { } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java index f77c91d06..b7eff03f0 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Item.class) -public class ItemMixin implements AxoItem { +public abstract class ItemMixin implements AxoItem { @Override public boolean br$is(AxoItemClass itemClass) { return switch (itemClass) { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java index 12d52455d..3b2128c51 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java @@ -39,7 +39,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(ItemStack.class) -public abstract class ItemStackMixin implements AxoItemStack{ +public abstract class ItemStackMixin implements AxoItemStack { @Shadow public abstract Item getItem(); @@ -97,7 +97,8 @@ public abstract class ItemStackMixin implements AxoItemStack{ } - @Override public int br$getMaxDamage() { + @Override + public int br$getMaxDamage() { return getMaxDamage(); } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java index 729c866f2..7d711f41e 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(PlayerInventory.class) -public abstract class PlayerInventoryMixin implements AxoPlayerInventory{ +public abstract class PlayerInventoryMixin implements AxoPlayerInventory { @Shadow public abstract ItemStack getMainHandStack(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java index 6e93f39f3..e7ae76c5f 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoKeys.class, remap = false) -public class AxoKeysMixin { +public abstract class AxoKeysMixin { @Mutable @Shadow diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java index eeb84ce28..ea4aac579 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java @@ -30,7 +30,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(GameOptions.class) -public class GameOptionsMixin implements AxoClientKeybinds{ +public abstract class GameOptionsMixin implements AxoClientKeybinds { @Shadow public KeyBinding sprintKey; diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java index e9624b6ae..6cf9ecbb8 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java @@ -36,7 +36,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoSprites.class, remap = false) -public class AxoSpritesMixin { +public abstract class AxoSpritesMixin { @Mutable @Shadow @Final diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java index 25c97c6a6..541dd7b6c 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java @@ -47,7 +47,7 @@ public interface ResourceManagerMixin extends AxoResourceManager { @Override default Map br$listResources(String namespace, String prefix, Predicate filter) { // this cast is maybe not ideal - return (Map) (Object) ((SearchableResourceManager)this).findResources(namespace, prefix, filter::test); + return (Map) (Object) ((SearchableResourceManager) this).findResources(namespace, prefix, filter::test); } @Override diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java index e92e90de0..9c7428889 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java @@ -28,7 +28,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(Identifier.class) -public abstract class IdentifierMixin implements AxoIdentifier{ +public abstract class IdentifierMixin implements AxoIdentifier { @Shadow public abstract String getPath(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java index 61359dc51..be7259d08 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java @@ -23,6 +23,8 @@ package io.github.axolotlclient.bridge.mixin.util; import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.sugar.Local; import io.github.axolotlclient.bridge.util.AxoText; import net.minecraft.text.Formatting; @@ -31,6 +33,7 @@ import net.minecraft.text.Text; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -56,6 +59,13 @@ public abstract class StyleMixin implements AxoText.Style { @Shadow private Style parent; + @Shadow + protected abstract Style getParent(); + + @Shadow + @Final + private static Style ROOT; + @Override public AxoText.Style br$color(AxoText.Color color) { return copy().setColor(switch (color) { @@ -85,9 +95,18 @@ public abstract class StyleMixin implements AxoText.Style { return copy; } + @Unique + private Integer axolotlclient$getColor() { + if (((Object) this) == ROOT) return null; + if (axolotlclient$color == null) { + return ((StyleMixin) (Object) getParent()).axolotlclient$getColor(); + } + return axolotlclient$color; + } + @ModifyReturnValue(method = "copy", at = @At("RETURN")) public Style copyColor(Style original) { - ((StyleMixin) (Object) original).axolotlclient$color = axolotlclient$color; + ((StyleMixin) (Object) original).axolotlclient$color = axolotlclient$getColor(); return original; } @@ -104,16 +123,15 @@ public Style deepCopyColor(Style original) { @Inject(method = "asString", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/Style;isBold()Z")) private void formatColorCode(CallbackInfoReturnable cir, @Local StringBuilder sb) { - Integer color = null; - StyleMixin s = this; - - while (s != null && color == null) { - color = s.axolotlclient$color; - s = (StyleMixin) (Object) s.parent; - } + Integer color = axolotlclient$getColor(); if (color != null) { sb.append("§#").append(StringUtils.leftPad(Integer.toUnsignedString(color & 0xffffff, 16), 6, "0")); } } + + @WrapMethod(method = "isEmpty") + private boolean isEmptyColor(Operation original) { + return original.call() && axolotlclient$color == null; + } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java b/1.8.9/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java index d52662c5e..95700e45c 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java @@ -30,21 +30,24 @@ import io.github.axolotlclient.AxolotlClientConfig.api.options.Option; import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.api.ui.ConfigUI; +import io.github.axolotlclient.AxolotlClientConfig.api.ui.screen.ConfigScreen; import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import io.github.axolotlclient.AxolotlClientConfig.impl.options.*; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.RecreatableScreen; +import io.github.axolotlclient.AxolotlClientConfig.impl.util.ConfigStyles; import io.github.axolotlclient.AxolotlClientConfigCommon; import io.github.axolotlclient.config.screen.CreditsScreen; import io.github.axolotlclient.config.screen.ProfilesScreen; import io.github.axolotlclient.modules.Module; -import io.github.axolotlclient.util.GLFWUtil; +import io.github.axolotlclient.util.WindowAccess; import io.github.axolotlclient.util.options.ForceableBooleanOption; import io.github.axolotlclient.util.options.GenericOption; import lombok.Getter; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.options.KeyBinding; import net.ornithemc.osl.keybinds.api.KeyBindingEvents; import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import org.lwjgl.glfw.GLFW; public class AxolotlClientConfig extends AxolotlClientConfigCommon { @@ -73,7 +76,7 @@ public class AxolotlClientConfig extends AxolotlClientConfigCommon { public final ColorOption loadingScreenColor = new ColorOption("loadingBgColor", new Color(-1)); public final BooleanOption nightMode = new BooleanOption("nightMode", false); public final BooleanOption rawMouseInput = new BooleanOption("rawMouseInput", false, v -> - GLFWUtil.runUsingGlfwHandle(h -> GLFW.glfwSetInputMode(h, GLFW.GLFW_RAW_MOUSE_MOTION, v ? 1 : 0))); + WindowAccess.getInstance().setRawMouseMotion(v)); public final BooleanOption enableCustomOutlines = new BooleanOption("enabled", false); public final ColorOption outlineColor = new ColorOption("color", Color.parse("#DD000000")); @@ -136,7 +139,9 @@ public AxolotlClientConfig() { general.add(configStyle = new StringArrayOption("configStyle", themes, "configStyle." + ConfigUI.getInstance().getCurrentStyle().getName(), s -> { ConfigUI.getInstance().setStyle(s.split("\\.")[1]); - Minecraft.getInstance().openScreen(null); + + Screen newScreen = RecreatableScreen.tryRecreate(Minecraft.getInstance().screen); + Minecraft.getInstance().openScreen(newScreen); })); AxolotlClient.getInstance().getConfigManager().load(); ConfigUI.getInstance().setStyle(configStyle.get().split("\\.")[1]); @@ -175,10 +180,15 @@ public AxolotlClientConfig() { AxolotlClient.getInstance().modules.add(new Module() { @Override public void lateInit() { - if (System.getProperty("org.lwjgl.input.Mouse.disableRawInput") == null) { - System.setProperty("org.lwjgl.input.Mouse.disableRawInput", "true"); + if (WindowAccess.getInstance().rawMouseMotionAvailable()) { + + if (System.getProperty("org.lwjgl.input.Mouse.disableRawInput") == null) { + System.setProperty("org.lwjgl.input.Mouse.disableRawInput", "true"); + } + WindowAccess.getInstance().setRawMouseMotion(rawMouseInput.get()); + } else { + AxolotlClient.getInstance().getConfigManager().suppressName(rawMouseInput.getName()); } - GLFWUtil.runUsingGlfwHandle(h -> GLFW.glfwSetInputMode(h, GLFW.GLFW_RAW_MOUSE_MOTION, rawMouseInput.get() ? 1 : 0)); } }); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java index a8a54db16..92f892cbc 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java @@ -116,14 +116,13 @@ public List children() { @Environment(EnvType.CLIENT) public class ProfileEntry extends Entry { + private static final String EXPORT_BUTTON_TITLE = I18n.translate("profiles.profile.export"); private static final String CURRENT_TEXT = I18n.translate("profiles.profile.current"); private static final String LOAD_BUTTON_TITLE = I18n.translate("profiles.profile.load"); private static final String DUPLICATE_BUTTON_TITLE = I18n.translate("profiles.profile.duplicate"); private static final String REMOVE_BUTTON_TITLE = I18n.translate("profiles.profile.remove"); private final TextFieldWidget profileName; - private final ButtonWidget loadButton; - private final ButtonWidget duplicateButton; - private final ButtonWidget removeButton; + private final ButtonWidget exportButton, loadButton, duplicateButton, removeButton; private final Profiles.Profile profile; ProfileEntry(Profiles.Profile profile) { @@ -131,6 +130,8 @@ public class ProfileEntry extends Entry { profileName = new TextFieldWidget(textRenderer, 0, 0, 150, 20, ""); profileName.setText(profile.name()); profileName.setChangedListener(profile::setName); + exportButton = new VanillaButtonWidget(0, 0, 50, 20, EXPORT_BUTTON_TITLE, btn -> + Profiles.getInstance().exportProfile(profile)); loadButton = new VanillaButtonWidget(0, 0, 50, 20, LOAD_BUTTON_TITLE, btn -> Profiles.getInstance().switchTo(profile)); duplicateButton = new VanillaButtonWidget(0, 0, 50, 20, DUPLICATE_BUTTON_TITLE, b -> { @@ -160,10 +161,13 @@ public void render(int index, int top, int left, int width, int height, int mous boolean current = Profiles.getInstance().getCurrent() == profile; loadButton.setMessage(current ? CURRENT_TEXT : LOAD_BUTTON_TITLE); - loadButton.active = !current; + loadButton.active = removeButton.active = !current; i -= loadButton.getWidth(); this.loadButton.setPosition(i, j); this.loadButton.render(mouseX, mouseY, partialTick); + i -= exportButton.getWidth(); + exportButton.setPosition(i, j); + exportButton.render(mouseX, mouseY, partialTick); profileName.setWidth(i - left - 4); profileName.setPosition(left, j); profileName.render(mouseX, mouseY, partialTick); @@ -177,7 +181,7 @@ public List children() { public class NewEntry extends Entry { - private final ButtonWidget addButton; + private final ButtonWidget addButton, importButton; public NewEntry() { this.addButton = new VanillaButtonWidget(0, 0, 150, 20, I18n.translate("profiles.profile.add"), button -> { @@ -186,19 +190,23 @@ public NewEntry() { Profiles.getInstance().saveProfiles(); setScrollAmount(getMaxScroll()); }); + this.importButton = new VanillaButtonWidget(0, 0, 150, 20, I18n.translate("profiles.profile.import"), btn -> + Profiles.getInstance().importProfiles().thenRun(ProfilesList.this::reload)); } @Override public void render(int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() / 2; + int i = getScrollbarPositionX() - width / 2 - 10 - addButton.getWidth() + 2; int j = top - 2; this.addButton.setPosition(i, j); this.addButton.render(mouseX, mouseY, partialTick); + this.importButton.setPosition(addButton.getX() + addButton.getWidth() + 2, j); + this.importButton.render(mouseX, mouseY, partialTick); } @Override public List children() { - return List.of(addButton); + return List.of(addButton, importButton); } } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java index 9f19ac4f7..e4f12975a 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java @@ -37,7 +37,7 @@ public abstract class ClientPlayerEntityMixin { * @param sprintKey the sprint key that the user has bound * @return whether or not the user should try to sprint * @author DragonEggBedrockBreaking - * @license MPL-2.0 + *

License: MPL-2.0

*/ @Redirect(method = "tickAi", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/options/KeyBinding;isPressed()Z")) private boolean axolotlclient$alwaysPressed(KeyBinding sprintKey) { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/ConfigVanillaButtonWidgetMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/ConfigVanillaButtonWidgetMixin.java new file mode 100644 index 000000000..ad1ace962 --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/ConfigVanillaButtonWidgetMixin.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.ButtonWidget; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.vanilla.widgets.VanillaButtonWidget; +import io.github.axolotlclient.modules.hud.util.DrawUtil; +import io.github.axolotlclient.util.ButtonWidgetTextures; +import net.minecraft.client.Minecraft; +import net.minecraft.resource.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(VanillaButtonWidget.class) +public abstract class ConfigVanillaButtonWidgetMixin extends ButtonWidget { + private ConfigVanillaButtonWidgetMixin(int x, int y, int width, int height, String message, PressAction action) { + super(x, y, width, height, message, action); + } + + @Redirect(method = "drawWidget", at = @At(value = "INVOKE", target = "Lio/github/axolotlclient/AxolotlClientConfig/impl/ui/vanilla/widgets/VanillaButtonWidget;drawTexture(IIIIII)V", ordinal = 0)) + private void drawTexture$1(VanillaButtonWidget instance, int x, int y, int u, int v, int width, int height) { + + } + + @Redirect(method = "drawWidget", at = @At(value = "INVOKE", target = "Lio/github/axolotlclient/AxolotlClientConfig/impl/ui/vanilla/widgets/VanillaButtonWidget;drawTexture(IIIIII)V", ordinal = 1)) + private void drawTexture$2$replaceWithNineSlice(VanillaButtonWidget instance, int x, int y, int u, int v, int width, int height) { + Identifier tex = ButtonWidgetTextures.get(active ? (this.hovered ? 2 : 1) : 0); + DrawUtil.blitSprite(tex, getX(), getY(), getWidth(), getHeight(), new DrawUtil.NineSlice(200, 20, 3)); + Minecraft.getInstance().getTextureManager().bind(WIDGETS_LOCATION); + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/ConfirmScreenMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/ConfirmScreenMixin.java new file mode 100644 index 000000000..b5b79b214 --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/ConfirmScreenMixin.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import java.util.List; + +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.render.TextRenderUtils; +import net.minecraft.client.render.TextRenderer; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ConfirmScreen.class) +public abstract class ConfirmScreenMixin { + + @Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/TextRenderer;split(Ljava/lang/String;I)Ljava/util/List;")) + private List fixTextWrapFormatting(TextRenderer instance, String string, int i) { + return TextRenderUtils.wrapText(new LiteralText(string), i, instance, true, true).stream().map(Text::getFormattedString).toList(); + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java index 83f007775..fc283dae4 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java @@ -22,8 +22,8 @@ package io.github.axolotlclient.mixin; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import net.minecraft.entity.Entity; import net.minecraft.util.math.MathHelper; import org.spongepowered.asm.mixin.Mixin; @@ -52,6 +52,6 @@ public abstract class EntityMixin { pitch = (float) ((double) prevPitch - (double) pitch * 0.15); yaw = (float) ((double) prevYaw + (double) yaw * 0.15); pitch = MathHelper.clamp(pitch, -90.0F, 90.0F); - Events.PLAYER_DIRECTION_CHANGE.invoker().invoke(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); + Events.PLAYER_DIRECTION_CHANGE.invoker().accept(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java index 81991cfb8..d9ad28e83 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java @@ -58,7 +58,6 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -94,7 +93,7 @@ public abstract class GameRendererMixin { this.viewDistance = (float) (this.viewDistance * 2 + Minecraft.getInstance().player.getSourcePos().y); Entity entity = this.minecraft.getCamera(); - GL11.glFog(2918, this.setFogColor(this.fogRed, this.fogGreen, this.fogBlue, 1.0F)); + GL11.glFogfv(2918, this.setFogColor(this.fogRed, this.fogGreen, this.fogBlue, 1.0F)); GL11.glNormal3f(0.0F, -1.0F, 0.0F); GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); Block block = Camera.getBlockInside(this.minecraft.world, entity, tickDelta); @@ -197,7 +196,7 @@ public abstract class GameRendererMixin { } } - @Inject(method = "render(FJ)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;bindWrite(Z)V", shift = Shift.BEFORE)) + @Inject(method = "render(FJ)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;bindWrite(Z)V")) public void axolotlclient$worldMotionBlur(float tickDelta, long nanoTime, CallbackInfo ci) { MenuBlur.getInstance().updateBlur(); axolotlclient$postRender(tickDelta, nanoTime, null); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java index af58a8da4..2c1e9d9b7 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java @@ -22,12 +22,16 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.bridge.impl.AxoRenderContextImpl; +import io.github.axolotlclient.modules.hud.HudManager; +import io.github.axolotlclient.modules.hud.gui.hud.IconHud; import io.github.axolotlclient.modules.scrollableTooltips.ScrollableTooltips; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.inventory.menu.InventoryMenuScreen; import net.minecraft.inventory.slot.InventorySlot; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -37,6 +41,7 @@ public abstract class HandledScreenMixin { @Shadow private InventorySlot hoveredSlot; + @Unique private InventorySlot cachedSlot; @Shadow @@ -62,4 +67,12 @@ public abstract class HandledScreenMixin { private void axolotlclient$mouseClickedTail(int mouseX, int mouseY, int mouseButton, CallbackInfo ci) { moveHoveredSlotToHotbar(mouseButton - 100); } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/inventory/menu/InventoryMenuScreen;drawBackground(FII)V")) + private void renderIcon(int i, int j, float f, CallbackInfo ci) { + var hud = (IconHud) HudManager.getInstance().get(IconHud.ID); + if (hud != null && hud.isEnabled()) { + hud.renderInGui(AxoRenderContextImpl.getInstance(), f); + } + } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java index 360ddf977..998f6df97 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java @@ -173,7 +173,7 @@ protected MinecraftClientMixin(TextureManager textureManager) { } } - @Inject(method = "updateWindow", at = @At("TAIL")) + @Inject(method = "updateWindow", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;onResolutionChanged(II)V")) public void axolotlclient$onResize(CallbackInfo ci) { Util.window = null; HudManager.getInstance().refreshAllBounds(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/TextRenderUtilsMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/TextRenderUtilsMixin.java index 18b27c646..7a79e753f 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/TextRenderUtilsMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/TextRenderUtilsMixin.java @@ -31,6 +31,7 @@ import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import io.github.axolotlclient.AxolotlClient; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.client.render.TextRenderUtils; import net.minecraft.client.render.TextRenderer; @@ -44,7 +45,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(TextRenderUtils.class) -public class TextRenderUtilsMixin { +public abstract class TextRenderUtilsMixin { @Unique private static final Map formattingCodes; @@ -100,16 +101,29 @@ private static Formatting byCodeOfFirstChar(String code) { @Unique private static Text format(Text text) { - var reformatted = formatFromCodes(text.getStyle().asString()+text.getContent()); - var s = text.getStyle(); - var rS = reformatted.getStyle(); - rS.setClickEvent(s.getClickEvent()); - rS.setHoverEvent(s.getHoverEvent()); - rS.setInsertion(s.getInsertion()); - for (Text sib : text.getSiblings()) { - reformatted.append(format(sib)); + Text n = null; + for (var t : text) { + if (!t.getContent().contains("§")) { + var r = new LiteralText(t.getContent()); + r.setStyle(t.getStyle()); + if (n == null) { + n = r; + } else { + n.append(r); + t.getStyle().setParent(n.getStyle()); + } + } else { + var formatted = formatFromCodes(t.getContent()); + formatted.setStyle(t.getStyle()); + if (n == null) { + n = formatted; + } else { + n.append(formatted); + formatted.getStyle().setParent(n.getStyle()); + } + } } - return reformatted; + return n; } @Unique @@ -119,6 +133,7 @@ private static Text formatFromCodes(String formattedString) { List modifiers = new ArrayList<>(); Formatting color = null; + Integer br$color = null; for (int i = 0, length = arr.length; i < length; i++) { String s = arr[i]; if (s.isEmpty()) { @@ -128,28 +143,37 @@ private static Text formatFromCodes(String formattedString) { continue; } Formatting formatting = byCodeOfFirstChar(s); - if (formatting == null) { - text.append(s); - continue; - } - Text part; int pL = s.length(); - if (formatting.equals(Formatting.RESET)) { - modifiers.clear(); - color = null; - } else if (formatting.isModifier()) { - modifiers.add(formatting); + int formatLength = 1; + if (formatting == null) { + if (s.toLowerCase(Locale.ROOT).charAt(0) == '#') { + br$color = Color.parse(s.substring(0, 7)).toInt(); + formatLength = 7; + } else { + text.append(s); + continue; + } } else { - color = formatting; + if (formatting.equals(Formatting.RESET)) { + modifiers.clear(); + color = null; + } else if (formatting.isModifier()) { + modifiers.add(formatting); + } else { + color = formatting; + } } if (pL == 1) { continue; } - part = new LiteralText(s.substring(1)); + part = new LiteralText(s.substring(formatLength)); if (color != null) { - part.getStyle().setColor(color); + part.setStyle(part.getStyle().setColor(color)); + } + if (br$color != null) { + part.br$setStyle(part.getStyle().br$color(br$color)); } if (!modifiers.isEmpty()) { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java index 7247d5289..0fd0cea42 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java @@ -45,7 +45,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ @Mixin(WorldRenderer.class) diff --git a/1.8.9/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java b/1.8.9/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java index a24268bb2..cdce756e4 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java @@ -44,7 +44,7 @@ import org.spongepowered.asm.mixin.injection.invoke.arg.Args; @Mixin(MultiplayerScreen.class) -public class JoinMulitplayerScreenMixin extends Screen { +public abstract class JoinMulitplayerScreenMixin extends Screen { @Shadow private Screen parent; diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java index a8ec67039..2476a5971 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java @@ -27,6 +27,7 @@ import com.mojang.blaze3d.platform.GlStateManager; import io.github.axolotlclient.modules.hud.util.DrawUtil; +import lombok.Getter; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -95,6 +96,7 @@ public static class Entry extends DrawUtil implements EntryListWidget.Entry { private static final Identifier warningSign = new Identifier("axolotlclient", "textures/warning.png"); private final AccountsScreen screen; + @Getter private final Account account; private final Minecraft client; private long time; @@ -150,8 +152,5 @@ public void mouseReleased(int i, int j, int k, int l, int m, int n) { } - public Account getAccount() { - return account; - } } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java index 84b0896a3..a3d64b909 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/AccountsScreen.java @@ -22,6 +22,7 @@ package io.github.axolotlclient.modules.auth; +import io.github.axolotlclient.modules.auth.skin.SkinManagementScreen; import net.minecraft.client.gui.screen.ConfirmScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; @@ -35,6 +36,7 @@ public class AccountsScreen extends Screen { private ButtonWidget loginButton; private ButtonWidget deleteButton; private ButtonWidget refreshButton; + private ButtonWidget skinsButton; public AccountsScreen(Screen currentScreen) { title = I18n.translate("accounts"); @@ -112,13 +114,17 @@ protected void buttonClicked(ButtonWidget buttonWidget) { login(); break; case 2: + minecraft.openScreen(new SkinManagementScreen( + this, accountsListWidget.getSelectedEntry().getAccount())); + break; + case 3: if (Auth.getInstance().allowOfflineAccounts()) { minecraft.openScreen(new ConfirmScreen(this, I18n.translate("auth.add.choose"), "", I18n.translate("auth.add.offline"), I18n.translate("auth.add.ms"), 234)); } else { initMSAuth(); } break; - case 3: + case 4: AccountsListWidget.Entry entry = this.accountsListWidget.getSelectedEntry(); if (entry != null) { buttonWidget.active = false; @@ -126,7 +132,7 @@ protected void buttonClicked(ButtonWidget buttonWidget) { refresh(); } break; - case 4: + case 5: refreshAccount(); break; } @@ -139,14 +145,16 @@ public void init() { accountsListWidget.setAccounts(Auth.getInstance().getAccounts()); - buttons.add(loginButton = new ButtonWidget(1, this.width / 2 - 154, this.height - 52, 150, 20, I18n.translate("auth.login"))); + buttons.add(loginButton = new ButtonWidget(1, this.width / 2 - 154, this.height - 52, 100, 20, I18n.translate("auth.login"))); + + buttons.add(skinsButton = new ButtonWidget(2, this.width / 2 - 50, this.height - 52, 100, 20, I18n.translate("skins.manage"))); - this.buttons.add(new ButtonWidget(2, this.width / 2 + 4, this.height - 52, 150, 20, I18n.translate("auth.add"))); + this.buttons.add(new ButtonWidget(3, this.width / 2 + 4 + 50, this.height - 52, 100, 20, I18n.translate("auth.add"))); - this.buttons.add(this.deleteButton = new ButtonWidget(3, this.width / 2 - 50, this.height - 28, 100, 20, I18n.translate("selectServer.delete"))); + this.buttons.add(this.deleteButton = new ButtonWidget(4, this.width / 2 - 50, this.height - 28, 100, 20, I18n.translate("selectServer.delete"))); - this.buttons.add(refreshButton = new ButtonWidget(4, this.width / 2 - 154, this.height - 28, 100, 20, + this.buttons.add(refreshButton = new ButtonWidget(5, this.width / 2 - 154, this.height - 28, 100, 20, I18n.translate("auth.refresh"))); this.buttons.add(new ButtonWidget(0, this.width / 2 + 4 + 50, this.height - 28, 100, 20, @@ -190,9 +198,10 @@ private void updateButtonActivationStates() { AccountsListWidget.Entry entry = accountsListWidget.getSelectedEntry(); if (minecraft.world == null && entry != null) { loginButton.active = entry.getAccount().isExpired() || !entry.getAccount().equals(Auth.getInstance().getCurrent()); - deleteButton.active = refreshButton.active = true; + refreshButton.active = skinsButton.active = !entry.getAccount().isOffline(); + deleteButton.active = true; } else { - loginButton.active = deleteButton.active = refreshButton.active = false; + loginButton.active = deleteButton.active = refreshButton.active = skinsButton.active = false; } } @@ -205,17 +214,14 @@ private void login() { } private void initMSAuth() { - Auth.getInstance().getAuth().startDeviceAuth().thenRun(() -> minecraft.submit(this::refresh)); + Auth.getInstance().getMsApi().startDeviceAuth().thenRun(() -> minecraft.submit(this::refresh)); } private void refreshAccount() { refreshButton.active = false; AccountsListWidget.Entry entry = accountsListWidget.getSelectedEntry(); if (entry != null) { - entry.getAccount().refresh(Auth.getInstance().getAuth()).thenRun(() -> minecraft.submit(() -> { - Auth.getInstance().save(); - refresh(); - })); + entry.getAccount().refresh(Auth.getInstance().getMsApi()); } } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/Auth.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/Auth.java index 15af0131a..976e33ddb 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/Auth.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/Auth.java @@ -23,17 +23,18 @@ package io.github.axolotlclient.modules.auth; import java.util.*; +import java.util.concurrent.CompletableFuture; import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftProfileTexture; import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.api.API; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.UUIDHelper; import io.github.axolotlclient.mixin.MinecraftClientAccessor; import io.github.axolotlclient.modules.Module; +import io.github.axolotlclient.modules.auth.skin.SkinManager; import io.github.axolotlclient.util.ThreadExecuter; import io.github.axolotlclient.util.notifications.Notifications; import io.github.axolotlclient.util.options.GenericOption; @@ -50,19 +51,20 @@ public class Auth extends Accounts implements Module { @Getter private static final Auth Instance = new Auth(); - public final BooleanOption showButton = new BooleanOption("auth.showButton", false); + public final BooleanOption skinManagerAnimations = new BooleanOption("skins.manage.animations", true); private final Minecraft client = Minecraft.getInstance(); private final GenericOption viewAccounts = new GenericOption("viewAccounts", "clickToOpen", () -> client.openScreen(new AccountsScreen(client.screen))); - private final Map textures = new HashMap<>(); private final Set loadingTexture = new HashSet<>(); private final Map profileCache = new WeakHashMap<>(); + @Getter + private final SkinManager skinManager = new SkinManager(); @Override public void init() { load(); - this.auth = new MSAuth(AxolotlClient.LOGGER, this, () -> client.options.language); + this.msApi = new MSApi(this, () -> client.options.language); if (isContained(client.getSession().getUuid())) { current = getAccounts().stream().filter(account -> account.getUuid().equals(client.getSession().getUuid())).toList().get(0); current.setAuthToken(client.getSession().getAccessToken()); @@ -74,7 +76,6 @@ public void init() { current = new Account(client.getSession().getUsername(), client.getSession().getUuid(), client.getSession().getAccessToken()); } - OptionCategory category = OptionCategory.create("auth"); category.add(showButton, viewAccounts); AxolotlClient.config().general.add(category); } @@ -89,11 +90,11 @@ protected void login(Account account) { if (account.isExpired()) { Notifications.getInstance().addStatus("auth.notif.title", "auth.notif.refreshing", account.getName()); } - account.refresh(auth).thenAccept(res -> res.ifPresent(a -> { + account.refresh(msApi).thenAccept(a -> { if (!a.isExpired()) { login(a); } - })).thenRun(this::save); + }).thenRun(this::save); } else { try { API.getInstance().shutdown(); @@ -140,14 +141,18 @@ public void loadTextures(String uuid, String name) { } @Override - void showAccountsExpiredScreen(Account account) { + CompletableFuture showAccountsExpiredScreen(Account account) { Screen current = client.screen; + var fut = new CompletableFuture(); client.submit(() -> client.openScreen(new ConfirmScreen((bl, i) -> { - client.openScreen(current); if (bl) { - auth.startDeviceAuth(); + msApi.startDeviceAuth().thenRun(() -> fut.complete(account)); + } else { + fut.cancel(true); } + client.openScreen(current); }, I18n.translate("auth"), I18n.translate("auth.accountExpiredNotice", account.getName()), 1))); + return fut; } @Override diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java new file mode 100644 index 000000000..e087668d6 --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; + +public class LoadingScreen extends Screen { + private final String description; + private final String title; + + public LoadingScreen(String title, String description) { + super(); + this.title = title; + this.description = description; + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + renderBackground(); + drawCenteredString(textRenderer, title, width / 2, 33 / 2 - textRenderer.fontHeight / 2, -1); + int centerX = width / 2; + int centerY = height / 2; + var text = description; + textRenderer.draw(text, centerX - textRenderer.getWidth(text) / 2, centerY - 9, -1); + String string = switch ((int) (Minecraft.getTime() / 300L % 4L)) { + case 1, 3 -> "o O o"; + case 2 -> "o o O"; + default -> "O o o"; + }; + textRenderer.draw(string, centerX - textRenderer.getWidth(string) / 2, centerY + 9, 0xFF808080); + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java new file mode 100644 index 000000000..2305697cd --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java @@ -0,0 +1,907 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tessellator; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Colors; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.ClickableWidget; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.Element; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.ParentElement; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.vanilla.ElementListWidget; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.vanilla.widgets.VanillaButtonWidget; +import io.github.axolotlclient.api.SimpleTextInputScreen; +import io.github.axolotlclient.api.util.UUIDHelper; +import io.github.axolotlclient.bridge.util.AxoText; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import io.github.axolotlclient.modules.hud.util.DrawUtil; +import io.github.axolotlclient.util.ButtonWidgetTextures; +import io.github.axolotlclient.util.ClientColors; +import io.github.axolotlclient.util.Watcher; +import io.github.axolotlclient.util.notifications.Notifications; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.render.TextRenderer; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.resource.Identifier; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SkinManagementScreen extends io.github.axolotlclient.AxolotlClientConfig.impl.ui.Screen { + private static final Path SKINS_DIR = FabricLoader.getInstance().getGameDir().resolve("skins"); + private static final int LIST_SKIN_WIDTH = 75; + private static final int LIST_SKIN_HEIGHT = 110; + private static final String TEXT_EQUIPPING = I18n.translate("skins.manage.equipping"); + private final Screen parent; + private final Account account; + private MSApi.MCProfile cachedProfile; + private SkinListWidget skinList; + private SkinListWidget capesList; + private boolean capesTab; + private SkinWidget current; + private final Watcher skinDirWatcher; + private final CompletableFuture loadingFuture; + private String tooltip = null; + + public SkinManagementScreen(Screen parent, Account account) { + super(I18n.translate("skins.manage")); + this.parent = parent; + this.account = account; + skinDirWatcher = Watcher.createSelfTicking(SKINS_DIR, () -> { + AxolotlClientCommon.getInstance().getLogger().info("Reloading screen as local files changed!"); + loadSkinsList(); + }); + loadingFuture = (account.needsRefresh() ? account.refresh(Auth.getInstance().getMsApi()) + : CompletableFuture.completedFuture(null)) + .thenComposeAsync(unused -> Auth.getInstance().getMsApi().getProfile(account)); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + tooltip = null; + super.render(mouseX, mouseY, delta); + if (tooltip != null) { + renderTooltip(tooltip, mouseX, mouseY + 20); + Lighting.turnOff(); + } + } + + @Override + public void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + class TextWidget extends ClickableWidget { + + public TextWidget(int x, int y, int width, int height, String message) { + super(x, y, width, height, message); + active = false; + } + + @Override + public void drawWidget(int mouseX, int mouseY, float delta) { + drawCenteredString(textRenderer, getMessage(), getX() + getWidth() / 2, getY() + getHeight() / 2 - textRenderer.fontHeight / 2, -1); + } + } + + var titleWidget = new TextWidget(0, headerHeight / 2 - textRenderer.fontHeight / 2, width, textRenderer.fontHeight, getTitle()); + addDrawableChild(titleWidget); + + var back = addDrawableChild(new VanillaButtonWidget(width / 2 - 75, height - headerHeight / 2 - 10, 150, 20, I18n.translate("gui.back"), btn -> closeScreen())); + + var loadingPlaceholder = new ClickableWidget(0, headerHeight, width, contentHeight, I18n.translate("skins.loading")) { + @Override + protected void drawWidget(int mouseX, int mouseY, float delta) { + int centerX = this.getX() + this.getWidth() / 2; + int centerY = this.getY() + this.getHeight() / 2; + var text = this.getMessage(); + textRenderer.draw(text, centerX - textRenderer.getWidth(text) / 2f, centerY - 9, -1, false); + String string = switch ((int) (System.currentTimeMillis() / 300L % 4L)) { + case 1, 3 -> "o O o"; + case 2 -> "o o O"; + default -> "O o o"; + }; + textRenderer.draw(string, centerX - textRenderer.getWidth(string) / 2f, centerY + 9, 0xFF808080, false); + } + }; + loadingPlaceholder.active = false; + addDrawableChild(loadingPlaceholder); + addDrawableChild(back); + + skinList = new SkinListWidget(minecraft, width / 2, contentHeight - 24, headerHeight + 24, LIST_SKIN_HEIGHT + 34); + capesList = new SkinListWidget(minecraft, width / 2, contentHeight - 24, headerHeight + 24, skinList.getEntryContentsHeight() + 24); + skinList.setLeftPos(width / 2); + capesList.setLeftPos(width / 2); + var currentHeight = Math.min((width / 2f) * 120 / 85, contentHeight); + var currentWidth = currentHeight * 85 / 120; + current = new SkinWidget((int) currentWidth, (int) currentHeight, null, account); + current.setPosition((int) (width / 4f - currentWidth / 2), (int) (height / 2f - currentHeight / 2)); + + if (!capesTab) { + capesList.visible = capesList.active = false; + } else { + skinList.visible = skinList.active = false; + } + List navBar = new ArrayList<>(); + var skinsTab = new VanillaButtonWidget(Math.max(width * 3 / 4 - 102, width / 2 + 2), headerHeight, Math.min(100, width / 4 - 2), 20, I18n.translate("skins.nav.skins"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = true; + capesList.visible = capesList.active = false; + capesTab = false; + }); + navBar.add(skinsTab); + var capesTab = new VanillaButtonWidget(width * 3 / 4 + 2, headerHeight, Math.min(100, width / 4 - 2), 20, I18n.translate("skins.nav.capes"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = false; + capesList.visible = capesList.active = true; + this.capesTab = true; + }); + navBar.add(capesTab); + var importButton = new SpriteButton(I18n.translate("skins.manage.import.local"), btn -> { + btn.active = false; + SkinImportUtil.openImportSkinDialog().thenAccept(this::onFileDrop).thenRun(() -> btn.active = true); + }, new Identifier("axolotlclient", "textures/gui/sprites/folder.png")); + var downloadButton = new SpriteButton(I18n.translate("skins.manage.import.online"), btn -> { + btn.active = false; + promptForSkinDownload(); + }, new Identifier("axolotlclient", "textures/gui/sprites/download.png")); + if (width - (capesTab.getX() + capesTab.getWidth()) > 28) { + importButton.setX(width - importButton.getWidth() - 2); + downloadButton.setX(importButton.getX() - downloadButton.getWidth() - 2); + importButton.setY(capesTab.getY() + capesTab.getHeight() - 11); + downloadButton.setY(importButton.getY()); + } else { + importButton.setX(capesTab.getX() + capesTab.getWidth() - 11); + importButton.setY(capesTab.getY() - 13); + downloadButton.setX(importButton.getX() - 2 - 11); + downloadButton.setY(importButton.getY()); + } + skinsTab.active = this.capesTab; + capesTab.active = !this.capesTab; + Runnable addWidgets = () -> { + clearChildren(); + addDrawableChild(titleWidget); + addDrawableChild(current); + addDrawableChild(skinList); + addDrawableChild(capesList); + addDrawableChild(skinsTab); + addDrawableChild(capesTab); + addDrawableChild(downloadButton); + addDrawableChild(importButton); + addDrawableChild(back); + }; + if (cachedProfile != null) { + initDisplay(); + addWidgets.run(); + return; + } + loadingFuture.thenAcceptAsync(profile -> { + cachedProfile = profile; + initDisplay(); + addWidgets.run(); + }).exceptionally(t -> { + if (t.getCause() instanceof CancellationException) { + minecraft.openScreen(parent); + return null; + } + AxolotlClientCommon.getInstance().getLogger().error("Failed to load skins!", t); + var error = I18n.translate("skins.error.failed_to_load"); + var errorDesc = I18n.translate("skins.error.failed_to_load_desc"); + clearChildren(); + addDrawableChild(titleWidget); + + addDrawableChild(new TextWidget(width / 2 - textRenderer.getWidth(error) / 2, height / 2 - textRenderer.fontHeight - 2, textRenderer.getWidth(error), textRenderer.fontHeight, error)); + addDrawableChild(new TextWidget(width / 2 - textRenderer.getWidth(errorDesc) / 2, height / 2 + 1, textRenderer.getWidth(errorDesc), textRenderer.fontHeight, errorDesc)); + addDrawableChild(back); + return null; + }); + } + + private void promptForSkinDownload() { + minecraft.openScreen(new SimpleTextInputScreen(this, I18n.translate("skins.manage.import.online"), I18n.translate("skins.manage.import.online.input"), s -> + UUIDHelper.ensureUuidOpt(s).thenAccept(o -> { + if (o.isPresent()) { + AxolotlClientCommon.getInstance().getLogger().info("Downloading skin of {} ({})", s, o.get()); + Auth.getInstance().getMsApi().getTextures(o.get()) + .exceptionally(th -> { + AxolotlClientCommon.getInstance().getLogger().info("Failed to download skin of {} ({})", s, o.get(), th); + return null; + }).thenAccept(t -> { + if (t == null) { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_download", s); + return; + } + try { + var bytes = t.skin().join(); + var out = ensureNonexistent(SKINS_DIR.resolve(t.skinKey())); + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, t.classicModel(), "name", t.name(), "uuid", t.id(), "download_time", Instant.now())); + Files.write(out, bytes); + minecraft.submit(this::loadSkinsList); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.downloaded", t.name()); + AxolotlClientCommon.getInstance().getLogger().info("Downloaded skin of {} ({})", t.name(), o.get()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to write skin file", e); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_save", t.name()); + } + }); + } else { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.not_found", s); + } + }))); + } + + private void initDisplay() { + loadSkinsList(); + loadCapesList(); + } + + private void refreshCurrentList() { + if (capesTab) { + var scroll = capesList.getScrollAmount(); + loadCapesList(); + capesList.setScrollAmount(scroll); + } else { + var scroll = skinList.getScrollAmount(); + loadSkinsList(); + skinList.setScrollAmount(scroll); + } + } + + private void loadCapesList() { + List rows = new ArrayList<>(); + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + var capes = profile.capes(); + var deselectCape = createWidgetForCape(current.getSkin(), null); + var activeCape = capes.stream().filter(Cape::active).findFirst(); + current.setCape(activeCape.orElse(null)); + deselectCape.noCape(activeCape.isEmpty()); + for (int i = 0; i < capes.size() + 1; i += columns) { + Entry widget; + if (i == 0) { + widget = createEntry(capesList.getEntryContentsHeight(), deselectCape, I18n.translate("skins.capes.no_cape")); + } else { + var cape = capes.get(i - 1); + widget = createEntryForCape(current.getSkin(), cape, capesList.getEntryContentsHeight()); + } + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < capes.size() + 1 - c)) continue; + var cape2 = capes.get(i + c - 1); + Entry widget2 = createEntryForCape(current.getSkin(), cape2, capesList.getEntryContentsHeight()); + + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + minecraft.submit(() -> capesList.replaceEntries(rows)); + } + + private void loadSkinsList() { + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + List skins = new ArrayList<>(profile.skins()); + var hashes = skins.stream().map(Asset::sha256).collect(Collectors.toSet()); + var defaultSkin = Skin.getDefaultSkin(account); + var local = new ArrayList<>(loadLocalSkins()); + var localHashes = local.stream().collect(Collectors.toMap(Asset::sha256, Function.identity(), (skin, skin2) -> skin)); + local.removeIf(s -> !localHashes.containsValue(s)); + skins.replaceAll(s -> { + if (s instanceof MSApi.MCProfile.OnlineSkin online) { + if (localHashes.containsKey(s.sha256()) && localHashes.get(s.sha256()) instanceof Skin.LocalSkin file) { + local.remove(localHashes.remove(s.sha256())); + return new Skin.Shared(file, online); + } + } + return s; + }); + skins.addAll(local); + if (!hashes.contains(defaultSkin.sha256())) { + skins.add(defaultSkin); + } + populateSkinList(skins, columns); + } + + private List loadLocalSkins() { + try { + Files.createDirectories(SKINS_DIR); + try (Stream skins = Files.list(SKINS_DIR)) { + return skins.filter(Files::isRegularFile).sorted(Comparator.comparingLong(p -> { + try { + return Files.getLastModifiedTime(p).toMillis(); + } catch (IOException e) { + return 0L; + } + }).reversed()).map(Auth.getInstance().getSkinManager()::read).filter(Objects::nonNull).toList(); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to read skins dir!", e); + } + return Collections.emptyList(); + } + + private void populateSkinList(List skins, int columns) { + int entryHeight = skinList.getEntryContentsHeight(); + List rows = new ArrayList<>(); + for (int i = 0; i < skins.size(); i += columns) { + var s = skins.get(i); + if (s != null && s.active()) { + current.setSkin(s); + } + var widget = createEntryForSkin(s, entryHeight); + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < skins.size() - c)) continue; + var s2 = skins.get(i + c); + if (s2 != null && s2.active()) { + current.setSkin(s2); + } + var widget2 = createEntryForSkin(s2, entryHeight); + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + minecraft.submit(() -> skinList.replaceEntries(rows)); + } + + private Path ensureNonexistent(Path p) { + if (Files.exists(p)) { + int counter = 0; + do { + counter++; + p = p.resolveSibling(p.getFileName().toString() + "_" + counter); + } while (Files.exists(p)); + } + return p; + } + + @Override + public void onFileDrop(List packs) { + if (packs.isEmpty()) return; + + CompletableFuture[] futs = new CompletableFuture[packs.size()]; + for (int i = 0; i < packs.size(); i++) { + Path p = packs.get(i); + futs[i] = CompletableFuture.runAsync(() -> { + try { + var target = ensureNonexistent(SKINS_DIR.resolve(p.getFileName())); + var skin = Auth.getInstance().getSkinManager().read(p, false); + if (skin != null) { + Files.write(target, skin.image()); + } else { + AxolotlClientCommon.getInstance().getLogger().info("Skipping dragged file {} because it does not seem to be a valid skin!", p); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.not_copied", p.getFileName()); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to copy skin file: ", e); + } + }, minecraft); + } + CompletableFuture.allOf(futs).thenRun(this::loadSkinsList); + } + + private @NotNull Entry createEntryForSkin(Skin skin, int entryHeight) { + return createEntry(entryHeight, new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, skin, account)); + } + + private @NotNull Entry createEntryForCape(Skin currentSkin, Cape cape, int entryHeight) { + return createEntry(entryHeight, createWidgetForCape(currentSkin, cape), I18n.translate(cape.alias())); + } + + private SkinWidget createWidgetForCape(Skin currentSkin, Cape cape) { + SkinWidget widget2 = new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, currentSkin, cape, account); + widget2.setRotationY(210); + return widget2; + } + + @Override + public void clearAndInit() { + Auth.getInstance().getSkinManager().releaseAll(); + super.clearAndInit(); + } + + @Override + public void removed() { + Auth.getInstance().getSkinManager().releaseAll(); + Watcher.close(skinDirWatcher); + } + + public void closeScreen() { + minecraft.openScreen(parent); + } + + private SkinListWidget getCurrentList() { + return capesTab ? capesList : skinList; + } + + private class SkinListWidget extends ElementListWidget { + public boolean active = true, visible = true; + + public SkinListWidget(Minecraft minecraft, int width, int height, int y, int entryHeight) { + super(minecraft, width, SkinManagementScreen.this.height, y, y + height, entryHeight); + setRenderHeader(false, 0); + setRenderBackground(false); + setRenderHorizontalShadows(false); + } + + @Override + protected int getScrollbarPositionX() { + return right - 8; + } + + @Override + public int getRowLeft() { + return left + 3; + } + + @Override + public int getRowWidth() { + if (!(getMaxScroll() > 0)) { + return width - 4; + } + return width - 14; + } + + public int getEntryContentsHeight() { + return itemHeight - 4; + } + + @Override + public void replaceEntries(Collection newEntries) { + super.replaceEntries(newEntries); + } + + @Override + public void centerScrollOn(Row entry) { + super.centerScrollOn(entry); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amountX, double amountY) { + if (!visible) return false; + return super.mouseScrolled(mouseX, mouseY, amountX, amountY); + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + return active && visible && super.isMouseOver(mouseX, mouseY); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + if (!visible) return; + super.render(mouseX, mouseY, delta); + renderGradient(); + } + + private void renderGradient() { + GlStateManager.depthFunc(515); + GlStateManager.disableDepthTest(); + GlStateManager.enableBlend(); + GlStateManager.blendFuncSeparate(770, 771, 0, 1); + GlStateManager.disableAlphaTest(); + GlStateManager.shadeModel(7425); + GlStateManager.disableTexture(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture(); + var tessellator = Tessellator.getInstance(); + var bufferBuilder = tessellator.getBuilder(); + bufferBuilder.begin(7, DefaultVertexFormat.POSITION_TEX_COLOR); + bufferBuilder.vertex(left, top + 4, 0.0F).texture(0.0F, 1.0F).color(0, 0, 0, 0).nextVertex(); + bufferBuilder.vertex(right, top + 4, 0.0F).texture(1.0F, 1.0F).color(0, 0, 0, 0).nextVertex(); + bufferBuilder.vertex(right, top, 0.0F).texture(1.0F, 0.0F).color(0, 0, 0, 255).nextVertex(); + bufferBuilder.vertex(left, top, 0.0F).texture(0.0F, 0.0F).color(0, 0, 0, 255).nextVertex(); + tessellator.end(); + bufferBuilder.begin(7, DefaultVertexFormat.POSITION_TEX_COLOR); + bufferBuilder.vertex(this.left, this.bottom, 0.0F).texture(0.0F, 1.0F).color(0, 0, 0, 255).nextVertex(); + bufferBuilder.vertex(this.right, this.bottom, 0.0F).texture(1.0F, 1.0F).color(0, 0, 0, 255).nextVertex(); + bufferBuilder.vertex(this.right, this.bottom - 4, 0.0F).texture(1.0F, 0.0F).color(0, 0, 0, 0).nextVertex(); + bufferBuilder.vertex(this.left, this.bottom - 4, 0.0F).texture(0.0F, 0.0F).color(0, 0, 0, 0).nextVertex(); + tessellator.end(); + GlStateManager.enableTexture(); + } + } + + private class Row extends ElementListWidget.Entry { + private final List widgets; + + public Row(List entries) { + this.widgets = entries; + } + + @Override + public void render(int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + int x = left; + if (widgets.isEmpty()) return; + int count = widgets.size(); + int padding = ((width - 5 * (count - 1)) / count); + for (var w : widgets) { + w.setPosition(x, top); + w.setWidth(padding); + w.render(mouseX, mouseY, partialTick); + x += w.getWidth() + 5; + } + } + + @Override + public @NotNull List children() { + return widgets; + } + + @Override + public void setFocusedChild(@Nullable Element focused) { + super.setFocusedChild(focused); + if (focused != null) { + getCurrentList().centerScrollOn(this); + } + } + } + + Entry createEntry(int height, SkinWidget widget) { + return createEntry(height, widget, null); + } + + Entry createEntry(int height, SkinWidget widget, String label) { + return new Entry(height, widget, label); + } + + private class Entry extends ClickableWidget implements ParentElement { + private final SkinWidget skinWidget; + private final @Nullable ClickableWidget label; + private final List actionButtons = new ArrayList<>(); + private final ClickableWidget equipButton; + private boolean equipping; + private long equippingStart; + @Nullable + private Element focused; + private boolean dragging; + + public Entry(int height, SkinWidget widget, @Nullable String label) { + super(0, 0, widget.getWidth(), height, ""); + widget.setWidth(getWidth() - 4); + var asset = widget.getFocusedAsset(); + if (asset != null) { + if (asset instanceof Skin skin) { + var wideSprite = new Identifier("axolotlclient", "textures/gui/sprites/wide.png"); + var slimSprite = new Identifier("axolotlclient", "textures/gui/sprites/slim.png"); + var slimText = I18n.translate("skins.manage.variant.classic"); + var wideText = I18n.translate("skins.manage.variant.slim"); + actionButtons.add(new SpriteButton(skin.classicVariant() ? wideText : slimText, btn -> { + var self = (SpriteButton) btn; + skin.classicVariant(!skin.classicVariant()); + self.sprite = skin.classicVariant() ? slimSprite : wideSprite; + self.setMessage(skin.classicVariant() ? wideText : slimText); + }, skin.classicVariant() ? slimSprite : wideSprite)); + } + if (asset instanceof Asset.Local local) { + this.actionButtons.add(new SpriteButton(I18n.translate("skins.manage.delete"), btn -> { + btn.active = false; + client.openScreen(new ConfirmScreen((confirmed, i) -> { + client.openScreen(new LoadingScreen(getTitle(), I18n.translate("menu.working"))); + if (confirmed) { + try { + Files.delete(local.file()); + Skin.LocalSkin.deleteMetadata(local.file()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to delete: ", e); + } + } + client.openScreen(SkinManagementScreen.this); + btn.active = true; + }, I18n.translate("skins.manage.delete.confirm"), ((Text) (asset.active() ? + AxoText.translatable("skins.manage.delete.confirm.desc_active") : + AxoText.translatable("skins.manage.delete.confirm.desc") + ).br$color(Colors.RED.toInt())).getFormattedString(), 0)); + }, new Identifier("axolotlclient", "textures/gui/sprites/delete.png"))); + } + if (asset instanceof Asset.Online online && online.supportsDownload() && !(asset instanceof Asset.Local)) { + this.actionButtons.add(new SpriteButton(I18n.translate("skins.manage.download"), btn -> { + btn.active = false; + download(asset).thenRun(() -> { + refreshCurrentList(); + btn.active = true; + }); + }, new Identifier("axolotlclient", "textures/gui/sprites/download.png"))); + } + } + if (label != null) { + this.label = new ClickableWidget(0, 0, widget.getWidth(), 16, label) { + @Override + protected void drawWidget(int mouseX, int mouseY, float partialTick) { + DrawUtil.drawScrollableText(textRenderer, getMessage(), getX() + 2, getY(), getX() + getWidth() - 2, getY() + getHeight(), -1); + } + }; + this.label.active = false; + } else { + this.label = null; + } + this.equipButton = new VanillaButtonWidget(0, 0, widget.getWidth(), 20, I18n.translate( + widget.isEquipped() ? "skins.manage.equipped" : "skins.manage.equip"), + btn -> { + equippingStart = System.currentTimeMillis(); + equipping = true; + btn.setMessage(TEXT_EQUIPPING); + btn.active = false; + Consumer> consumer = f -> f.thenAcceptAsync(p -> { + cachedProfile = p; + if (client.screen == SkinManagementScreen.this) { + refreshCurrentList(); + } else { + client.submit(() -> client.openScreen(SkinManagementScreen.this)); + } + }).exceptionally(t -> { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to equip asset!", t); + equipping = false; + return null; + }); + if (asset instanceof Skin && !(current.getSkin() instanceof Skin.Local)) { + client.openScreen(new ConfirmScreen((confirmed, i) -> { + client.openScreen(new LoadingScreen(getTitle(), TEXT_EQUIPPING)); + if (confirmed) { + consumer.accept(download(current.getSkin()).thenCompose(a -> widget.equip())); + } else { + consumer.accept(widget.equip()); + } + }, I18n.translate("skins.manage.equip.confirm"), I18n.translate("skins.manage.equip.download_current"), 0)); + } else { + consumer.accept(widget.equip()); + } + }); + this.equipButton.active = !widget.isEquipped(); + this.skinWidget = widget; + } + + private @NotNull CompletableFuture download(Asset asset) { + return CompletableFuture.runAsync(() -> { + try { + var out = SKINS_DIR.resolve(asset.sha256()); + Files.createDirectories(out.getParent()); + Files.write(out, asset.image()); + if (asset instanceof Skin skin) { + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, skin.classicVariant())); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to download: ", e); + } + }); + } + + @Override + public final boolean isDragging() { + return this.dragging; + } + + @Override + public final void setDragging(boolean dragging) { + this.dragging = dragging; + } + + @Nullable + @Override + public Element getFocused() { + return this.focused; + } + + @Override + public void setFocusedChild(@Nullable Element child) { + if (this.focused != null) { + this.focused.setFocused(false); + } + + if (child != null) { + child.setFocused(true); + } + + this.focused = child; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return ParentElement.super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return ParentElement.super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + return ParentElement.super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean isFocused() { + return ParentElement.super.isFocused(); + } + + @Override + public void setFocused(boolean focused) { + ParentElement.super.setFocused(focused); + } + + @Override + public @NotNull List children() { + return Stream.concat(actionButtons.stream(), Stream.of(skinWidget, label, equipButton)).filter(Objects::nonNull).toList(); + } + + private float applyEasing(float x) { + return x * x * x; + } + + @Override + protected void drawWidget(int mouseX, int mouseY, float partialTick) { + int y = getY() + 4; + int x = getX() + 2; + skinWidget.setPosition(x, y); + skinWidget.setWidth(getWidth() - 4); + if (skinWidget.isEquipped() || equipping) { + long prog; + if (Auth.getInstance().skinManagerAnimations.get()) { + if (equipping) prog = (System.currentTimeMillis() - equippingStart) / 20 % 100; + else prog = Math.abs((System.currentTimeMillis() / 30 % 200) - 100); + } else prog = 100; + var percent = (prog / 100f); + float gradientWidth; + if (equipping) { + gradientWidth = percent * Math.min(getWidth() / 3f, getHeight() / 3f); + } else { + gradientWidth = Math.min(getWidth() / 15f, getHeight() / 6f) + applyEasing(percent) * Math.min(getWidth() * 2 / 15f, getHeight() / 6f); + } + GradientHoleRectangleRenderState.render(getX() + 2, getY() + 2, getX() + getWidth() - 2, + skinWidget.getY() + skinWidget.getHeight() + 2, + gradientWidth, + equipping ? 0xFFFF0088 : ClientColors.SELECTOR_GREEN.toInt(), 0); + } + skinWidget.render(mouseX, mouseY, partialTick); + int actionButtonY = getY() + 2; + for (var button : actionButtons) { + button.setPosition(skinWidget.getX() + skinWidget.getWidth() - button.getWidth(), actionButtonY); + if (isHovered() || button.isHovered()) { + button.render(mouseX, mouseY, partialTick); + } + actionButtonY += button.getHeight() + 2; + } + if (label != null) { + label.setPosition(x, skinWidget.getY() + skinWidget.getHeight() + 6); + label.render(mouseX, mouseY, partialTick); + label.setWidth(getWidth() - 4); + equipButton.setPosition(x, label.getY() + label.getHeight() + 2); + } else { + equipButton.setPosition(x, skinWidget.getY() + skinWidget.getHeight() + 4); + } + equipButton.setWidth(getWidth() - 4); + equipButton.render(mouseX, mouseY, partialTick); + + if (isHovered()) { + DrawUtil.outlineRect(getX(), getY(), getWidth(), getHeight(), -1); + } + } + + private static class GradientHoleRectangleRenderState { + + public static void render(int x0, int y0, int x1, int y1, float gradientWidth, int col1, int col2) { + var tess = Tessellator.getInstance(); + var vertexConsumer = tess.getBuilder(); + float z = 0; + int a1 = ClientColors.ARGB.alpha(col1); + int r1 = ClientColors.ARGB.red(col1); + int g1 = ClientColors.ARGB.green(col1); + int b1 = ClientColors.ARGB.blue(col1); + int a2 = ClientColors.ARGB.alpha(col2); + int r2 = ClientColors.ARGB.red(col2); + int g2 = ClientColors.ARGB.green(col2); + int b2 = ClientColors.ARGB.blue(col2); + GlStateManager.disableTexture(); + GlStateManager.enableBlend(); + GlStateManager.disableAlphaTest(); + GlStateManager.blendFuncSeparate(770, 771, 1, 0); + GlStateManager.shadeModel(7425); + //top + vertexConsumer.begin(7, DefaultVertexFormat.POSITION_COLOR); + vertexConsumer.vertex(x0, y0, z).color(r1, g1, b1, a1).nextVertex(); + vertexConsumer.vertex(x0 + gradientWidth, y0 + gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x1 - gradientWidth, y0 + gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x1, y0, z).color(r1, g1, b1, a1).nextVertex(); + //left + vertexConsumer.vertex(x0, y1, z).color(r1, g1, b1, a1).nextVertex(); + vertexConsumer.vertex(x0 + gradientWidth, y1 - gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x0 + gradientWidth, y0 + gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x0, y0, z).color(r1, g1, b1, a1).nextVertex(); + //bottom + vertexConsumer.vertex(x1, y1, z).color(r1, g1, b1, a1).nextVertex(); + vertexConsumer.vertex(x1 - gradientWidth, y1 - gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x0 + gradientWidth, y1 - gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x0, y1, z).color(r1, g1, b1, a1).nextVertex(); + //right + vertexConsumer.vertex(x1, y0, z).color(r1, g1, b1, a1).nextVertex(); + vertexConsumer.vertex(x1 - gradientWidth, y0 + gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x1 - gradientWidth, y1 - gradientWidth, z).color(r2, g2, b2, a2).nextVertex(); + vertexConsumer.vertex(x1, y1, z).color(r1, g1, b1, a1).nextVertex(); + tess.end(); + GlStateManager.shadeModel(7424); + GlStateManager.disableBlend(); + GlStateManager.enableAlphaTest(); + GlStateManager.enableTexture(); + } + } + } + + private class SpriteButton extends VanillaButtonWidget { + private Identifier sprite; + + SpriteButton(String message, PressAction action, Identifier sprite) { + super(0, 0, 11, 11, message, action); + this.sprite = sprite; + } + + @Override + protected void drawWidget(int mouseX, int mouseY, float delta) { + int i = 1; + if (!this.active) { + i = 0; + } else if (hovered) { + i = 2; + tooltip = getMessage(); + } + + Identifier tex = ButtonWidgetTextures.get(i); + DrawUtil.blitSprite(tex, getX(), getY(), getWidth(), getHeight(), new DrawUtil.NineSlice(200, 20, 3)); + minecraft.getTextureManager().bind(sprite); + DrawUtil.drawTexture(getX() + 2, getY() + 2, 0, 0, 7, 7, 7, 7); + } + + @Override + protected void drawScrollingText(TextRenderer renderer, int offset, Color color) { + + } + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java new file mode 100644 index 000000000..8317792cd --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java @@ -0,0 +1,130 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import javax.imageio.ImageIO; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import com.google.common.hash.Hashing; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.util.ClientColors; +import net.minecraft.client.Minecraft; +import net.minecraft.client.render.texture.DynamicTexture; +import net.minecraft.client.render.texture.SkinImageProcessor; +import net.minecraft.resource.Identifier; + +public class SkinManager { + + private final Set loadedTextures = new ConcurrentSkipListSet<>(Comparator.comparing(Object::toString)); + + public Skin read(Path p) { + return read(p, true); + } + + @SuppressWarnings("UnstableApiUsage") + public Skin read(Path p, boolean fix) { + boolean slim; + String sha256; + try { + var in = Files.readAllBytes(p); + sha256 = Hashing.sha256().hashBytes(in).toString(); + try (var bs = new ByteArrayInputStream(in)) { + var img = ImageIO.read(bs); + int height = img.getHeight(); + int width = img.getWidth(); + if (width != 64) return null; + if (height == 32) { + if (fix) { + try (var out = Files.newOutputStream(p)) { + ImageIO.write(new SkinImageProcessor().process(img), "png", out); + } + } + slim = false; + } else if (height != 64) { + return null; + } else { + slim = ClientColors.ARGB.alpha(img.getRGB(50, 16)) == 0; + } + var metadata = Skin.LocalSkin.readMetadata(p); + if (metadata != null && metadata.containsKey(Skin.LocalSkin.CLASSIC_METADATA_KEY)) { + slim = !(boolean) metadata.get(Skin.LocalSkin.CLASSIC_METADATA_KEY); + } + } + return new Skin.LocalSkin(!slim, p, in, sha256); + } catch (Exception e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to probe skin: ", e); + } + return null; + } + + public AxoIdentifier loadSkin(Skin skin) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "skins/" + skin.sha256()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try (var bs = new ByteArrayInputStream(skin.image())) { + var img = ImageIO.read(bs); + var tex = new DynamicTexture(img.getWidth(), img.getHeight()); + img.getRGB(0, 0, img.getWidth(), img.getHeight(), tex.getPixels(), 0, img.getWidth()); + tex.upload(); + Minecraft.getInstance().getTextureManager().register((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public AxoIdentifier loadCape(Cape cape) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "capes/" + cape.id()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try (var bs = new ByteArrayInputStream(cape.image())) { + var img = ImageIO.read(bs); + var tex = new DynamicTexture(img.getWidth(), img.getHeight()); + img.getRGB(0, 0, img.getWidth(), img.getHeight(), tex.getPixels(), 0, img.getWidth()); + tex.upload(); + Minecraft.getInstance().getTextureManager().register((Identifier) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public void releaseAll() { + loadedTextures.forEach(id -> Minecraft.getInstance().getTextureManager().close((Identifier) id)); + loadedTextures.clear(); + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java new file mode 100644 index 000000000..f353e61d9 --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java @@ -0,0 +1,110 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import com.mojang.blaze3d.platform.GLX; +import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.render.model.entity.PlayerModel; +import net.minecraft.resource.Identifier; +import org.jetbrains.annotations.Nullable; + +public class SkinRenderer { + private static PlayerModel classicModel, slimModel; + private static final Minecraft minecraft = Minecraft.getInstance(); + + private SkinRenderer() { + } + + public static void render(boolean classicVariant, + Identifier skinTexture, + @Nullable Identifier cape, + float rotationX, + float rotationY, + float pivotY, + int x0, + int y0, + int x1, + int y1, + float scale) { + + if (classicModel == null && classicVariant) { + classicModel = new PlayerModel(0, false); + classicModel.isBaby = false; + classicModel.setVisible(true); + } + if (slimModel == null && !classicVariant) { + slimModel = new PlayerModel(0, true); + slimModel.isBaby = false; + slimModel.setVisible(true); + } + + int width = x1 - x0; + int light = 15728880; + GLX.multiTexCoord2f(GLX.GL_TEXTURE1, light % 65536, light / 65536f); + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.pushMatrix(); + GlStateManager.translatef(x0 + width / 2.0F, (float) (y1), 00.0F); + GlStateManager.scalef(scale, scale, 1); + GlStateManager.translatef(0.0F, -0.0625F, 0.0F); + GlStateManager.translatef(0, pivotY, 0); + GlStateManager.rotatef(rotationX, 1, 0, 0); + GlStateManager.translatef(0, -pivotY, 0); + GlStateManager.rotatef(rotationY, 0, 1, 0); + GlStateManager.pushMatrix(); + GlStateManager.scalef(1.0F, 1.0F, -1.0F); + GlStateManager.translatef(0.0F, -1.5F, 0.0F); + var model = classicVariant ? classicModel : slimModel; + minecraft.getTextureManager().bind(skinTexture); + GlStateManager.enableBlend(); + GlStateManager.enableDepthTest(); + GlStateManager.pushMatrix(); + float k = 0.0625F; + model.head.render(k); + model.body.render(k); + model.rightLeg.render(k); + model.leftLeg.render(k); + model.hat.render(k); + model.leftPants.render(k); + model.rightPants.render(k); + model.jacket.render(k); + model.renderLeftArm(); + model.rightArm.render(0.0625F); + GlStateManager.translatef(0, 0, -0.62F); // why? + model.rightSleeve.render(0.0625F); + GlStateManager.popMatrix(); + if (cape != null) { + GlStateManager.pushMatrix(); + minecraft.getTextureManager().bind(cape); + GlStateManager.translatef(0.0F, 0.0F, 0.125F); + GlStateManager.rotatef(6.0F, 1, 0, 0); + GlStateManager.rotatef(180.0F, 0, 1, 0); + model.renderCape(0.0625F); + GlStateManager.popMatrix(); + } + GlStateManager.popMatrix(); + GlStateManager.popMatrix(); + GlStateManager.disableBlend(); + GlStateManager.disableDepthTest(); + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java new file mode 100644 index 000000000..ab149d099 --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java @@ -0,0 +1,119 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.concurrent.CompletableFuture; + +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.ClickableWidget; +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.sound.system.SoundManager; +import net.minecraft.resource.Identifier; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; + +public class SkinWidget extends ClickableWidget { + private static final float MODEL_HEIGHT = 2.125F; + private static final float FIT_SCALE = 0.97F; + private static final float ROTATION_SENSITIVITY = 2.5F; + private static final float DEFAULT_ROTATION_X = -5.0F; + private static final float DEFAULT_ROTATION_Y = 30.0F; + private static final float ROTATION_X_LIMIT = 50.0F; + private float rotationX = DEFAULT_ROTATION_X; + @Setter + private float rotationY = DEFAULT_ROTATION_Y; + @Getter + @Setter + private Skin skin; + @Getter + @Setter + private Cape cape; + private final Account owner; + private boolean noCape, noCapeActive; + + public SkinWidget(int width, int height, Skin skin, @Nullable Cape cape, Account owner) { + super(0, 0, width, height, ""); + this.skin = skin; + this.cape = cape; + this.owner = owner; + } + + public SkinWidget(int width, int height, Skin skin, Account owner) { + this(width, height, skin, null, owner); + } + + public void noCape(boolean noCapeActive) { + noCape = true; + this.noCapeActive = noCapeActive; + } + + @Override + protected void drawWidget(int mouseX, int mouseY, float partialTick) { + float scale = FIT_SCALE * this.getHeight() / MODEL_HEIGHT; + float pivotY = -1.0625F; + + SkinManager skinManager = Auth.getInstance().getSkinManager(); + AxoIdentifier skinRl = skinManager.loadSkin(skin); + boolean classic = skin.classicVariant(); + var capeRl = cape == null ? null : skinManager.loadCape(cape); + + SkinRenderer.render(classic, (Identifier) skinRl, (Identifier) capeRl, this.rotationX, this.rotationY, pivotY, this.getX(), this.getY(), this.getX() + getWidth(), this.getY() + getHeight(), scale); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) { + this.rotationX = MathHelper.clamp(this.rotationX - (float) dragY * ROTATION_SENSITIVITY, -ROTATION_X_LIMIT, ROTATION_X_LIMIT); + this.rotationY += (float) dragX * ROTATION_SENSITIVITY; + } + + @Override + public void playDownSound(SoundManager soundManager) { + + } + + public boolean isEquipped() { + return noCape ? noCapeActive : (cape != null ? cape.active() : skin != null && skin.active()); + } + + public CompletableFuture equip() { + var msApi = Auth.getInstance().getMsApi(); + if (noCape) { + return msApi.hideCape(owner); + } + if (cape != null) { + return cape.equip(msApi, owner); + } + if (skin != null) { + return skin.equip(msApi, owner); + } + return msApi.resetSkin(owner); + } + + public Asset getFocusedAsset() { + return noCape ? null : cape != null ? cape : skin; + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java index 6b62c2429..2432ed70e 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java @@ -36,18 +36,17 @@ import io.github.axolotlclient.modules.hud.snapping.SnappingHelper; import io.github.axolotlclient.modules.hud.util.DrawPosition; import io.github.axolotlclient.modules.hud.util.Rectangle; -import io.github.axolotlclient.util.GLFWUtil; +import io.github.axolotlclient.util.WindowAccess; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.resource.language.I18n; -import org.lwjgl.glfw.GLFW; /** * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudEditScreen extends Screen { @@ -55,10 +54,10 @@ public class HudEditScreen extends Screen { private static final BooleanOption snapping = new BooleanOption("snapping", true); private static final OptionCategory hudEditScreenCategory = OptionCategory.create("hudEditScreen"); private static final int GRAB_TOLERANCE = 5; - private static final long MOVE_CURSOR = GLFW.glfwCreateStandardCursor(GLFW.GLFW_RESIZE_ALL_CURSOR); - private static final long DEFAULT_CURSOR = GLFW.glfwCreateStandardCursor(GLFW.GLFW_ARROW_CURSOR); - private static final long NWSE_RESIZE_CURSOR = GLFW.glfwCreateStandardCursor(GLFW.GLFW_RESIZE_NWSE_CURSOR), - NESW_RESIZE_CURSOR = GLFW.glfwCreateStandardCursor(GLFW.GLFW_RESIZE_NESW_CURSOR); + private final long MOVE_CURSOR = WindowAccess.getInstance().createCursor(WindowAccess.Cursor.RESIZE_ALL); + private final long DEFAULT_CURSOR = WindowAccess.getInstance().createCursor(WindowAccess.Cursor.ARROW); + private final long NWSE_RESIZE_CURSOR = WindowAccess.getInstance().createCursor(WindowAccess.Cursor.RESIZE_NWSE), + NESW_RESIZE_CURSOR = WindowAccess.getInstance().createCursor(WindowAccess.Cursor.RESIZE_NESW); public static boolean isSnappingEnabled() { return snapping.get(); @@ -106,7 +105,7 @@ private void updateSnapState() { private void setCursor(long cursor) { if (cursor > 0 && cursor != currentCursor) { currentCursor = cursor; - GLFWUtil.runUsingGlfwHandle(ctx -> GLFW.glfwSetCursor(ctx, cursor)); + WindowAccess.getInstance().setCursor(cursor); } } @@ -134,19 +133,20 @@ public void render(int mouseX, int mouseY, float delta) { if (entry.isPresent()) { var bounds = entry.get().getTrueBounds(); if (mode == ModificationMode.NONE && bounds.isMouseOver(mouseX, mouseY)) { + var supportsScaling = entry.get().supportsScaling(); var xBound = Math.max(0, mouseX - bounds.x()); var yBound = Math.max(0, mouseY - bounds.y()); var tolerance = GRAB_TOLERANCE; - if (xBound < tolerance && yBound < tolerance) { + if (supportsScaling && xBound < tolerance && yBound < tolerance) { // top-left setCursor(NWSE_RESIZE_CURSOR); - } else if (Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-right setCursor(NWSE_RESIZE_CURSOR); - } else if (xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-left setCursor(NESW_RESIZE_CURSOR); - } else if (yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { + } else if (supportsScaling && yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { // top-right setCursor(NESW_RESIZE_CURSOR); } else { @@ -287,27 +287,28 @@ public void removed() { super.removed(); setCursor(DEFAULT_CURSOR); mode = ModificationMode.NONE; + WindowAccess.getInstance().destroyStandardCursor(DEFAULT_CURSOR, NWSE_RESIZE_CURSOR, NESW_RESIZE_CURSOR, MOVE_CURSOR); } @Override protected void buttonClicked(ButtonWidget button) { switch (button.id) { - case 3: - snapping.toggle(); - button.message = I18n.translate("hud.snapping") + ": " - + I18n.translate(snapping.get() ? "options.on" : "options.off"); - AxolotlClient.getInstance().getConfigManager().save(); - break; - case 1: - Screen screen = ConfigStyles.createScreen(this, AxolotlClient.getInstance().getConfigManager().getRoot()); - Minecraft.getInstance().openScreen(screen); - break; - case 0: - Minecraft.getInstance().openScreen(parent); - break; - case 2: - Minecraft.getInstance().openScreen(null); - break; + case 3: + snapping.toggle(); + button.message = I18n.translate("hud.snapping") + ": " + + I18n.translate(snapping.get() ? "options.on" : "options.off"); + AxolotlClient.getInstance().getConfigManager().save(); + break; + case 1: + Screen screen = ConfigStyles.createScreen(this, AxolotlClient.getInstance().getConfigManager().getRoot()); + Minecraft.getInstance().openScreen(screen); + break; + case 0: + Minecraft.getInstance().openScreen(parent); + break; + case 2: + Minecraft.getInstance().openScreen(null); + break; } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java index 28dda0425..6e0cfea28 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java @@ -27,9 +27,9 @@ import io.github.axolotlclient.modules.hud.gui.hud.KeystrokeHud; import io.github.axolotlclient.modules.hud.gui.hud.PackDisplayHud; import io.github.axolotlclient.modules.hud.gui.hud.PlayerHud; -import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import io.github.axolotlclient.modules.hud.gui.hud.simple.ComboHud; import io.github.axolotlclient.modules.hud.gui.hud.simple.ReachHud; +import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import lombok.Getter; import net.minecraft.client.Minecraft; @@ -37,7 +37,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudManager extends HudManagerCommon { @Getter @@ -69,7 +69,7 @@ protected void addExtraHud() { public void render(AxoRenderContext context, float delta) { final var mc = ((Minecraft) client); mc.profiler.push("Hud render"); - if(!(mc.screen instanceof HudEditScreen)) { + if (!(mc.screen instanceof HudEditScreen)) { super.render(context, delta); } mc.profiler.pop(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java index 07aeb1d83..e519f8b61 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java @@ -69,7 +69,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class KeystrokeHud extends TextHudEntry implements ProfileAware { @@ -476,6 +476,7 @@ public boolean isLabelEditable() { } public void saveKeystrokes() { + if (keystrokes == null) return; try { var path = AxolotlClientCommon.resolveProfileConfigFile(KEYSTROKE_SAVE_FILE_NAME); Files.createDirectories(path.getParent()); @@ -494,7 +495,11 @@ public void loadKeystrokes() { var loaded = entries.stream().map(e -> (Map) e) .map(KeystrokeHud.this::deserializeKey) .toList(); - keystrokes.clear(); + if (keystrokes == null) { + keystrokes = new ArrayList<>(); + } else { + keystrokes.clear(); + } keystrokes.addAll(loaded); } else { saveKeystrokes(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java index 31f0145ef..37838c7e3 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java @@ -25,9 +25,9 @@ import com.mojang.blaze3d.platform.GLX; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.Lighting; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.render.AxoRenderContext; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import lombok.Getter; import net.minecraft.block.material.Material; import net.minecraft.client.Minecraft; @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class PlayerHud extends PlayerHudCommon { @@ -54,7 +54,7 @@ public PlayerHud() { } public void onPlayerDirectionChange(PlayerDirectionChangeEvent event) { - yawOffset += (event.getYaw() - event.getPrevYaw()) / 2; + yawOffset += (event.yaw() - event.prevYaw()) / 2; } @Override diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java index 2ff063c66..470fc4d32 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java @@ -38,7 +38,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ActionBarHud extends TextHudEntry { @@ -118,6 +118,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(timeShown); options.add(customTextColor); return options; diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java index ded4c8290..a3eca97f2 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java @@ -47,7 +47,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class BossBarHud extends TextHudEntry implements DynamicallyPositionable { @@ -109,6 +109,7 @@ public Identifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(text); options.add(bar); options.add(anchor); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java index c234fa3c8..5bc7f5f35 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java @@ -53,7 +53,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CrosshairHud extends AbstractHudEntry implements DynamicallyPositionable { @@ -105,6 +105,7 @@ public boolean movable() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(type); options.add(customTextureGraphics); options.add(showInF5); @@ -161,6 +162,7 @@ public void render(AxoRenderContext context, float delta) { Minecraft.getInstance().getTextureManager().bind(GuiElement.ICONS_LOCATION); // Draw crosshair + //noinspection DataFlowIssue client.gui.drawTexture((int) (((Util.getWindow().getScaledWidth() / getScale()) - 14) / 2), (int) (((Util.getWindow().getScaledHeight() / getScale()) - 14) / 2), 0, 0, 16, 16); } else if (type.get().equals(Crosshair.CUSTOM)) { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java index 445cd67d1..b091cb373 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java @@ -134,6 +134,7 @@ public AnchorPoint getAnchor() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(anchor); options.add(showCCount); options.add(showECount); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java index cb9eaa3cf..f41e8963d 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/HotbarHUD.java @@ -46,6 +46,7 @@ public class HotbarHUD extends TextHudEntry { public HotbarHUD() { super(182, 22, false); + supportsScaling = false; } @Override @@ -113,6 +114,7 @@ public boolean overridesF3() { public List> getConfigurationOptions() { List> list = new ArrayList<>(); list.add(enabled); + list.add(hide); list.add(shadow); return list; } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java index b4647a31a..395629255 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java @@ -60,7 +60,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ScoreboardHud extends TextHudEntry implements DynamicallyPositionable { @@ -250,6 +250,7 @@ public List> getConfigurationOptions() { options.add(backgroundColor); options.add(outline); options.add(outlineColor); + options.add(hide); options.add(topColor); options.add(scores); options.add(scoreColor); @@ -269,4 +270,14 @@ public Identifier getId() { public AnchorPoint getAnchor() { return anchor.get(); } + + @Override + public double getDefaultX() { + return 1.0; + } + + @Override + public double getDefaultY() { + return 0.5; + } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java index 51e3b2c67..68ed6e050 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java @@ -117,7 +117,7 @@ protected void drawWidget(int mouseX, int mouseY, float partialTick) { label.setChangedListener(stroke::setLabel); if (supportsSynchronization) { var s = (KeystrokeHud.LabelKeystroke) stroke; - ButtonWidget synchronizeButton = addDrawableChild(new VanillaButtonWidget(rightColX + + 30 + 4, rightColY, 58, 20, I18n.translate("keystrokes.stroke.label.synchronize_with_key", s.isSynchronizeLabel() ? I18n.translate("options.on") : I18n.translate("options.off")), b -> { + ButtonWidget synchronizeButton = addDrawableChild(new VanillaButtonWidget(rightColX + 30 + 4, rightColY, 58, 20, I18n.translate("keystrokes.stroke.label.synchronize_with_key", s.isSynchronizeLabel() ? I18n.translate("options.on") : I18n.translate("options.off")), b -> { s.setSynchronizeLabel(!s.isSynchronizeLabel()); b.setMessage(I18n.translate("keystrokes.stroke.label.synchronize_with_key", s.isSynchronizeLabel() ? I18n.translate("options.on") : I18n.translate("options.off"))); label.setEditable(!s.isSynchronizeLabel()); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java index bafc38d99..0136a220b 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java @@ -38,7 +38,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class SnappingHelper { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java index dea6ea464..5c51c50d3 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java @@ -36,7 +36,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class DrawUtil extends GuiElement { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java index bc384c0b2..df9e76376 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/ItemUtil.java @@ -22,158 +22,26 @@ package io.github.axolotlclient.modules.hud.util; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; - import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.Lighting; -import com.mojang.blaze3d.platform.TextureUtil; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.Tessellator; -import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import lombok.experimental.UtilityClass; import net.minecraft.client.Minecraft; -import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.TextRenderer; -import net.minecraft.client.render.item.BlockEntityItemRenderer; -import net.minecraft.client.render.model.block.ModelTransformations; -import net.minecraft.client.render.texture.TextureAtlas; -import net.minecraft.client.resource.model.BakedModel; -import net.minecraft.client.resource.model.BakedQuad; import net.minecraft.item.ItemStack; -import net.minecraft.resource.Identifier; import net.minecraft.text.Formatting; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3i; /** * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @UtilityClass public class ItemUtil { - - private static final Identifier ITEM_GLINT_TEXTURE = new Identifier("textures/misc/enchanted_item_glint.png"); - - public static int getTotal(Minecraft client, ItemStack stack) { - List item = ItemUtil.getItems(client); - if (item == null) { - return 0; - } - AtomicInteger count = new AtomicInteger(); - item.forEach(itemStack -> { - if (itemStack != null && stack != null && itemStack.getItem() == stack.getItem()) { - count.addAndGet(itemStack.size); - } - }); - return count.get(); - } - - public static List getItems(Minecraft client) { - ArrayList items = new ArrayList<>(); - if (client.player == null) { - return null; - } - items.addAll(Arrays.asList(client.player.inventory.armorSlots)); - items.addAll(Arrays.asList(client.player.inventory.inventorySlots)); - return items; - } - - /** - * Compares two ItemStorage Lists. - * If list1.get(1) is 10, and list2 is 5, it will return 5. - * Will return nothing if negative... - * - * @param list1 one to be based off of - * @param list2 one to compare to - * @return the item storage - */ - public static List compare(List list1, List list2) { - ArrayList list = new ArrayList<>(); - for (ItemStorage current : list1) { - Optional optional = getItemFromItem(current.stack, list2); - if (optional.isPresent()) { - ItemStorage other = optional.get(); - if (current.times - other.times <= 0) { - continue; - } - list.add(new ItemStorage(other.stack.copy(), current.times - other.times)); - } else { - list.add(current.copy()); - } - } - return list; - } - - public static Optional getItemFromItem(ItemStack item, List list) { - ItemStack compare = item.copy(); - compare.size = 1; - for (ItemUtil.ItemStorage storage : list) { - if (isEqual(storage.stack, compare)) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - private static boolean isEqual(ItemStack stack, ItemStack compare) { - return stack != null && compare != null && stack.getItem() == compare.getItem(); - } - - public static ArrayList removeOld(List list, int time) { - ArrayList stored = new ArrayList<>(); - for (ItemUtil.TimedItemStorage storage : list) { - if (storage.getPassedTime() <= time) { - stored.add(storage); - } - } - return stored; - } - - public static Optional getTimedItemFromItem(ItemStack item, - List list) { - ItemStack compare = item.copy(); - compare.size = 1; - for (ItemUtil.TimedItemStorage storage : list) { - if (isEqual(storage.stack, compare)) { - return Optional.of(storage); - } - } - return Optional.empty(); - } - - public static List storageFromItem(List items) { - ArrayList storage = new ArrayList<>(); - for (ItemStack item : items) { - if (item == null) { - continue; - } - Optional s = getItemFromItem(item, storage); - if (s.isPresent()) { - ItemUtil.ItemStorage store = s.get(); - store.incrementTimes(item.size); - } else { - storage.add(new ItemUtil.ItemStorage(item, item.size)); - } - } - return storage; - } - - public static List untimedToTimed(List list) { - ArrayList timed = new ArrayList<>(); - for (ItemStorage stack : list) { - timed.add(stack.timed()); - } - return timed; - } - // The scaling stuff wasn't a problem on 1.8.9 so no need to create more complicated stuff public static void renderGuiItemModel(ItemStack stack, int x, int y) { @@ -186,151 +54,6 @@ public static void renderGuiItemModel(ItemStack stack, int x, int y) { } } - public static void renderColoredGuiItemModel(ItemStack stack, int x, int y, Color color) { - Lighting.turnOnGui(); - GlStateManager.pushMatrix(); - - Minecraft client = Minecraft.getInstance(); - - if (stack != null && stack.getItem() != null) { - client.getItemRenderer().zOffset += 50.0F; - - - BakedModel bakedModel = client.getItemRenderer().getModelShaper().getModel(stack); - GlStateManager.pushMatrix(); - client.getTextureManager().bind(TextureAtlas.BLOCKS_LOCATION); - client.getTextureManager().get(TextureAtlas.BLOCKS_LOCATION).pushFilter(false, false); - GlStateManager.enableRescaleNormal(); - GlStateManager.enableAlphaTest(); - GlStateManager.alphaFunc(516, 0.1F); - GlStateManager.enableBlend(); - GlStateManager.blendFunc(770, 771); - GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); - - - GlStateManager.translatef((float) x, (float) y, 100.0F + client.getItemRenderer().zOffset); - GlStateManager.translatef(8.0F, 8.0F, 0.0F); - GlStateManager.scalef(1.0F, 1.0F, -1.0F); - GlStateManager.scalef(0.5F, 0.5F, 0.5F); - if (bakedModel.isGui3d()) { - GlStateManager.scalef(40.0F, 40.0F, 40.0F); - GlStateManager.rotatef(210.0F, 1.0F, 0.0F, 0.0F); - GlStateManager.rotatef(-135.0F, 0.0F, 1.0F, 0.0F); - GlStateManager.enableLighting(); - } else { - GlStateManager.scalef(64.0F, 64.0F, 64.0F); - GlStateManager.rotatef(180.0F, 1.0F, 0.0F, 0.0F); - GlStateManager.disableLighting(); - } - - - bakedModel.getTransformations().apply(ModelTransformations.Type.GUI); - - - GlStateManager.pushMatrix(); - GlStateManager.scalef(0.5F, 0.5F, 0.5F); - if (bakedModel.isCustomRenderer()) { - GlStateManager.rotatef(180.0F, 0.0F, 1.0F, 0.0F); - GlStateManager.translatef(-0.5F, -0.5F, -0.5F); - GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); - GlStateManager.enableRescaleNormal(); - BlockEntityItemRenderer.INSTANCE.render(stack); - } else { - GlStateManager.translatef(-0.5F, -0.5F, -0.5F); - renderBakedItemModel(bakedModel, color.toInt(), stack); - if (stack.hasEnchantmentGlint()) { - renderGlint(bakedModel); - } - } - - GlStateManager.popMatrix(); - - - GlStateManager.disableAlphaTest(); - GlStateManager.disableRescaleNormal(); - GlStateManager.disableLighting(); - GlStateManager.popMatrix(); - client.getTextureManager().bind(TextureAtlas.BLOCKS_LOCATION); - client.getTextureManager().get(TextureAtlas.BLOCKS_LOCATION).popFilter(); - - - client.getItemRenderer().zOffset -= 50.0F; - } - - GlStateManager.popMatrix(); - Lighting.turnOff(); - } - - private void renderBakedItemModel(BakedModel bakedModel, int color, ItemStack itemStack) { - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuilder(); - bufferBuilder.begin(7, DefaultVertexFormat.BLOCK_NORMALS); - - for (Direction direction : Direction.values()) { - renderBakedItemQuads(bufferBuilder, bakedModel.getQuads(direction), color, itemStack); - } - - renderBakedItemQuads(bufferBuilder, bakedModel.getQuads(), color, itemStack); - tessellator.end(); - } - - private void renderBakedItemQuads(BufferBuilder bufferBuilder, List list, int color, ItemStack itemStack) { - boolean bl = color == -1 && itemStack != null; - int j = 0; - - for (int k = list.size(); j < k; ++j) { - BakedQuad bakedQuad = list.get(j); - int l = color; - if (bl && bakedQuad.hasTint()) { - l = itemStack.getItem().getDisplayColor(itemStack, bakedQuad.getTintIndex()); - if (GameRenderer.anaglyphEnabled) { - l = TextureUtil.getAnaglyphColor(l); - } - - l |= -16777216; - } - - renderQuad(bufferBuilder, bakedQuad, l); - } - } - - private void renderGlint(BakedModel bakedModel) { - GlStateManager.depthMask(false); - GlStateManager.depthFunc(514); - GlStateManager.disableLighting(); - GlStateManager.blendFunc(768, 1); - Minecraft.getInstance().getTextureManager().bind(ITEM_GLINT_TEXTURE); - GlStateManager.matrixMode(5890); - GlStateManager.pushMatrix(); - GlStateManager.scalef(8.0F, 8.0F, 8.0F); - float f = (float) (Minecraft.getTime() % 3000L) / 3000.0F / 8.0F; - GlStateManager.translatef(f, 0.0F, 0.0F); - GlStateManager.rotatef(-50.0F, 0.0F, 0.0F, 1.0F); - renderBakedItemModel(bakedModel, -8372020, null); - GlStateManager.popMatrix(); - GlStateManager.pushMatrix(); - GlStateManager.scalef(8.0F, 8.0F, 8.0F); - float g = (float) (Minecraft.getTime() % 4873L) / 4873.0F / 8.0F; - GlStateManager.translatef(-g, 0.0F, 0.0F); - GlStateManager.rotatef(10.0F, 0.0F, 0.0F, 1.0F); - renderBakedItemModel(bakedModel, -8372020, null); - GlStateManager.popMatrix(); - GlStateManager.matrixMode(5888); - GlStateManager.blendFunc(770, 771); - GlStateManager.enableLighting(); - GlStateManager.depthFunc(515); - GlStateManager.depthMask(true); - Minecraft.getInstance().getTextureManager().bind(TextureAtlas.BLOCKS_LOCATION); - } - - private void renderQuad(BufferBuilder bufferBuilder, BakedQuad bakedQuad, int color) { - bufferBuilder.vertices(bakedQuad.getVertices()); - bufferBuilder.setQuadColor(color); - Vec3i vec3i = bakedQuad.getFace().getNormal(); - bufferBuilder.postNormal((float) vec3i.getX(), (float) vec3i.getY(), (float) vec3i.getZ()); - } - - public static void renderGuiItemOverlay(TextRenderer renderer, ItemStack stack, int x, int y, String countLabel, int textColor, boolean shadow) { Lighting.turnOnGui(); @@ -387,53 +110,4 @@ private static void renderGuiQuad(BufferBuilder buffer, int x, int y, int width, buffer.vertex(x + width, y, 0.0).color(red, green, blue, alpha).nextVertex(); Tessellator.getInstance().end(); } - - public static class ItemStorage { - - public final ItemStack stack; - public int times; - - public ItemStorage(ItemStack stack, int times) { - ItemStack copy = stack.copy(); - copy.size = 1; - this.stack = copy; - this.times = times; - } - - public void incrementTimes(int num) { - times = times + num; - } - - public ItemStorage copy() { - return new ItemStorage(stack.copy(), times); - } - - public TimedItemStorage timed() { - return new TimedItemStorage(stack, times); - } - } - - public static class TimedItemStorage extends ItemStorage { - - public float start; - - public TimedItemStorage(ItemStack stack, int times) { - super(stack, times); - this.start = Minecraft.getTime(); - } - - public float getPassedTime() { - return Minecraft.getTime() - start; - } - - @Override - public void incrementTimes(int num) { - super.incrementTimes(num); - refresh(); - } - - public void refresh() { - start = Minecraft.getTime(); - } - } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java index 88225e1e2..9877e31ff 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/hud/util/RenderUtil.java @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @UtilityClass diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java index c6e6e9548..96b58f5df 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java @@ -54,9 +54,8 @@ public class ScreenshotUtils extends AbstractModule { private static final ScreenshotUtils Instance = new ScreenshotUtils(); private final OptionCategory category = OptionCategory.create("screenshotUtils"); private final BooleanOption enabled = new BooleanOption("enabled", false); - private final GenericOption openViewer = new GenericOption("imageViewer", "openViewer", () -> { - Minecraft.getInstance().openScreen(new GalleryScreen(Minecraft.getInstance().screen)); - }); + private final GenericOption openViewer = new GenericOption("imageViewer", "openViewer", + () -> Minecraft.getInstance().openScreen(new GalleryScreen(Minecraft.getInstance().screen))); private final Map actions = new LinkedHashMap<>(); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java index 10393e60c..96f0b339a 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/FSBSkyboxInstance.java @@ -36,7 +36,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: GPL-3.0

**/ public class FSBSkyboxInstance extends SkyboxInstance { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java index be934189c..0f2805803 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyResourceManager.java @@ -43,7 +43,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ public class SkyResourceManager extends AbstractModule { @@ -139,8 +139,8 @@ private void loadMCPSky(String loader, Identifier id, ResourceManager resourceMa } SkyboxManager.getInstance().addSkybox(new MCPSkyboxInstance(object)); - } catch (Exception ignored) { - AxolotlClient.LOGGER.debug("Error while loading sky", ignored); + } catch (Exception e) { + AxolotlClient.LOGGER.debug("Error while loading sky", e); } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java index c9713b6be..216c42586 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxInstance.java @@ -45,7 +45,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ // TODO fix rotation & blending issues with shooting stars, implement more missing features like worlds, weather, biomes... @@ -142,29 +142,21 @@ protected int parseBlend(String str) { if (str == null) { return 1; } else { - switch (str.toLowerCase(Locale.ENGLISH).trim()) { - case "alpha": - return 0; - case "add": - return 1; - case "subtract": - return 2; - case "multiply": - return 3; - case "dodge": - return 4; - case "burn": - return 5; - case "screen": - return 6; - case "overlay": - return 7; - case "replace": - return 8; - default: + return switch (str.toLowerCase(Locale.ENGLISH).trim()) { + case "alpha" -> 0; + case "add" -> 1; + case "subtract" -> 2; + case "multiply" -> 3; + case "dodge" -> 4; + case "burn" -> 5; + case "screen" -> 6; + case "overlay" -> 7; + case "replace" -> 8; + default -> { AxolotlClient.LOGGER.warn("Unknown blend: " + str); - return 1; - } + yield 1; + } + }; } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java index 9246357ac..c875feed3 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/modules/sky/SkyboxManager.java @@ -30,7 +30,7 @@ * This implementation of custom skies is based on the FabricSkyBoxes mod by AMereBagatelle * Github Link. * - * @license MIT + *

License: MIT

**/ public class SkyboxManager { @@ -52,6 +52,7 @@ public void addSkybox(SkyboxInstance skybox) { public void renderSkyboxes(float delta, float brightness) { this.skyboxes.stream().filter(this.renderPredicate).forEach(this.active_skies::add); + //noinspection ComparatorMethodParameterNotUsed this.active_skies.sort((skybox1, skybox2) -> skybox1.alpha >= skybox2.alpha ? 0 : 1); this.active_skies.forEach(skyboxInstance -> skyboxInstance.render(delta, brightness)); this.active_skies.removeIf((skybox) -> skybox.alpha <= MINIMUM_ALPHA); diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/GLFWUtil.java b/1.8.9/src/main/java/io/github/axolotlclient/util/GLFWUtil.java deleted file mode 100644 index 797ab0162..000000000 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/GLFWUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright © 2025 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.util; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.function.Consumer; - -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import org.lwjgl.opengl.Display; - -public class GLFWUtil { - - private static MethodHandle getHandle; - - static { - try { - getHandle = MethodHandles.lookup().findStatic(Class.forName("org.lwjgl.opengl.Display"), "getHandle", MethodType.methodType(long.class)); - } catch (Throwable ignored) { - } - } - - private static long windowHandle = -1; - - public static long getWindowHandle() { - if (windowHandle == -1) { - try { - windowHandle = (long) getHandle.invoke(); - } catch (Throwable ignored) { - } - } - return windowHandle; - } - - // Since the reflection used for this only works with legacy-lwjgl3 it's possible for us not being able to access the window handle. - // This however should not lead to a crash despite compiling against glfw. - public static boolean isHandleAvailable() { - return getWindowHandle() != -1; - } - - public static void runUsingGlfwHandle(Consumer action) { - if (!Display.isCreated()) { - MinecraftClientEvents.READY.register(mc -> { - if (isHandleAvailable()) { - action.accept(getWindowHandle()); - } - }); - } else if (isHandleAvailable()) { - action.accept(getWindowHandle()); - } - } -} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/LoggerImpl.java b/1.8.9/src/main/java/io/github/axolotlclient/util/LoggerImpl.java index e3e9dac66..df1440b6e 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/LoggerImpl.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/util/LoggerImpl.java @@ -33,23 +33,23 @@ public class LoggerImpl implements Logger { private static final String modId = FabricLoader.getInstance().isDevelopmentEnvironment() ? "" : "(AxolotlClient) "; public void warn(String message, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.warn(modId + message, args); } public void error(String message, Object... args) { - try { - LOGGER.error(modId + message, args); - } catch (Exception e) { - LOGGER.warn(modId + "[ERROR]" + message, args); - } + //noinspection StringConcatenationArgumentToLogCall + LOGGER.error(modId + message, args); } public void info(String message, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(modId + message, args); } public void debug(String message, Object... args) { if (AxolotlClient.config().debugLogOutput.get()) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(modId + "[DEBUG] " + message, args); } } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/Util.java b/1.8.9/src/main/java/io/github/axolotlclient/util/Util.java index db735461e..a52d80403 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/Util.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/util/Util.java @@ -239,11 +239,15 @@ public static float lerp(float start, float end, float percent) { } public static Identifier getTexture(GraphicsOption option) { - return getTexture(option.get(), option.getName()); + return getTexture(option.get(), "graphics_" + option.getName()); } public static Identifier getTexture(Graphics graphics, String name) { - Identifier id = new Identifier("axolotlclient", "graphics_" + name.toLowerCase(Locale.ROOT)); + Identifier id = new Identifier("axolotlclient", name.toLowerCase(Locale.ROOT)); + return getTexture(graphics, id); + } + + public static Identifier getTexture(Graphics graphics, Identifier id) { try { DynamicTexture texture; if (Minecraft.getInstance().getTextureManager().get(id) == null) { @@ -262,7 +266,7 @@ public static Identifier getTexture(Graphics graphics, String name) { texture.upload(); } catch (IOException e) { - AxolotlClient.LOGGER.error("Failed to bind texture for " + name + ": ", e); + AxolotlClient.LOGGER.error("Failed to bind texture for " + id + ": ", e); } return id; } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/WindowAccess.java b/1.8.9/src/main/java/io/github/axolotlclient/util/WindowAccess.java new file mode 100644 index 000000000..e045dab56 --- /dev/null +++ b/1.8.9/src/main/java/io/github/axolotlclient/util/WindowAccess.java @@ -0,0 +1,220 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.util; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.sdl.SDLMouse; + +public sealed abstract class WindowAccess permits WindowAccess.GLFWAccess, WindowAccess.SDLAccess, WindowAccess.NoOpAccess { + + private static final boolean GLFW_AVAILABLE = checkGlfwAvailable(); + private static final boolean SDL_AVAILABLE = checkSDLAvailable(); + + public static boolean isGlfwAvailable() { + return WindowAccess.GLFW_AVAILABLE; + } + + public static boolean isSdlAvailable() { + return WindowAccess.SDL_AVAILABLE; + } + + public enum Cursor { + RESIZE_ALL, + ARROW, + RESIZE_NWSE, + RESIZE_NESW + } + + public abstract long createCursor(Cursor cursor); + + public abstract void setCursor(long cursor); + + public abstract void destroyStandardCursor(long... cursors); + + public abstract boolean rawMouseMotionAvailable(); + + public abstract void setRawMouseMotion(boolean enabled); + + private static final WindowAccess INSTANCE = create(); + + public static WindowAccess getInstance() { + return INSTANCE; + } + + private static boolean checkGlfwAvailable() { + try { + Class.forName("org.lwjgl.glfw.GLFW"); + return true; + } catch (Throwable ignored) { + } + return false; + } + + private static boolean checkSDLAvailable() { + try { + Class.forName("org.lwjgl.sdl.SDL"); + return true; + } catch (Throwable ignored) { + } + return false; + } + + private static WindowAccess create() { + if (GLFW_AVAILABLE) { + return new GLFWAccess(); + } else if (SDL_AVAILABLE) { + return new SDLAccess(); + } + return new NoOpAccess(); + } + + final static class NoOpAccess extends WindowAccess { + + @Override + public long createCursor(Cursor cursor) { + return 0; + } + + @Override + public void setCursor(long cursor) { + + } + + @Override + public void destroyStandardCursor(long... cursors) { + + } + + @Override + public boolean rawMouseMotionAvailable() { + return false; + } + + @Override + public void setRawMouseMotion(boolean enabled) { + + } + } + + final static class SDLAccess extends WindowAccess { + + @Override + public long createCursor(Cursor cursor) { + return SDLMouse.SDL_CreateSystemCursor(switch (cursor) { + case RESIZE_ALL -> SDLMouse.SDL_SYSTEM_CURSOR_MOVE; + case ARROW -> SDLMouse.SDL_SYSTEM_CURSOR_DEFAULT; + case RESIZE_NWSE -> SDLMouse.SDL_SYSTEM_CURSOR_NWSE_RESIZE; + case RESIZE_NESW -> SDLMouse.SDL_SYSTEM_CURSOR_NESW_RESIZE; + }); + } + + @Override + public void setCursor(long cursor) { + SDLMouse.SDL_SetCursor(cursor); + } + + @Override + public void destroyStandardCursor(long... cursors) { + for (long c : cursors) { + SDLMouse.SDL_DestroyCursor(c); + } + } + + @Override + public boolean rawMouseMotionAvailable() { + return false; + } + + @Override + public void setRawMouseMotion(boolean enabled) { + + } + } + + final static class GLFWAccess extends WindowAccess { + + @Override + public long createCursor(Cursor cursor) { + return GLFW.glfwCreateStandardCursor(switch (cursor) { + case RESIZE_ALL -> GLFW.GLFW_RESIZE_ALL_CURSOR; + case ARROW -> GLFW.GLFW_ARROW_CURSOR; + case RESIZE_NWSE -> GLFW.GLFW_RESIZE_NWSE_CURSOR; + case RESIZE_NESW -> GLFW.GLFW_RESIZE_NESW_CURSOR; + }); + } + + @Override + public void setCursor(long cursor) { + GLFW.glfwSetCursor(WindowHandleAccess.getWindowHandle(), cursor); + } + + @Override + public void destroyStandardCursor(long... cursors) { + // we do not need to destroy glfw standard cursors ourselves + } + + @Override + public boolean rawMouseMotionAvailable() { + return WindowHandleAccess.isHandleAvailable(); + } + + @Override + public void setRawMouseMotion(boolean enabled) { + GLFW.glfwSetInputMode(WindowHandleAccess.getWindowHandle(), GLFW.GLFW_RAW_MOUSE_MOTION, enabled ? 1 : 0); + } + } + + public static class WindowHandleAccess { + + private static MethodHandle getHandle; + + static { + try { + getHandle = MethodHandles.lookup().findStatic(Class.forName("org.lwjgl.opengl.Display"), "getHandle", MethodType.methodType(long.class)); + } catch (Throwable ignored) { + } + } + + private static long windowHandle = -1; + + public static long getWindowHandle() { + if (windowHandle == -1) { + try { + windowHandle = (long) getHandle.invoke(); + } catch (Throwable ignored) { + } + } + return windowHandle; + } + + // Since the reflection used for this only works with legacy-lwjgl3 it's possible for us not being able to access the window handle. + // This however should not lead to a crash despite compiling against glfw. + public static boolean isHandleAvailable() { + return getWindowHandle() != -1; + } + } +} diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/events/Events.java b/1.8.9/src/main/java/io/github/axolotlclient/util/events/Events.java index e71e91abc..b3560ed89 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/events/Events.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/util/events/Events.java @@ -22,7 +22,8 @@ package io.github.axolotlclient.util.events; -import io.github.axolotlclient.util.events.impl.*; +import io.github.axolotlclient.util.events.impl.KeyBindChangeEvent; +import io.github.axolotlclient.util.events.impl.MouseInputEvent; import net.minecraft.client.Minecraft; import net.ornithemc.osl.core.api.events.Event; @@ -30,7 +31,6 @@ public class Events { public static final Event> MOUSE_INPUT = createEvent(); public static final Event> KEYBIND_CHANGE = createEvent(); - public static final Event> PLAYER_DIRECTION_CHANGE = createEvent(); public static final Event> GAME_LOAD_EVENT = createEvent(); private static Event> createEvent() { diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java b/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java index 7ecf675d0..9539da175 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java @@ -22,11 +22,6 @@ package io.github.axolotlclient.util.events.impl; -import lombok.Data; - -@Data -public class KeyBindChangeEvent { - - private final int boundKey; +public record KeyBindChangeEvent(int boundKey) { } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java b/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java index b844718fa..156d5e810 100644 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java +++ b/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/MouseInputEvent.java @@ -22,10 +22,6 @@ package io.github.axolotlclient.util.events.impl; -import lombok.Data; +public record MouseInputEvent(int button) { -@Data -public class MouseInputEvent { - - private final int button; } diff --git a/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java b/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java deleted file mode 100644 index 8396e1ccb..000000000 --- a/1.8.9/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2023 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.util.events.impl; - -import lombok.Data; - -@Data -public class PlayerDirectionChangeEvent { - - private final float prevPitch, prevYaw, pitch, yaw; - -} diff --git a/1.8.9/src/main/resources/axolotlclient.mixins.json b/1.8.9/src/main/resources/axolotlclient.mixins.json index 53595af66..0e0b07819 100644 --- a/1.8.9/src/main/resources/axolotlclient.mixins.json +++ b/1.8.9/src/main/resources/axolotlclient.mixins.json @@ -15,6 +15,8 @@ "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerMixin", "ClientWorldMixin", + "ConfigVanillaButtonWidgetMixin", + "ConfirmScreenMixin", "ConnectScreenMixin", "ControlsOptionsScreenMixin", "DebugHudMixin", diff --git a/1.8.9/src/main/resources/fabric.mod.json b/1.8.9/src/main/resources/fabric.mod.json index 6eaebc52a..6d0123bfa 100644 --- a/1.8.9/src/main/resources/fabric.mod.json +++ b/1.8.9/src/main/resources/fabric.mod.json @@ -113,16 +113,17 @@ "net/minecraft/unmapped/C_8525326": [ "io/github/axolotlclient/bridge/util/AxoProfiler" ] - }, - "depends": { - "fabricloader": ">=0.15.0", - "minecraft": "1.8.9", - "osl-resource-loader": "*", - "osl-lifecycle-events": "*", - "osl-keybinds": "*", - "osl-entrypoints": "*", - "axolotlclientconfig": "*", - "axolotlclient-common": "*" } + }, + "depends": { + "fabricloader": ">=0.15.0", + "minecraft": "1.8.9", + "osl-resource-loader": "*", + "osl-lifecycle-events": "*", + "osl-keybinds": "*", + "osl-entrypoints": "*", + "axolotlclientconfig": "*", + "axolotlclient-common": "*", + "legacy-lwjgl3": ">1.2.8" } } diff --git a/1.21.7/build.gradle.kts b/1.latest/build.gradle.kts similarity index 95% rename from 1.21.7/build.gradle.kts rename to 1.latest/build.gradle.kts index 202d4c3c7..b9e65218d 100644 --- a/1.21.7/build.gradle.kts +++ b/1.latest/build.gradle.kts @@ -5,12 +5,12 @@ plugins { id("io.github.p03w.machete") } -val minecraft = "1.21.8" -val minecraftFriendly = "1.21.8" -val parchmentMinecraft = "1.21.8" -val parchment = "2025.07.18" -val modmenu = "14.0.0-rc.2" -val fapi = "0.133.0" +val minecraft = "1.21.10" +val minecraftFriendly = "1.21.10" +val parchmentMinecraft = "1.21.9" +val parchment = "2025.10.05" +val modmenu = "16.0.0-rc.1" +val fapi = "0.135.0" group = project.property("maven_group") as String version = "${project.property("version")}+$minecraftFriendly" base.archivesName = "AxolotlClient" @@ -58,7 +58,6 @@ dependencies { api("org.lwjgl:lwjgl-nanovg:3.3.3") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-linux") - runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-linux-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-windows") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-windows-arm64") runtimeOnly("org.lwjgl:lwjgl-nanovg:3.3.3:natives-macos") @@ -104,6 +103,7 @@ java { tasks.runClient { classpath(sourceSets.getByName("test").runtimeClasspath) + jvmArgs("-XX:+AllowEnhancedClassRedefinition", "-XX:+IgnoreUnrecognizedVMOptions") } // Configure the maven publication diff --git a/1.21.7/src/main/java/io/github/axolotlclient/AxolotlClient.java b/1.latest/src/main/java/io/github/axolotlclient/AxolotlClient.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/AxolotlClient.java rename to 1.latest/src/main/java/io/github/axolotlclient/AxolotlClient.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/APIOptions.java b/1.latest/src/main/java/io/github/axolotlclient/api/APIOptions.java similarity index 99% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/APIOptions.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/APIOptions.java index b5c55a2c3..39fd33c70 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/APIOptions.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/APIOptions.java @@ -62,7 +62,7 @@ public void init() { return fut; }; KeyBinds.getInstance().registerWithSimpleAction( - new KeyMapping("api.chats.sidebar.open", InputConstants.KEY_O, "category.axolotlclient"), () -> { + new KeyMapping("api.chats.sidebar.open", InputConstants.KEY_O, KeyBinds.CATEGORY_AXOLOTLCLIENT), () -> { if (API.getInstance().isAuthenticated()) { client.setScreen(new ChatsSidebar(client.screen)); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/AddFriendScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/AddFriendScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/AddFriendScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/AddFriendScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java b/1.latest/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java index 139defe1d..5e407a67d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/ChatsSidebar.java @@ -34,6 +34,7 @@ import io.github.axolotlclient.api.types.Channel; import io.github.axolotlclient.api.types.User; import io.github.axolotlclient.api.util.AlphabeticalComparator; +import lombok.Getter; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.*; @@ -42,6 +43,8 @@ import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; @@ -176,18 +179,18 @@ private void close() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { if (contextMenu.getMenu() != null) { - if (contextMenu.mouseClicked(mouseX, mouseY, button)) { + if (contextMenu.mouseClicked(event, doubleClick)) { return true; } contextMenu.removeMenu(); } - if (mouseX > sidebarWidth) { + if (event.x() > sidebarWidth) { remove(); return true; } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } private void removeChat() { @@ -216,13 +219,13 @@ private void addChat(Channel channel) { addRenderableWidget(chatWidget); addRenderableWidget(input = new EditBox(font, 75, height - 30, sidebarWidth - 80, 20, Component.translatable("api.friends.chat.input")) { @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == InputConstants.KEY_RETURN) { + public boolean keyPressed(KeyEvent event) { + if (event.key() == InputConstants.KEY_RETURN) { ChatHandler.getInstance().sendMessage(channel, input.getValue()); input.setValue(""); return true; } - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(event); } }); input.setSuggestion(input.getMessage().getString()); @@ -258,6 +261,7 @@ private class ListWidget extends AbstractContainerEventHandler implements Render private final int height; private final int entryHeight = 25; protected boolean hovered; + @Getter private int x; private int scrollAmount; private boolean visible; @@ -318,10 +322,6 @@ public boolean isMouseOver(double mouseX, double mouseY) { return hovered = visible && mouseX >= (double) this.x && mouseY >= (double) this.y && mouseX < (double) (this.x + this.width) && mouseY < (double) (this.y + this.height); } - public int getX() { - return x; - } - public void setX(int x) { this.x = x; elements.forEach(e -> e.setX(x)); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenu.java b/1.latest/src/main/java/io/github/axolotlclient/api/ContextMenu.java similarity index 91% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenu.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/ContextMenu.java index 052f4565f..91ea197b4 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenu.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/ContextMenu.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Optional; +import io.github.axolotlclient.modules.hud.util.DrawUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractButton; @@ -36,6 +37,8 @@ import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarratedElementType; import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.input.InputWithModifiers; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; @@ -122,7 +125,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { graphics.pose().pushMatrix(); //graphics.pose().translate(0, 0, 200); graphics.fill(xStart, yStart, xStart + width + 1, y, 0xDD1E1F22); - graphics.renderOutline(xStart, yStart, width + 1, y - yStart + 1, -1); + DrawUtil.outlineRect(graphics, xStart, yStart, width + 1, y - yStart + 1, -1); for (AbstractButton c : children) { c.setWidth(width); c.render(graphics, mouseX, mouseY, delta); @@ -147,13 +150,13 @@ public void updateNarration(NarrationElementOutput builder) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - Optional optional = this.getChildAt(mouseX, mouseY); + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + Optional optional = this.getChildAt(event.x(), event.y()); if (optional.isPresent()) { GuiEventListener guiEventListener = optional.get(); - if (guiEventListener.mouseClicked(mouseX, mouseY, button)) { + if (guiEventListener.mouseClicked(event, doubleClick)) { this.setFocused(guiEventListener); - if (button == 0) { + if (event.button() == 0) { this.setDragging(true); } return true; @@ -212,7 +215,7 @@ public ContextMenuEntry(Component content) { } @Override - public void onPress() { + public void onPress(InputWithModifiers input) { } @@ -222,7 +225,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float del } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { return false; } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenuContainer.java b/1.latest/src/main/java/io/github/axolotlclient/api/ContextMenuContainer.java similarity index 82% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenuContainer.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/ContextMenuContainer.java index 4fdffc178..ac71ed30c 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenuContainer.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/ContextMenuContainer.java @@ -33,6 +33,9 @@ import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -85,30 +88,30 @@ public void mouseMoved(double mouseX, double mouseY) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { if (menu != null) { - if (!menu.isMouseOver(mouseX, mouseY)) { + if (!menu.isMouseOver(event.x(), event.y())) { removeMenu(); return true; } - if (menu.mouseClicked(mouseX, mouseY, button)) removeMenu(); + if (menu.mouseClicked(event, doubleClick)) removeMenu(); return true; } return false; } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { + public boolean mouseReleased(MouseButtonEvent event) { if (menu != null) { - return menu.mouseReleased(mouseX, mouseY, button); + return menu.mouseReleased(event); } return false; } @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) { if (menu != null) { - return menu.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + return menu.mouseDragged(event, deltaX, deltaY); } return false; } @@ -122,29 +125,29 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amountX, doubl } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(KeyEvent event) { if (menu != null) { - if (keyCode == InputConstants.KEY_ESCAPE) { + if (event.key() == InputConstants.KEY_ESCAPE) { removeMenu(); return true; } - return menu.keyPressed(keyCode, scanCode, modifiers); + return menu.keyPressed(event); } return false; } @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { + public boolean keyReleased(KeyEvent event) { if (menu != null) { - return menu.keyReleased(keyCode, scanCode, modifiers); + return menu.keyReleased(event); } return false; } @Override - public boolean charTyped(char chr, int modifiers) { + public boolean charTyped(CharacterEvent event) { if (menu != null) { - return menu.charTyped(chr, modifiers); + return menu.charTyped(event); } return false; } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenuScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/ContextMenuScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/ContextMenuScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/ContextMenuScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/FriendsScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/FriendsScreen.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/FriendsScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/FriendsScreen.java index 691c74574..2014b9182 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/FriendsScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/FriendsScreen.java @@ -29,6 +29,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; @@ -60,15 +61,15 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (super.keyPressed(keyCode, scanCode, modifiers)) { + public boolean keyPressed(KeyEvent event) { + if (super.keyPressed(event)) { return true; - } else if (keyCode == 294) { + } else if (event.key() == 294) { this.refresh(); return true; } else if (this.widget.getSelected() != null) { - if (keyCode != 257 && keyCode != 335) { - return this.widget.keyPressed(keyCode, scanCode, modifiers); + if (event.key() != 257 && event.key() != 335) { + return this.widget.keyPressed(event); } else { this.openChat(); return true; @@ -82,7 +83,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { protected void init() { addRenderableWidget(widget = new UserListWidget(this, minecraft, width, height, 32, height - 64, 35)); - widget.children().clear(); + widget.clearEntries(); if (current == Tab.ALL || current == Tab.ONLINE) { FriendRequest.getInstance().getFriends().whenCompleteAsync((list, t) -> widget.setUsers( diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/NewsScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/NewsScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/NewsScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/NewsScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/PrivacyNoticeScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/PrivacyNoticeScreen.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/PrivacyNoticeScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/PrivacyNoticeScreen.java index 434f58094..e06f5ddbb 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/PrivacyNoticeScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/PrivacyNoticeScreen.java @@ -52,7 +52,7 @@ protected PrivacyNoticeScreen(Screen parent, CompletableFuture accepted public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { super.render(graphics, mouseX, mouseY, delta); graphics.drawCenteredString(this.font, this.title, this.width / 2, getTitleY(), -1); - message.renderCentered(graphics, width / 2, getMessageY()); + message.render(graphics, MultiLineLabel.Align.CENTER, width / 2, getMessageY(), 10, true, -1); } @Override @@ -82,9 +82,8 @@ private void addButtons(int y) { APIOptions.getInstance().privacyAccepted.set(Options.PrivacyPolicyState.DENIED); accepted.complete(false); }).bounds(width / 2 - 50 + 105, y, 100, 20).build()); - addRenderableWidget(Button.builder(Component.translatable("api.privacyNotice.openPolicy"), buttonWidget -> { - OSUtil.getOS().open(TERMS_URI); - }).bounds(width / 2 - 50 - 105, y, 100, 20).build()); + addRenderableWidget(Button.builder(Component.translatable("api.privacyNotice.openPolicy"), + buttonWidget -> OSUtil.getOS().open(TERMS_URI)).bounds(width / 2 - 50 - 105, y, 100, 20).build()); } private int getTitleY() { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java similarity index 90% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java index a2d31634f..a73d1a016 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/SimpleTextInputScreen.java @@ -51,12 +51,16 @@ public void init() { addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, button -> minecraft.setScreen(parent)) .bounds(width / 2 - 155, height - 50, 150, 20).build()); - addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, button -> { - if (!input.getValue().isEmpty()) { + var done = addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, button -> { + if (!input.getValue().isBlank()) { consumer.accept(input.getValue()); - minecraft.setScreen(parent); } + minecraft.setScreen(parent); }).bounds(width / 2 + 5, height - 50, 150, 20).build()); + input.setResponder(s -> { + done.active = !s.isBlank(); + }); + done.active = false; } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/StatusUpdateProviderImpl.java b/1.latest/src/main/java/io/github/axolotlclient/api/StatusUpdateProviderImpl.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/StatusUpdateProviderImpl.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/StatusUpdateProviderImpl.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/UserListWidget.java b/1.latest/src/main/java/io/github/axolotlclient/api/UserListWidget.java similarity index 88% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/UserListWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/UserListWidget.java index caf367949..0b675297b 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/UserListWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/UserListWidget.java @@ -30,11 +30,12 @@ import io.github.axolotlclient.modules.auth.Auth; import lombok.Getter; import net.minecraft.ChatFormatting; -import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.ObjectSelectionList; import net.minecraft.client.gui.components.PlayerFaceRenderer; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; @@ -73,16 +74,20 @@ public boolean isFocused() { } @Override - protected boolean isValidClickButton(int index) { + protected boolean isValidClickButton(MouseButtonInfo mouseButtonInfo) { return true; } + @Override + public void clearEntries() { + super.clearEntries(); + } + public static class UserListEntry extends Entry { @Getter private final User user; private final Minecraft client; - private long time; private MutableComponent note; private FriendsScreen screen; @@ -115,7 +120,11 @@ public Component getNarration() { } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovered, float tickDelta) { + var x = getContentX(); + var y = getContentY(); + var entryWidth = getContentWidth(); + var entryHeight = getContentHeight(); if (user.isSystem()) { MutableComponent fronters = Component.literal( user.getSystem().getFronters().stream().map(PkSystem.Member::getDisplayName) @@ -145,13 +154,12 @@ public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { this.screen.select(this); - if (Util.getMillis() - this.time < 250L && client.level == null) { + if (doubleClick && client.level == null) { screen.openChat(); } - this.time = Util.getMillis(); return false; } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/UsernameManagementScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/UsernameManagementScreen.java similarity index 94% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/UsernameManagementScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/UsernameManagementScreen.java index 2878b6d7e..49398587d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/UsernameManagementScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/UsernameManagementScreen.java @@ -129,13 +129,13 @@ public List children() { } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovered, float tickDelta) { int deleteX = UsernameListWidget.this.scrollBarX() - delete.getWidth() - 10; - delete.setPosition(deleteX, y - 2); - visibility.setPosition(deleteX - visibility.getWidth() - 5, y - 2); + delete.setPosition(deleteX, getContentY() - 2); + visibility.setPosition(deleteX - visibility.getWidth() - 5, getContentY() - 2); delete.render(graphics, mouseX, mouseY, tickDelta); visibility.render(graphics, mouseX, mouseY, tickDelta); - graphics.drawString(font, name, x, y + entryHeight / 2 - 9 / 2, -1); + graphics.drawString(font, name, getContentX(), getContentYMiddle() - 9 / 2, -1); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChannelInvitesScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChannelInvitesScreen.java similarity index 90% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChannelInvitesScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChannelInvitesScreen.java index 908af458b..bb4ce78a7 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChannelInvitesScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChannelInvitesScreen.java @@ -34,6 +34,7 @@ import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; @@ -65,13 +66,13 @@ protected void init() { acceptButton = footerTop.addChild(Button.builder(Component.translatable("api.channels.invite.accept"), w -> { if (invites.getSelected() != null) { w.active = false; - ChannelRequest.acceptChannelInvite(invites.getSelected().invite).thenRun(() -> minecraft.submit(this::rebuildWidgets)); + ChannelRequest.acceptChannelInvite(invites.getSelected().invite).thenRun(() -> minecraft.execute(this::rebuildWidgets)); } }).width(73).build()); denyButton = footerTop.addChild(Button.builder(Component.translatable("api.channels.invite.ignore"), w -> { if (invites.getSelected() != null) { w.active = false; - ChannelRequest.ignoreChannelInvite(invites.getSelected().invite).thenRun(() -> minecraft.submit(this::rebuildWidgets)); + ChannelRequest.ignoreChannelInvite(invites.getSelected().invite).thenRun(() -> minecraft.execute(this::rebuildWidgets)); } }).width(73).build()); footer.addChild(Button.builder(CommonComponents.GUI_BACK, w -> onClose()).build()); @@ -100,8 +101,8 @@ public InvitesListWidget(Minecraft client, int y, int width, int height, int ent } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - boolean bl = super.mouseClicked(mouseX, mouseY, button); + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + boolean bl = super.mouseClicked(event, doubleClick); updateButtons(); return bl; } @@ -122,7 +123,9 @@ public InvitesListEntry(ChannelInvite invite) { } @Override - public void render(GuiGraphics graphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + var left = getContentX(); + var top = getContentY(); graphics.drawString(font, Component.translatable("api.channels.invite.name", invite.channelName()), left + 2, top + 2, -1); if (fromName.isDone()) { graphics.drawString(font, Component.translatable("api.channels.invite.from", fromName.join()).withStyle(Style.EMPTY.withItalic(true)), left + 15, top + height - font.lineHeight - 1, 0xFF808080); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChannelSettingsScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChannelSettingsScreen.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChannelSettingsScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChannelSettingsScreen.java index 76b2599e7..ffc54bde6 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChannelSettingsScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChannelSettingsScreen.java @@ -23,6 +23,7 @@ package io.github.axolotlclient.api.chat; import java.util.Arrays; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; @@ -116,7 +117,8 @@ protected void init() { footer.addChild(Button.builder(CommonComponents.GUI_DONE, widget -> { ChannelRequest.updateChannel(channel.getId(), nameField.getValue(), Persistence.of(persistence.getValue(), count.get().get(), duration.get().get()), - Arrays.stream(namesInput.getValue().split(",")).filter(s -> !s.isEmpty()).map(UUIDHelper::ensureUuid).toArray(String[]::new)); + Arrays.stream(namesInput.getValue().split(",")).filter(s -> !s.isEmpty()).map(UUIDHelper::ensureUuid) + .map(CompletableFuture::join).toArray(String[]::new)); minecraft.setScreen(parent); }).build()); layout.addToFooter(footer); @@ -138,6 +140,10 @@ protected void updateMessage() { protected void applyValue() { currentVal.set(valueFunc.apply(value)); } + + public void setValue(double d) { + this.value = d; + } }; slider.updateMessage(); slider.applyValue(); @@ -151,7 +157,7 @@ protected void applyValue() { text.setValue(String.valueOf(currentVal.get())); } else { try { - slider.onClick(slider.getX() + (1d / slider.getWidth()) * Double.parseDouble(text.getValue()), slider.getY()); + slider.setValue(Double.parseDouble(text.getValue())); } catch (Exception ignored) { } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatListScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatListScreen.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatListScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatListScreen.java index cd0f57867..9954ee20d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatListScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatListScreen.java @@ -29,6 +29,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; @@ -85,13 +86,13 @@ public Screen getSelf() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { if (container.getMenu() != null) { - if (container.mouseClicked(mouseX, mouseY, button)) { + if (container.mouseClicked(event, doubleClick)) { return true; } container.removeMenu(); } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatListWidget.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatListWidget.java similarity index 89% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatListWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatListWidget.java index 6cc4fe962..3df4d2609 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatListWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatListWidget.java @@ -38,6 +38,8 @@ import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.screens.ConfirmScreen; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; @@ -75,7 +77,7 @@ protected int scrollBarX() { } @Override - protected boolean isValidClickButton(int index) { + protected boolean isValidClickButton(MouseButtonInfo index) { return true; } @@ -96,9 +98,9 @@ public ChatListEntry(Channel channel) { } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - widget.setX(x); - widget.setY(y); + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovered, float tickDelta) { + widget.setX(getContentX()); + widget.setY(getContentY()); widget.render(graphics, mouseX, mouseY, tickDelta); } @@ -108,11 +110,11 @@ public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (widget.isMouseOver(mouseX, mouseY)) { - if (button == 0) { - return widget.mouseClicked(mouseX, mouseY, button); - } else if (button == 1) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (widget.isMouseOver(event.x(), event.y())) { + if (event.button() == 0) { + return widget.mouseClicked(event, doubleClick); + } else if (event.button() == 1) { ContextMenu.Builder builder = ContextMenu.builder() .title(Component.literal(channel.getName())) .spacer() @@ -137,7 +139,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { return true; } } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java similarity index 88% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java index 849f0c687..e5f4c6179 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatScreen.java @@ -33,6 +33,8 @@ import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; @@ -46,7 +48,7 @@ public class ChatScreen extends Screen implements ContextMenuScreen { private EditBox input; public ChatScreen(Screen parent, Channel channel) { - super(Component.translatable("api.screen.chat")); + super(Component.literal(channel.getName())); this.channel = channel; this.parent = parent; } @@ -75,13 +77,13 @@ protected void init() { 300, 20, Component.translatable("api.chat.enterMessage")) { @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == InputConstants.KEY_RETURN && !getValue().isEmpty()) { + public boolean keyPressed(KeyEvent event) { + if (event.key() == InputConstants.KEY_RETURN && !getValue().isEmpty()) { ChatHandler.getInstance().sendMessage(channel, getValue()); setValue(""); return true; } - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(event); } }); @@ -96,10 +98,12 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { input.setMaxLength(1024); if (channel.getOwner().equals(API.getInstance().getSelf())) { + //noinspection DataFlowIssue addRenderableWidget(Button.builder(Component.translatable("api.channel.configure"), b -> minecraft.setScreen(new ChannelSettingsScreen(this, channel))) .bounds(width - 60, 5, 50, 20).build()); } + //noinspection DataFlowIssue this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, button -> this.minecraft.setScreen(this.parent)) .bounds(this.width / 2 - 75, this.height - 28, 150, 20) .build() @@ -116,14 +120,14 @@ public void removed() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { if (contextMenu.getMenu() != null) { - if (contextMenu.mouseClicked(mouseX, mouseY, button)) { + if (contextMenu.mouseClicked(event, doubleClick)) { return true; } contextMenu.removeMenu(); } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatUserListWidget.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatUserListWidget.java similarity index 92% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatUserListWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatUserListWidget.java index 6990c9042..964af6664 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatUserListWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatUserListWidget.java @@ -40,6 +40,8 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.ObjectSelectionList; import net.minecraft.client.gui.components.PlayerFaceRenderer; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; @@ -77,7 +79,7 @@ public boolean isFocused() { } @Override - protected boolean isValidClickButton(int index) { + protected boolean isValidClickButton(MouseButtonInfo index) { return true; } @@ -87,7 +89,6 @@ public class UserListEntry extends Entry { private final User user; private final Minecraft client; private final Channel channel; - private long time; private ChatScreen screen; public UserListEntry(User user, Channel channel) { @@ -126,7 +127,11 @@ public Component getNarration() { } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovered, float tickDelta) { + var x = getContentX(); + var y = getContentY(); + var entryWidth = getContentWidth(); + var entryHeight = getContentHeight(); if (hovered && !screen.hasContextMenu()) { graphics.fill(x - 2, y - 1, x + entryWidth - 3, y + entryHeight + 1, 0x55ffffff); } @@ -141,14 +146,9 @@ public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { ChatUserListWidget.this.setSelected(this); - if (button == 0) { // left click - if (Util.getMillis() - this.time < 250L && client.level == null) { // left *double* click - - } - this.time = Util.getMillis(); - } else if (button == 1) { // right click + if (event.button() == 1) { // right click if (!user.equals(API.getInstance().getSelf())) { ContextMenu.Builder menu = ContextMenu.builder().title(Component.literal(user.getName())).spacer(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java similarity index 87% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java index 84d8eed1d..c4bbd5e7d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/ChatWidget.java @@ -47,6 +47,8 @@ import net.minecraft.client.gui.components.PlayerFaceRenderer; import net.minecraft.client.gui.screens.ConfirmScreen; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; @@ -114,7 +116,7 @@ private void addMessage(ChatMessage message) { list.forEach(t -> addEntry(new ChatLine(t, message))); messages.add(message); - children().sort(Comparator.comparingLong(c -> c.getOrigin().timestamp().getEpochSecond())); + sort(Comparator.comparingLong(c -> c.getOrigin().timestamp().getEpochSecond())); if (scrollToBottom) { setScrollAmount(maxScrollAmount()); @@ -134,7 +136,7 @@ private void loadMessages() { @Override public boolean mouseScrolled(double mouseX, double mouseY, double amountX, double amountY) { - double scrollAmount = (this.scrollAmount() - amountY * (double) this.itemHeight / 2.0); + double scrollAmount = (this.scrollAmount() - amountY * scrollRate()); if (scrollAmount < 0) { loadMessages(); } @@ -149,11 +151,11 @@ public void remove() { } @Override - protected void renderSelection(GuiGraphics graphics, int y, int entryWidth, int entryHeight, int borderColor, int fillColor) { + protected void renderSelection(GuiGraphics guiGraphics, ChatLine entry, int i) { } @Override - protected boolean isValidClickButton(int index) { + protected boolean isValidClickButton(MouseButtonInfo mouseButtonInfo) { return true; } @@ -171,20 +173,19 @@ public ChatLine(FormattedCharSequence content, ChatMessage origin) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (button == 0) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (event.button() == 0) { ChatWidget.this.setSelected(this); return true; } - if (button == 1) { + if (event.button() == 1) { ContextMenu.Builder builder = ContextMenu.builder().title(Component.literal(origin.sender().getName())).spacer(); if (!origin.sender().equals(API.getInstance().getSelf())) { - builder.entry(Component.translatable("api.friends.chat"), buttonWidget -> { - ChannelRequest.getOrCreateDM(origin.sender()).whenCompleteAsync( + builder.entry(Component.translatable("api.friends.chat"), + buttonWidget -> ChannelRequest.getOrCreateDM(origin.sender()).whenCompleteAsync( (channel, throwable) -> client.execute( - () -> client.setScreen(new ChatScreen(screen.getParent(), channel)))); - }).spacer(); + () -> client.setScreen(new ChatScreen(screen.getParent(), channel))))).spacer(); } builder.entry(Component.translatable("api.chat.report.message"), buttonWidget -> { Screen previous = client.screen; @@ -205,7 +206,7 @@ protected void renderExtras(GuiGraphics graphics, int x, int y, int mouseX, int } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovered, float tickDelta) { for (ChatLine l : children()) { if (l.getOrigin().equals(origin)) { if (Objects.equals(getHovered(), l)) { @@ -215,6 +216,11 @@ public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth } } if (hovered && !screen.hasContextMenu()) { + var x = getContentX(); + var y = getContentY(); + var entryWidth = getContentWidth(); + var entryHeight = getContentHeight(); + var index = ChatWidget.this.children().indexOf(this); graphics.fill(x - 2 - 22, y - 2, x + entryWidth + 20, y + entryHeight - 1, 0x33FFFFFF); if (index < children().size() - 1 && children().get(index + 1).getOrigin().equals(origin)) { graphics.fill(x - 2 - 22, y + entryHeight - 1, x + entryWidth + 20, y + entryHeight + 2, @@ -226,8 +232,8 @@ public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth graphics.fill(x - 2 - 22, y + entryHeight - 1, x + entryWidth + 20, y + entryHeight, 0x33FFFFFF); } } - renderExtras(graphics, x, y, mouseX, mouseY); - graphics.drawString(client.font, content, x, y, -1, false); + renderExtras(graphics, getContentX(), getContentY(), mouseX, mouseY); + graphics.drawString(client.font, content, getContentX(), getContentY(), -1, false); } @Override @@ -251,7 +257,6 @@ public NameChatLine(ChatMessage message) { @Override protected void renderExtras(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { graphics.pose().pushMatrix(); - //graphics.pose().translate(0, 0, 5); ResourceLocation texture = Auth.getInstance().getSkinTexture(getOrigin().sender().getUuid()); PlayerFaceRenderer.draw(graphics, texture, x - 22, y, 18, true, false, -1); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/CreateChannelScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/chat/CreateChannelScreen.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/chat/CreateChannelScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/chat/CreateChannelScreen.java index 3d9d5643a..63bfe805a 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/chat/CreateChannelScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/chat/CreateChannelScreen.java @@ -114,7 +114,7 @@ protected void init() { ), Arrays.stream(namesInput.getValue().split(",")).filter(s -> !s.isEmpty()) .toArray(String[]::new) - ).thenRun(() -> minecraft.submit(() -> minecraft.setScreen(parent))); + ).thenRun(() -> minecraft.execute(() -> minecraft.setScreen(parent))); }).build()); layout.addToFooter(footer); @@ -135,6 +135,10 @@ protected void updateMessage() { protected void applyValue() { currentVal.set(valueFunc.apply(value)); } + + public void setValue(double v) { + this.value = v; + } }; slider.updateMessage(); slider.applyValue(); @@ -148,9 +152,7 @@ protected void applyValue() { text.setValue(String.valueOf(currentVal.get())); } else { try { - slider.onClick(slider.getX() + (1d / slider.getWidth()) * Double.parseDouble(text.getValue()), - slider.getY() - ); + slider.setValue(Double.parseDouble(text.getValue())); } catch (Exception ignored) { } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/AxolotlClientE4mcPlugin.java b/1.latest/src/main/java/io/github/axolotlclient/api/e4mc/AxolotlClientE4mcPlugin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/AxolotlClientE4mcPlugin.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/e4mc/AxolotlClientE4mcPlugin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/E4mcMixinPlugin.java b/1.latest/src/main/java/io/github/axolotlclient/api/e4mc/E4mcMixinPlugin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/E4mcMixinPlugin.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/e4mc/E4mcMixinPlugin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/E4mcStatusProvider.java b/1.latest/src/main/java/io/github/axolotlclient/api/e4mc/E4mcStatusProvider.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/E4mcStatusProvider.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/e4mc/E4mcStatusProvider.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionInnerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionInnerMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionInnerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionInnerMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionMixin.java b/1.latest/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/e4mc/mixin/QuiclimeSessionMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java b/1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerSelectionList.java b/1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerSelectionList.java similarity index 87% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerSelectionList.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerSelectionList.java index 520c8f20f..53e561082 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerSelectionList.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/FriendsMultiplayerSelectionList.java @@ -51,6 +51,8 @@ import net.minecraft.client.gui.components.PlayerFaceRenderer; import net.minecraft.client.gui.screens.FaviconTexture; import net.minecraft.client.gui.screens.LoadingDotsText; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.*; @@ -112,9 +114,9 @@ public void setSelected(@Nullable FriendsMultiplayerSelectionList.Entry entry) { } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(KeyEvent event) { FriendsMultiplayerSelectionList.Entry entry = this.getSelected(); - return entry != null && entry.keyPressed(keyCode, scanCode, modifiers) || super.keyPressed(keyCode, scanCode, modifiers); + return entry != null && entry.keyPressed(event) || super.keyPressed(event); } public void updateList(List friends) { @@ -136,7 +138,7 @@ private Entry createEntry(User friend) { return e4mcServerFriendEntry(this.screen, friend); } } - return new StatusFriendEntry(screen, friend); + return new StatusFriendEntry(friend); } public void updateEntry(User user) { @@ -177,7 +179,7 @@ public class StatusFriendEntry extends Entry { protected final User user; - protected StatusFriendEntry(final FriendsMultiplayerScreen screen, final User friend) { + protected StatusFriendEntry(final User friend) { this.user = friend; } @@ -187,27 +189,27 @@ public Component getNarration() { } @Override - public void render(GuiGraphics graphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics graphics, int mouseX, int mouseY, boolean hovering, float partialTick) { if (user.isSystem()) { MutableComponent fronters = Component.literal( user.getSystem().getFronters().stream().map(PkSystem.Member::getDisplayName) .collect(Collectors.joining("/"))); Component tag = Component.literal("(" + user.getSystem().getName() + "/" + user.getName() + ")") .setStyle(Style.EMPTY.withItalic(true).withColor(ChatFormatting.GRAY)); - graphics.drawString(minecraft.font, fronters.append(tag), left + 3, top + 1, -1); + graphics.drawString(minecraft.font, fronters.append(tag), getContentX() + 3, getContentY() + 1, -1); } else { - graphics.drawString(minecraft.font, user.getName(), left + 3 + 32, top + 1, -1); + graphics.drawString(minecraft.font, user.getName(), getContentX() + 3 + 32, getContentY() + 1, -1); } if (user.getStatus().isOnline() && user.getStatus().getActivity() != null) { - graphics.drawString(minecraft.font, user.getStatus().getTitle(), left + 3 + 32, top + 12, 0xFF808080); - graphics.drawString(minecraft.font, user.getStatus().getDescription(), left + 3 + 40, top + 23, 0xFF808080); + graphics.drawString(minecraft.font, user.getStatus().getTitle(), getContentX() + 3 + 32, getContentY() + 12, 0xFF808080); + graphics.drawString(minecraft.font, user.getStatus().getDescription(), getContentX() + 3 + 40, getContentY() + 23, 0xFF808080); } else if (user.getStatus().getLastOnline() != null) { - graphics.drawString(minecraft.font, user.getStatus().getLastOnline(), left + 3 + 32, top + 12, 0xFF808080); + graphics.drawString(minecraft.font, user.getStatus().getLastOnline(), getContentX() + 3 + 32, getContentY() + 12, 0xFF808080); } ResourceLocation texture = Auth.getInstance().getSkinTexture(user); - PlayerFaceRenderer.draw(graphics, texture, left, top, 32, true, false, -1); + PlayerFaceRenderer.draw(graphics, texture, getContentX(), getContentY(), 32, true, false, -1); } } @@ -223,7 +225,6 @@ protected class ServerEntry extends Entry { protected final ServerData serverData; private final FaviconTexture icon; private byte @Nullable [] lastIconBytes; - private long lastClickTime; @Nullable private List onlinePlayersTooltip; @Nullable @@ -284,7 +285,7 @@ protected void refreshStatus() { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { if (this.serverData.state() == ServerData.State.INITIAL) { this.serverData.setState(ServerData.State.PINGING); this.serverData.motd = CommonComponents.EMPTY; @@ -320,18 +321,18 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi ); } - guiGraphics.drawString(this.minecraft.font, this.serverData.name, left + ICON_WIDTH + 3, top + 1, -1); + guiGraphics.drawString(this.minecraft.font, this.serverData.name, getContentX() + ICON_WIDTH + 3, getContentY() + 1, -1); List list = this.minecraft.font.split(this.serverData.motd, width - ICON_WIDTH - 2); for (int i = 0; i < Math.min(list.size(), 2); i++) { - guiGraphics.drawString(this.minecraft.font, list.get(i), left + ICON_WIDTH + 3, top + 12 + 9 * i, -8355712); + guiGraphics.drawString(this.minecraft.font, list.get(i), getContentX() + ICON_WIDTH + 3, getContentY() + 12 + 9 * i, -8355712); } - guiGraphics.blit(RenderPipelines.GUI_TEXTURED, this.icon.textureLocation(), left, top, 0.0F, 0.0F, ICON_WIDTH, ICON_HEIGHT, ICON_WIDTH, ICON_HEIGHT); + guiGraphics.blit(RenderPipelines.GUI_TEXTURED, this.icon.textureLocation(), getContentX(), getContentY(), 0.0F, 0.0F, ICON_WIDTH, ICON_HEIGHT, ICON_WIDTH, ICON_HEIGHT); ResourceLocation texture = Auth.getInstance().getSkinTexture(user); - PlayerFaceRenderer.draw(guiGraphics, texture, left + ICON_WIDTH - 10, top + ICON_HEIGHT - 10, 10, true, false, -1); + PlayerFaceRenderer.draw(guiGraphics, texture, getContentX() + ICON_WIDTH - 10, getContentY() + ICON_HEIGHT - 10, 10, true, false, -1); if (this.serverData.state() == ServerData.State.PINGING) { - int i = (int) (Util.getMillis() / 100L + index * 2 & 7L); + int i = (int) (Util.getMillis() / 100L + FriendsMultiplayerSelectionList.this.children().indexOf(this) * 2 & 7L); if (i > 4) { i = 8 - i; } @@ -344,9 +345,9 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi }; } - int i = left + width - STATUS_ICON_WIDTH - SPACING; + int i = getContentX() + width - STATUS_ICON_WIDTH - SPACING; if (this.statusIcon != null) { - guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, this.statusIcon, i, top, STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT); + guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, this.statusIcon, i, getContentY(), STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT); } byte[] bs = this.serverData.getIconBytes(); @@ -370,22 +371,21 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi } int j = this.minecraft.font.width(component); int k = i - j - SPACING; - guiGraphics.drawString(this.minecraft.font, component, k, top + 1, -8355712); - if (this.statusIconTooltip != null && mouseX >= i && mouseX <= i + STATUS_ICON_WIDTH && mouseY >= top && mouseY <= top + STATUS_ICON_HEIGHT) { + guiGraphics.drawString(this.minecraft.font, component, k, getContentY() + 1, -8355712); + if (this.statusIconTooltip != null && mouseX >= i && mouseX <= i + STATUS_ICON_WIDTH && mouseY >= getContentY() && mouseY <= getContentY() + STATUS_ICON_HEIGHT) { guiGraphics.setTooltipForNextFrame(this.statusIconTooltip, mouseX, mouseY); - } else if (this.onlinePlayersTooltip != null && mouseX >= k && mouseX <= k + j && mouseY >= top && mouseY <= top - 1 + 9) { + } else if (this.onlinePlayersTooltip != null && mouseX >= k && mouseX <= k + j && mouseY >= getContentY() && mouseY <= getContentY() - 1 + 9) { guiGraphics.setTooltipForNextFrame(Lists.transform(this.onlinePlayersTooltip, Component::getVisualOrderText), mouseX, mouseY); } if (this.minecraft.options.touchscreen().get() || hovering) { - int l = mouseX - left; - int m = mouseY - top; + int l = mouseX - getContentX(); if (this.canJoin()) { - guiGraphics.fill(left, top, left + ICON_WIDTH, top + ICON_HEIGHT, -1601138544); + guiGraphics.fill(getContentX(), getContentY(), getContentX() + ICON_WIDTH, getContentY() + ICON_HEIGHT, -1601138544); if (l < ICON_WIDTH && l > ICON_WIDTH / 2) { - guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, FriendsMultiplayerSelectionList.JOIN_HIGHLIGHTED_SPRITE, left, top, ICON_WIDTH, ICON_HEIGHT); + guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, FriendsMultiplayerSelectionList.JOIN_HIGHLIGHTED_SPRITE, getContentX(), getContentY(), ICON_WIDTH, ICON_HEIGHT); } else { - guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, FriendsMultiplayerSelectionList.JOIN_SPRITE, left, top, ICON_WIDTH, ICON_HEIGHT); + guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, FriendsMultiplayerSelectionList.JOIN_SPRITE, getContentX(), getContentY(), ICON_WIDTH, ICON_HEIGHT); } } } @@ -416,9 +416,8 @@ private boolean uploadIcon(byte @Nullable [] iconBytes) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - double d = mouseX - FriendsMultiplayerSelectionList.this.getRowLeft(); - double e = mouseY - FriendsMultiplayerSelectionList.this.getRowTop(FriendsMultiplayerSelectionList.this.children().indexOf(this)); + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + double d = event.x() - FriendsMultiplayerSelectionList.this.getRowLeft(); if (d <= 32.0) { if (d < 32.0 && d > 16.0 && this.canJoin()) { this.screen.setSelected(this); @@ -428,12 +427,11 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } this.screen.setSelected(this); - if (Util.getMillis() - this.lastClickTime < 250L && canJoin()) { + if (doubleClick && canJoin()) { this.screen.joinSelectedServer(); } - this.lastClickTime = Util.getMillis(); - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } @Override @@ -539,8 +537,8 @@ public static class LoadingHeader extends FriendsMultiplayerSelectionList.Entry private final Minecraft minecraft = Minecraft.getInstance(); @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = top + height / 2 - 9 / 2; + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + int i = getContentYMiddle() - 9 / 2; String string = LoadingDotsText.get(Util.getMillis()); guiGraphics.drawString(this.minecraft.font, string, this.minecraft.screen.width / 2 - this.minecraft.font.width(string) / 2, i, -8355712); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java b/1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java similarity index 91% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java index 1a5b72799..25d82e033 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/multiplayer/ServerInfoUtil.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Optional; -import com.mojang.authlib.GameProfile; import io.github.axolotlclient.api.types.Status; import io.github.axolotlclient.api.util.UUIDHelper; import net.minecraft.ChatFormatting; @@ -34,6 +33,7 @@ import net.minecraft.client.multiplayer.ServerStatusPinger; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.status.ServerStatus; +import net.minecraft.server.players.NameAndId; public class ServerInfoUtil { public static Status.Activity.ServerInfo getServerInfo(String levelName, ServerStatus status) { @@ -44,7 +44,7 @@ public static Status.Activity.ServerInfo getServerInfo(String levelName, ServerS new Status.Activity.ServerInfo.Favicon(status.favicon().map(ServerStatus.Favicon::iconBytes).orElse(null)), status.players().map(p -> new Status.Activity.ServerInfo.Players(p.max(), p.online(), - p.sample().stream().map(prof -> new Status.Activity.ServerInfo.Players.Player(prof.getName(), UUIDHelper.toUndashed(prof.getId()))).toList()) + p.sample().stream().map(prof -> new Status.Activity.ServerInfo.Players.Player(prof.name(), UUIDHelper.toUndashed(prof.id()))).toList()) ).orElse(null), status.version().map(v -> new Status.Activity.ServerInfo.Version(v.name(), v.protocol())).orElse(null)); } @@ -53,7 +53,7 @@ public static ServerStatus getServerStatus(Status.Activity.ServerInfo info) { return new ServerStatus(Component.nullToEmpty(info.description()), Optional.ofNullable(info.players()).map(p -> new ServerStatus.Players(p.max(), p.online(), - p.sample().stream().map(prof -> new GameProfile(UUIDHelper.fromUndashed(prof.uuid()), prof.name())).toList())), + p.sample().stream().map(prof -> new NameAndId(UUIDHelper.fromUndashed(prof.uuid()), prof.name())).toList())), Optional.ofNullable(info.version()).map(v -> new ServerStatus.Version(v.name(), v.protocol())), Optional.ofNullable(info.icon()).map(f -> new ServerStatus.Favicon(f.iconBytes())), false); @@ -78,8 +78,8 @@ public static ServerData getServerData(String username, Status.Activity.E4mcMeta if (!player.sample().isEmpty()) { List list = new ArrayList<>(player.sample().size()); - for (GameProfile gameProfile : player.sample()) { - list.add(Component.literal(gameProfile.getName())); + for (var gameProfile : player.sample()) { + list.add(Component.literal(gameProfile.name())); } if (player.sample().size() < player.online()) { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/worldhost/AxolotlClientWorldHostPlugin.java b/1.latest/src/main/java/io/github/axolotlclient/api/worldhost/AxolotlClientWorldHostPlugin.java similarity index 99% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/worldhost/AxolotlClientWorldHostPlugin.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/worldhost/AxolotlClientWorldHostPlugin.java index 7dbd69493..046c25929 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/api/worldhost/AxolotlClientWorldHostPlugin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/api/worldhost/AxolotlClientWorldHostPlugin.java @@ -95,7 +95,7 @@ public void refreshOnlineFriends() { .filter(u -> u.getStatus().isOnline()).filter(u -> u.getStatus().getActivity() != null) .filter(u -> u.getStatus().getActivity().hasMetadata()) .map(AxolotlClientOnlineFriend::of) - .forEach(friend -> WorldHost.ONLINE_FRIENDS.put(friend.profile.getId(), friend)); + .forEach(friend -> WorldHost.ONLINE_FRIENDS.put(friend.profile.id(), friend)); WorldHost.ONLINE_FRIEND_UPDATES.forEach(FriendsListUpdate::friendsListUpdate); }); } @@ -130,7 +130,7 @@ private static AxolotlClientOnlineFriend of(User user) { @Override public UUID uuid() { - return profile.getId(); + return profile.id(); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/api/worldhost/WorldHostStatusProvider.java b/1.latest/src/main/java/io/github/axolotlclient/api/worldhost/WorldHostStatusProvider.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/api/worldhost/WorldHostStatusProvider.java rename to 1.latest/src/main/java/io/github/axolotlclient/api/worldhost/WorldHostStatusProvider.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/AxoEnchantImpl.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/impl/AxoEnchantImpl.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/AxoEnchantImpl.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/impl/AxoEnchantImpl.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/AxoSpriteImpl.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/impl/AxoSpriteImpl.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/AxoSpriteImpl.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/impl/AxoSpriteImpl.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java similarity index 73% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java index affbe7fbe..6f1453976 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/impl/Bridge.java @@ -28,11 +28,10 @@ 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.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.resource.ResourceManagerHelper; -import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.fabricmc.fabric.api.resource.v1.ResourceLoader; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.ResourceManagerReloadListener; public class Bridge { @SuppressWarnings({"rawtypes", "unchecked"}) @@ -40,19 +39,9 @@ public static void init() { ClientLifecycleEvents.CLIENT_STARTED.register(minecraft -> Events.CLIENT_START.invoker().run()); ClientLifecycleEvents.CLIENT_STOPPING.register(minecraft -> Events.CLIENT_STOP.invoker().run()); ClientTickEvents.END_CLIENT_TICK.register(minecraft -> Events.TICK.invoker().run()); - ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { - - @Override - public void onResourceManagerReload(ResourceManager resourceManager) { - Events.END_RESOURCE_RELOAD.invoker().run(); - } - - @Override - public ResourceLocation getFabricId() { - return ResourceLocation.fromNamespaceAndPath("axolotlclient", "bridge/resource_listener"); - } - }); - ClientPlayConnectionEvents.INIT.register((clientPlayNetworkHandler, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); + ResourceLoader.get(PackType.CLIENT_RESOURCES).registerReloader(ResourceLocation.fromNamespaceAndPath("axolotlclient", "bridge/resource_listener"), + (ResourceManagerReloadListener) resourceManager -> Events.END_RESOURCE_RELOAD.invoker().run()); + ClientPlayConnectionEvents.JOIN.register((clientPlayNetworkHandler, sender, minecraftClient) -> Events.CONNECTION_PLAY_READY.invoker().run()); ClientPlayConnectionEvents.DISCONNECT.register((clientPlayNetworkHandler, minecraftClient) -> Events.DISCONNECT.invoker().run()); ClientCommandRegistrationCallback.EVENT.register((commandDispatcher, commandBuildContext) -> diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java index 3fc7a7b7e..9efdb2e42 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/MinecraftClientMixin.java @@ -146,7 +146,7 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient { @Override public void br$reinitScreen() { if (screen != null) { - screen.init((Minecraft) (Object)this, screen.width, screen.height); + screen.init((Minecraft) (Object) this, screen.width, screen.height); } } @@ -154,4 +154,9 @@ public abstract class MinecraftClientMixin implements AxoMinecraftClient { public AxoResourceManager br$getResourceManager() { return getResourceManager(); } + + @Override + public Object br$getScreen() { + return screen; + } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java index dd9b781cc..83f999874 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/PlatformDispatchMixin.java @@ -45,7 +45,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(value = PlatformDispatch.class, remap = false) -public class PlatformDispatchMixin { +public abstract class PlatformDispatchMixin { @Unique private static final ServerStatusPinger axo$pinger = new ServerStatusPinger(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java similarity index 92% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java index 33151372d..1e425be70 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/PlayerListEntryMixin.java @@ -32,18 +32,18 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(PlayerInfo.class) -public class PlayerListEntryMixin implements AxoPlayerListEntry { +public abstract class PlayerListEntryMixin implements AxoPlayerListEntry { @Shadow @Final private GameProfile profile; @Override public String br$getName() { - return profile.getName(); + return profile.name(); } @Override public UUID br$getId() { - return profile.getId(); + return profile.id(); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/EntityMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/EntityMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/EntityMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/EntityMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java index 7206350bc..ef22ade01 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/LivingEntityMixin.java @@ -36,7 +36,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(LivingEntity.class) -public class LivingEntityMixin implements AxoLivingEntity { +public abstract class LivingEntityMixin implements AxoLivingEntity { @Shadow @Final private Map, MobEffectInstance> activeEffects; diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/PlayerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/PlayerMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/PlayerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/PlayerMixin.java index 6c5be6287..1c001a608 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/PlayerMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/PlayerMixin.java @@ -60,6 +60,6 @@ public abstract class PlayerMixin implements AxoPlayer { @Override public String br$getName() { - return gameProfile.getName(); + return gameProfile.name(); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java index 10401dc7a..7511d59cc 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/AxoStatusEffectsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoStatusEffects.class, remap = false) -public class AxoStatusEffectsMixin { +public abstract class AxoStatusEffectsMixin { @Mutable @Shadow @Final diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectInstanceMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectInstanceMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectInstanceMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectInstanceMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/entity/effect/StatusEffectMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java index 6f3a80080..3d7dd0839 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/internal/PlatformImplInternalMixin.java @@ -70,7 +70,7 @@ @SuppressWarnings("OverwriteModifiers") @Mixin(value = PlatformImplInternal.class, remap = false) -public class PlatformImplInternalMixin { +public abstract class PlatformImplInternalMixin { /** * @author Flowey * @reason Implement bridge platform. @@ -148,9 +148,9 @@ public static int getCurrentFps() { * @reason Implement bridge platform. */ @Overwrite - public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name, String category) { + public static AxoKeybinding createKeyBinding(AxoKey defaultKey, String name) { int code = ((InputConstants.Key) Objects.requireNonNullElse(defaultKey, AxoKeys.KEY_UNKNOWN)).getValue(); - final var binding = new KeyMapping(name, code, category); + final var binding = new KeyMapping(name, code, KeyBinds.CATEGORY_AXOLOTLCLIENT); KeyBinds.getInstance().register(binding); return binding; } @@ -247,14 +247,12 @@ public static AxoStatusEffectInstance createStatusEffectInstance(AxoStatusEffect */ @Overwrite public static AxoSprite createTexture(GraphicsOption option) { - return (AxoSpriteImpl) (client, stack, sX, sY, sW, sH) -> { - // TODO: specify the correct pipeline for rendering, need to hoist this + return (AxoSpriteImpl) (client, stack, sX, sY, sW, sH) -> stack.blit( RenderPipelines.GUI_TEXTURED, io.github.axolotlclient.util.Util.getTexture(option), sX, sY, 0, 0, - sW, sH, option.get().getWidth(), option.get().getHeight(), 0xffffff + sW, sH, option.get().getWidth(), option.get().getHeight() ); - }; } /** diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java index edbfc9153..da631e2c6 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoEnchantsMixin.java @@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoEnchants.class, remap = false) -public class AxoEnchantsMixin { +public abstract class AxoEnchantsMixin { @Mutable @Shadow @Final diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java similarity index 99% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java index b225aa772..ef8b77631 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/AxoItemsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoItems.class, remap = false) -public class AxoItemsMixin { +public abstract class AxoItemsMixin { @Mutable @Shadow @Final diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java similarity index 94% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java index df5586e32..9b715681f 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/EnchantmentMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Enchantment.class) -public class EnchantmentMixin implements AxoEnchant { +public abstract class EnchantmentMixin implements AxoEnchant { } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java index f2e1394d9..ea8b5d758 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemMixin.java @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(Item.class) -public class ItemMixin implements AxoItem { +public abstract class ItemMixin implements AxoItem { @Override public boolean br$is(AxoItemClass itemClass) { return switch (itemClass) { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/ItemStackMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java index bf0e2d50b..6b7f45ad3 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/item/PlayerInventoryMixin.java @@ -77,7 +77,7 @@ public abstract class PlayerInventoryMixin implements AxoPlayerInventory { @Override public List br$getNonEquipmentItems() { - return items; + return items.subList(9, 36); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java index 16af8eec7..0360ad571 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/AxoKeysMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoKeys.class, remap = false) -public class AxoKeysMixin { +public abstract class AxoKeysMixin { @Mutable @Shadow diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java index 7e608bc5d..0d6d950be 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/GameOptionsMixin.java @@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(Options.class) -public class GameOptionsMixin implements AxoClientKeybinds { +public abstract class GameOptionsMixin implements AxoClientKeybinds { @Shadow @Final public KeyMapping keySprint; diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyBindingMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyBindingMixin.java similarity index 92% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyBindingMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyBindingMixin.java index 42d51d8da..13117a4ad 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyBindingMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyBindingMixin.java @@ -46,7 +46,7 @@ public abstract class KeyBindingMixin implements AxoKeybinding { public abstract boolean isDown(); @Shadow - private InputConstants.Key key; + protected InputConstants.Key key; @Shadow public abstract boolean consumeClick(); @@ -68,8 +68,8 @@ private void dispatchHandlers(boolean pressed, CallbackInfo ci) { } } - @Inject(method = "(Ljava/lang/String;Lcom/mojang/blaze3d/platform/InputConstants$Type;ILjava/lang/String;)V", at = @At("TAIL")) - private void registerClickHandler(String name, InputConstants.Type type, int keyCode, String category, CallbackInfo ci) { + @Inject(method = "(Ljava/lang/String;Lcom/mojang/blaze3d/platform/InputConstants$Type;ILnet/minecraft/client/KeyMapping$Category;)V", at = @At("TAIL")) + private void registerClickHandler(String string, InputConstants.Type type, int i, KeyMapping.Category category, CallbackInfo ci) { Events.TICK.register(() -> { while (axolotlclient$onConsumeClick != null && consumeClick()) { axolotlclient$onConsumeClick.forEach(Runnable::run); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java index f4882f2f6..6e543798f 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/key/KeyMixin.java @@ -27,5 +27,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(InputConstants.Key.class) -public class KeyMixin implements AxoKey { +public abstract class KeyMixin implements AxoKey { } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java index 2a90c26a9..997b9a671 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/AxoSpritesMixin.java @@ -39,7 +39,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AxoSprites.class, remap = false) -public class AxoSpritesMixin { +public abstract class AxoSpritesMixin { @Mutable @Shadow @Final diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/FontMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/FontMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/FontMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/FontMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java index 453388a2e..6007d935e 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/GuiGraphicsMixin.java @@ -89,13 +89,13 @@ public abstract class GuiGraphicsMixin implements AxoRenderContext { @Override public void br$translateMatrix(float x, float y, float z) { - pose.scale(x, y); + pose.translate(x, y); } // scissor @Override public void br$pushScissor(int x, int y, int w, int h) { - enableScissor(x, y, x+w, y+h); + enableScissor(x, y, x + w, y + h); } @Override @@ -129,18 +129,18 @@ public abstract class GuiGraphicsMixin implements AxoRenderContext { @Override public int br$drawString(String value, int x, int y, int color, boolean shadow) { drawString(minecraft.font, value, x, y, color, shadow); - return x+minecraft.font.width(value); + return x + minecraft.font.width(value); } @Override public int br$drawString(AxoText value, int x, int y, int color, boolean shadow) { drawString(minecraft.font, (Component) value, x, y, color, shadow); - return x+minecraft.font.width((FormattedText) value); + return x + minecraft.font.width((FormattedText) value); } @Override public void br$fillRect(int x, int y, int width, int height, int color) { - fill(x, y, x+width, y+height, color); + fill(x, y, x + width, y + height, color); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/WindowMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/WindowMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/render/WindowMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/render/WindowMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceManagerMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/resource/ResourceMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ObjectiveMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ObjectiveMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ObjectiveMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ObjectiveMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/PlayerScoreEntryMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/PlayerScoreEntryMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/PlayerScoreEntryMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/PlayerScoreEntryMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ScoreboardMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ScoreboardMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ScoreboardMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/ScoreboardMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/TeamMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/TeamMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/TeamMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/scoreboard/TeamMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/ComponentMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/ComponentMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/ComponentMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/ComponentMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/IdentifierMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableComponentMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableComponentMixin.java similarity index 73% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableComponentMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableComponentMixin.java index 4ff806669..70289f8dc 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableComponentMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/MutableComponentMixin.java @@ -30,20 +30,20 @@ @Mixin(MutableComponent.class) public abstract class MutableComponentMixin implements Component, AxoText.Mutable { - @Shadow - public abstract MutableComponent append(Component sibling); + @Shadow + public abstract MutableComponent append(Component sibling); - @Shadow - public abstract MutableComponent setStyle(net.minecraft.network.chat.Style style); + @Shadow + public abstract MutableComponent setStyle(net.minecraft.network.chat.Style style); - @Override - public Mutable br$append(AxoText child) { - return append((Component) child); - } + @Override + public Mutable br$append(AxoText child) { + return append((Component) child); + } - @Override - public Mutable br$setStyle(Style style) { - // can't shadow setStyle because of stupid mapping bug... - return setStyle((net.minecraft.network.chat.Style) style); - } + @Override + public Mutable br$setStyle(Style style) { + // can't shadow setStyle because of stupid mapping bug... + return setStyle((net.minecraft.network.chat.Style) style); + } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/ProfilerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/ProfilerMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/ProfilerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/ProfilerMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/util/StyleMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/world/WorldMixin.java b/1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/world/WorldMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/bridge/mixin/world/WorldMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/bridge/mixin/world/WorldMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java b/1.latest/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java rename to 1.latest/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java index 29ae0d0bf..7aa0a4200 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java +++ b/1.latest/src/main/java/io/github/axolotlclient/config/AxolotlClientConfig.java @@ -33,6 +33,7 @@ import io.github.axolotlclient.AxolotlClientConfig.api.ui.ConfigUI; import io.github.axolotlclient.AxolotlClientConfig.api.util.Color; import io.github.axolotlclient.AxolotlClientConfig.impl.options.*; +import io.github.axolotlclient.AxolotlClientConfig.impl.ui.RecreatableScreen; import io.github.axolotlclient.AxolotlClientConfigCommon; import io.github.axolotlclient.config.screen.CreditsScreen; import io.github.axolotlclient.config.screen.ProfilesScreen; @@ -43,6 +44,7 @@ import lombok.Getter; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.texture.DynamicTexture; public class AxolotlClientConfig extends AxolotlClientConfigCommon { @@ -140,7 +142,10 @@ public AxolotlClientConfig() { general.add(configStyle = new StringArrayOption("configStyle", themes, "configStyle." + ConfigUI.getInstance().getCurrentStyle().getName(), s -> { ConfigUI.getInstance().setStyle(s.split("\\.")[1]); - Minecraft.getInstance().schedule(() -> Minecraft.getInstance().setScreen(null)); + Minecraft.getInstance().schedule(() -> { + Screen newScreen = RecreatableScreen.tryRecreate(Minecraft.getInstance().screen); + Minecraft.getInstance().setScreen(newScreen); + }); })); AxolotlClient.getInstance().getConfigManager().load(); ConfigUI.getInstance().setStyle(configStyle.get().split("\\.")[1]); @@ -173,7 +178,7 @@ public AxolotlClientConfig() { general.add(new GenericOption("profiles.title", "profiles.configure", () -> Minecraft.getInstance().setScreen(new ProfilesScreen(Minecraft.getInstance().screen))), false); - var toggleFullbright = new KeyMapping("toggle_fullbright", -1, "category.axolotlclient"); + var toggleFullbright = new KeyMapping("toggle_fullbright", -1, KeyBinds.CATEGORY_AXOLOTLCLIENT); KeyBinds.getInstance().registerWithSimpleAction(toggleFullbright, fullBright::toggle); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/config/modmenu/ModMenuCompat.java b/1.latest/src/main/java/io/github/axolotlclient/config/modmenu/ModMenuCompat.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/config/modmenu/ModMenuCompat.java rename to 1.latest/src/main/java/io/github/axolotlclient/config/modmenu/ModMenuCompat.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java b/1.latest/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java similarity index 94% rename from 1.21.7/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java index 62b5a507d..d74f752ba 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/config/screen/CreditsScreen.java @@ -176,9 +176,9 @@ protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, - int mouseY, boolean hovered, float tickDelta) { - c.setPosition(x, y); + public void renderContent(GuiGraphics graphics, int mouseX, + int mouseY, boolean hovered, float tickDelta) { + c.setPosition(getContentX(), getContentY()); c.render(graphics, mouseX, mouseY, tickDelta); } @@ -228,7 +228,7 @@ public void init() { @Override public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float delta) { super.renderBackground(graphics, mouseX, mouseY, delta); - DrawUtil.outlineRect(graphics, 100, 50, width - 200, height - 100, + DrawUtil.fillRect(graphics, 100, 50, width - 200, height - 100, ClientColors.DARK_GRAY.withAlpha(127).toInt()); DrawUtil.outlineRect(graphics, 100, 50, width - 200, height - 100, ClientColors.BLACK.toInt()); @@ -250,14 +250,15 @@ public void tick() { private class SpacerTitle extends Entry { private final String name; + public SpacerTitle(String name) { this.name = name; } @Override - public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, - int mouseY, boolean hovered, float tickDelta) { - DrawUtil.drawCenteredString(graphics, font, name, x + entryWidth / 2, y, -128374, + public void renderContent(GuiGraphics graphics, int mouseX, + int mouseY, boolean hovered, float tickDelta) { + DrawUtil.drawCenteredString(graphics, font, name, getContentXMiddle(), getContentY(), -128374, true); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java b/1.latest/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java similarity index 70% rename from 1.21.7/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java index 8cbf6540a..734ef6135 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/config/screen/ProfilesScreen.java @@ -22,6 +22,7 @@ package io.github.axolotlclient.config.screen; +import java.util.ArrayList; import java.util.List; import io.github.axolotlclient.config.profiles.Profiles; @@ -39,9 +40,11 @@ import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ProfilesScreen extends Screen { @@ -81,6 +84,7 @@ protected void repositionElements() { @Override public void onClose() { Profiles.getInstance().saveProfiles(); + //noinspection DataFlowIssue minecraft.setScreen(parent); } @@ -106,10 +110,10 @@ public int getRowWidth() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { children().stream().filter(e -> e instanceof ProfileEntry) .map(e -> (ProfileEntry) e).map(e -> e.profileName).forEach(e -> e.setFocused(false)); - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } @Environment(EnvType.CLIENT) @@ -120,17 +124,17 @@ public abstract static class Entry extends ContainerObjectSelectionList.Entry narratables() { + public @NotNull List narratables() { return List.of(); } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { } @Override - public List children() { + public @NotNull List children() { return List.of(); } @@ -143,14 +147,13 @@ public ComponentPath nextFocusPath(FocusNavigationEvent event) { @Environment(EnvType.CLIENT) public class ProfileEntry extends Entry { + private static final Component EXPORT_BUTTON_TITLE = Component.translatable("profiles.profile.export"); private static final Component CURRENT_TEXT = Component.translatable("profiles.profile.current"); private static final Component LOAD_BUTTON_TITLE = Component.translatable("profiles.profile.load"); private static final Component DUPLICATE_BUTTON_TITLE = Component.translatable("profiles.profile.duplicate"); private static final Component REMOVE_BUTTON_TITLE = Component.translatable("profiles.profile.remove"); private final EditBox profileName; - private final Button loadButton; - private final Button duplicateButton; - private final Button removeButton; + private final Button exportButton, loadButton, duplicateButton, removeButton; private final Profiles.Profile profile; ProfileEntry(Profiles.Profile profile) { @@ -158,12 +161,16 @@ public class ProfileEntry extends Entry { profileName = new EditBox(getFont(), 0, 0, 150, 20, Component.empty()); profileName.setValue(profile.name()); profileName.setResponder(profile::setName); + exportButton = Button.builder(EXPORT_BUTTON_TITLE, btn -> Profiles.getInstance().exportProfile(profile)) + .bounds(0, 0, 50, 20).build(); loadButton = Button.builder(LOAD_BUTTON_TITLE, btn -> Profiles.getInstance().switchTo(profile)).bounds(0, 0, 50, 20).build(); duplicateButton = Button.builder(DUPLICATE_BUTTON_TITLE, b -> { var dup = Profiles.getInstance().duplicate(profile); double d = (double) ProfilesList.this.maxScrollAmount() - ProfilesList.this.scrollAmount(); - ProfilesList.this.children().add(ProfilesList.this.children().indexOf(ProfileEntry.this) + 1, new ProfileEntry(dup)); + @SuppressWarnings("unchecked") var entries = new ArrayList<>((List) children()); + entries.add(entries.indexOf(ProfileEntry.this) + 1, new ProfileEntry(dup)); + replaceEntries(entries); ProfilesList.this.setScrollAmount(ProfilesList.this.maxScrollAmount() - d); }).bounds(0, 0, 50, 20).build(); @@ -176,9 +183,9 @@ public class ProfileEntry extends Entry { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { int i = scrollBarX() - removeButton.getWidth() - 4; - int j = top - 2; + int j = getContentY() - 2; this.removeButton.setPosition(i, j); this.removeButton.render(guiGraphics, mouseX, mouseY, partialTick); @@ -188,56 +195,64 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi boolean current = Profiles.getInstance().getCurrent() == profile; loadButton.setMessage(current ? CURRENT_TEXT : LOAD_BUTTON_TITLE); - loadButton.active = !current; + loadButton.active = removeButton.active = !current; i -= loadButton.getWidth(); this.loadButton.setPosition(i, j); this.loadButton.render(guiGraphics, mouseX, mouseY, partialTick); - profileName.setWidth(i - left - 4); - profileName.setPosition(left, j); + i -= exportButton.getWidth(); + exportButton.setPosition(i, j); + exportButton.render(guiGraphics, mouseX, mouseY, partialTick); + profileName.setWidth(i - getContentX() - 4); + profileName.setPosition(getContentX(), j); profileName.render(guiGraphics, mouseX, mouseY, partialTick); } @Override - public List children() { - return List.of(profileName, this.loadButton, duplicateButton, removeButton); + public @NotNull List children() { + return List.of(profileName, exportButton, this.loadButton, duplicateButton, removeButton); } @Override - public List narratables() { - return List.of(profileName, this.loadButton, duplicateButton, removeButton); + public @NotNull List narratables() { + return List.of(profileName, exportButton, this.loadButton, duplicateButton, removeButton); } } public class NewEntry extends Entry { - private final Button addButton; + private final Button addButton, importButton; public NewEntry() { this.addButton = Button.builder(Component.translatable("profiles.profile.add"), button -> { - int i = ProfilesList.this.children().indexOf(this); - ProfilesList.this.children().add(Math.max(i - 1, 0), new ProfilesList.ProfileEntry(Profiles.getInstance().newProfile(I18n.get("profiles.profile.default_new_name")))); + var entries = new ArrayList<>(ProfilesList.this.children()); + entries.add(Math.max(entries.indexOf(this) - 1, 0), new ProfileEntry(Profiles.getInstance().newProfile(I18n.get("profiles.profile.default_new_name")))); + replaceEntries(entries); Profiles.getInstance().saveProfiles(); setScrollAmount(maxScrollAmount()); }).bounds(0, 0, 150, 20) .build(); + this.importButton = Button.builder(Component.translatable("profiles.profile.import"), btn -> + Profiles.getInstance().importProfiles().thenRun(ProfilesList.this::reload)).build(); } @Override - public List narratables() { + public @NotNull List narratables() { return List.of(addButton); } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = scrollBarX() - width / 2 - 10 - addButton.getWidth() / 2; - int j = top - 2; + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + int i = scrollBarX() - getContentWidth() / 2 - 10 - addButton.getWidth() + 2; + int j = getContentY() - 2; this.addButton.setPosition(i, j); this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); + this.importButton.setPosition(addButton.getRight() + 2, j); + this.importButton.render(guiGraphics, mouseX, mouseY, partialTick); } @Override - public List children() { - return List.of(addButton); + public @NotNull List children() { + return List.of(addButton, importButton); } } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/AbstractContainerScreenAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/AbstractContainerScreenAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/AbstractContainerScreenAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/AbstractContainerScreenAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/AddServerScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/AddServerScreenMixin.java similarity index 94% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/AddServerScreenMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/AddServerScreenMixin.java index a43ef6846..ab2257f26 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/AddServerScreenMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/AddServerScreenMixin.java @@ -23,14 +23,14 @@ package io.github.axolotlclient.mixin; import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.screens.EditServerScreen; +import net.minecraft.client.gui.screens.ManageServerScreen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(EditServerScreen.class) +@Mixin(ManageServerScreen.class) public abstract class AddServerScreenMixin { @Shadow diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/BeaconBlockEntityRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/BeaconBlockEntityRendererMixin.java similarity index 73% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/BeaconBlockEntityRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/BeaconBlockEntityRendererMixin.java index ee5198165..cb3333038 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/BeaconBlockEntityRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/BeaconBlockEntityRendererMixin.java @@ -24,7 +24,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import io.github.axolotlclient.modules.renderOptions.BeaconBeam; -import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.blockentity.BeaconRenderer; import net.minecraft.resources.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; @@ -36,9 +36,8 @@ public abstract class BeaconBlockEntityRendererMixin { - @Inject(method = "renderBeaconBeam(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/resources/ResourceLocation;FFJIIIFF)V", at = @At("HEAD"), cancellable = true) - private static void axolotlclient$cancelBeamRender(PoseStack matrices, MultiBufferSource vertexConsumers, - ResourceLocation texture, float tickDelta, float heightScale, long time, int segmentBottom, int segmentHeight, int color, float innerRadius, float outerRadius, CallbackInfo ci) { + @Inject(method = "submitBeaconBeam(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/resources/ResourceLocation;FFIIIFF)V", at = @At("HEAD"), cancellable = true) + private static void axolotlclient$cancelBeamRender(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, ResourceLocation texture, float f, float g, int i, int j, int k, float h, float l, CallbackInfo ci) { if (!BeaconBeam.getInstance().showBeam(texture.getPath().contains("end_gateway"))) { ci.cancel(); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/BossBarHudAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/BossBarHudAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/BossBarHudAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/BossBarHudAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/BossBarHudMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/BossBarHudMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/BossBarHudMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/BossBarHudMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/CameraMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ChatHudMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ChatHudMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ChatHudMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ChatHudMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientBrandRetrieverMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ClientBrandRetrieverMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientBrandRetrieverMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ClientBrandRetrieverMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientPlayNetworkHandlerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ClientPlayNetworkHandlerMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientPlayNetworkHandlerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ClientPlayNetworkHandlerMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ClientPlayerEntityMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientWorldMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ClientWorldMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ClientWorldMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ClientWorldMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/DebugHudMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/DebugHudMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/DebugHudMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/DebugHudMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/DownloadedPackSourceAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/DownloadedPackSourceAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/DownloadedPackSourceAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/DownloadedPackSourceAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/EmitterParticleMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/EmitterParticleMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/EmitterParticleMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/EmitterParticleMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java similarity index 92% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java index 827215f89..4d83a27be 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/EntityMixin.java @@ -22,10 +22,10 @@ package io.github.axolotlclient.mixin; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.modules.freelook.Freelook; import io.github.axolotlclient.modules.hypixel.Skyblock; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -62,6 +62,6 @@ public abstract class EntityMixin { float pitch = prevPitch + (float) (mouseDeltaY * .15); float yaw = prevYaw + (float) (mouseDeltaX * .15); pitch = Mth.clamp(pitch, -90.0F, 90.0F); - Events.PLAYER_DIRECTION_CHANGE.invoker().invoke(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); + Events.PLAYER_DIRECTION_CHANGE.invoker().accept(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GameMenuScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GameMenuScreenMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/GameMenuScreenMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/GameMenuScreenMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java index 20cb88d5d..916ca8c19 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/GameOptionsMixin.java @@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Options.class) -public class GameOptionsMixin { +public abstract class GameOptionsMixin { @Mutable @Shadow diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GameRendererAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GameRendererAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/GameRendererAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/GameRendererAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java similarity index 82% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java index 556d92737..668992a29 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/GameRendererMixin.java @@ -22,9 +22,6 @@ package io.github.axolotlclient.mixin; -import java.util.ArrayList; -import java.util.List; - import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; @@ -35,14 +32,11 @@ import com.mojang.math.Axis; import io.github.axolotlclient.AxolotlClient; import io.github.axolotlclient.modules.blur.MotionBlur; -import io.github.axolotlclient.modules.hud.util.PlayerHudEntityRenderer; import io.github.axolotlclient.modules.zoom.Zoom; import net.minecraft.client.Camera; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.util.Mth; import net.minecraft.util.profiling.Profiler; import org.joml.Matrix4f; @@ -51,7 +45,6 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameRenderer.class) @@ -64,13 +57,6 @@ public abstract class GameRendererMixin { @Shadow private boolean panoramicMode; - @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/GuiRenderer;(Lnet/minecraft/client/gui/render/state/GuiRenderState;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Ljava/util/List;)V"), index = 2) - private List> addPlayerHudEntityRenderer(List> list, @Local MultiBufferSource.BufferSource source, @Local(argsOnly = true) Minecraft minecraft) { - List> mutable = new ArrayList<>(list); - mutable.add(new PlayerHudEntityRenderer(source, minecraft.getEntityRenderDispatcher())); - return mutable; - } - @WrapOperation(method = "getFov", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;lerp(FFF)F")) private float disableDynamicFov(float delta, float start, float end, Operation original) { if (!AxolotlClient.config().dynamicFOV.get()) { @@ -114,7 +100,7 @@ private float getFov(Camera camera, float partialTick, boolean useFovSetting, Op at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;translate(FFF)V"), cancellable = true) private void axolotlclient$minimalViewBob(PoseStack matrices, float tickDelta, CallbackInfo ci, - @Local(ordinal = 2) float g, @Local(ordinal = 3) float h) { + @Local(ordinal = 1) float g, @Local(ordinal = 2) float h) { if (AxolotlClient.config().minimalViewBob.get()) { g /= 2; h /= 2; diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java index 56e652aa9..b64253bb7 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/GuiGraphicsMixin.java @@ -39,7 +39,7 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(GuiGraphics.class) -public class GuiGraphicsMixin { +public abstract class GuiGraphicsMixin { @Unique private int recursionDepth; diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/GuiRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/GuiRendererMixin.java new file mode 100644 index 000000000..2ee466417 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/GuiRendererMixin.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import java.util.Map; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.util.IdentifiablePiPRenderState; +import net.minecraft.client.gui.render.GuiRenderer; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; +import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(GuiRenderer.class) +public abstract class GuiRendererMixin { + + @WrapOperation(method = "preparePictureInPictureState", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;")) + private Object improvePiPRenderers(Map, PictureInPictureRenderer> instance, Object o, Operation> original, PictureInPictureRenderState state) { + if (state instanceof IdentifiablePiPRenderState idState) { + return idState.renderer(); + } + return original.call(instance, o); + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java similarity index 78% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java index 9d3723249..b70ab91d5 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/HandledScreenMixin.java @@ -23,6 +23,8 @@ package io.github.axolotlclient.mixin; import com.llamalad7.mixinextras.sugar.Local; +import io.github.axolotlclient.modules.hud.HudManager; +import io.github.axolotlclient.modules.hud.gui.hud.IconHud; import io.github.axolotlclient.modules.scrollableTooltips.ScrollableTooltips; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; @@ -46,4 +48,12 @@ public abstract class HandledScreenMixin { ScrollableTooltips.getInstance().resetScroll(); } } + + @Inject(method = "renderBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/inventory/AbstractContainerScreen;renderBg(Lnet/minecraft/client/gui/GuiGraphics;FII)V")) + private void renderIcon(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci) { + var hud = (IconHud) HudManager.getInstance().get(IconHud.ID); + if (hud != null && hud.isEnabled()) { + hud.renderInGui(guiGraphics, partialTick); + } + } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java index 17edd01ff..9774bb825 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/InGameHudMixin.java @@ -78,7 +78,7 @@ private void onHudRender(GuiGraphics guiGraphics, DeltaTracker deltaTracker, Cal if (minecraft.gui.getDebugOverlay().showDebugScreen() && !hud.overridesF3()) { return; } - hud.renderCrosshair(graphics, tracker.getGameTimeDeltaTicks()); + hud.renderCrosshair(graphics); ci.cancel(); } } @@ -109,6 +109,7 @@ private void onHudRender(GuiGraphics guiGraphics, DeltaTracker deltaTracker, Cal @WrapOperation(method = "renderHearts", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;renderHeart(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/gui/Gui$HeartType;IIZZZ)V")) public void axolotlclient$displayHardcoreHearts(Gui instance, GuiGraphics graphics, Gui.HeartType type, int x, int y, boolean hardcore, boolean blinking, boolean half, Operation original) { + //noinspection OptionalGetWithoutIsPresent boolean hardcoreMod = BedwarsMod.getInstance().isEnabled() && BedwarsMod.getInstance().inGame() && BedwarsMod.getInstance().hardcoreHearts.get() && !BedwarsMod.getInstance().getGame().get().getSelf().isBed(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/InGameOverlayRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/InGameOverlayRendererMixin.java similarity index 91% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/InGameOverlayRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/InGameOverlayRendererMixin.java index 38a85addd..cf46ce206 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/InGameOverlayRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/InGameOverlayRendererMixin.java @@ -26,6 +26,7 @@ import io.github.axolotlclient.AxolotlClient; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.ScreenEffectRenderer; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -35,7 +36,7 @@ public abstract class InGameOverlayRendererMixin { @Inject(method = "renderFire", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V")) - private static void axolotlclient$lowFire(PoseStack poseStack, MultiBufferSource multiBufferSource, CallbackInfo ci) { + private static void axolotlclient$lowFire(PoseStack poseStack, MultiBufferSource multiBufferSource, TextureAtlasSprite textureAtlasSprite, CallbackInfo ci) { if (AxolotlClient.config().lowFire.get()) { poseStack.translate(0, -0.2F, 0); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyBindMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/KeyBindMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyBindMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/KeyBindMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyboardInputMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/KeyboardInputMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/KeyboardInputMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/KeyboardInputMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/LightmapManagerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/LightmapManagerMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/LightmapManagerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/LightmapManagerMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/LivingEntityMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/LivingEntityMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/LivingEntityMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/LivingEntityMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/LivingEntityRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/LivingEntityRendererMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/LivingEntityRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/LivingEntityRendererMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientAccessor.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientAccessor.java index c2572d8b1..34d1f5565 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientAccessor.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientAccessor.java @@ -26,7 +26,6 @@ import com.mojang.authlib.minecraft.UserApiService; import com.mojang.authlib.yggdrasil.ProfileResult; -import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.client.gui.screens.social.PlayerSocialManager; @@ -64,9 +63,6 @@ public interface MinecraftClientAccessor { @Mutable void axolotlclient$setUserApiService(UserApiService service); - @Accessor("authenticationService") - YggdrasilAuthenticationService getAuthService(); - @Accessor("profileFuture") @Mutable void axolotlclient$setProfileFuture(CompletableFuture future); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java similarity index 71% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java index 9ac435873..219269181 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMainMixin.java @@ -22,16 +22,21 @@ package io.github.axolotlclient.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.util.OSUtil; import net.minecraft.client.main.Main; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(Main.class) public abstract class MinecraftClientMainMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) - private static String axolotlclient$noHeadless(String key, String value) { + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/System;setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) + private static String axolotlclient$noHeadless(String key, String value, Operation original) { + if (OSUtil.getOS() != OSUtil.OperatingSystem.WINDOWS) { + return original.call(key, value); + } return ""; } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java similarity index 94% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java index 064348e97..e2f0ecc1a 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftClientMixin.java @@ -29,7 +29,6 @@ import net.fabricmc.loader.api.FabricLoader; import net.minecraft.SharedConstants; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.ReceivingLevelScreen; import net.minecraft.client.main.GameConfig; import net.minecraft.client.multiplayer.ClientLevel; import org.spongepowered.asm.mixin.Mixin; @@ -67,7 +66,7 @@ public abstract class MinecraftClientMixin { } @Inject(method = "setLevel", at = @At("HEAD")) - private void axolotlclient$onWorldLoad(ClientLevel world, ReceivingLevelScreen.Reason type, CallbackInfo ci) { + private void axolotlclient$onWorldLoad(ClientLevel world, CallbackInfo ci) { io.github.axolotlclient.bridge.events.Events.WORLD_LOAD_EVENT.invoker().accept(new WorldLoadEvent(world)); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftServerAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftServerAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/MinecraftServerAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/MinecraftServerAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ModStatusMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ModStatusMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ModStatusMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ModStatusMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MouseMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/MouseMixin.java similarity index 83% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/MouseMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/MouseMixin.java index 5eed13973..43f3b6493 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MouseMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/MouseMixin.java @@ -25,8 +25,6 @@ import io.github.axolotlclient.modules.hud.HudManager; import io.github.axolotlclient.modules.scrollableTooltips.ScrollableTooltips; import io.github.axolotlclient.modules.zoom.Zoom; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.MouseInputEvent; import net.minecraft.client.MouseHandler; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -37,14 +35,6 @@ @Mixin(MouseHandler.class) public abstract class MouseMixin { - @Inject(method = "onPress", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/KeyMapping;set(Lcom/mojang/blaze3d/platform/InputConstants$Key;Z)V")) - private void axolotlclient$onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) { - if (action == 1) { - Events.MOUSE_INPUT.invoker().invoke(new MouseInputEvent(window, button, action, mods)); - } - } - @Inject(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDDD)Z"), cancellable = true) private void axolotlclient$scrollTooltips(long window, double scrollDeltaX, double scrollDeltaY, CallbackInfo ci) { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MultiPackResourceManagerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/MultiPackResourceManagerMixin.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/MultiPackResourceManagerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/MultiPackResourceManagerMixin.java index c0e75ecf1..f9b2eeb8a 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/MultiPackResourceManagerMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/MultiPackResourceManagerMixin.java @@ -37,7 +37,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(MultiPackResourceManager.class) -public class MultiPackResourceManagerMixin { +public abstract class MultiPackResourceManagerMixin { @Inject(method = "getResource", at = @At("HEAD"), cancellable = true) private void injectResources(ResourceLocation resourceLocation, CallbackInfoReturnable> cir) { diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagFeatureRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagFeatureRendererMixin.java new file mode 100644 index 000000000..3a8f422a5 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagFeatureRendererMixin.java @@ -0,0 +1,105 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import io.github.axolotlclient.AxolotlClient; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.modules.hypixel.LevelHead; +import io.github.axolotlclient.util.Util; +import io.github.axolotlclient.util.duck.NameTagSubmitExtension; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.feature.NameTagFeatureRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ARGB; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(NameTagFeatureRenderer.class) +public abstract class NameTagFeatureRendererMixin { + @Unique + private static final RenderType TEXTURED_TYPE = RenderType.create("textured_quads", 1536, RenderPipeline.builder(RenderPipelines.GUI_TEXTURED_SNIPPET) + .withLocation(ResourceLocation.fromNamespaceAndPath(AxolotlClientCommon.MODID, "pipeline/badge")) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST).build(), + RenderType.CompositeState.builder().setTextureState(new RenderStateShard.TextureStateShard(AxolotlClient.badgeIcon, false)) + .createCompositeState(false)); + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V", ordinal = 1, shift = At.Shift.AFTER)) + private void renderBadges(SubmitNodeCollection submitNodeCollection, MultiBufferSource.BufferSource bufferSource, Font font, CallbackInfo ci, @Local SubmitNodeStorage.NameTagSubmit submit) { + if (((NameTagSubmitExtension) (Object) submit).axolotlclient$hasBadge()) { + var nameStartX = submit.x(); + if (AxolotlClient.config().customBadge.get()) { + + Component badgeText = Util.formatFromCodes(AxolotlClient.config().badgeText.get()); + var x = nameStartX - (font.width(badgeText) + 4); + Minecraft.getInstance().font.drawInBatch(badgeText, x, 0, -1, AxolotlClient.config().useShadows.get(), submit.pose(), bufferSource, Font.DisplayMode.NORMAL, 0, 15728880); + } else { + var x = nameStartX - 10; + var builder = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(TEXTURED_TYPE); + Matrix4f matrix4f = submit.pose(); + builder.addVertex(matrix4f, x, 0, 0).setUv(0, 0).setColor(-1); + builder.addVertex(matrix4f, x, 8, 0).setUv(0, 1).setColor(-1); + builder.addVertex(matrix4f, x + 8, 8, 0).setUv(1, 1).setColor(-1); + builder.addVertex(matrix4f, x + 8, 0, 0).setUv(1, 0).setColor(-1); + Minecraft.getInstance().renderBuffers().bufferSource().endBatch(); + } + } + } + + @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V", ordinal = 1), index = 4) + public boolean axolotlclient$enableShadows(boolean shadow) { + return AxolotlClient.config().useShadows.get(); + } + + @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V"), index = 8) + public int axolotlclient$bgColor(int color, @Local SubmitNodeStorage.NameTagSubmit submit) { + if (AxolotlClient.config().nametagBackground.get()) { + return color; + } else { + return 0; + } + } + + @WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Font;drawInBatch(Lnet/minecraft/network/chat/Component;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/gui/Font$DisplayMode;II)V")) + private void applyLevelHeadOptions(Font instance, Component text, float x, float y, int color, boolean drawShadow, Matrix4f pose, MultiBufferSource bufferSource, Font.DisplayMode mode, int backgroundColor, int packedLightCoords, Operation original, @Local SubmitNodeStorage.NameTagSubmit submit) { + if (((NameTagSubmitExtension) (Object) submit).axolotlclient$isForLevelHead()) { + color = ARGB.color(ARGB.alpha(color), LevelHead.getInstance().textColor.get().toInt()); + if (backgroundColor != 0 && !LevelHead.getInstance().background.get()) { + backgroundColor = 0; + } + } + original.call(instance, text, x, y, color, drawShadow, pose, bufferSource, mode, backgroundColor, packedLightCoords); + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagFeatureRendererStorageMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagFeatureRendererStorageMixin.java new file mode 100644 index 000000000..f47f82679 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagFeatureRendererStorageMixin.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import java.util.List; + +import io.github.axolotlclient.util.duck.NameTagFeatureRendererStorageExtension; +import io.github.axolotlclient.util.duck.NameTagSubmitExtension; +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.feature.NameTagFeatureRenderer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(NameTagFeatureRenderer.Storage.class) +public abstract class NameTagFeatureRendererStorageMixin implements NameTagFeatureRendererStorageExtension { + + @Shadow + @Final + List nameTagSubmitsNormal; + + @Override + public void axolotlclient$lastNameTagSubmitHasBadge() { + ((NameTagSubmitExtension) (Object) nameTagSubmitsNormal.getLast()).axolotlclient$hasBadge(true); + } + + @Override + public void axolotlclient$lastNameTagSubmitIsLevelHead() { + ((NameTagSubmitExtension) (Object) nameTagSubmitsNormal.getLast()).axolotlclient$isForLevelHead(true); + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/DownloadingTerrainScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagSubmitMixin.java similarity index 55% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/DownloadingTerrainScreenMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagSubmitMixin.java index 4ad71579f..520a12d74 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/DownloadingTerrainScreenMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/NameTagSubmitMixin.java @@ -1,5 +1,5 @@ /* - * Copyright © 2024 moehreag & Contributors + * Copyright © 2025 moehreag & Contributors * * This file is part of AxolotlClient. * @@ -22,21 +22,33 @@ package io.github.axolotlclient.mixin; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.ReceivingLevelScreen; +import io.github.axolotlclient.util.duck.NameTagSubmitExtension; +import net.minecraft.client.renderer.SubmitNodeStorage; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.Unique; -@Mixin(ReceivingLevelScreen.class) -public abstract class DownloadingTerrainScreenMixin { +@Mixin(SubmitNodeStorage.NameTagSubmit.class) +public abstract class NameTagSubmitMixin implements NameTagSubmitExtension { + @Unique + private boolean hasBadge, forLevelHead; - @Inject(method = "", at = @At("TAIL")) - public void axolotlclient$noLoadingScreen(CallbackInfo ci) { - if (Minecraft.getInstance().screen != null) { - Minecraft.getInstance().screen.onClose(); - Minecraft.getInstance().screen = null; - } + @Override + public void axolotlclient$hasBadge(boolean b) { + this.hasBadge = b; + } + + @Override + public boolean axolotlclient$hasBadge() { + return hasBadge; + } + + @Override + public boolean axolotlclient$isForLevelHead() { + return forLevelHead; + } + + @Override + public void axolotlclient$isForLevelHead(boolean b) { + forLevelHead = b; } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/OverlayTextureAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/OverlayTextureAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/OverlayTextureAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/OverlayTextureAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/OverlayTextureMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/OverlayTextureMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/OverlayTextureMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/OverlayTextureMixin.java diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/ParticleManagerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ParticleManagerMixin.java new file mode 100644 index 000000000..d428f7bac --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/ParticleManagerMixin.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2024 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.modules.particles.Particles; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.SingleQuadParticle; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.util.RandomSource; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ParticleEngine.class) +public abstract class ParticleManagerMixin { + + @Inject( + method = "makeParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)Lnet/minecraft/client/particle/Particle;", + at = @At(value = "HEAD"), cancellable = true) + private void axolotlclient$afterCreation(ParticleOptions parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ, CallbackInfoReturnable cir) { + + if (!Particles.getInstance().getShowParticle(parameters.getType())) { + cir.setReturnValue(null); + cir.cancel(); + } + } + + @WrapOperation(method = "makeParticle", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleProvider;createParticle(Lnet/minecraft/core/particles/ParticleOptions;Lnet/minecraft/client/multiplayer/ClientLevel;DDDDDDLnet/minecraft/util/RandomSource;)Lnet/minecraft/client/particle/Particle;")) + private @Nullable Particle applyParticleOptions(ParticleProvider instance, ParticleOptions t, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed, RandomSource randomSource, Operation original) { + var p = original.call(instance, t, level, x, y, z, xSpeed, ySpeed, zSpeed, randomSource); + if (p instanceof SingleQuadParticle s) { + Particles.getInstance().applyOptions(s, t.getType()); + } + return p; + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerEntityMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerEntityMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerEntityMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerEntityMixin.java diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerEntityRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerEntityRendererMixin.java new file mode 100644 index 000000000..60af776c8 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerEntityRendererMixin.java @@ -0,0 +1,114 @@ +/* + * Copyright © 2024 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.vertex.PoseStack; +import io.github.axolotlclient.AxolotlClient; +import io.github.axolotlclient.api.requests.UserRequest; +import io.github.axolotlclient.modules.hypixel.LevelHead; +import io.github.axolotlclient.modules.hypixel.NickHider; +import io.github.axolotlclient.modules.hypixel.bedwars.BedwarsMod; +import io.github.axolotlclient.util.duck.SubmitNodeCollectorExtension; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.entity.player.AvatarRenderer; +import net.minecraft.client.renderer.entity.state.AvatarRenderState; +import net.minecraft.client.renderer.state.CameraRenderState; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(AvatarRenderer.class) +public abstract class PlayerEntityRendererMixin { + + @WrapOperation(method = "submitNameTag(Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitNameTag(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/phys/Vec3;ILnet/minecraft/network/chat/Component;ZIDLnet/minecraft/client/renderer/state/CameraRenderState;)V")) + private void axolotlclient$modifiyName(SubmitNodeCollector instance, PoseStack poseStack, Vec3 vec3, int a, Component component, boolean b, int i, double v, CameraRenderState cameraRenderState, Operation original, @Local(argsOnly = true) AvatarRenderState state) { + if (AxolotlClient.config() != null) { + Level level = Minecraft.getInstance().level; + Entity player = level.getEntity(state.id); + boolean self = player.getUUID() == Minecraft.getInstance().player.getUUID(); + if (self && NickHider.getInstance().hideOwnName.get()) { + component = (Component) NickHider.getInstance().editComponent(component, player.getName().getString(), NickHider.getInstance().hiddenNameSelf.get()); + } else if (!self && NickHider.getInstance().hideOtherNames.get()) { + component = (Component) NickHider.getInstance().editComponent(component, player.getName().getString(), NickHider.getInstance().hiddenNameOthers.get()); + } + } + original.call(instance, poseStack, vec3, a, component, b, i, v, cameraRenderState); + } + + @Inject(method = "submitNameTag(Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitNameTag(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/phys/Vec3;ILnet/minecraft/network/chat/Component;ZIDLnet/minecraft/client/renderer/state/CameraRenderState;)V", ordinal = 1, shift = At.Shift.AFTER)) + public void axolotlclient$addBadges(AvatarRenderState state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState cameraRenderState, CallbackInfo ci) { + if (!state.isDiscrete) { + if (AxolotlClient.config().showBadges.get()) { + Player entity = (Player) Minecraft.getInstance().level.getEntity(state.id); + if (entity != null && UserRequest.getOnline(entity.getStringUUID())) { + ((SubmitNodeCollectorExtension) submitNodeCollector).axolotlclient$lastNameTagSubmitHasBadge(); + } + } + } + } + + @Inject(method = "submitNameTag(Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;popPose()V")) + private void addLevel(AvatarRenderState state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState cameraRenderState, CallbackInfo ci) { + if (Minecraft.getInstance().getCurrentServer() != null && Minecraft.getInstance().getCurrentServer().ip.endsWith("hypixel.net")) { + AbstractClientPlayer entity = (AbstractClientPlayer) Minecraft.getInstance().level.getEntity(state.id); + if (entity != null) { + if (BedwarsMod.getInstance().isEnabled() && BedwarsMod.getInstance().inGame() && BedwarsMod.getInstance().bedwarsLevelHead.get()) { + String text = BedwarsMod.getInstance().getGame().get().getLevelHead(entity); + if (text != null) { + var y = state.showExtraEars ? -20 : -10; + + if (LevelHead.getInstance().background.get()) { + y -= 2; + } + + submitNodeCollector.submitNameTag(poseStack, state.nameTagAttachment, y, Component.literal(text).withStyle(s -> s.withColor(LevelHead.getInstance().textColor.get().toInt())), !state.isDiscrete, state.lightCoords, state.distanceToCameraSq, cameraRenderState); + ((SubmitNodeCollectorExtension) submitNodeCollector).axolotlclient$lastNameTagSubmitIsLevelHead(); + } + } else if (LevelHead.getInstance().enabled.get()) { + String text = LevelHead.getInstance().getDisplayString(entity.getStringUUID()); + + var y = state.showExtraEars ? -20 : -10; + + if (LevelHead.getInstance().background.get()) { + y -= 2; + } + + submitNodeCollector.submitNameTag(poseStack, state.nameTagAttachment, y, Component.literal(text).withStyle(s -> s.withColor(LevelHead.getInstance().textColor.get().toInt())), !state.isDiscrete, state.lightCoords, state.distanceToCameraSq, cameraRenderState); + ((SubmitNodeCollectorExtension) submitNodeCollector).axolotlclient$lastNameTagSubmitIsLevelHead(); + } + } + } + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerListEntryMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerListEntryMixin.java similarity index 73% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerListEntryMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerListEntryMixin.java index 3c926a61f..abce33f1c 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerListEntryMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerListEntryMixin.java @@ -22,15 +22,15 @@ package io.github.axolotlclient.mixin; -import java.util.function.Supplier; - import com.mojang.authlib.GameProfile; import io.github.axolotlclient.modules.hypixel.NickHider; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.PlayerInfo; import net.minecraft.client.resources.DefaultPlayerSkin; -import net.minecraft.client.resources.PlayerSkin; +import net.minecraft.world.entity.player.PlayerSkin; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -38,14 +38,18 @@ @Mixin(PlayerInfo.class) public abstract class PlayerListEntryMixin { - @Inject(method = "createSkinLookup", at = @At("RETURN"), cancellable = true) - private static void axolotlclient$hideSkins(GameProfile gameProfile, CallbackInfoReturnable> cir) { - if (gameProfile.equals(Minecraft.getInstance().player.getGameProfile()) + @Shadow + @Final + private GameProfile profile; + + @Inject(method = "getSkin", at = @At("HEAD"), cancellable = true) + private void hideSkins(CallbackInfoReturnable cir) { + if (profile.equals(Minecraft.getInstance().player.getGameProfile()) && NickHider.getInstance().hideOwnSkin.get()) { - cir.setReturnValue(() -> DefaultPlayerSkin.get(gameProfile.getId())); - } else if (!gameProfile.equals(Minecraft.getInstance().player.getGameProfile()) + cir.setReturnValue(DefaultPlayerSkin.get(profile.id())); + } else if (!profile.equals(Minecraft.getInstance().player.getGameProfile()) && NickHider.getInstance().hideOtherSkins.get()) { - cir.setReturnValue(() -> DefaultPlayerSkin.get(gameProfile.getId())); + cir.setReturnValue(DefaultPlayerSkin.get(profile.id())); } } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerListHudMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerListHudMixin.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerListHudMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerListHudMixin.java index bc2ef9116..b9b7677ff 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/PlayerListHudMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/PlayerListHudMixin.java @@ -74,10 +74,10 @@ private Component nickHider(PlayerInfo playerInfo, Operation original return orig; } if (playerInfo.getProfile().equals(minecraft.player.getGameProfile()) && NickHider.getInstance().hideOwnName.get()) { - return (Component) NickHider.getInstance().editComponent(orig, playerInfo.getProfile().getName(), NickHider.getInstance().hiddenNameSelf.get()); + return (Component) NickHider.getInstance().editComponent(orig, playerInfo.getProfile().name(), NickHider.getInstance().hiddenNameSelf.get()); } else if (!playerInfo.getProfile().equals(minecraft.player.getGameProfile()) && NickHider.getInstance().hideOtherNames.get()) { - return (Component) NickHider.getInstance().editComponent(orig, playerInfo.getProfile().getName(), NickHider.getInstance().hiddenNameOthers.get()); + return (Component) NickHider.getInstance().editComponent(orig, playerInfo.getProfile().name(), NickHider.getInstance().hiddenNameOthers.get()); } return orig; } @@ -87,7 +87,7 @@ private Component nickHider(PlayerInfo playerInfo, Operation original private int axolotlclient$moveName(Font instance, FormattedText text, Operation original, @Local PlayerInfo info) { int width = original.call(instance, text); if (AxolotlClient.config().showBadges.get() && - UserRequest.getOnline(info.getProfile().getId().toString())) width += 10; + UserRequest.getOnline(info.getProfile().id().toString())) width += 10; if (Tablist.getInstance().numericalPing.get()) width += (instance.width(String.valueOf(info.getLatency())) - 10); return width; @@ -97,7 +97,7 @@ private Component nickHider(PlayerInfo playerInfo, Operation original target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Lnet/minecraft/network/chat/Component;III)V")) public void axolotlclient$moveName2(GuiGraphics instance, Font font, Component component, int x, int y, int color, Operation original, @Local PlayerInfo info) { if (AxolotlClient.config().showBadges.get() && - UserRequest.getOnline(info.getProfile().getId().toString())) { + UserRequest.getOnline(info.getProfile().id().toString())) { instance.blit(RenderPipelines.GUI_TEXTURED, AxolotlClient.badgeIcon, x, y, 0, 0, 8, 8, 8, 8); x += 9; } @@ -189,7 +189,7 @@ private Component nickHider(PlayerInfo playerInfo, Operation original if (game == null || !game.isStarted()) { return; } - BedwarsPlayer player = game.getPlayer(entry.getProfile().getName()).orElse(null); + BedwarsPlayer player = game.getPlayer(entry.getProfile().name()).orElse(null); if (player == null) { return; } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ReloadableResourceManagerMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ReloadableResourceManagerMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ReloadableResourceManagerMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ReloadableResourceManagerMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ScreenMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ScreenMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ScreenMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ScreenshotRecorderMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ScreenshotRecorderMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ScreenshotRecorderMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ScreenshotRecorderMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ServerPackManagerAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ServerPackManagerAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ServerPackManagerAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ServerPackManagerAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ShieldSpecialRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/ShieldSpecialRendererMixin.java similarity index 82% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ShieldSpecialRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/ShieldSpecialRendererMixin.java index af35d2e7a..de042bf65 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ShieldSpecialRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/ShieldSpecialRendererMixin.java @@ -25,7 +25,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import io.github.axolotlclient.AxolotlClient; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.special.ShieldSpecialRenderer; import net.minecraft.core.component.DataComponentMap; import net.minecraft.world.item.ItemDisplayContext; @@ -37,8 +37,8 @@ @Mixin(ShieldSpecialRenderer.class) public abstract class ShieldSpecialRendererMixin { - @Inject(method = "render(Lnet/minecraft/core/component/DataComponentMap;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IIZ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/ShieldModel;handle()Lnet/minecraft/client/model/geom/ModelPart;")) - private void axolotlclient$lowShield(DataComponentMap dataComponentMap, ItemDisplayContext itemDisplayContext, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, int j, boolean bl, CallbackInfo ci) { + @Inject(method = "submit(Lnet/minecraft/core/component/DataComponentMap;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IIZI)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/ShieldModel;handle()Lnet/minecraft/client/model/geom/ModelPart;")) + private void axolotlclient$lowShield(DataComponentMap dataComponentMap, ItemDisplayContext itemDisplayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int i, int j, boolean bl, int k, CallbackInfo ci) { if (AxolotlClient.config().lowShield.get() && Minecraft.getInstance().options.getCameraType().isFirstPerson() && (itemDisplayContext.equals(ItemDisplayContext.FIRST_PERSON_LEFT_HAND) diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ParticleAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/SingleQuadParticleAccessor.java similarity index 89% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/ParticleAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/SingleQuadParticleAccessor.java index 70af304c1..883723866 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/ParticleAccessor.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/SingleQuadParticleAccessor.java @@ -22,12 +22,12 @@ package io.github.axolotlclient.mixin; -import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.SingleQuadParticle; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(Particle.class) -public interface ParticleAccessor { +@Mixin(SingleQuadParticle.class) +public interface SingleQuadParticleAccessor { @Accessor("alpha") void axolotlclient$setColorAlpha(float alpha); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashManagerAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/SplashManagerAccessor.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashManagerAccessor.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/SplashManagerAccessor.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashOverlayMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/SplashOverlayMixin.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashOverlayMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/SplashOverlayMixin.java index 7d3ea8208..988f690f1 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashOverlayMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/SplashOverlayMixin.java @@ -57,7 +57,7 @@ public abstract class SplashOverlayMixin { } @Inject(method = "render", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/gui/screens/Screen;init(Lnet/minecraft/client/Minecraft;II)V")) + target = "Lnet/minecraft/client/Minecraft;setOverlay(Lnet/minecraft/client/gui/screens/Overlay;)V")) private void onReloadFinish(GuiGraphics graphics, int mouseX, int mouseY, float delta, CallbackInfo ci) { if (!API.getInstance().isSocketConnected() && !Auth.getInstance().getCurrent().isOffline()) { API.getInstance().startup(Auth.getInstance().getCurrent()); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java index 061bc988d..45f8cf613 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/SplashTextResourceSupplierMixin.java @@ -38,7 +38,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(SplashManager.class) -public class SplashTextResourceSupplierMixin { +public abstract class SplashTextResourceSupplierMixin { @Unique private static final ResourceLocation EXTRA_SPLASHES = ResourceLocation.fromNamespaceAndPath("axolotlclient", "texts/splashes.txt"); diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/SubmitNodeCollectionMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/SubmitNodeCollectionMixin.java new file mode 100644 index 000000000..0c73d5f0b --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/SubmitNodeCollectionMixin.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import io.github.axolotlclient.util.duck.NameTagFeatureRendererStorageExtension; +import io.github.axolotlclient.util.duck.SubmitNodeCollectorExtension; +import net.minecraft.client.renderer.SubmitNodeCollection; +import net.minecraft.client.renderer.feature.NameTagFeatureRenderer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(SubmitNodeCollection.class) +public abstract class SubmitNodeCollectionMixin implements SubmitNodeCollectorExtension { + + @Shadow + @Final + private NameTagFeatureRenderer.Storage nameTagSubmits; + + @Override + public void axolotlclient$lastNameTagSubmitHasBadge() { + ((NameTagFeatureRendererStorageExtension) nameTagSubmits).axolotlclient$lastNameTagSubmitHasBadge(); + } + + @Override + public void axolotlclient$lastNameTagSubmitIsLevelHead() { + ((NameTagFeatureRendererStorageExtension) nameTagSubmits).axolotlclient$lastNameTagSubmitIsLevelHead(); + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/SubmitNodeStorageMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/SubmitNodeStorageMixin.java new file mode 100644 index 000000000..5a086fc58 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/SubmitNodeStorageMixin.java @@ -0,0 +1,40 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import io.github.axolotlclient.util.duck.SubmitNodeCollectorExtension; +import net.minecraft.client.renderer.SubmitNodeCollection; +import net.minecraft.client.renderer.SubmitNodeStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(SubmitNodeStorage.class) +public abstract class SubmitNodeStorageMixin implements SubmitNodeCollectorExtension { + @Shadow + public abstract SubmitNodeCollection order(int i); + + @Override + public void axolotlclient$lastNameTagSubmitHasBadge() { + ((SubmitNodeCollectorExtension) order(0)).axolotlclient$lastNameTagSubmitHasBadge(); + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/TitleScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/TitleScreenMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/TitleScreenMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/TitleScreenMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/TntEntityRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/TntEntityRendererMixin.java similarity index 74% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/TntEntityRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/TntEntityRendererMixin.java index 5f6cb62ac..37906e8ff 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/TntEntityRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/TntEntityRendererMixin.java @@ -24,11 +24,12 @@ import com.mojang.blaze3d.vertex.PoseStack; import io.github.axolotlclient.modules.tnttime.TntTime; -import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.entity.TntRenderer; import net.minecraft.client.renderer.entity.state.TntRenderState; +import net.minecraft.client.renderer.state.CameraRenderState; import net.minecraft.world.entity.item.PrimedTnt; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; @@ -44,22 +45,30 @@ protected TntEntityRendererMixin(EntityRendererProvider.Context ctx) { } @Inject( - method = "render(Lnet/minecraft/client/renderer/entity/state/TntRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", + method = "submit(Lnet/minecraft/client/renderer/entity/state/TntRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", at = @At(value = "TAIL")) - private void axolotlclient$render(TntRenderState tntRenderState, PoseStack matrices, MultiBufferSource vertexConsumers, int i, CallbackInfo ci) { + private void axolotlclient$render(TntRenderState tntRenderState, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState cameraRenderState, CallbackInfo ci) { if (TntTime.getInstance().enabled.get()) { - matrices.pushPose(); + poseStack.pushPose(); if (tntRenderState.nameTag != null) { - matrices.translate(0, 0.25, 0); + poseStack.translate(0, 0.25, 0); } Vec3 prevAttachment = tntRenderState.nameTagAttachment; if (prevAttachment == null) { tntRenderState.nameTagAttachment = new Vec3(0, 1, 0); } - renderNameTag(tntRenderState, TntTime.getInstance().getFuseTime(tntRenderState.fuseRemainingInTicks), - matrices, vertexConsumers, i); + submitNodeCollector.submitNameTag( + poseStack, + tntRenderState.nameTagAttachment, + 0, + TntTime.getInstance().getFuseTime(tntRenderState.fuseRemainingInTicks), + !tntRenderState.isDiscrete, + tntRenderState.lightCoords, + tntRenderState.distanceToCameraSq, + cameraRenderState + ); tntRenderState.nameTagAttachment = prevAttachment; - matrices.popPose(); + poseStack.popPose(); } } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/WeatherEffectRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/WeatherEffectRendererMixin.java similarity index 81% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/WeatherEffectRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/WeatherEffectRendererMixin.java index 3213ac6a8..7711f1ffc 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/WeatherEffectRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/WeatherEffectRendererMixin.java @@ -23,8 +23,8 @@ package io.github.axolotlclient.mixin; import io.github.axolotlclient.AxolotlClient; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.WeatherEffectRenderer; +import net.minecraft.client.renderer.state.WeatherRenderState; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; @@ -34,9 +34,9 @@ @Mixin(WeatherEffectRenderer.class) public class WeatherEffectRendererMixin { - @Inject(method = "render(Lnet/minecraft/world/level/Level;Lnet/minecraft/client/renderer/MultiBufferSource;IFLnet/minecraft/world/phys/Vec3;)V", at = @At("HEAD"), + @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void noRain(Level level, MultiBufferSource multiBufferSource, int i, float f, Vec3 vec3, CallbackInfo ci) { + private void noRain(Level level, int i, float f, Vec3 vec3, WeatherRenderState weatherRenderState, CallbackInfo ci) { if (AxolotlClient.config().noRain.get()) { ci.cancel(); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/WorldListWidgetEntryMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/WorldListWidgetEntryMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/WorldListWidgetEntryMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/WorldListWidgetEntryMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java similarity index 75% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java index b24578d3a..2751d29bf 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/WorldRendererMixin.java @@ -28,9 +28,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import io.github.axolotlclient.AxolotlClient; import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.client.renderer.state.BlockOutlineRenderState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -38,11 +36,11 @@ public abstract class WorldRendererMixin { @WrapOperation(method = "renderBlockOutline", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/LevelRenderer;renderHitOutline(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/entity/Entity;DDDLnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)V", ordinal = 1)) - private void axolotlclient$customOutlineColor(LevelRenderer instance, PoseStack matrices, VertexConsumer consumer, Entity entity, double offsetX, double offsetY, double offsetZ, BlockPos blockPos, BlockState blockState, int i, Operation original) { + target = "Lnet/minecraft/client/renderer/LevelRenderer;renderHitOutline(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;DDDLnet/minecraft/client/renderer/state/BlockOutlineRenderState;I)V", ordinal = 1)) + private void axolotlclient$customOutlineColor(LevelRenderer instance, PoseStack poseStack, VertexConsumer vertexConsumer, double d, double e, double f, BlockOutlineRenderState blockOutlineRenderState, int i, Operation original) { if (AxolotlClient.config().enableCustomOutlines.get()) { i = AxolotlClient.config().outlineColor.get().toInt(); } - original.call(instance, matrices, consumer, entity, offsetX, offsetY, offsetZ, blockPos, blockState, i); + original.call(instance, poseStack, vertexConsumer, d, e, f, blockOutlineRenderState, i); } } diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java new file mode 100644 index 000000000..463ebebeb --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/api/JoinMulitplayerScreenMixin.java @@ -0,0 +1,76 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin.api; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.api.API; +import io.github.axolotlclient.api.multiplayer.FriendsMultiplayerScreen; +import io.github.axolotlclient.api.requests.FriendRequest; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; +import net.minecraft.client.gui.layouts.LayoutSettings; +import net.minecraft.client.gui.layouts.LinearLayout; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; +import net.minecraft.network.chat.Component; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(JoinMultiplayerScreen.class) +public abstract class JoinMulitplayerScreenMixin extends Screen { + + @Shadow + @Final + private Screen lastScreen; + @Unique + private static final boolean WORLD_HOST_INSTALLED = FabricLoader.getInstance().isModLoaded("world-host"); + + protected JoinMulitplayerScreenMixin(Component title) { + super(title); + } + + @WrapOperation(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/layouts/HeaderAndFooterLayout;addTitleHeader(Lnet/minecraft/network/chat/Component;Lnet/minecraft/client/gui/Font;)V")) + private void modifyHeader(HeaderAndFooterLayout instance, Component message, Font font, Operation original) { + if (API.getInstance().isAuthenticated() && !WORLD_HOST_INSTALLED) { + instance.setHeaderHeight(60); + var header = instance.addToHeader(LinearLayout.vertical()).spacing(8); + header.addChild(new StringWidget(message, font), LayoutSettings::alignHorizontallyCenter); + var buttons = header.addChild(LinearLayout.horizontal()).spacing(4); + buttons.addChild(Button.builder(Component.translatable("api.servers"), button -> { + + }).width(100).build()).active = false; + var friends = buttons.addChild(Button.builder(Component.translatable("api.servers.friends", "..."), + button -> minecraft.setScreen(new FriendsMultiplayerScreen(this.lastScreen))).width(100).build()); + FriendRequest.getInstance().getOnlineFriendCount().thenAccept(count -> friends.setMessage(Component.translatable("api.servers.friends", count))); + } else { + original.call(instance, message, font); + } + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/mixin/skins/SkinTextureDownloaderAccessor.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/skins/SkinTextureDownloaderAccessor.java new file mode 100644 index 000000000..b561887b4 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/mixin/skins/SkinTextureDownloaderAccessor.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin.skins; + +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.renderer.texture.SkinTextureDownloader; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(SkinTextureDownloader.class) +public interface SkinTextureDownloaderAccessor { + @Invoker("processLegacySkin") + static NativeImage invokeProcessLegacySkin(NativeImage img, String url) { + throw new UnsupportedOperationException(); + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/mixin/translation/TranslationStorageMixin.java b/1.latest/src/main/java/io/github/axolotlclient/mixin/translation/TranslationStorageMixin.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/mixin/translation/TranslationStorageMixin.java rename to 1.latest/src/main/java/io/github/axolotlclient/mixin/translation/TranslationStorageMixin.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/AbstractModule.java b/1.latest/src/main/java/io/github/axolotlclient/modules/AbstractModule.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/AbstractModule.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/AbstractModule.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/ModuleLoader.java b/1.latest/src/main/java/io/github/axolotlclient/modules/ModuleLoader.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/ModuleLoader.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/ModuleLoader.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java similarity index 78% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java index 70fb7b2f2..a3b7cd1d1 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/AccountsListWidget.java @@ -24,13 +24,14 @@ import java.util.List; +import lombok.Getter; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.ObjectSelectionList; import net.minecraft.client.gui.components.PlayerFaceRenderer; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -72,9 +73,9 @@ public static class Entry extends ObjectSelectionList.Entry login()) - .bounds(this.width / 2 - 154, this.height - 52, 150, 20).build()); + .bounds(this.width / 2 - 154, this.height - 52, 100, 20).build()); + + addRenderableWidget(skinsButton = Button.builder(Component.translatable("skins.manage"), + btn -> minecraft.setScreen(new SkinManagementScreen( + this, accountsListWidget.getSelected().getAccount()))) + .bounds(this.width / 2 - 50, this.height - 52, 100, 20).build()); this.addRenderableWidget(Button.builder(Component.translatable("auth.add"), button -> { if (!Auth.getInstance().allowOfflineAccounts()) { @@ -93,7 +101,7 @@ public void init() { Component.translatable("auth.add.ms") )); } - }).bounds(this.width / 2 + 4, this.height - 52, 150, 20).build()); + }).bounds(this.width / 2 + 4 + 50, this.height - 52, 100, 20).build()); this.deleteButton = this.addRenderableWidget(Button.builder(Component.translatable("selectServer.delete"), button -> { @@ -116,17 +124,14 @@ public void init() { } private void initMSAuth() { - Auth.getInstance().getAuth().startDeviceAuth().thenRun(() -> minecraft.execute(this::refresh)); + Auth.getInstance().getMsApi().startDeviceAuth().thenRun(() -> minecraft.execute(this::refresh)); } private void refreshAccount() { refreshButton.active = false; AccountsListWidget.Entry entry = accountsListWidget.getSelected(); if (entry != null) { - entry.getAccount().refresh(Auth.getInstance().getAuth()).thenRun(() -> minecraft.execute(() -> { - Auth.getInstance().save(); - refresh(); - })); + entry.getAccount().refresh(Auth.getInstance().getMsApi()); } } @@ -134,9 +139,10 @@ private void updateButtonActivationStates() { AccountsListWidget.Entry entry = accountsListWidget.getSelected(); if (minecraft.level == null && entry != null) { loginButton.active = entry.getAccount().isExpired() || !entry.getAccount().equals(Auth.getInstance().getCurrent()); - deleteButton.active = refreshButton.active = true; + refreshButton.active = skinsButton.active = !entry.getAccount().isOffline(); + deleteButton.active = true; } else { - loginButton.active = deleteButton.active = refreshButton.active = false; + loginButton.active = deleteButton.active = refreshButton.active = skinsButton.active = false; } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java index fb42fbe32..60f9c5434 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/AddOfflineScreen.java @@ -43,12 +43,11 @@ public AddOfflineScreen(Screen parent) { @Override public void render(GuiGraphics graphics, int i, int j, float f) { - renderBackground(graphics, i, j, f); super.render(graphics, i, j, f); graphics.drawString(font, Component.translatable("auth.add.offline.name"), (int) (width / 2F - 100), (int) (height / 2f - 20), -1 ); - graphics.drawString(this.font, this.title, this.width / 2, 20, -1); + graphics.drawCenteredString(this.font, this.title, this.width / 2, 20, -1); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/Auth.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/Auth.java similarity index 82% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/auth/Auth.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/auth/Auth.java index 4a041f634..6189bdb52 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/Auth.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/Auth.java @@ -27,8 +27,8 @@ import com.mojang.authlib.minecraft.UserApiService; import com.mojang.authlib.yggdrasil.ProfileResult; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import io.github.axolotlclient.AxolotlClient; -import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.api.API; import io.github.axolotlclient.api.util.UUIDHelper; @@ -37,6 +37,7 @@ import io.github.axolotlclient.mixin.ServerPackManagerAccessor; import io.github.axolotlclient.mixin.SplashManagerAccessor; import io.github.axolotlclient.modules.Module; +import io.github.axolotlclient.modules.auth.skin.SkinManager; import io.github.axolotlclient.util.ThreadExecuter; import io.github.axolotlclient.util.notifications.Notifications; import io.github.axolotlclient.util.options.GenericOption; @@ -59,26 +60,28 @@ public class Auth extends Accounts implements Module { @Getter private final static Auth Instance = new Auth(); public final BooleanOption showButton = new BooleanOption("auth.showButton", false); + public final BooleanOption skinManagerAnimations = new BooleanOption("skins.manage.animations", true); private final Minecraft mc = Minecraft.getInstance(); private final GenericOption viewAccounts = new GenericOption("viewAccounts", "clickToOpen", () -> mc.setScreen(new AccountsScreen(mc.screen))); private final Set loadingTexture = new HashSet<>(); private final Map textures = new WeakHashMap<>(); + @Getter + private final SkinManager skinManager = new SkinManager(); @Override public void init() { load(); - this.auth = new MSAuth(AxolotlClient.LOGGER, this, () -> mc.options.languageCode); + this.msApi = new MSApi(this, () -> mc.options.languageCode); if (isContained(mc.getUser().getSessionId())) { current = getAccounts().stream().filter(account -> account.getUuid().equals(UUIDHelper.toUndashed(mc.getUser().getProfileId()))).toList().getFirst(); if (current.needsRefresh()) { - current.refresh(auth).thenRun(this::save); + current.refresh(msApi).thenRun(this::save); } } else { current = new Account(mc.getUser().getName(), UUIDHelper.toUndashed(mc.getUser().getProfileId()), mc.getUser().getAccessToken()); } - OptionCategory category = OptionCategory.create("auth"); - category.add(showButton, viewAccounts); + category.add(showButton, viewAccounts, skinManagerAnimations); AxolotlClient.config().general.add(category); } @@ -92,22 +95,21 @@ protected void login(Account account) { if (account.isExpired()) { Notifications.getInstance().addStatus(Component.translatable("auth.notif.title"), Component.translatable("auth.notif.refreshing", account.getName())); } - account.refresh(auth).thenAccept(res -> res.ifPresent(a -> { + account.refresh(msApi).thenAccept(a -> { if (!a.isExpired()) { login(a); } - })).thenRun(this::save); + }).thenRun(this::save); } else { try { API.getInstance().shutdown(); var mcAccessor = (MinecraftClientAccessor) mc; - mcAccessor.axolotlclient$setSession(new User(account.getName(), UUIDHelper.fromUndashed(account.getUuid()), account.getAuthToken(), Optional.empty(), Optional.empty(), User.Type.MSA)); + mcAccessor.axolotlclient$setSession(new User(account.getName(), UUIDHelper.fromUndashed(account.getUuid()), account.getAuthToken(), Optional.empty(), Optional.empty())); UserApiService service; if (account.isOffline()) { service = UserApiService.OFFLINE; } else { - - service = mcAccessor.getAuthService().createUserApiService(mc.getUser().getAccessToken()); + service = new YggdrasilAuthenticationService(mc.getProxy()).createUserApiService(mc.getUser().getAccessToken()); } mcAccessor.axolotlclient$setUserApiService(service); var sourceAccessor = (DownloadedPackSourceAccessor) mc.getDownloadedPackSource(); @@ -116,7 +118,7 @@ protected void login(Account account) { mcAccessor.axolotlclient$setSocialInteractionsManager(new PlayerSocialManager(mc, service)); mcAccessor.axolotlclient$setPlayerKeyPairManager(ProfileKeyPairManager.create(service, mc.getUser(), mc.gameDirectory.toPath())); mcAccessor.axolotlclient$setChatReportingContext(ReportingContext.create(ReportEnvironment.local(), service)); - mcAccessor.axolotlclient$setProfileFuture(CompletableFuture.supplyAsync(() -> mc.getMinecraftSessionService().fetchProfile(mc.getUser().getProfileId(), true), Util.nonCriticalIoPool())); + mcAccessor.axolotlclient$setProfileFuture(CompletableFuture.supplyAsync(() -> mc.services().sessionService().fetchProfile(mc.getUser().getProfileId(), true), Util.nonCriticalIoPool())); ((SplashManagerAccessor) mc.getSplashManager()).setUser(mc.getUser()); save(); current = account; @@ -129,14 +131,18 @@ protected void login(Account account) { } @Override - void showAccountsExpiredScreen(Account account) { + CompletableFuture showAccountsExpiredScreen(Account account) { Screen current = mc.screen; + var fut = new CompletableFuture(); mc.execute(() -> mc.setScreen(new ConfirmScreen((bl) -> { - mc.setScreen(current); if (bl) { - auth.startDeviceAuth(); + msApi.startDeviceAuth().thenRun(() -> fut.complete(account)); + } else { + fut.cancel(true); } + mc.setScreen(current); }, Component.translatable("auth"), Component.translatable("auth.accountExpiredNotice", account.getName())))); + return fut; } @Override @@ -149,9 +155,9 @@ private void loadTexture(String uuid) { loadingTexture.add(uuid); ThreadExecuter.scheduleTask(() -> { UUID uUID = UUIDHelper.fromUndashed(uuid); - ProfileResult profileResult = mc.getMinecraftSessionService().fetchProfile(uUID, false); + ProfileResult profileResult = mc.services().sessionService().fetchProfile(uUID, false); if (profileResult != null) { - mc.getSkinManager().getOrLoad(profileResult.profile()).thenAccept(playerSkin -> playerSkin.ifPresent(skin -> textures.put(uuid, skin.texture()))); + mc.getSkinManager().get(profileResult.profile()).thenAccept(playerSkin -> playerSkin.ifPresent(skin -> textures.put(uuid, skin.body().texturePath()))); } loadingTexture.remove(uuid); }); @@ -169,7 +175,7 @@ public ResourceLocation getSkinTexture(io.github.axolotlclient.api.types.User us public ResourceLocation getSkinTexture(String uuid) { if (!textures.containsKey(uuid)) { loadTexture(uuid); - return Objects.requireNonNullElseGet(textures.get(uuid), () -> DefaultPlayerSkin.get(UUIDHelper.fromUndashed(uuid)).texture()); + return Objects.requireNonNullElseGet(textures.get(uuid), () -> DefaultPlayerSkin.get(UUIDHelper.fromUndashed(uuid)).body().texturePath()); } return textures.get(uuid); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AuthWidget.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/AuthWidget.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/auth/AuthWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/auth/AuthWidget.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/auth/DeviceCodeDisplayScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/DeviceCodeDisplayScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/auth/DeviceCodeDisplayScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/auth/DeviceCodeDisplayScreen.java diff --git a/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java new file mode 100644 index 000000000..738373196 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/LoadingScreen.java @@ -0,0 +1,50 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import net.minecraft.client.gui.components.LoadingDotsWidget; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +public class LoadingScreen extends Screen { + private final Component description; + + public LoadingScreen(Component title, Component description) { + super(title); + this.description = description; + } + + @Override + protected void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + StringWidget titleWidget = new StringWidget(width / 2 - font.width(getTitle()) / 2, headerHeight / 2 - font.lineHeight / 2, font.width(getTitle()), font.lineHeight, getTitle(), getFont()); + addRenderableWidget(titleWidget); + + var loadingPlaceholder = new LoadingDotsWidget(getFont(), description); + loadingPlaceholder.setRectangle(width, contentHeight, 0, + headerHeight); + addRenderableWidget(loadingPlaceholder); + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java new file mode 100644 index 000000000..d7f0b6929 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManagementScreen.java @@ -0,0 +1,807 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.util.Colors; +import io.github.axolotlclient.api.SimpleTextInputScreen; +import io.github.axolotlclient.api.util.UUIDHelper; +import io.github.axolotlclient.mixin.GameRendererAccessor; +import io.github.axolotlclient.mixin.GuiGraphicsAccessor; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import io.github.axolotlclient.modules.hud.util.DrawUtil; +import io.github.axolotlclient.util.ClientColors; +import io.github.axolotlclient.util.Watcher; +import io.github.axolotlclient.util.notifications.Notifications; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.*; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import net.minecraft.client.gui.screens.ConfirmScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2f; + +public class SkinManagementScreen extends Screen { + private static final Path SKINS_DIR = FabricLoader.getInstance().getGameDir().resolve("skins"); + private static final int LIST_SKIN_WIDTH = 75; + private static final int LIST_SKIN_HEIGHT = 110; + private static final Component TEXT_EQUIPPING = Component.translatable("skins.manage.equipping"); + private final Screen parent; + private final Account account; + private MSApi.MCProfile cachedProfile; + private SkinListWidget skinList; + private SkinListWidget capesList; + private boolean capesTab; + private SkinWidget current; + private final Watcher skinDirWatcher; + private final CompletableFuture loadingFuture; + + public SkinManagementScreen(Screen parent, Account account) { + super(Component.translatable("skins.manage")); + this.parent = parent; + this.account = account; + skinDirWatcher = Watcher.createSelfTicking(SKINS_DIR, () -> { + AxolotlClientCommon.getInstance().getLogger().info("Reloading screen as local files changed!"); + loadSkinsList(); + }); + loadingFuture = (account.needsRefresh() ? account.refresh(Auth.getInstance().getMsApi()) + : CompletableFuture.completedFuture(null)) + .thenComposeAsync(unused -> Auth.getInstance().getMsApi().getProfile(account)); + } + + @Override + protected void init() { + int headerHeight = 33; + int contentHeight = height - headerHeight * 2; + + StringWidget titleWidget = new StringWidget(width / 2 - font.width(getTitle()) / 2, headerHeight / 2 - font.lineHeight / 2, font.width(getTitle()), font.lineHeight, getTitle(), getFont()); + addRenderableWidget(titleWidget); + + var back = Button.builder(CommonComponents.GUI_BACK, btn -> onClose()) + .bounds(width / 2 - 75, height - headerHeight / 2 - 10, 150, 20).build(); + + var loadingPlaceholder = new LoadingDotsWidget(getFont(), Component.translatable("skins.loading")); + loadingPlaceholder.setRectangle(width, contentHeight, 0, + headerHeight); + addRenderableWidget(loadingPlaceholder); + addRenderableWidget(back); + + skinList = new SkinListWidget(minecraft, width / 2, contentHeight - 24, headerHeight + 24, LIST_SKIN_HEIGHT + 34); + capesList = new SkinListWidget(minecraft, width / 2, contentHeight - 24, headerHeight + 24, skinList.getEntryContentsHeight() + 24); + skinList.setX(width / 2); + capesList.setX(width / 2); + var currentHeight = Math.min((width / 2f) * 120 / 85, contentHeight); + var currentWidth = currentHeight * 85 / 120; + current = new SkinWidget((int) currentWidth, (int) currentHeight, null, account); + current.setPosition((int) (width / 4f - currentWidth / 2), (int) (height / 2f - currentHeight / 2)); + + if (!capesTab) { + capesList.visible = capesList.active = false; + } else { + skinList.visible = skinList.active = false; + } + List navBar = new ArrayList<>(); + var skinsTab = Button.builder(Component.translatable("skins.nav.skins"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = true; + capesList.visible = capesList.active = false; + capesTab = false; + }).pos(Math.max(width * 3 / 4 - 102, width / 2 + 2), headerHeight).width(Math.min(100, width / 4 - 2)).build(); + navBar.add(skinsTab); + var capesTab = Button.builder(Component.translatable("skins.nav.capes"), btn -> { + navBar.forEach(w -> { + if (w != btn) w.active = true; + }); + btn.active = false; + skinList.visible = skinList.active = false; + capesList.visible = capesList.active = true; + this.capesTab = true; + }).pos(width * 3 / 4 + 2, headerHeight).width(Math.min(100, width / 4 - 2)).build(); + navBar.add(capesTab); + var importButton = SpriteIconButton.builder(Component.translatable("skins.manage.import.local"), btn -> { + btn.active = false; + SkinImportUtil.openImportSkinDialog().thenAccept(this::onFilesDrop).thenRun(() -> btn.active = true); + }, true).sprite(ResourceLocation.fromNamespaceAndPath("axolotlclient", "folder"), 7, 7).size(11, 11).build(); + importButton.setTooltip(Tooltip.create(importButton.getMessage())); + var downloadButton = SpriteIconButton.builder(Component.translatable("skins.manage.import.online"), btn -> { + btn.active = false; + promptForSkinDownload(); + }, true).sprite(ResourceLocation.fromNamespaceAndPath("axolotlclient", "download"), 7, 7).size(11, 11).build(); + downloadButton.setTooltip(Tooltip.create(downloadButton.getMessage())); + if (width - (capesTab.getX() + capesTab.getWidth()) > 28) { + importButton.setX(width - importButton.getWidth() - 2); + downloadButton.setX(importButton.getX() - downloadButton.getWidth() - 2); + importButton.setY(capesTab.getY() + capesTab.getHeight() - 11); + downloadButton.setY(importButton.getY()); + } else { + importButton.setX(capesTab.getX() + capesTab.getWidth() - 11); + importButton.setY(capesTab.getY() - 13); + downloadButton.setX(importButton.getX() - 2 - 11); + downloadButton.setY(importButton.getY()); + } + skinsTab.active = this.capesTab; + capesTab.active = !this.capesTab; + Runnable addWidgets = () -> { + clearWidgets(); + addRenderableWidget(titleWidget); + addRenderableWidget(current); + addRenderableWidget(skinsTab); + addRenderableWidget(capesTab); + addRenderableWidget(downloadButton); + addRenderableWidget(importButton); + addRenderableWidget(skinList); + addRenderableWidget(capesList); + addRenderableWidget(back); + }; + if (cachedProfile != null) { + initDisplay(); + addWidgets.run(); + return; + } + + loadingFuture.thenAcceptAsync(profile -> { + cachedProfile = profile; + initDisplay(); + addWidgets.run(); + }).exceptionally(t -> { + if (t.getCause() instanceof CancellationException) { + minecraft.setScreen(parent); + return null; + } + AxolotlClientCommon.getInstance().getLogger().error("Failed to load skins!", t); + var error = Component.translatable("skins.error.failed_to_load"); + var errorDesc = Component.translatable("skins.error.failed_to_load_desc"); + clearWidgets(); + addRenderableWidget(titleWidget); + addRenderableWidget(new StringWidget(width / 2 - getFont().width(error) / 2, height / 2 - getFont().lineHeight - 2, getFont().width(error), getFont().lineHeight, error, getFont())); + addRenderableWidget(new StringWidget(width / 2 - getFont().width(errorDesc) / 2, height / 2 + 1, getFont().width(errorDesc), getFont().lineHeight, errorDesc, getFont())); + addRenderableWidget(back); + return null; + }); + } + + private void promptForSkinDownload() { + minecraft.setScreen(new SimpleTextInputScreen(this, Component.translatable("skins.manage.import.online"), Component.translatable("skins.manage.import.online.input"), s -> + UUIDHelper.ensureUuidOpt(s).thenAcceptAsync(o -> { + if (o.isPresent()) { + AxolotlClientCommon.getInstance().getLogger().info("Downloading skin of {} ({})", s, o.get()); + Auth.getInstance().getMsApi().getTextures(o.get()) + .exceptionally(th -> { + AxolotlClientCommon.getInstance().getLogger().info("Failed to download skin of {} ({})", s, o.get(), th); + return null; + }).thenAcceptAsync(t -> { + if (t == null) { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_download", s); + return; + } + try { + var bytes = t.skin().join(); + var out = ensureNonexistent(SKINS_DIR.resolve(t.skinKey())); + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, t.classicModel(), "name", t.name(), "uuid", t.id(), "download_time", Instant.now())); + Files.write(out, bytes); + minecraft.execute(this::loadSkinsList); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.downloaded", t.name()); + AxolotlClientCommon.getInstance().getLogger().info("Downloaded skin of {} ({})", t.name(), o.get()); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to write skin file", e); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.failed_to_save", t.name()); + } + }); + } else { + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.import.online.not_found", s); + } + }))); + } + + private void initDisplay() { + loadSkinsList(); + loadCapesList(); + } + + private void refreshCurrentList() { + if (capesTab) { + var scroll = capesList.scrollAmount(); + loadCapesList(); + capesList.setScrollAmount(scroll); + } else { + var scroll = skinList.scrollAmount(); + loadSkinsList(); + skinList.setScrollAmount(scroll); + } + } + + private void loadCapesList() { + List rows = new ArrayList<>(); + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + var capes = profile.capes(); + var deselectCape = createWidgetForCape(current.getSkin(), null); + var activeCape = capes.stream().filter(Cape::active).findFirst(); + current.setCape(activeCape.orElse(null)); + deselectCape.noCape(activeCape.isEmpty()); + for (int i = 0; i < capes.size() + 1; i += columns) { + Entry widget; + if (i == 0) { + widget = createEntry(capesList.getEntryContentsHeight(), deselectCape, Component.translatable("skins.capes.no_cape")); + } else { + var cape = capes.get(i - 1); + widget = createEntryForCape(current.getSkin(), cape, capesList.getEntryContentsHeight()); + } + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < capes.size() + 1 - c)) continue; + var cape2 = capes.get(i + c - 1); + Entry widget2 = createEntryForCape(current.getSkin(), cape2, capesList.getEntryContentsHeight()); + + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + minecraft.execute(() -> capesList.replaceEntries(rows)); + capesList.setScrollAmount(capesList.scrollAmount()); + } + + private void loadSkinsList() { + var profile = cachedProfile; + int columns = Math.max(2, (width / 2 - 25) / LIST_SKIN_WIDTH); + List skins = new ArrayList<>(profile.skins()); + var hashes = skins.stream().map(Asset::sha256).collect(Collectors.toSet()); + var defaultSkin = Skin.getDefaultSkin(account); + var local = new ArrayList<>(loadLocalSkins()); + var localHashes = local.stream().collect(Collectors.toMap(Asset::sha256, Function.identity(), (skin, skin2) -> skin)); + local.removeIf(s -> !localHashes.containsValue(s)); + skins.replaceAll(s -> { + if (s instanceof MSApi.MCProfile.OnlineSkin online) { + if (localHashes.containsKey(s.sha256()) && localHashes.get(s.sha256()) instanceof Skin.LocalSkin file) { + local.remove(localHashes.remove(s.sha256())); + return new Skin.Shared(file, online); + } + } + return s; + }); + + skins.addAll(local); + if (!hashes.contains(defaultSkin.sha256())) { + skins.add(defaultSkin); + } + populateSkinList(skins, columns); + skinList.setScrollAmount(skinList.scrollAmount()); + } + + private List loadLocalSkins() { + try { + Files.createDirectories(SKINS_DIR); + try (Stream skins = Files.list(SKINS_DIR)) { + return skins.filter(Files::isRegularFile).sorted(Comparator.comparingLong(p -> { + try { + return Files.getLastModifiedTime(p).toMillis(); + } catch (IOException e) { + return 0L; + } + }).reversed()).map(Auth.getInstance().getSkinManager()::read).filter(Objects::nonNull).toList(); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to read skins dir!", e); + } + return Collections.emptyList(); + } + + private void populateSkinList(List skins, int columns) { + int entryHeight = skinList.getEntryContentsHeight(); + List rows = new ArrayList<>(); + for (int i = 0; i < skins.size(); i += columns) { + var s = skins.get(i); + if (s != null && s.active()) { + current.setSkin(s); + } + var widget = createEntryForSkin(s, entryHeight); + List widgets = new ArrayList<>(); + widgets.add(widget); + for (int c = 1; c < columns; c++) { + if (!(i < skins.size() - c)) continue; + var s2 = skins.get(i + c); + if (s2 != null && s2.active()) { + current.setSkin(s2); + } + var widget2 = createEntryForSkin(s2, entryHeight); + widgets.add(widget2); + } + rows.add(new Row(widgets)); + } + minecraft.execute(() -> skinList.replaceEntries(rows)); + } + + private Path ensureNonexistent(Path p) { + if (Files.exists(p)) { + int counter = 0; + do { + counter++; + p = p.resolveSibling(p.getFileName().toString() + "_" + counter); + } while (Files.exists(p)); + } + return p; + } + + @Override + public void onFilesDrop(List packs) { + if (packs.isEmpty()) return; + + CompletableFuture[] futs = new CompletableFuture[packs.size()]; + for (int i = 0; i < packs.size(); i++) { + Path p = packs.get(i); + futs[i] = CompletableFuture.runAsync(() -> { + try { + var target = ensureNonexistent(SKINS_DIR.resolve(p.getFileName())); + var skin = Auth.getInstance().getSkinManager().read(p, false); + if (skin != null) { + Files.write(target, skin.image()); + } else { + AxolotlClientCommon.getInstance().getLogger().info("Skipping dragged file {} because it does not seem to be a valid skin!", p); + Notifications.getInstance().addStatus("skins.notification.title", "skins.notification.not_copied", p.getFileName()); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to copy skin file: ", e); + } + }, minecraft); + } + CompletableFuture.allOf(futs).thenRun(this::loadSkinsList); + } + + private @NotNull Entry createEntryForSkin(Skin skin, int entryHeight) { + return createEntry(entryHeight, new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, skin, account)); + } + + private @NotNull Entry createEntryForCape(Skin currentSkin, Cape cape, int entryHeight) { + return createEntry(entryHeight, createWidgetForCape(currentSkin, cape), Component.literal(cape.alias())); + } + + private SkinWidget createWidgetForCape(Skin currentSkin, Cape cape) { + SkinWidget widget2 = new SkinWidget(LIST_SKIN_WIDTH, LIST_SKIN_HEIGHT, currentSkin, cape, account); + widget2.setRotationY(210); + return widget2; + } + + @Override + protected void clearWidgets() { + super.clearWidgets(); + SkinRenderer.closeRenderers(); + Auth.getInstance().getSkinManager().releaseAll(); + } + + @Override + public void removed() { + Auth.getInstance().getSkinManager().releaseAll(); + Watcher.close(skinDirWatcher); + SkinRenderer.closeRenderers(); + } + + @Override + public void onClose() { + minecraft.setScreen(parent); + } + + private SkinListWidget getCurrentList() { + return capesTab ? capesList : skinList; + } + + private static class SkinListWidget extends ContainerObjectSelectionList { + public SkinListWidget(Minecraft minecraft, int width, int height, int y, int entryHeight) { + super(minecraft, width, height, y, entryHeight); + } + + @Override + protected int scrollBarX() { + return getRight() - 8; + } + + @Override + public int getRowLeft() { + return getX() + 3; + } + + @Override + public int getRowWidth() { + if (!scrollbarVisible()) { + return getWidth() - 4; + } + return getWidth() - 14; + } + + public int getEntryContentsHeight() { + return defaultEntryHeight - 4; + } + + @Override + public @Nullable ComponentPath nextFocusPath(FocusNavigationEvent event) { + if (!active || !visible) return null; + return super.nextFocusPath(event); + } + + @Override + public void replaceEntries(Collection newEntries) { + super.replaceEntries(newEntries); + } + + @Override + public void centerScrollOn(Row entry) { + super.centerScrollOn(entry); + } + } + + private class Row extends ContainerObjectSelectionList.Entry { + private final List widgets; + + public Row(List entries) { + this.widgets = entries; + } + + @Override + public @NotNull List narratables() { + return widgets; + } + + @Override + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + int x = getX(); + if (widgets.isEmpty()) return; + int count = widgets.size(); + int padding = ((getWidth() - 5 * (count - 1)) / count); + for (var w : widgets) { + w.setPosition(x, getContentY()); + w.setWidth(padding); + w.render(guiGraphics, mouseX, mouseY, partialTick); + x += w.getWidth() + 5; + } + } + + @Override + public @NotNull List children() { + return widgets; + } + + @Override + public void setFocused(@Nullable GuiEventListener focused) { + super.setFocused(focused); + if (focused != null) { + getCurrentList().centerScrollOn(this); + } + } + } + + Entry createEntry(int height, SkinWidget widget) { + return createEntry(height, widget, null); + } + + Entry createEntry(int height, SkinWidget widget, Component label) { + return new Entry(height, widget, label); + } + + private class Entry extends AbstractContainerWidget { + private final SkinWidget skinWidget; + private final @Nullable AbstractWidget label; + private final List actionButtons = new ArrayList<>(); + private final AbstractWidget equipButton; + private boolean equipping; + private long equippingStart; + + public Entry(int height, SkinWidget widget, @Nullable Component label) { + super(0, 0, widget.getWidth(), height, Component.empty()); + widget.setWidth(getWidth() - 4); + var asset = widget.getFocusedAsset(); + if (asset != null) { + class SpriteButton extends Button { + private ResourceLocation sprite; + + public SpriteButton(Component message, OnPress onPress, ResourceLocation sprite) { + super(0, 0, 11, 11, message, onPress, DEFAULT_NARRATION); + this.sprite = sprite; + setTooltip(Tooltip.create(message, Component.empty())); + } + + @Override + public void setMessage(Component message) { + super.setMessage(message); + setTooltip(Tooltip.create(message, Component.empty())); + } + + @Override + protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + super.renderWidget(graphics, mouseX, mouseY, delta); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, this.getX() + 2, this.getY() + 2, 7, 7); + } + + @Override + public void renderString(GuiGraphics guiGraphics, Font font, int color) { + + } + } + if (asset instanceof Skin skin) { + var wideSprite = ResourceLocation.fromNamespaceAndPath("axolotlclient", "wide"); + var slimSprite = ResourceLocation.fromNamespaceAndPath("axolotlclient", "slim"); + var slimText = Component.translatable("skins.manage.variant.classic"); + var wideText = Component.translatable("skins.manage.variant.slim"); + actionButtons.add(new SpriteButton(skin.classicVariant() ? wideText : slimText, btn -> { + var self = (SpriteButton) btn; + skin.classicVariant(!skin.classicVariant()); + self.sprite = skin.classicVariant() ? slimSprite : wideSprite; + self.setMessage(skin.classicVariant() ? wideText : slimText); + }, skin.classicVariant() ? slimSprite : wideSprite)); + } + if (asset instanceof Asset.Local local) { + this.actionButtons.add(new SpriteButton(Component.translatable("skins.manage.delete"), btn -> { + btn.active = false; + minecraft.setScreen(new ConfirmScreen(confirmed -> { + minecraft.setScreen(new LoadingScreen(getTitle(), Component.translatable("menu.working"))); + if (confirmed) { + try { + Files.delete(local.file()); + Skin.LocalSkin.deleteMetadata(local.file()); + refreshCurrentList(); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to delete: ", e); + } + } + minecraft.setScreen(SkinManagementScreen.this); + btn.active = true; + }, Component.translatable("skins.manage.delete.confirm"), (asset.active() ? + Component.translatable("skins.manage.delete.confirm.desc_active") : + Component.translatable("skins.manage.delete.confirm.desc") + ).withColor(Colors.RED.toInt()))); + }, ResourceLocation.fromNamespaceAndPath("axolotlclient", "delete"))); + } + if (asset instanceof Asset.Online online && online.supportsDownload() && !(asset instanceof Asset.Local)) { + this.actionButtons.add(new SpriteButton(Component.translatable("skins.manage.download"), btn -> { + btn.active = false; + download(asset).thenRun(() -> { + refreshCurrentList(); + btn.active = true; + }); + }, ResourceLocation.fromNamespaceAndPath("axolotlclient", "download"))); + } + } + if (label != null) { + this.label = new AbstractStringWidget(0, 0, widget.getWidth(), 16, label, Minecraft.getInstance().font) { + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + renderScrollingString(guiGraphics, getFont(), 2, -1); + } + }; + this.label.active = false; + } else { + this.label = null; + } + this.equipButton = Button.builder(Component.translatable( + widget.isEquipped() ? "skins.manage.equipped" : "skins.manage.equip"), + btn -> { + equippingStart = Util.getMillis(); + equipping = true; + btn.setMessage(TEXT_EQUIPPING); + btn.active = false; + Consumer> consumer = f -> { + f.thenAcceptAsync(p -> { + cachedProfile = p; + if (minecraft.screen == SkinManagementScreen.this) { + refreshCurrentList(); + } else { + minecraft.execute(() -> minecraft.setScreen(SkinManagementScreen.this)); + } + }).exceptionally(t -> { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to equip asset!", t); + equipping = false; + return null; + }); + }; + if (asset instanceof Skin && !(current.getSkin() instanceof Skin.Local)) { + minecraft.setScreen(new ConfirmScreen(confirmed -> { + minecraft.setScreen(new LoadingScreen(getTitle(), TEXT_EQUIPPING)); + if (confirmed) { + consumer.accept(download(current.getSkin()).thenCompose(a -> widget.equip())); + } else { + consumer.accept(widget.equip()); + } + }, Component.translatable("skins.manage.equip.confirm"), Component.translatable("skins.manage.equip.download_current"))); + } else { + consumer.accept(widget.equip()); + } + }).width(widget.getWidth()).build(); + this.equipButton.active = !widget.isEquipped(); + this.skinWidget = widget; + } + + private @NotNull CompletableFuture download(Asset asset) { + return CompletableFuture.runAsync(() -> { + try { + var out = SKINS_DIR.resolve(asset.sha256()); + Files.createDirectories(out.getParent()); + Files.write(out, asset.image()); + if (asset instanceof Skin skin) { + Skin.LocalSkin.writeMetadata(out, Map.of(Skin.LocalSkin.CLASSIC_METADATA_KEY, skin.classicVariant())); + } + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to download: ", e); + } + }); + } + + @Override + public @NotNull List children() { + return Stream.concat(actionButtons.stream(), Stream.of(skinWidget, label, equipButton)).filter(Objects::nonNull).toList(); + } + + @Override + protected int contentHeight() { + return getHeight(); + } + + @Override + protected double scrollRate() { + return 0; + } + + private float applyEasing(float x) { + return x * x * x; + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + int y = getY() + 4; + int x = getX() + 2; + skinWidget.setPosition(x, y); + skinWidget.setWidth(getWidth() - 4); + if (skinWidget.isEquipped() || equipping) { + long prog; + if (Auth.getInstance().skinManagerAnimations.get()) { + if (equipping) prog = (Util.getMillis() - equippingStart) / 20 % 100; + else prog = Math.abs((Util.getMillis() / 30 % 200) - 100); + } else prog = 100; + var percent = prog / 100f; + float gradientWidth; + if (equipping) { + gradientWidth = percent * Math.min(getWidth() / 3f, getHeight() / 3f); + } else { + gradientWidth = Math.min(getWidth() / 15f, getHeight() / 6f) + applyEasing(percent) * Math.min(getWidth() * 2 / 15f, getHeight() / 6f); + } + GradientHoleRectangleRenderState.create(guiGraphics, getX() + 2, getY() + 2, getRight() - 2, + skinWidget.getBottom() + 2, + gradientWidth, + equipping ? 0xFFFF0088 : ClientColors.SELECTOR_GREEN.toInt(), 0).submit(); + } + skinWidget.render(guiGraphics, mouseX, mouseY, partialTick); + int actionButtonY = getY() + 2; + for (var button : actionButtons) { + button.setPosition(skinWidget.getRight() - button.getWidth(), actionButtonY); + if (isHovered() || button.isHoveredOrFocused()) { + button.render(guiGraphics, mouseX, mouseY, partialTick); + } + actionButtonY += button.getHeight() + 2; + } + if (label != null) { + label.setPosition(x, skinWidget.getBottom() + 6); + label.render(guiGraphics, mouseX, mouseY, partialTick); + label.setWidth(getWidth() - 4); + equipButton.setPosition(x, label.getBottom() + 2); + } else { + equipButton.setPosition(x, skinWidget.getBottom() + 4); + } + equipButton.setWidth(getWidth() - 4); + equipButton.render(guiGraphics, mouseX, mouseY, partialTick); + + if (isHovered()) { + DrawUtil.outlineRect(guiGraphics, getX(), getY(), getWidth(), getHeight(), -1); + } + } + + @Override + protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { + skinWidget.updateNarration(narrationElementOutput); + actionButtons.forEach(w -> w.updateNarration(narrationElementOutput)); + if (label != null) { + label.updateNarration(narrationElementOutput); + } + equipButton.updateNarration(narrationElementOutput); + } + + private record GradientHoleRectangleRenderState(RenderPipeline pipeline, TextureSetup textureSetup, + Matrix3x2f pose, + int x0, int y0, int x1, int y1, float gradientWidth, int col1, + int col2, @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds) implements GuiElementRenderState { + + public static GradientHoleRectangleRenderState create(GuiGraphics graphics, int x0, int y0, int x1, int y1, float gradientWidth, int col1, int col2) { + var matrix = new Matrix3x2f(graphics.pose()); + var area = ((GuiGraphicsAccessor) graphics).getScissorStack().peek(); + return new GradientHoleRectangleRenderState(RenderPipelines.GUI, TextureSetup.noTexture(), matrix, x0, y0, x1, y1, gradientWidth, col1, col2, area, getBounds(x0, y0, x1, y1, matrix, area)); + } + + public void submit() { + ((GameRendererAccessor) Minecraft.getInstance().gameRenderer).getGuiRenderState().submitGuiElement(this); + } + + @Override + public void buildVertices(VertexConsumer vertexConsumer) { + //top + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y0()).setColor(this.col1()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0() + gradientWidth(), this.y0() + gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1() - gradientWidth(), this.y0() + gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y0()).setColor(this.col1()); + //left + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y1()).setColor(this.col1()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0() + gradientWidth(), this.y1() - gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0() + gradientWidth(), this.y0() + gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y0()).setColor(this.col1()); + //bottom + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y1()).setColor(this.col1()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1() - gradientWidth(), this.y1() - gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0() + gradientWidth(), this.y1() - gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y1()).setColor(this.col1()); + //right + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y0()).setColor(this.col1()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1() - gradientWidth(), this.y0() + gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1() - gradientWidth(), this.y1() - gradientWidth()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y1()).setColor(this.col1()); + } + + @Nullable + private static ScreenRectangle getBounds(int i, int j, int k, int l, Matrix3x2f matrix3x2f, @Nullable ScreenRectangle screenRectangle) { + ScreenRectangle screenRectangle2 = new ScreenRectangle(i, j, k - i, l - j).transformMaxBounds(matrix3x2f); + return screenRectangle != null ? screenRectangle.intersection(screenRectangle2) : screenRectangle2; + } + } + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java new file mode 100644 index 000000000..2b58731ac --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinManager.java @@ -0,0 +1,122 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import com.google.common.hash.Hashing; +import com.mojang.blaze3d.platform.NativeImage; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.mixin.skins.SkinTextureDownloaderAccessor; +import io.github.axolotlclient.util.ClientColors; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.resources.ResourceLocation; + +public class SkinManager { + + private final Set loadedTextures = new ConcurrentSkipListSet<>(Comparator.comparing(Object::toString)); + + public Skin read(Path p) { + return read(p, true); + } + + public Skin read(Path p, boolean fix) { + boolean slim; + String sha256; + try { + var in = Files.readAllBytes(p); + sha256 = Hashing.sha256().hashBytes(in).toString(); + try (var img = NativeImage.read(in)) { + int width = img.getWidth(); + int height = img.getHeight(); + if (width != 64) return null; + if (height == 32) { + if (fix) { + try (var img2 = SkinTextureDownloaderAccessor.invokeProcessLegacySkin(img, "local")) { + img2.writeToFile(p); + } + } + slim = false; + } else if (height != 64) { + return null; + } else { + slim = ClientColors.ARGB.alpha(img.getPixel(50, 16)) == 0; + } + var metadata = Skin.LocalSkin.readMetadata(p); + if (metadata != null && metadata.containsKey(Skin.LocalSkin.CLASSIC_METADATA_KEY)) { + slim = !(boolean) metadata.get(Skin.LocalSkin.CLASSIC_METADATA_KEY); + } + } + return new Skin.LocalSkin(!slim, p, in, sha256); + } catch (Exception e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to probe skin: ", e); + } + return null; + } + + + public AxoIdentifier loadSkin(Skin skin) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "skins/" + skin.sha256()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try { + var tex = new DynamicTexture(rl::toString, NativeImage.read(skin.image())); + Minecraft.getInstance().getTextureManager().register((ResourceLocation) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public AxoIdentifier loadCape(Cape cape) { + var rl = AxoIdentifier.of(AxolotlClientCommon.MODID, "capes/" + cape.id()); + if (loadedTextures.contains(rl)) { + return rl; + } + + try { + var tex = new DynamicTexture(rl::toString, NativeImage.read(cape.image())); + Minecraft.getInstance().getTextureManager().register((ResourceLocation) rl, tex); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + loadedTextures.add(rl); + return rl; + } + + public void releaseAll() { + loadedTextures.forEach(id -> Minecraft.getInstance().getTextureManager().release((ResourceLocation) id)); + loadedTextures.clear(); + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderState.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderState.java new file mode 100644 index 000000000..cd5652e6b --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderState.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import io.github.axolotlclient.util.IdentifiablePiPRenderState; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +public record SkinRenderState(boolean classicVariant, + ResourceLocation skinTexture, + @Nullable ResourceLocation cape, + float rotationX, + float rotationY, + float pivotY, + int x0, + int y0, + int x1, + int y1, + float scale, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds, + SkinRenderer renderer) implements PictureInPictureRenderState, IdentifiablePiPRenderState { + + public SkinRenderState(boolean classicVariant, + ResourceLocation skinTexture, + @Nullable ResourceLocation cape, + float rotationX, + float rotationY, + float pivotY, + int x0, + int y0, + int x1, + int y1, + float scale, + @Nullable ScreenRectangle scissorArea, + SkinRenderer renderer) { + this(classicVariant, skinTexture, cape, rotationX, rotationY, pivotY, x0, y0, x1, y1, scale, scissorArea, PictureInPictureRenderState.getBounds(x0, y0, x1, y1, scissorArea), renderer); + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java new file mode 100644 index 000000000..e77ad970e --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinRenderer.java @@ -0,0 +1,106 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; +import net.minecraft.client.model.PlayerCapeModel; +import net.minecraft.client.model.PlayerModel; +import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4fStack; + +public class SkinRenderer extends PictureInPictureRenderer { + private static final Map renderers = new ConcurrentHashMap<>(); + + public static void closeRenderers() { + renderers.values().forEach(PictureInPictureRenderer::close); + renderers.clear(); + } + + public static SkinRenderer getOrCreate(MultiBufferSource.BufferSource bufferSource, Minecraft minecraft, String id) { + return renderers.computeIfAbsent(id, _id -> new SkinRenderer(bufferSource, minecraft, id)); + } + + private PlayerModel classicModel, slimModel; + private PlayerCapeModel capeModel; + private final Minecraft minecraft; + private final String id; + + private SkinRenderer(MultiBufferSource.BufferSource bufferSource, Minecraft minecraft, String id) { + super(bufferSource); + this.minecraft = minecraft; + this.id = id; + } + + @Override + public @NotNull Class getRenderStateClass() { + return SkinRenderState.class; + } + + @Override + protected void renderToTexture(SkinRenderState renderState, PoseStack poseStack) { + if (classicModel == null && renderState.classicVariant()) { + classicModel = new PlayerModel(minecraft.getEntityModels().bakeLayer(ModelLayers.PLAYER), false); + } + if (slimModel == null && !renderState.classicVariant()) { + slimModel = new PlayerModel(minecraft.getEntityModels().bakeLayer(ModelLayers.PLAYER_SLIM), true); + } + Minecraft.getInstance().gameRenderer.getLighting().setupFor(Lighting.Entry.PLAYER_SKIN); + int i = Minecraft.getInstance().getWindow().getGuiScale(); + Matrix4fStack matrix4fStack = RenderSystem.getModelViewStack(); + matrix4fStack.pushMatrix(); + float f = renderState.scale() * i; + matrix4fStack.rotateAround(Axis.XP.rotationDegrees(renderState.rotationX()), 0.0F, f * -renderState.pivotY(), 0.0F); + poseStack.mulPose(Axis.YP.rotationDegrees(-renderState.rotationY())); + poseStack.translate(0.0F, -1.6010001F, 0.0F); + var model = renderState.classicVariant() ? classicModel : slimModel; + RenderType renderType = model.renderType(renderState.skinTexture()); + model.renderToBuffer(poseStack, this.bufferSource.getBuffer(renderType), 15728880, OverlayTexture.NO_OVERLAY); + if (renderState.cape() != null) { + if (capeModel == null) { + capeModel = new PlayerCapeModel(minecraft.getEntityModels().bakeLayer(ModelLayers.PLAYER_CAPE)); + } + var type = capeModel.renderType(renderState.cape()); + poseStack.mulPose(Axis.XP.rotationDegrees(6.0F)); + capeModel.renderToBuffer(poseStack, bufferSource.getBuffer(type), 15728880, OverlayTexture.NO_OVERLAY); + } + this.bufferSource.endBatch(); + matrix4fStack.popMatrix(); + } + + @Override + protected @NotNull String getTextureLabel() { + return "axolotlclient/skin_render/" + id; + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java new file mode 100644 index 000000000..ee806a14e --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinWidget.java @@ -0,0 +1,143 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.util.concurrent.CompletableFuture; + +import io.github.axolotlclient.bridge.util.AxoIdentifier; +import io.github.axolotlclient.mixin.GuiGraphicsAccessor; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.Auth; +import io.github.axolotlclient.modules.auth.MSApi; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.Nullable; + +public class SkinWidget extends AbstractWidget { + private static final float MODEL_HEIGHT = 2.125F; + private static final float FIT_SCALE = 0.97F; + private static final float ROTATION_SENSITIVITY = 2.5F; + private static final float DEFAULT_ROTATION_X = -5.0F; + private static final float DEFAULT_ROTATION_Y = 30.0F; + private static final float ROTATION_X_LIMIT = 50.0F; + private float rotationX = DEFAULT_ROTATION_X; + @Setter + private float rotationY = DEFAULT_ROTATION_Y; + @Getter + @Setter + private Skin skin; + @Getter + @Setter + private Cape cape; + private final Account owner; + private boolean noCape, noCapeActive; + + public SkinWidget(int width, int height, Skin skin, @Nullable Cape cape, Account owner) { + super(0, 0, width, height, CommonComponents.EMPTY); + this.skin = skin; + this.cape = cape; + this.owner = owner; + } + + public SkinWidget(int width, int height, Skin skin, Account owner) { + this(width, height, skin, null, owner); + } + + public void noCape(boolean noCapeActive) { + noCape = true; + this.noCapeActive = noCapeActive; + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + var minecraft = Minecraft.getInstance(); + + float scale = FIT_SCALE * this.getHeight() / MODEL_HEIGHT; + float pivotY = -1.0625F; + + SkinManager skinManager = Auth.getInstance().getSkinManager(); + AxoIdentifier skinRl = skinManager.loadSkin(skin); + boolean classic = skin.classicVariant(); + var capeRl = cape == null ? null : skinManager.loadCape(cape); + + // You might say that using `hashCode()` like this isn't ideal, but in reality it doesn't matter. These objects get freed + // correctly by the screen so we mostly only need unique identifiers per widget which `hashCode()` provides. + var renderer = SkinRenderer.getOrCreate(minecraft.renderBuffers().bufferSource(), minecraft, "" + hashCode()); + ((GuiGraphicsAccessor) guiGraphics).getGuiRenderState() + .submitPicturesInPictureState( + new SkinRenderState(classic, (ResourceLocation) skinRl, (ResourceLocation) capeRl, this.rotationX, this.rotationY, pivotY, this.getX(), this.getY(), this.getRight(), this.getBottom(), scale, guiGraphics.scissorStack.peek(), renderer)); + } + + @Override + protected void onDrag(MouseButtonEvent mouseButtonEvent, double dragX, double dragY) { + this.rotationX = Mth.clamp(this.rotationX - (float) dragY * ROTATION_SENSITIVITY, -ROTATION_X_LIMIT, ROTATION_X_LIMIT); + this.rotationY += (float) dragX * ROTATION_SENSITIVITY; + } + + @Override + public void playDownSound(SoundManager handler) { + } + + @Override + protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { + } + + @Nullable + @Override + public ComponentPath nextFocusPath(FocusNavigationEvent event) { + return null; + } + + public boolean isEquipped() { + return noCape ? noCapeActive : (cape != null ? cape.active() : skin != null && skin.active()); + } + + public CompletableFuture equip() { + var msApi = Auth.getInstance().getMsApi(); + if (noCape) { + return msApi.hideCape(owner); + } + if (cape != null) { + return cape.equip(msApi, owner); + } + if (skin != null) { + return skin.equip(msApi, owner); + } + return msApi.resetSkin(owner); + } + + public Asset getFocusedAsset() { + return noCape ? null : cape != null ? cape : skin; + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java b/1.latest/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/blur/MotionBlur.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java b/1.latest/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java index eaca9cab4..573e8d5a0 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/freelook/Freelook.java @@ -43,8 +43,8 @@ public class Freelook extends AbstractModule { private static final Freelook INSTANCE = new Freelook(); - private static final KeyMapping KEY = KeyBinds.getInstance().register(new KeyMapping("key.freelook", InputConstants.KEY_V, "category.axolotlclient")); - private static final KeyMapping KEY_ALT = KeyBinds.getInstance().register(new KeyMapping("key.freelook.alt", InputConstants.UNKNOWN.getValue(), "category.axolotlclient")); + private static final KeyMapping KEY = KeyBinds.getInstance().register(new KeyMapping("key.freelook", InputConstants.KEY_V, KeyBinds.CATEGORY_AXOLOTLCLIENT)); + private static final KeyMapping KEY_ALT = KeyBinds.getInstance().register(new KeyMapping("key.freelook.alt", InputConstants.UNKNOWN.getValue(), KeyBinds.CATEGORY_AXOLOTLCLIENT)); public final ForceableBooleanOption enabled = new ForceableBooleanOption("enabled", false); private final Minecraft client = Minecraft.getInstance(); private final OptionCategory category = OptionCategory.create("freelook"); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java similarity index 90% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java index 3e3b95182..628eb7fdf 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudEditScreen.java @@ -38,6 +38,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; @@ -46,7 +47,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudEditScreen extends Screen { @@ -104,7 +105,7 @@ private void updateSnapState() { private void setCursor(long cursor) { if (cursor > 0 && cursor != currentCursor) { currentCursor = cursor; - GLFW.glfwSetCursor(Minecraft.getInstance().getWindow().getWindow(), cursor); + GLFW.glfwSetCursor(Minecraft.getInstance().getWindow().handle(), cursor); } } @@ -124,19 +125,20 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { if (entry.isPresent()) { var bounds = entry.get().getTrueBounds(); if (mode == ModificationMode.NONE && bounds.isMouseOver(mouseX, mouseY)) { + var supportsScaling = entry.get().supportsScaling(); var xBound = Math.max(0, mouseX - bounds.x()); var yBound = Math.max(0, mouseY - bounds.y()); var tolerance = GRAB_TOLERANCE; - if (xBound < tolerance && yBound < tolerance) { + if (supportsScaling && xBound < tolerance && yBound < tolerance) { // top-left setCursor(NWSE_RESIZE_CURSOR); - } else if (Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && Math.abs(xBound - bounds.width()) < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-right setCursor(NWSE_RESIZE_CURSOR); - } else if (xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { + } else if (supportsScaling && xBound < tolerance && Math.abs(yBound - bounds.height()) < tolerance) { // bottom-left setCursor(NESW_RESIZE_CURSOR); - } else if (yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { + } else if (supportsScaling && yBound < tolerance && Math.abs(xBound - bounds.width()) < tolerance) { // top-right setCursor(NESW_RESIZE_CURSOR); } else { @@ -159,6 +161,7 @@ public void removed() { super.removed(); } + @SuppressWarnings("DataFlowIssue") @Override public void init() { mode = ModificationMode.NONE; @@ -190,11 +193,13 @@ public void init() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - boolean value = super.mouseClicked(mouseX, mouseY, button); + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + boolean value = super.mouseClicked(event, doubleClick); + var mouseX = event.x(); + var mouseY = event.y(); Optional entry = HudManager.getInstance().getEntryXY((int) Math.round(mouseX), (int) Math.round(mouseY)); - if (button == 0) { + if (event.button() == 0) { mouseDown = true; if (entry.isPresent()) { current = entry.get(); @@ -228,9 +233,10 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { mode = ModificationMode.NONE; current = null; } - } else if (button == 1) { + } else if (event.button() == 1) { entry.ifPresent(abstractHudEntry -> { Screen screen = ConfigStyles.createScreen(this, abstractHudEntry.getCategory()); + //noinspection DataFlowIssue minecraft.setScreen(screen); }); } @@ -238,7 +244,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { + public boolean mouseReleased(MouseButtonEvent event) { if (current != null) { AxolotlClientConfig.getInstance().getConfigManager(current.getCategory()).save(); } @@ -247,11 +253,13 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { mouseDown = false; mode = ModificationMode.NONE; setCursor(DEFAULT_CURSOR); - return super.mouseReleased(mouseX, mouseY, button); + return super.mouseReleased(event); } @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) { + var mouseX = event.x(); + var mouseY = event.y(); if (current != null) { if (mode == ModificationMode.MOVE) { current.setX((int) mouseX - offset.x() + current.offsetTrueWidth()); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudEntryWidget.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudEntryWidget.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudEntryWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudEntryWidget.java index 2fa2b50aa..872f66aa6 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudEntryWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudEntryWidget.java @@ -37,7 +37,7 @@ import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.navigation.ScreenRectangle; -import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -93,7 +93,7 @@ public boolean isMouseOver(double mouseX, double mouseY) { public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { if (isFocused()) { var bounds = entry.getTrueBounds(); - guiGraphics.renderOutline(bounds.x() - 1, bounds.y() - 1, bounds.width() + 2, bounds.height() + 2, moving ? ClientColors.SELECTOR_RED.toInt() : -1); + guiGraphics.br$outlineRect(bounds.x() - 1, bounds.y() - 1, bounds.width() + 2, bounds.height() + 2, moving ? ClientColors.SELECTOR_RED.toInt() : -1); } } @@ -108,12 +108,13 @@ public ComponentPath nextFocusPath(FocusNavigationEvent event) { } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(KeyEvent event) { var mc = Minecraft.getInstance(); boolean consume = false; + var keyCode = event.key(); if (moving) { consume = true; - int step = Screen.hasControlDown() ? 10 : 1; + int step = mc.hasControlDown() ? 10 : 1; if (keyCode == InputConstants.KEY_ESCAPE || keyCode == InputConstants.KEY_SPACE) { moving = false; } else if (keyCode == InputConstants.KEY_UP) { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java index a81b5c936..40012aed4 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/HudManager.java @@ -26,9 +26,9 @@ import io.github.axolotlclient.modules.hud.gui.hud.KeystrokeHud; import io.github.axolotlclient.modules.hud.gui.hud.PackDisplayHud; import io.github.axolotlclient.modules.hud.gui.hud.PlayerHud; -import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import io.github.axolotlclient.modules.hud.gui.hud.simple.ComboHud; import io.github.axolotlclient.modules.hud.gui.hud.simple.ReachHud; +import io.github.axolotlclient.modules.hud.gui.hud.vanilla.*; import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.util.profiling.Profiler; @@ -37,7 +37,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class HudManager extends HudManagerCommon { @Getter @@ -67,7 +67,7 @@ protected void addExtraHud() { public void render(AxoRenderContext context, float delta) { final var mc = Profiler.get(); mc.push("Hud render"); - if(!(Minecraft.getInstance().screen instanceof HudEditScreen)) { + if (!(Minecraft.getInstance().screen instanceof HudEditScreen)) { super.render(context, delta); } mc.pop(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java index cbbf07bbe..62f2e7416 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/KeystrokeHud.java @@ -38,9 +38,9 @@ import io.github.axolotlclient.bridge.render.AxoRenderContext; import io.github.axolotlclient.config.profiles.ProfileAware; import io.github.axolotlclient.modules.hud.ClickInputTracker; +import io.github.axolotlclient.modules.hud.gui.entry.TextHudEntry; import io.github.axolotlclient.modules.hud.gui.keystrokes.KeystrokePositioningScreen; import io.github.axolotlclient.modules.hud.gui.keystrokes.KeystrokesScreen; -import io.github.axolotlclient.modules.hud.gui.entry.TextHudEntry; import io.github.axolotlclient.modules.hud.gui.layout.Justification; import io.github.axolotlclient.modules.hud.util.DrawPosition; import io.github.axolotlclient.modules.hud.util.Rectangle; @@ -67,7 +67,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class KeystrokeHud extends TextHudEntry implements ProfileAware { @@ -91,6 +91,7 @@ public class KeystrokeHud extends TextHudEntry implements ProfileAware { public KeystrokeHud() { super(53, 61, true); Events.KEYBIND_CHANGE.register(key -> { + //noinspection ConstantValue if (Minecraft.getInstance().getWindow() != null) { KeyMapping.releaseAll(); KeyMapping.setAll(); @@ -132,6 +133,7 @@ public void setDefaultKeystrokes() { } public void setKeystrokes() { + //noinspection ConstantValue if (client.getWindow() == null) { keystrokes = null; return; @@ -475,6 +477,7 @@ public boolean isLabelEditable() { } public void saveKeystrokes() { + if (keystrokes == null) return; try { var path = AxolotlClientCommon.resolveProfileConfigFile(KEYSTROKE_SAVE_FILE_NAME); Files.createDirectories(path.getParent()); @@ -493,7 +496,11 @@ public void loadKeystrokes() { var loaded = entries.stream().map(e -> (Map) e) .map(KeystrokeHud.this::deserializeKey) .toList(); - keystrokes.clear(); + if (keystrokes == null) { + keystrokes = new ArrayList<>(); + } else { + keystrokes.clear(); + } keystrokes.addAll(loaded); } else { saveKeystrokes(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PackDisplayHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PackDisplayHud.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PackDisplayHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PackDisplayHud.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java similarity index 90% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java index e19ce2d52..22d10afab 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PlayerHud.java @@ -22,11 +22,12 @@ package io.github.axolotlclient.modules.hud.gui.hud; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.render.AxoRenderContext; import io.github.axolotlclient.mixin.GuiGraphicsAccessor; import io.github.axolotlclient.modules.hud.util.PlayerHudEntityRenderState; -import io.github.axolotlclient.util.events.Events; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; +import io.github.axolotlclient.modules.hud.util.PlayerHudEntityRenderer; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; @@ -43,12 +44,13 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class PlayerHud extends PlayerHudCommon { private LivingEntityRenderState reusedPlayerRendererState = null; + private PlayerHudEntityRenderer renderer; public PlayerHud() { super(); @@ -56,7 +58,7 @@ public PlayerHud() { } public void onPlayerDirectionChange(PlayerDirectionChangeEvent event) { - yawOffset += (event.getYaw() - event.getPrevYaw()) / 2; + yawOffset += (event.yaw() - event.prevYaw()) / 2; } @Override @@ -110,7 +112,7 @@ protected void renderPlayer(AxoRenderContext ctx, boolean placeholder, double x, float lerpY = (lastYOffset + ((yOffset - lastYOffset) * delta)); - float scale = getScale() * 30; + float scale = getScale() * 40; Quaternionf quaternion = new Quaternionf().rotateZ((float) Math.PI); @@ -148,7 +150,10 @@ private void renderEntityInInventory( @Nullable Quaternionf quaternionf2, LivingEntity livingEntity ) { - EntityRenderDispatcher entityRenderDispatcher = Minecraft.getInstance().getEntityRenderDispatcher(); + Minecraft mc = Minecraft.getInstance(); + EntityRenderDispatcher entityRenderDispatcher = mc.getEntityRenderDispatcher(); + if (renderer == null) + renderer = new PlayerHudEntityRenderer(mc.renderBuffers().bufferSource(), entityRenderDispatcher); EntityRenderer entityRenderer = (EntityRenderer) entityRenderDispatcher.getRenderer(livingEntity); if (reusedPlayerRendererState == null) { reusedPlayerRendererState = entityRenderer.createRenderState(); @@ -156,12 +161,13 @@ private void renderEntityInInventory( entityRenderer.extractRenderState(livingEntity, reusedPlayerRendererState, 1.0f); reusedPlayerRendererState.nameTag = null; reusedPlayerRendererState.hitboxesRenderState = null; - ((GuiGraphicsAccessor) guiGraphics).getGuiRenderState().submitPicturesInPictureState(new PlayerHudEntityRenderState(reusedPlayerRendererState, vector3f, quaternionf, quaternionf2, i, j, k, l, f, ((GuiGraphicsAccessor) guiGraphics).getScissorStack().peek())); + ((GuiGraphicsAccessor) guiGraphics).getGuiRenderState().submitPicturesInPictureState(new PlayerHudEntityRenderState(reusedPlayerRendererState, vector3f, quaternionf, quaternionf2, i, j, k, l, f, ((GuiGraphicsAccessor) guiGraphics).getScissorStack().peek(), renderer)); } private boolean isPerformingAction() { // inspired by tr7zw's mod LocalPlayer player = Minecraft.getInstance().player; + //noinspection DataFlowIssue return player.isCrouching() || player.isSprinting() || player.isFallFlying() || player.getAbilities().flying || player.isUnderWater() || player.isVisuallySwimming() || player.isPassenger() || player.isUsingItem() || player.isHandsBusy() || player.hurtTime > 0 || player.isOnFire(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java index 3746c2c21..278eb4600 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ActionBarHud.java @@ -40,7 +40,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ActionBarHud extends TextHudEntry { @@ -88,6 +88,7 @@ public ResourceLocation getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(timeShown); options.add(customTextColor); return options; diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java similarity index 99% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java index 219a73b83..b1f20efca 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/BossBarHud.java @@ -51,7 +51,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class BossBarHud extends TextHudEntry implements DynamicallyPositionable { @@ -175,6 +175,7 @@ public ResourceLocation getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(text); options.add(bar); options.add(anchor); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java index a7925c63d..4edf528e3 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/CrosshairHud.java @@ -62,7 +62,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CrosshairHud extends AbstractHudEntry implements DynamicallyPositionable { @@ -120,6 +120,7 @@ public AxoIdentifier getId() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(type); options.add(customTextureGraphics); options.add(showInF5); @@ -159,7 +160,7 @@ public double getDefaultY() { public void render(AxoRenderContext graphics, float delta) { } - public void renderCrosshair(GuiGraphics graphics, float delta) { + public void renderCrosshair(GuiGraphics graphics) { if (!client.options.getCameraType().isFirstPerson() && !showInF5.get()) { return; } @@ -208,6 +209,7 @@ public void renderCrosshair(GuiGraphics graphics, float delta) { // Draw attack indicator if (!customAttackIndicator.get() && indicator == AttackIndicatorStatus.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackStrengthScale(0.0F); // Whether a cross should be displayed under the indicator @@ -231,6 +233,7 @@ public void renderCrosshair(GuiGraphics graphics, float delta) { } } if (((type.get().equals(Crosshair.TEXTURE) || type.get().equals(Crosshair.CUSTOM)) ? customAttackIndicator.get() : true) && indicator == AttackIndicatorStatus.CROSSHAIR) { + //noinspection DataFlowIssue float progress = this.client.player.getAttackStrengthScale(0.0F); if (progress != 1.0F) { fillRenderType(graphics, blend, getRawX() + (getWidth() / 2) - 6, getRawY() + (getHeight() / 2) + 9, @@ -263,6 +266,7 @@ public Color getColor() { } else if (hit.getType() == HitResult.Type.BLOCK) { BlockPos blockPos = ((BlockHitResult) hit).getBlockPos(); Level world = this.client.level; + //noinspection DataFlowIssue if (world.getBlockState(blockPos).getMenuProvider(world, blockPos) != null || world.getBlockState(blockPos).getBlock() instanceof AbstractChestBlock) { return containerColor.get(); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java similarity index 99% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java index 71e5f8f31..892fd419b 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/DebugCountersHud.java @@ -138,6 +138,7 @@ public AnchorPoint getAnchor() { @Override public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); + options.add(hide); options.add(anchor); options.add(showCCount); options.add(showECount); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java index 8f5b15ccc..d00636f05 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/ScoreboardHud.java @@ -55,7 +55,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ScoreboardHud extends TextHudEntry implements DynamicallyPositionable { @@ -105,8 +105,10 @@ public void render(AxoRenderContext graphics, float delta) { @Override public void renderComponent(AxoRenderContext graphics, float delta) { + //noinspection DataFlowIssue Scoreboard scoreboard = this.client.level.getScoreboard(); Objective objective = null; + //noinspection DataFlowIssue PlayerTeam playerTeam = scoreboard.getPlayersTeam(client.player.getScoreboardName()); if (playerTeam != null) { DisplaySlot displaySlot = DisplaySlot.teamColorToSlot(playerTeam.getColor()); @@ -216,6 +218,7 @@ record DisplayEntry(Component name, Component score, int scoreWidth) { public List> getConfigurationOptions() { List> options = super.getConfigurationOptions(); options.set(options.indexOf(super.backgroundColor), backgroundColor); + options.add(hide); options.add(topColor); options.add(scores); options.add(scoreColor); @@ -233,6 +236,16 @@ public ResourceLocation getId() { @Override public AnchorPoint getAnchor() { - return (anchor.get()); + return anchor.get(); + } + + @Override + public double getDefaultX() { + return 1.0; + } + + @Override + public double getDefaultY() { + return 0.5; } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java similarity index 95% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java index ecff264ca..055acbbc0 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/AddSpecialKeystrokeScreen.java @@ -35,7 +35,7 @@ public class AddSpecialKeystrokeScreen extends Screen { private final Screen lastScreen; public final KeystrokeHud hud; private SpecialKeystrokeSelectionList keyBindsList; - public HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); + public final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); public AddSpecialKeystrokeScreen(Screen lastScreen, KeystrokeHud hud) { super(TITLE); @@ -62,6 +62,7 @@ protected void repositionElements() { @Override public void onClose() { + //noinspection DataFlowIssue minecraft.setScreen(lastScreen); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java index a8d934a60..51874480e 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/ConfigureKeyBindScreen.java @@ -32,6 +32,7 @@ import net.minecraft.client.gui.components.*; import net.minecraft.client.gui.layouts.FrameLayout; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; +import net.minecraft.client.gui.layouts.LayoutSettings; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.screens.Screen; @@ -90,7 +91,7 @@ protected void updateWidgetNarration(NarrationElementOutput narrationElementOutp } }).active = false; body.addChild(labelFrame); - currentKey = body.addChild(new StringWidget(Component.empty(), font)); + currentKey = body.addChild(new StringWidget(Component.empty(), font), LayoutSettings::alignHorizontallyCenter); var optionsFrame = new FrameLayout(); optionsFrame.setMinWidth(super.width); @@ -163,7 +164,6 @@ protected void updateWidgetNarration(NarrationElementOutput narrationElementOutp @Override protected void repositionElements() { - layout.arrangeElements(); if (isAddScreen && stroke.getKey() != null) { addButton.active = true; } @@ -176,6 +176,7 @@ protected void repositionElements() { if (synchronizeButton != null) { synchronizeButton.active = stroke.getKey() != null; } + layout.arrangeElements(); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionList.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionList.java similarity index 87% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionList.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionList.java index b0abd5f5f..431fea4ac 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionList.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionList.java @@ -58,13 +58,13 @@ public KeyBindSelectionList(KeyBindSelectionScreen keyBindsScreen, Minecraft min this.selectionConsumer = selectionConsumer; KeyMapping[] keyMappings = ArrayUtils.clone(minecraft.options.keyMappings); Arrays.sort(keyMappings); - String string = null; + KeyMapping.Category string = null; for (KeyMapping keyMapping : keyMappings) { - String string2 = keyMapping.getCategory(); + var string2 = keyMapping.getCategory(); if (!string2.equals(string)) { string = string2; - this.addEntry(new KeyBindSelectionList.CategoryEntry(Component.translatable(string2))); + this.addEntry(new KeyBindSelectionList.CategoryEntry(string2.label())); } Component component = Component.translatable(keyMapping.getName()); @@ -88,8 +88,8 @@ public CategoryEntry(final Component name) { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - guiGraphics.drawString(KeyBindSelectionList.this.minecraft.font, this.name, KeyBindSelectionList.this.width / 2 - this.width / 2, top + height - 9 - 1, -1); + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + guiGraphics.drawString(KeyBindSelectionList.this.minecraft.font, this.name, KeyBindSelectionList.this.width / 2 - this.width / 2, getContentY() + getContentHeight() - 9 - 1, -1); } @Nullable @@ -142,14 +142,14 @@ public class KeyEntry extends KeyBindSelectionList.Entry { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { int i = KeyBindSelectionList.this.scrollBarX() - 10; - int j = top - 2; + int j = getContentY() - 2; int k = i - 5 - this.changeButton.getWidth(); this.changeButton.setPosition(k, j); this.changeButton.render(guiGraphics, mouseX, mouseY, partialTick); - guiGraphics.drawString(minecraft.font, this.name, left, top + height / 2 - 9 / 2, -1); - guiGraphics.drawString(minecraft.font, boundKey, left + width / 2 - minecraft.font.width(boundKey) / 2, top + height / 2 - 9 / 2, Colors.GRAY.toInt()); + guiGraphics.drawString(minecraft.font, this.name, getContentX(), getContentY() + getContentHeight() / 2 - 9 / 2, -1); + guiGraphics.drawString(minecraft.font, boundKey, getContentX() + getContentWidth() / 2 - minecraft.font.width(boundKey) / 2, getContentY() + getContentHeight() / 2 - 9 / 2, Colors.GRAY.toInt()); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java index 428ee133d..7ca90e3ea 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindSelectionScreen.java @@ -35,7 +35,7 @@ public class KeyBindSelectionScreen extends Screen { private final Screen lastScreen; public final KeystrokeHud.Keystroke stroke; private KeyBindSelectionList keyBindsList; - public HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); + public final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); public KeyBindSelectionScreen(Screen lastScreen, KeystrokeHud.Keystroke stroke) { super(TITLE); @@ -46,9 +46,7 @@ public KeyBindSelectionScreen(Screen lastScreen, KeystrokeHud.Keystroke stroke) @Override public void init() { layout.addTitleHeader(getTitle(), getFont()); - this.keyBindsList = this.layout.addToContents(new KeyBindSelectionList(this, this.minecraft, key -> { - stroke.setKey(key); - })); + this.keyBindsList = this.layout.addToContents(new KeyBindSelectionList(this, this.minecraft, stroke::setKey)); LinearLayout linearLayout = this.layout.addToFooter(LinearLayout.horizontal().spacing(8)); linearLayout.addChild(Button.builder(CommonComponents.GUI_DONE, button -> this.onClose()).build()); @@ -64,6 +62,7 @@ protected void repositionElements() { @Override public void onClose() { + //noinspection DataFlowIssue minecraft.setScreen(lastScreen); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindsList.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindsList.java similarity index 87% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindsList.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindsList.java index 651c8bf06..d03980870 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindsList.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeyBindsList.java @@ -87,7 +87,7 @@ public List narratables() { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { } @@ -127,9 +127,9 @@ public class KeyEntry extends Entry { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { int i = KeyBindsList.this.scrollBarX() - removeButton.getWidth() - 10; - int j = top - 2; + int j = getContentY() - 2; this.removeButton.setPosition(i, j); this.removeButton.render(guiGraphics, mouseX, mouseY, partialTick); int k = i - this.configureButton.getWidth(); @@ -137,13 +137,13 @@ public void render(GuiGraphics guiGraphics, int index, int top, int left, int wi this.configureButton.render(guiGraphics, mouseX, mouseY, partialTick); guiGraphics.pose().pushMatrix(); var rect = key.getRenderPosition(); - float scale = Math.min((float) height / rect.height(), (float) 100 / rect.width()); - guiGraphics.pose().translate(left, top); + float scale = Math.min((float) getContentHeight() / rect.height(), (float) 100 / rect.width()); + guiGraphics.pose().translate(getContentX(), getContentY()); guiGraphics.pose().scale(scale, scale); guiGraphics.pose().translate(-rect.x(), -rect.y()); key.render(guiGraphics); guiGraphics.pose().popMatrix(); - guiGraphics.drawString(minecraft.font, name, left + width / 2 - minecraft.font.width(name) / 2, top + height / 2 - 9 / 2, Colors.GRAY.toInt()); + guiGraphics.drawString(minecraft.font, name, getContentX() + getContentWidth() / 2 - minecraft.font.width(name) / 2, getContentY() + getContentHeight() / 2 - 9 / 2, Colors.GRAY.toInt()); } @Override @@ -177,9 +177,9 @@ public List narratables() { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = KeyBindsList.this.scrollBarX() - width / 2 - 10 + 4; - int j = top - 2; + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + int i = KeyBindsList.this.scrollBarX() - getContentWidth() / 2 - 10 + 4; + int j = getContentY() - 2; this.addButton.setPosition(i, j); this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); int k = i - addButton.getWidth() - 8; diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokePositioningScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokePositioningScreen.java similarity index 91% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokePositioningScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokePositioningScreen.java index fc3a6b5b0..0e6e01679 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokePositioningScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokePositioningScreen.java @@ -39,6 +39,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; @@ -118,9 +119,11 @@ private void drawStroke(GuiGraphics guiGraphics, int mouseX, int mouseY, Keystro } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - var value = super.mouseClicked(mouseX, mouseY, button); - if (button == 0) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + var value = super.mouseClicked(event, doubleClick); + if (event.button() == 0) { + var mouseX = event.x(); + var mouseY = event.y(); Optional entry = Optional.empty(); Optional pos = Optional.empty(); if (editing == null) { @@ -159,21 +162,21 @@ public void onClose() { } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { + public boolean mouseReleased(MouseButtonEvent event) { if (focused != null) { hud.saveKeystrokes(); } snap = null; mouseDown = false; focused = null; - return super.mouseReleased(mouseX, mouseY, button); + return super.mouseReleased(event); } @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) { if (focused != null && mouseDown) { - focused.setX((int) Math.round((mouseX - offset.x()) / hud.getScale())); - focused.setY((int) Math.round((mouseY - offset.y()) / hud.getScale())); + focused.setX((int) Math.round((event.x() - offset.x()) / hud.getScale())); + focused.setY((int) Math.round((event.y() - offset.y()) / hud.getScale())); if (snap != null) { Integer snapX, snapY; var rect = getScaledRenderPos(focused); diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokesScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokesScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokesScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/KeystrokesScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/SpecialKeystrokeSelectionList.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/SpecialKeystrokeSelectionList.java similarity index 91% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/SpecialKeystrokeSelectionList.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/SpecialKeystrokeSelectionList.java index bb8708c1c..3da177eef 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/SpecialKeystrokeSelectionList.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/gui/keystrokes/SpecialKeystrokeSelectionList.java @@ -80,21 +80,21 @@ public class KeyEntry extends Entry { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { int i = SpecialKeystrokeSelectionList.this.scrollBarX() - 10; - int j = top - 2; + int j = getContentY() - 2; int k = i - 5 - this.addButton.getWidth(); this.addButton.setPosition(k, j); this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); guiGraphics.pose().pushMatrix(); var rect = keystroke.getRenderPosition(); float scale = Math.min((float) height / rect.height(), (float) 100 / rect.width()); - guiGraphics.pose().translate(left, top); + guiGraphics.pose().translate(getContentX(), getContentY()); guiGraphics.pose().scale(scale, scale); guiGraphics.pose().translate(-rect.x(), -rect.y()); keystroke.render(guiGraphics); guiGraphics.pose().popMatrix(); - guiGraphics.drawString(minecraft.font, boundKey, left + 110 + (k - left - 110) / 3, top + height / 2 - 9 / 2, Colors.GRAY.toInt()); + guiGraphics.drawString(minecraft.font, boundKey, getContentX() + 110 + (k - getContentX() - 110) / 3, getContentY() + height / 2 - 9 / 2, Colors.GRAY.toInt()); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java similarity index 99% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java index 06f1e413f..3332b555b 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/snapping/SnappingHelper.java @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class SnappingHelper { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java similarity index 88% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java index fb3a8e7da..3d8e3dcd3 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/DrawUtil.java @@ -31,7 +31,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class DrawUtil { @@ -49,7 +49,10 @@ public static void outlineRect(GuiGraphics graphics, Rectangle rectangle, Color } public static void outlineRect(GuiGraphics graphics, int x, int y, int width, int height, int color) { - graphics.renderOutline(x, y, width, height, color); + graphics.fill(x, y, x + width, y + 1, color); + graphics.fill(x, y + height - 1, x + width, y + height, color); + graphics.fill(x, y + 1, x + 1, y + height - 1, color); + graphics.fill(x + width - 1, y + 1, x + width, y + height - 1, color); } public static void drawCenteredString(GuiGraphics graphics, Font renderer, String text, int x, int y, Color color, boolean shadow) { @@ -59,7 +62,7 @@ public static void drawCenteredString(GuiGraphics graphics, Font renderer, Strin public static void drawCenteredString(GuiGraphics graphics, Font renderer, String text, int x, int y, int color, boolean shadow) { if (shadow) { graphics.drawCenteredString(renderer, text, x, y, color); - } else drawString(graphics, text, (x - renderer.width(text) / 2), y, color, shadow); + } else graphics.drawString(renderer, text, (x - renderer.width(text) / 2), y, color); } public static int drawString(GuiGraphics graphics, String text, int x, int y, int color, boolean shadow) { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderState.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderState.java similarity index 78% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderState.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderState.java index 2038087f9..3257cb423 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderState.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderState.java @@ -22,6 +22,7 @@ package io.github.axolotlclient.modules.hud.util; +import io.github.axolotlclient.util.IdentifiablePiPRenderState; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState; import net.minecraft.client.renderer.entity.state.EntityRenderState; @@ -39,7 +40,8 @@ public record PlayerHudEntityRenderState(EntityRenderState renderState, int y1, float scale, @Nullable ScreenRectangle scissorArea, - @Nullable ScreenRectangle bounds) implements PictureInPictureRenderState { + @Nullable ScreenRectangle bounds, + PlayerHudEntityRenderer renderer) implements PictureInPictureRenderState, IdentifiablePiPRenderState { public PlayerHudEntityRenderState( EntityRenderState entityRenderState, @@ -51,11 +53,10 @@ public PlayerHudEntityRenderState( int k, int l, float f, - @Nullable ScreenRectangle screenRectangle + @Nullable ScreenRectangle screenRectangle, + PlayerHudEntityRenderer renderer ) { - this( - entityRenderState, vector3f, quaternionf, quaternionf2, i, j, k, l, f, screenRectangle, PictureInPictureRenderState.getBounds(i, j, k, l, screenRectangle) - ); + this(entityRenderState, vector3f, quaternionf, quaternionf2, i, j, k, l, f, screenRectangle, PictureInPictureRenderState.getBounds(i, j, k, l, screenRectangle), renderer); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderer.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderer.java similarity index 79% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderer.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderer.java index c7e66e0de..124f350a1 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderer.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hud/util/PlayerHudEntityRenderer.java @@ -28,6 +28,8 @@ import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.minecraft.client.renderer.state.CameraRenderState; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -55,13 +57,14 @@ protected void renderToTexture(PlayerHudEntityRenderState guiEntityRenderState, poseStack.translate(vector3f.x, vector3f.y, vector3f.z); poseStack.mulPose(guiEntityRenderState.rotation()); Quaternionf quaternionf = guiEntityRenderState.overrideCameraAngle(); + FeatureRenderDispatcher featureRenderDispatcher = Minecraft.getInstance().gameRenderer.getFeatureRenderDispatcher(); + CameraRenderState cameraRenderState = new CameraRenderState(); if (quaternionf != null) { - this.entityRenderDispatcher.overrideCameraOrientation(quaternionf.conjugate(new Quaternionf()).rotateY((float) Math.PI)); + cameraRenderState.orientation = quaternionf.conjugate(new Quaternionf()).rotateY((float) Math.PI); } - this.entityRenderDispatcher.setRenderShadow(false); - this.entityRenderDispatcher.render(guiEntityRenderState.renderState(), 0.0, 0.0, 0.0, poseStack, this.bufferSource, 15728880); - this.entityRenderDispatcher.setRenderShadow(true); + this.entityRenderDispatcher.submit(guiEntityRenderState.renderState(), cameraRenderState, 0.0, 0.0, 0.0, poseStack, featureRenderDispatcher.getSubmitNodeStorage()); + featureRenderDispatcher.renderAllFeatures(); } @Override diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FilterListConfigurationScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FilterListConfigurationScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FilterListConfigurationScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FilterListConfigurationScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FiltersList.java b/1.latest/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FiltersList.java similarity index 82% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FiltersList.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FiltersList.java index e52e946f0..9c2e922d8 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FiltersList.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/hypixel/autoboop/FiltersList.java @@ -36,11 +36,14 @@ import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class FiltersList extends ContainerObjectSelectionList { + private final SpacerEntry spacer = new SpacerEntry(); + private final NewEntry newEntry = new NewEntry(); final FilterListConfigurationScreen screen; public FiltersList(FilterListConfigurationScreen screen) { @@ -56,8 +59,8 @@ public void reload() { this.addEntry(new FilterEntry(entry)); } - addEntry(new SpacerEntry()); - addEntry(new NewEntry()); + addEntry(spacer); + addEntry(newEntry); } @Override @@ -74,10 +77,10 @@ public void apply() { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { children().stream().filter(e -> e instanceof FilterEntry) .map(e -> (FilterEntry) e).map(e -> e.editBox).forEach(e -> e.setFocused(false)); - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } @Environment(EnvType.CLIENT) @@ -93,7 +96,7 @@ public List narratables() { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { } @@ -128,14 +131,14 @@ public class FilterEntry extends Entry { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { int i = scrollBarX() - removeButton.getWidth() - 10; - int j = top - 2; + int j = getContentY() - 2; this.removeButton.setPosition(i, j); this.removeButton.render(guiGraphics, mouseX, mouseY, partialTick); - this.editBox.setPosition(left, j); - this.editBox.setWidth(i - left - 4); + this.editBox.setPosition(getContentX(), j); + this.editBox.setWidth(i - getContentX() - 4); this.editBox.render(guiGraphics, mouseX, mouseY, partialTick); } @@ -156,8 +159,11 @@ public class NewEntry extends Entry { public NewEntry() { this.addButton = Button.builder(Component.translatable("autoboop.filters.add"), button -> { - int i = FiltersList.this.children().indexOf(this); - FiltersList.this.children().add(Math.max(i - 1, 0), new FilterEntry("")); + removeEntry(spacer); + removeEntry(newEntry); + addEntry(new FilterEntry("")); + addEntry(spacer); + addEntry(newEntry); apply(); setScrollAmount(maxScrollAmount()); }).bounds(0, 0, 150, 20) @@ -170,9 +176,9 @@ public List narratables() { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - int i = scrollBarX() - width / 2 - 10 - addButton.getWidth() / 2; - int j = top - 2; + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + int i = scrollBarX() - getContentWidth() / 2 - 10 - addButton.getWidth() / 2; + int j = getContentY() - 2; this.addButton.setPosition(i, j); this.addButton.render(guiGraphics, mouseX, mouseY, partialTick); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandLocation.java b/1.latest/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandLocation.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandLocation.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandLocation.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandMods.java b/1.latest/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandMods.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandMods.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/mcci/MccIslandMods.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/mcci/NoxesiumIntegration.java b/1.latest/src/main/java/io/github/axolotlclient/modules/mcci/NoxesiumIntegration.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/mcci/NoxesiumIntegration.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/mcci/NoxesiumIntegration.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/particles/Particles.java b/1.latest/src/main/java/io/github/axolotlclient/modules/particles/Particles.java similarity index 85% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/particles/Particles.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/particles/Particles.java index faee83c84..10f9be839 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/particles/Particles.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/particles/Particles.java @@ -32,10 +32,11 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.AxolotlClientConfig.impl.options.ColorOption; import io.github.axolotlclient.AxolotlClientConfig.impl.options.IntegerOption; -import io.github.axolotlclient.mixin.ParticleAccessor; +import io.github.axolotlclient.mixin.SingleQuadParticleAccessor; import io.github.axolotlclient.modules.AbstractModule; import io.github.axolotlclient.util.ClientColors; -import net.minecraft.client.particle.Particle; +import lombok.Getter; +import net.minecraft.client.particle.SingleQuadParticle; import net.minecraft.core.particles.ParticleType; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.BuiltInRegistries; @@ -43,18 +44,14 @@ public class Particles extends AbstractModule { + @Getter private static final Particles Instance = new Particles(); public final HashMap, HashMap>> particleOptions = new HashMap<>(); - public final WeakHashMap> particleMap = new WeakHashMap<>(); private final OptionCategory cat = OptionCategory.create("particles"); private final BooleanOption enabled = new BooleanOption("enabled", false); - public static Particles getInstance() { - return Instance; - } - @Override public void init() { cat.add(enabled); @@ -66,6 +63,7 @@ public void init() { private void addParticleOptions() { for (ParticleType type : BuiltInRegistries.PARTICLE_TYPE.stream().sorted(new AlphabeticalComparator()).toList()) { if (BuiltInRegistries.PARTICLE_TYPE.getKey(type) != null) { + //noinspection DataFlowIssue OptionCategory category = OptionCategory.create( Arrays.stream(BuiltInRegistries.PARTICLE_TYPE.getKey(type).getPath().split("_")) .map(StringUtils::capitalize).collect(Collectors.joining(" "))); @@ -94,16 +92,13 @@ private void populateMap(HashMap> map, Option... options) { } } - public void applyOptions(Particle particle) { - if (enabled.get() && particleMap.containsKey(particle)) { - ParticleType type = particleMap.get(particle); - if (particleOptions.containsKey(type)) { - HashMap> options = particleOptions.get(type); - if (((BooleanOption) options.get("customColor")).get()) { - Color color = ((ColorOption) options.get("color")).get(); - particle.setColor(color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F); - ((ParticleAccessor) particle).axolotlclient$setColorAlpha(color.getAlpha() / 255F); - } + public void applyOptions(SingleQuadParticle particle, ParticleType type) { + if (enabled.get()) { + HashMap> options = particleOptions.get(type); + if (((BooleanOption) options.get("customColor")).get()) { + Color color = ((ColorOption) options.get("color")).get(); + particle.setColor(color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F); + ((SingleQuadParticleAccessor) particle).axolotlclient$setColorAlpha(color.getAlpha() / 255F); } } } @@ -145,6 +140,7 @@ public int compare(ParticleType s1, ParticleType s2) { private String getName(ParticleType type) { if (BuiltInRegistries.PARTICLE_TYPE.getKey(type) != null) { + //noinspection DataFlowIssue return BuiltInRegistries.PARTICLE_TYPE.getKey(type).getPath(); } return ""; diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/renderOptions/BeaconBeam.java b/1.latest/src/main/java/io/github/axolotlclient/modules/renderOptions/BeaconBeam.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/renderOptions/BeaconBeam.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/renderOptions/BeaconBeam.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/rpc/DiscordRPC.java b/1.latest/src/main/java/io/github/axolotlclient/modules/rpc/DiscordRPC.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/rpc/DiscordRPC.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/rpc/DiscordRPC.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java similarity index 98% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java index 8f4e3eb3c..e7a477e82 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/DownloadImageScreen.java @@ -56,7 +56,7 @@ protected void init() { var hFL = new ImprovedHeaderAndFooterLayout(this); hFL.addTitleHeader(getTitle(), font); - var urlBox = new EditBox(font, width / 2 - 100, height / 2 - 10, 200, 20, Component.translatable("urlBox")); + var urlBox = new EditBox(font, width / 2 - 100, height / 2 - 10, 200, 20, Component.translatable("pasteURL")); urlBox.setSuggestion(I18n.get("pasteURL")); urlBox.setResponder(s -> { if (s.isEmpty()) { @@ -74,6 +74,7 @@ protected void init() { if (url.isEmpty()) { return; } + //noinspection DataFlowIssue minecraft.setScreen(ImageScreen.create(this, ImageShare.getInstance().downloadImage(url), true)); }, true) .sprite(SPRITE, 20, 20) @@ -88,6 +89,7 @@ protected void init() { @Override public void onClose() { + //noinspection DataFlowIssue minecraft.setScreen(parent); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/GalleryScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/GalleryScreen.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/GalleryScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/GalleryScreen.java index 716418b32..6d06f57d3 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/GalleryScreen.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/GalleryScreen.java @@ -51,6 +51,7 @@ import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.InputWithModifiers; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; @@ -149,7 +150,7 @@ protected void init() { loadTab(current, columnCount, area); } catch (Exception e) { LinearLayout error = LinearLayout.vertical().spacing(8); - error.defaultCellSetting().alignVerticallyMiddle(); + error.defaultCellSetting().alignVerticallyMiddle().alignVerticallyMiddle(); error.addChild(new StringWidget(Component.translatable("gallery.error.loading"), font)); setInitialFocus(error.addChild(Button.builder(Component.translatable("gallery.reload"), b -> rebuildWidgets()).build())); layout.addToContents(error); @@ -255,7 +256,7 @@ private CompletableFuture load() { } @Override - public void onPress() { + public void onPress(InputWithModifiers inputWithModifiers) { minecraft.setScreen(ImageScreen.create(GalleryScreen.this, load(), false)); } @@ -273,7 +274,7 @@ protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, flo guiGraphics.fill(getX() + 2, getBottom() - font.lineHeight - 1, getRight() - 2, getBottom() - 2, bgColor); drawHorizontalGradient(guiGraphics, getX() + 2, getBottom() - font.lineHeight - 1, getBottom() - 2, lerp(delta, getX() + 2, getRight() - 2)); } - guiGraphics.renderOutline(getX(), getY(), getWidth(), getHeight(), isHoveredOrFocused() ? -1 : bgColor); + guiGraphics.br$outlineRect(getX(), getY(), getWidth(), getHeight(), isHoveredOrFocused() ? -1 : bgColor); } private void drawHorizontalGradient(GuiGraphics guiGraphics, int x1, int y1, int y2, int x2) { @@ -306,7 +307,6 @@ private static class ImageListEntry extends ContainerObjectSelectionList.Entry buttons; private final int size; private final ImageList list; - private final List removalQueue = new ArrayList<>(1); public ImageListEntry(int size, ImageList list) { this.size = size; @@ -320,17 +320,15 @@ public ImageListEntry(int size, ImageList list) { } @Override - public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { - if (Math.max(left, list.getX()) <= Math.min(left + width, list.getX() + list.getWidth()) - 1 && - Math.max(top - height, list.getY()) <= Math.min(top + height * 2, list.getY() + list.getHeight()) - 1) { + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { + if (Math.max(getContentX(), list.getX()) <= Math.min(getContentX() + getContentWidth(), list.getX() + list.getWidth()) - 1 && + Math.max(getContentY() - getContentHeight(), list.getY()) <= Math.min(getContentY() + getContentHeight() * 2, list.getY() + list.getHeight()) - 1) { buttons.forEach(e -> { - e.setY(top); + e.setY(getContentY()); e.render(guiGraphics, mouseX, mouseY, partialTick); }); } else { - buttons.forEach(e -> { - e.setY(top); - }); + buttons.forEach(e -> e.setY(getContentY())); } } @@ -400,8 +398,8 @@ public int getRowLeft() { } @Override - public boolean removeEntry(ImageListEntry entry) { - return super.removeEntry(entry); + public void removeEntry(ImageListEntry entry) { + super.removeEntry(entry); } public void shiftEntries(ImageListEntry origin) { @@ -410,7 +408,7 @@ public void shiftEntries(ImageListEntry origin) { if (originIndex == lastIndex) { return; } - ImageListEntry next = getEntry(originIndex + 1); + ImageListEntry next = children().get(originIndex + 1); origin.add(next.pop()); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageInstance.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageInstance.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageInstance.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageInstance.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageShare.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageShare.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageShare.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ImageShare.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/LoadingImageScreen.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java b/1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotUtils.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java b/1.latest/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java index 53af45a10..48b5464a4 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/scrollableTooltips/ScrollableTooltips.java @@ -30,7 +30,6 @@ import io.github.axolotlclient.modules.AbstractModule; import lombok.Getter; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; import net.minecraft.core.registries.BuiltInRegistries; @@ -68,10 +67,10 @@ public boolean onScroll(boolean reverse) { return false; } Slot hovered = ((AbstractContainerScreenAccessor) screen).getHoveredSlot(); - if (hovered == null || hovered.hasItem() && hovered.getItem().is(Items.BUNDLE) && !Screen.hasControlDown()) { + if (hovered == null || hovered.hasItem() && hovered.getItem().is(Items.BUNDLE) && !Minecraft.getInstance().hasControlDown()) { return false; } - if (Screen.hasShiftDown()) { + if (Minecraft.getInstance().hasShiftDown()) { if (applyInverse(reverse)) { tooltipOffsetX -= scrollAmount.get(); } else { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/tablist/Tablist.java b/1.latest/src/main/java/io/github/axolotlclient/modules/tablist/Tablist.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/tablist/Tablist.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/tablist/Tablist.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java b/1.latest/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/tnttime/TntTime.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java b/1.latest/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java similarity index 97% rename from 1.21.7/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java rename to 1.latest/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java index 7929cad4f..5f9d81c25 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java +++ b/1.latest/src/main/java/io/github/axolotlclient/modules/zoom/Zoom.java @@ -41,7 +41,7 @@ public class Zoom extends AbstractModule { - public static final KeyMapping key = new KeyMapping("key.zoom", InputConstants.KEY_C, "category.axolotlclient"); + public static final KeyMapping key = new KeyMapping("key.zoom", InputConstants.KEY_C, KeyBinds.CATEGORY_AXOLOTLCLIENT); public static final FloatOption zoomDivisor = new FloatOption("zoomDivisor", 4F, 1F, 16F); public static final FloatOption zoomSpeed = new FloatOption("zoomSpeed", 7.5F, 1F, 10F); public static final BooleanOption zoomScrolling = new BooleanOption("zoomScrolling", false); @@ -154,11 +154,11 @@ public void init() { active = false; KeyBinds.getInstance().registerWithSimpleAction( - new KeyMapping("key.zoom.increase", InputConstants.UNKNOWN.getValue(), "category.axolotlclient"), + new KeyMapping("key.zoom.increase", InputConstants.UNKNOWN.getValue(), KeyBinds.CATEGORY_AXOLOTLCLIENT), () -> scroll(zoomSpeed.get() / 2) ); KeyBinds.getInstance().registerWithSimpleAction( - new KeyMapping("key.zoom.decrease", InputConstants.UNKNOWN.getValue(), "category.axolotlclient"), + new KeyMapping("key.zoom.decrease", InputConstants.UNKNOWN.getValue(), KeyBinds.CATEGORY_AXOLOTLCLIENT), () -> scroll(-zoomSpeed.get() / 2) ); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/FeatureDisabler.java b/1.latest/src/main/java/io/github/axolotlclient/util/FeatureDisabler.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/FeatureDisabler.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/FeatureDisabler.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/HorizontalGradientRectangleRenderState.java b/1.latest/src/main/java/io/github/axolotlclient/util/HorizontalGradientRectangleRenderState.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/HorizontalGradientRectangleRenderState.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/HorizontalGradientRectangleRenderState.java index f10f151d0..876aebff4 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/HorizontalGradientRectangleRenderState.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/HorizontalGradientRectangleRenderState.java @@ -58,11 +58,11 @@ public void submit() { } @Override - public void buildVertices(VertexConsumer vertexConsumer, float f) { - vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y0(), f).setColor(this.col1()); - vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y1(), f).setColor(this.col1()); - vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y1(), f).setColor(this.col2()); - vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y0(), f).setColor(this.col2()); + public void buildVertices(VertexConsumer vertexConsumer) { + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y0()).setColor(this.col1()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x0(), this.y1()).setColor(this.col1()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y1()).setColor(this.col2()); + vertexConsumer.addVertexWith2DPose(this.pose(), this.x1(), this.y0()).setColor(this.col2()); } @Nullable diff --git a/1.20/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java b/1.latest/src/main/java/io/github/axolotlclient/util/IdentifiablePiPRenderState.java similarity index 75% rename from 1.20/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/IdentifiablePiPRenderState.java index 8396e1ccb..574e776b6 100644 --- a/1.20/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/IdentifiablePiPRenderState.java @@ -1,5 +1,5 @@ /* - * Copyright © 2023 moehreag & Contributors + * Copyright © 2025 moehreag & Contributors * * This file is part of AxolotlClient. * @@ -20,13 +20,10 @@ * For more information, see the LICENSE file. */ -package io.github.axolotlclient.util.events.impl; +package io.github.axolotlclient.util; -import lombok.Data; - -@Data -public class PlayerDirectionChangeEvent { - - private final float prevPitch, prevYaw, pitch, yaw; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; +public interface IdentifiablePiPRenderState> { + T renderer(); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/LoggerImpl.java b/1.latest/src/main/java/io/github/axolotlclient/util/LoggerImpl.java similarity index 88% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/LoggerImpl.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/LoggerImpl.java index 5eb4b1aaa..2aec0a520 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/LoggerImpl.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/LoggerImpl.java @@ -33,19 +33,23 @@ public class LoggerImpl implements Logger { private static final String prefix = FabricLoader.getInstance().isDevelopmentEnvironment() ? "" : "(AxolotlClient) "; public void info(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + msg, args); } public void warn(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.warn(prefix + msg, args); } public void error(String msg, Object... args) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.error(prefix + msg, args); } public void debug(String msg, Object... args) { if (AxolotlClient.config().debugLogOutput.get()) { + //noinspection StringConcatenationArgumentToLogCall LOGGER.info(prefix + "[DEBUG] " + msg, args); } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/Util.java b/1.latest/src/main/java/io/github/axolotlclient/util/Util.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/Util.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/Util.java diff --git a/1.latest/src/main/java/io/github/axolotlclient/util/duck/NameTagFeatureRendererStorageExtension.java b/1.latest/src/main/java/io/github/axolotlclient/util/duck/NameTagFeatureRendererStorageExtension.java new file mode 100644 index 000000000..1aff909cc --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/util/duck/NameTagFeatureRendererStorageExtension.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.util.duck; + +public interface NameTagFeatureRendererStorageExtension { + default void axolotlclient$lastNameTagSubmitHasBadge() { + + } + + default void axolotlclient$lastNameTagSubmitIsLevelHead() { + + } +} diff --git a/1.latest/src/main/java/io/github/axolotlclient/util/duck/NameTagSubmitExtension.java b/1.latest/src/main/java/io/github/axolotlclient/util/duck/NameTagSubmitExtension.java new file mode 100644 index 000000000..bfd21c798 --- /dev/null +++ b/1.latest/src/main/java/io/github/axolotlclient/util/duck/NameTagSubmitExtension.java @@ -0,0 +1,40 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.util.duck; + +public interface NameTagSubmitExtension { + default void axolotlclient$hasBadge(boolean b) { + + } + + default boolean axolotlclient$hasBadge() { + return false; + } + + default void axolotlclient$isForLevelHead(boolean b) { + } + + default boolean axolotlclient$isForLevelHead() { + return false; + } +} diff --git a/1.21/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java b/1.latest/src/main/java/io/github/axolotlclient/util/duck/SubmitNodeCollectorExtension.java similarity index 75% rename from 1.21/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/duck/SubmitNodeCollectorExtension.java index 5b8aff747..148401106 100644 --- a/1.21/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/duck/SubmitNodeCollectorExtension.java @@ -1,5 +1,5 @@ /* - * Copyright © 2024 moehreag & Contributors + * Copyright © 2025 moehreag & Contributors * * This file is part of AxolotlClient. * @@ -20,13 +20,14 @@ * For more information, see the LICENSE file. */ -package io.github.axolotlclient.util.events.impl; +package io.github.axolotlclient.util.duck; -import lombok.Data; +public interface SubmitNodeCollectorExtension { + default void axolotlclient$lastNameTagSubmitHasBadge() { -@Data -public class PlayerDirectionChangeEvent { + } - private final float prevPitch, prevYaw, pitch, yaw; + default void axolotlclient$lastNameTagSubmitIsLevelHead() { + } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/events/Events.java b/1.latest/src/main/java/io/github/axolotlclient/util/events/Events.java similarity index 83% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/events/Events.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/events/Events.java index f1a739d26..98cac1e73 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/events/Events.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/events/Events.java @@ -25,17 +25,13 @@ import java.util.Arrays; import io.github.axolotlclient.util.events.impl.KeyBindChangeEvent; -import io.github.axolotlclient.util.events.impl.MouseInputEvent; -import io.github.axolotlclient.util.events.impl.PlayerDirectionChangeEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.Minecraft; public class Events { - public static final Event> MOUSE_INPUT = createEvent(); public static final Event> KEYBIND_CHANGE = createEvent(); - public static final Event> PLAYER_DIRECTION_CHANGE = createEvent(); public static final Event> GAME_LOAD_EVENT = createEvent(); private static Event> createEvent() { diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java b/1.latest/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/events/impl/KeyBindChangeEvent.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/keybinds/KeyBinds.java b/1.latest/src/main/java/io/github/axolotlclient/util/keybinds/KeyBinds.java similarity index 85% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/keybinds/KeyBinds.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/keybinds/KeyBinds.java index 06dbb149a..d7cbe605d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/keybinds/KeyBinds.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/keybinds/KeyBinds.java @@ -26,12 +26,14 @@ import java.util.List; import com.google.common.collect.Lists; -import io.github.axolotlclient.mixin.KeyBindAccessor; +import io.github.axolotlclient.AxolotlClientCommon; import lombok.Getter; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.client.KeyMapping; +import net.minecraft.resources.ResourceLocation; public class KeyBinds { + public static final KeyMapping.Category CATEGORY_AXOLOTLCLIENT = KeyMapping.Category.register(ResourceLocation.fromNamespaceAndPath(AxolotlClientCommon.MODID, "title")); @Getter private final static KeyBinds instance = new KeyBinds(); @@ -40,11 +42,6 @@ public class KeyBinds { public KeyMapping register(KeyMapping bind) { binds.add(bind); - if (!KeyBindAccessor.getOrderByCategories().containsKey(bind.getCategory())) { - int index = KeyBindAccessor.getOrderByCategories().values().stream().max(Integer::compareTo).get() + 1; - KeyBindAccessor.getOrderByCategories().put(bind.getCategory(), index); - } - return bind; } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/notifications/AxolotlClientToast.java b/1.latest/src/main/java/io/github/axolotlclient/util/notifications/AxolotlClientToast.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/notifications/AxolotlClientToast.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/notifications/AxolotlClientToast.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/notifications/Notifications.java b/1.latest/src/main/java/io/github/axolotlclient/util/notifications/Notifications.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/notifications/Notifications.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/notifications/Notifications.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/AxoGraphicsWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/AxoGraphicsWidget.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/AxoGraphicsWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/AxoGraphicsWidget.java index 5c5367685..994424a8e 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/AxoGraphicsWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/AxoGraphicsWidget.java @@ -32,6 +32,7 @@ import io.github.axolotlclient.util.notifications.Notifications; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.InputWithModifiers; import net.minecraft.network.chat.Component; public class AxoGraphicsWidget extends GraphicsWidget { @@ -43,7 +44,7 @@ public AxoGraphicsWidget(int x, int y, int width, int height, GraphicsOption opt } @Override - public void onPress() { + public void onPress(InputWithModifiers input) { Minecraft.getInstance().setScreen(new AxoGraphicsEditorScreen(Minecraft.getInstance().screen, this.option)); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/ForceableBooleanWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/ForceableBooleanWidget.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/ForceableBooleanWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/ForceableBooleanWidget.java index 231685cfb..16a1429bb 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/ForceableBooleanWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/ForceableBooleanWidget.java @@ -25,6 +25,7 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.ui.rounded.widgets.PillBooleanWidget; import io.github.axolotlclient.util.options.ForceableBooleanOption; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.input.InputWithModifiers; public class ForceableBooleanWidget extends PillBooleanWidget { private final ForceableBooleanOption option; @@ -50,9 +51,9 @@ protected void drawHandle(long ctx, float x, float y, float width) { } @Override - public void onPress() { + public void onPress(InputWithModifiers mods) { if (!option.isForceOff()) { - super.onPress(); + super.onPress(mods); } } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/GenericWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/GenericWidget.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/GenericWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/GenericWidget.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/QuickToggleCategoryWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/QuickToggleCategoryWidget.java similarity index 88% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/QuickToggleCategoryWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/QuickToggleCategoryWidget.java index d96788157..180111e0a 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/options/rounded/QuickToggleCategoryWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/options/rounded/QuickToggleCategoryWidget.java @@ -31,6 +31,8 @@ import io.github.axolotlclient.util.options.ForceableBooleanOption; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; public class QuickToggleCategoryWidget extends CategoryWidget { private PillBooleanWidget enabledButton; @@ -43,6 +45,8 @@ public QuickToggleCategoryWidget(int x, int y, int width, int height, OptionCate .filter(o -> "enabled".equals(o.getName())).findFirst() .ifPresent(booleanOption -> { enabledButton = new PillBooleanWidget(x + (width - 43), y + 3, 40, height - 5, booleanOption); + enabledButton.setWidth(40); + enabledButton.setX(x + width - 43); enabledButton.active = !(booleanOption instanceof ForceableBooleanOption o && o.isForceOff()); }); } @@ -79,26 +83,26 @@ protected void drawScrollingText(NVGFont font, int offset, Color color) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { if (enabledButton != null && enabledButton.isHoveredOrFocused()) { playDownSound(Minecraft.getInstance().getSoundManager()); - enabledButton.onPress(); + enabledButton.onPress(event); return true; } - return this.isHovered && super.mouseClicked(mouseX, mouseY, button); + return this.isHovered && super.mouseClicked(event, doubleClick); } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(KeyEvent event) { if (!this.active || !this.visible) { return false; - } else if (keyCode != 257 && keyCode != 32 && keyCode != 335) { + } else if (!event.isSelection()) { return false; } else { this.playDownSound(Minecraft.getInstance().getSoundManager()); - mouseClicked(0, 0, 0); + onPress(event); return true; } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java similarity index 96% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java index 78a2da2e4..14765c905 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/AxoGraphicsWidget.java @@ -32,6 +32,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.InputWithModifiers; import net.minecraft.network.chat.Component; public class AxoGraphicsWidget extends GraphicsWidget { @@ -43,7 +44,7 @@ public AxoGraphicsWidget(int x, int y, int width, int height, GraphicsOption opt } @Override - public void onPress() { + public void onPress(InputWithModifiers mods) { Minecraft.getInstance().setScreen(new AxoGraphicsEditorScreen(Minecraft.getInstance().screen, this.option)); } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/ForceableBooleanWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/ForceableBooleanWidget.java similarity index 93% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/ForceableBooleanWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/ForceableBooleanWidget.java index 0cb65603b..13a579a67 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/ForceableBooleanWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/ForceableBooleanWidget.java @@ -25,6 +25,7 @@ import io.github.axolotlclient.AxolotlClientConfig.impl.ui.vanilla.widgets.BooleanWidget; import io.github.axolotlclient.util.options.ForceableBooleanOption; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.input.InputWithModifiers; public class ForceableBooleanWidget extends BooleanWidget { private final ForceableBooleanOption option; @@ -41,9 +42,9 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float del } @Override - public void onPress() { + public void onPress(InputWithModifiers mods) { if (!option.isForceOff()) { - super.onPress(); + super.onPress(mods); } } } diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/GenericWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/GenericWidget.java similarity index 100% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/GenericWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/GenericWidget.java diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/QuickToggleCategoryWidget.java b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/QuickToggleCategoryWidget.java similarity index 90% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/QuickToggleCategoryWidget.java rename to 1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/QuickToggleCategoryWidget.java index 77fc26e89..b7ee2915d 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/options/vanilla/QuickToggleCategoryWidget.java +++ b/1.latest/src/main/java/io/github/axolotlclient/util/options/vanilla/QuickToggleCategoryWidget.java @@ -30,6 +30,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; public class QuickToggleCategoryWidget extends CategoryWidget { private BooleanWidget enabledButton; @@ -78,26 +80,26 @@ protected void renderScrollingString(GuiGraphics graphics, Font textRenderer, in } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { if (enabledButton != null && enabledButton.isHoveredOrFocused()) { playDownSound(Minecraft.getInstance().getSoundManager()); - enabledButton.onPress(); + enabledButton.onPress(event); return true; } - return this.isHovered && super.mouseClicked(mouseX, mouseY, button); + return this.isHovered && super.mouseClicked(event, doubleClick); } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(KeyEvent event) { if (!this.active || !this.visible) { return false; - } else if (keyCode != 257 && keyCode != 32 && keyCode != 335) { + } else if (!event.isSelection()) { return false; } else { this.playDownSound(Minecraft.getInstance().getSoundManager()); - mouseClicked(0, 0, 0); + onPress(event); return true; } } diff --git a/1.21.7/src/main/resources/assets/axolotlclient/icon.png b/1.latest/src/main/resources/assets/axolotlclient/icon.png similarity index 100% rename from 1.21.7/src/main/resources/assets/axolotlclient/icon.png rename to 1.latest/src/main/resources/assets/axolotlclient/icon.png diff --git a/1.21.7/src/main/resources/assets/axolotlclient/post_effect/motion_blur.json b/1.latest/src/main/resources/assets/axolotlclient/post_effect/motion_blur.json similarity index 100% rename from 1.21.7/src/main/resources/assets/axolotlclient/post_effect/motion_blur.json rename to 1.latest/src/main/resources/assets/axolotlclient/post_effect/motion_blur.json diff --git a/1.21.7/src/main/resources/assets/axolotlclient/shaders/post/motion_blur.fsh b/1.latest/src/main/resources/assets/axolotlclient/shaders/post/motion_blur.fsh similarity index 100% rename from 1.21.7/src/main/resources/assets/axolotlclient/shaders/post/motion_blur.fsh rename to 1.latest/src/main/resources/assets/axolotlclient/shaders/post/motion_blur.fsh diff --git a/1.21.7/src/main/resources/assets/axolotlclient/texts/splashes.txt b/1.latest/src/main/resources/assets/axolotlclient/texts/splashes.txt similarity index 100% rename from 1.21.7/src/main/resources/assets/axolotlclient/texts/splashes.txt rename to 1.latest/src/main/resources/assets/axolotlclient/texts/splashes.txt diff --git a/1.21.7/src/main/resources/axolotlclient-bridge.mixins.json b/1.latest/src/main/resources/axolotlclient-bridge.mixins.json similarity index 100% rename from 1.21.7/src/main/resources/axolotlclient-bridge.mixins.json rename to 1.latest/src/main/resources/axolotlclient-bridge.mixins.json diff --git a/1.21.7/src/main/resources/axolotlclient.accesswidener b/1.latest/src/main/resources/axolotlclient.accesswidener similarity index 100% rename from 1.21.7/src/main/resources/axolotlclient.accesswidener rename to 1.latest/src/main/resources/axolotlclient.accesswidener diff --git a/1.21.7/src/main/resources/axolotlclient.e4mc.mixins.json b/1.latest/src/main/resources/axolotlclient.e4mc.mixins.json similarity index 100% rename from 1.21.7/src/main/resources/axolotlclient.e4mc.mixins.json rename to 1.latest/src/main/resources/axolotlclient.e4mc.mixins.json diff --git a/1.21.7/src/main/resources/axolotlclient.mixins.json b/1.latest/src/main/resources/axolotlclient.mixins.json similarity index 87% rename from 1.21.7/src/main/resources/axolotlclient.mixins.json rename to 1.latest/src/main/resources/axolotlclient.mixins.json index 1c53a17ec..27fcd3811 100644 --- a/1.21.7/src/main/resources/axolotlclient.mixins.json +++ b/1.latest/src/main/resources/axolotlclient.mixins.json @@ -16,20 +16,18 @@ "ClientWorldMixin", "DebugHudMixin", "DownloadedPackSourceAccessor", - "DownloadingTerrainScreenMixin", "EmitterParticleMixin", "EntityMixin", - "EntityRendererMixin", "GameMenuScreenMixin", "GameOptionsMixin", "GameRendererAccessor", "GameRendererMixin", "GuiGraphicsAccessor", "GuiGraphicsMixin", + "GuiRendererMixin", "HandledScreenMixin", "InGameHudMixin", "InGameOverlayRendererMixin", - "KeyBindAccessor", "KeyBindMixin", "KeyboardInputMixin", "LightmapManagerMixin", @@ -42,9 +40,11 @@ "ModStatusMixin", "MouseMixin", "MultiPackResourceManagerMixin", + "NameTagFeatureRendererMixin", + "NameTagFeatureRendererStorageMixin", + "NameTagSubmitMixin", "OverlayTextureAccessor", "OverlayTextureMixin", - "ParticleAccessor", "ParticleManagerMixin", "PlayerEntityMixin", "PlayerEntityRendererMixin", @@ -55,15 +55,19 @@ "ScreenshotRecorderMixin", "ServerPackManagerAccessor", "ShieldSpecialRendererMixin", + "SingleQuadParticleAccessor", "SplashManagerAccessor", "SplashOverlayMixin", "SplashTextResourceSupplierMixin", + "SubmitNodeCollectionMixin", + "SubmitNodeStorageMixin", "TitleScreenMixin", "TntEntityRendererMixin", "WeatherEffectRendererMixin", "WorldListWidgetEntryMixin", "WorldRendererMixin", "api.JoinMulitplayerScreenMixin", + "skins.SkinTextureDownloaderAccessor", "translation.TranslationStorageMixin" ], "injectors": { diff --git a/1.21.7/src/main/resources/fabric.mod.json b/1.latest/src/main/resources/fabric.mod.json similarity index 100% rename from 1.21.7/src/main/resources/fabric.mod.json rename to 1.latest/src/main/resources/fabric.mod.json diff --git a/1.21.7/src/test/java/io/github/axolotlclient/AxolotlClientTest.java b/1.latest/src/test/java/io/github/axolotlclient/AxolotlClientTest.java similarity index 100% rename from 1.21.7/src/test/java/io/github/axolotlclient/AxolotlClientTest.java rename to 1.latest/src/test/java/io/github/axolotlclient/AxolotlClientTest.java diff --git a/1.21.7/src/test/resources/fabric.mod.json b/1.latest/src/test/resources/fabric.mod.json similarity index 100% rename from 1.21.7/src/test/resources/fabric.mod.json rename to 1.latest/src/test/resources/fabric.mod.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 665a039fc..b767757a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ## Changelog: +### 3.1.6 + +- Implement more options for the Inventory HUD (#173) +- Add Skin Manager (#176) +- Add profile importing & exporting +- Update to 1.21.9/10 +- Fix some more bugs +- Preserve the current screen on config style change (#179) + ### 3.1.5 - fix a few bugs (#154, #155, #168, #175) diff --git a/build.gradle.kts b/build.gradle.kts index cffdfa764..20fa88376 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,6 +54,11 @@ allprojects { } mavenLocal() mavenCentral() + maven("https://central.sonatype.com/repository/maven-snapshots") + } + + tasks.withType().configureEach { + failOnNoDiscoveredTests = false } } @@ -61,7 +66,7 @@ subprojects { apply(plugin = "java") apply(plugin = "maven-publish") apply(plugin = "io.freefair.lombok") - apply(plugin = "com.modrinth.minotaur") + if (project.name != "common") apply(plugin = "com.modrinth.minotaur") apply(plugin = "dev.yumi.gradle.licenser") extensions.getByType(JavaPluginExtension::class).withSourcesJar() @@ -91,7 +96,7 @@ subprojects { return@forEach } val oldName = old.fileName.toString() - val oldVer = oldName.substring(0, oldName.indexOf("+")) + val oldVer = oldName.substringBefore("+") val mcVer = oldName.substring(oldName.indexOf("+") + 1, oldName.length - 4).removeSuffix("-sources") if (!project.version.toString().contains(mcVer)) { return@forEach @@ -131,7 +136,7 @@ tasks.register("generateVersionChangelog") { val out = project.layout.buildDirectory.file("changelog").get().asFile.toPath() if (matcher != null) { - var changelogContent = matcher.groups[1]?.value + var changelogContent = matcher.groups[1]?.value!! val changelogLines = changelogText.split("\n") val linkRefRegex = "^\\[([A-z0-9 _\\-/+.]+)]: ".toRegex() @@ -141,7 +146,7 @@ tasks.register("generateVersionChangelog") { else break } - out.writeText(changelogContent.toString()) + out.writeText(changelogContent) } else { out.writeText("") } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 60f4a0703..78f7d782b 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -25,6 +25,8 @@ dependencies { testRuntimeOnly(compileOnly("org.apache.commons:commons-lang3:3.3.2")!!) testRuntimeOnly(compileOnly("it.unimi.dsi:fastutil:8.2.1")!!) testRuntimeOnly(compileOnly("org.lwjgl:lwjgl-glfw:3.3.2")!!) + testRuntimeOnly(compileOnly("org.lwjgl:lwjgl-tinyfd:3.2.2")!!) + testRuntimeOnly(compileOnly("org.lwjgl:lwjgl-sdl:3.4.0-SNAPSHOT")!!) shadow(implementation("io.github.CDAGaming:DiscordIPC:0.10.2") { isTransitive = false @@ -32,7 +34,7 @@ dependencies { shadow(implementation("com.kohlschutter.junixsocket:junixsocket-common:2.10.1")!!) shadow(implementation("com.kohlschutter.junixsocket:junixsocket-native-common:2.10.1")!!) - shadow(implementation("com.github.mizosoft.methanol:methanol:1.8.0")!!) + shadow(implementation("com.github.mizosoft.methanol:methanol:1.8.3")!!) shadow(implementation("io.nayuki:qrcodegen:1.8.0")!!) compileOnly("net.hypixel:mod-api:1.0.1") @@ -111,7 +113,3 @@ publishing { } } } - -tasks.modrinth { - enabled = false -} diff --git a/common/src/main/java/io/github/axolotlclient/AxolotlClientCommon.java b/common/src/main/java/io/github/axolotlclient/AxolotlClientCommon.java index bb7c6d20e..a2dbb2777 100644 --- a/common/src/main/java/io/github/axolotlclient/AxolotlClientCommon.java +++ b/common/src/main/java/io/github/axolotlclient/AxolotlClientCommon.java @@ -64,7 +64,9 @@ public static Path resolveProfileConfigFile(String file) { } public static final boolean NVG_SUPPORTED = OSUtil.getOS() != OSUtil.OperatingSystem.OTHER && - !Objects.requireNonNullElse(System.getenv("TMPDIR"), "").contains("Android") && !FabricLoader.getInstance().isModLoaded("vulkanmod"); + !Objects.requireNonNullElse(System.getenv("TMPDIR"), "").contains("Android") && + !Objects.requireNonNullElse(System.getenv("HOME"), "").contains("Android") && + !FabricLoader.getInstance().isModLoaded("vulkanmod"); public static final String VERSION = FabricLoader.getInstance() .getModContainer("axolotlclient-common") diff --git a/common/src/main/java/io/github/axolotlclient/api/handlers/ChatHandler.java b/common/src/main/java/io/github/axolotlclient/api/handlers/ChatHandler.java index a89f77d75..1432652b0 100644 --- a/common/src/main/java/io/github/axolotlclient/api/handlers/ChatHandler.java +++ b/common/src/main/java/io/github/axolotlclient/api/handlers/ChatHandler.java @@ -75,7 +75,7 @@ public void handle(Response response) { } public void sendMessage(Channel channel, String message) { - if (message == null || message.isEmpty() || message.isBlank()) { + if (message == null || message.isBlank()) { return; } String displayName = API.getInstance().getSelf().getDisplayName(message); diff --git a/common/src/main/java/io/github/axolotlclient/api/requests/AccountSettingsRequest.java b/common/src/main/java/io/github/axolotlclient/api/requests/AccountSettingsRequest.java index 7e1504085..12672b3ed 100644 --- a/common/src/main/java/io/github/axolotlclient/api/requests/AccountSettingsRequest.java +++ b/common/src/main/java/io/github/axolotlclient/api/requests/AccountSettingsRequest.java @@ -41,17 +41,14 @@ public static CompletableFuture get() { response.getBodyOrElse("allow_friends_image_access", true))); } - public static CompletableFuture update(AccountSettings settings) { - return API.getInstance().patch(Request.Route.ACCOUNT_SETTINGS.builder() + public static void update(AccountSettings settings) { + API.getInstance().patch(Request.Route.ACCOUNT_SETTINGS.builder() .field("show_registered", settings.showRegistered()) .field("retain_usernames", settings.retainUsernames()) .field("show_last_online", settings.showLastOnline()) .field("show_activity", settings.showActivity()) .field("allow_friends_image_access", settings.allowFriendsImageAccess()) - .build()) - .thenAccept(response -> { - - }); + .build()); } public static CompletableFuture deleteAccount() { diff --git a/common/src/main/java/io/github/axolotlclient/api/requests/AccountUsernameRequest.java b/common/src/main/java/io/github/axolotlclient/api/requests/AccountUsernameRequest.java index a9795abf6..167f0b86a 100644 --- a/common/src/main/java/io/github/axolotlclient/api/requests/AccountUsernameRequest.java +++ b/common/src/main/java/io/github/axolotlclient/api/requests/AccountUsernameRequest.java @@ -30,8 +30,8 @@ public class AccountUsernameRequest { - public static CompletableFuture post(String username, boolean pub) { - return API.getInstance().post(Request.Route.ACCOUNT_USERNAME.builder() + public static void post(String username, boolean pub) { + API.getInstance().post(Request.Route.ACCOUNT_USERNAME.builder() .path(username).query("public", pub).build()); } diff --git a/common/src/main/java/io/github/axolotlclient/api/requests/FriendRequest.java b/common/src/main/java/io/github/axolotlclient/api/requests/FriendRequest.java index 531d00e15..22b3a7676 100644 --- a/common/src/main/java/io/github/axolotlclient/api/requests/FriendRequest.java +++ b/common/src/main/java/io/github/axolotlclient/api/requests/FriendRequest.java @@ -64,7 +64,7 @@ public CompletableFuture addFriend(String uuid) { } public CompletableFuture removeFriend(User user) { - return setRelation(api.sanitizeUUID(user.getUuid()), Relation.NONE).whenCompleteAsync((response, t) -> { + return setRelation(API.sanitizeUUID(user.getUuid()), Relation.NONE).whenCompleteAsync((response, t) -> { if (!response.isError()) { api.getNotificationProvider().addStatus("api.success.removeFriend", "api.success.removeFriend.desc", user.getName()); user.setRelation(Relation.NONE); @@ -72,8 +72,8 @@ public CompletableFuture removeFriend(User user) { }); } - public CompletableFuture blockUser(User user) { - return setRelation(user.getUuid(), Relation.BLOCKED).whenCompleteAsync((response, t) -> { + public void blockUser(User user) { + setRelation(user.getUuid(), Relation.BLOCKED).whenCompleteAsync((response, t) -> { if (!response.isError()) { api.getNotificationProvider().addStatus("api.success.blockUser", "api.success.blockUser.desc", user.getName()); user.setRelation(Relation.BLOCKED); diff --git a/common/src/main/java/io/github/axolotlclient/api/requests/UserRequest.java b/common/src/main/java/io/github/axolotlclient/api/requests/UserRequest.java index d88233b7d..297aa08e8 100644 --- a/common/src/main/java/io/github/axolotlclient/api/requests/UserRequest.java +++ b/common/src/main/java/io/github/axolotlclient/api/requests/UserRequest.java @@ -53,7 +53,7 @@ public static boolean getOnline(String uuid) { return false; } - String sanitized = API.getInstance().sanitizeUUID(uuid); + String sanitized = API.sanitizeUUID(uuid); if (API.getInstance().getSelf() != null && sanitized.equals(API.getInstance().getSelf().getUuid())) { return true; @@ -89,7 +89,7 @@ public User toUser() { } public static CompletableFuture> get(String dUuid) { - final String uuid = API.getInstance().sanitizeUUID(dUuid); + final String uuid = API.sanitizeUUID(dUuid); if (userCache.asMap().containsKey(uuid)) { return CompletableFuture.completedFuture(userCache.asMap().get(uuid)); } diff --git a/common/src/main/java/io/github/axolotlclient/api/types/User.java b/common/src/main/java/io/github/axolotlclient/api/types/User.java index d35f1a2ed..604a42a21 100644 --- a/common/src/main/java/io/github/axolotlclient/api/types/User.java +++ b/common/src/main/java/io/github/axolotlclient/api/types/User.java @@ -44,7 +44,7 @@ public class User { private PkSystem system; public User(String uuid, String name, Relation relation, Instant registered, Status status, List previousUsernames) { - this.uuid = API.getInstance().sanitizeUUID(uuid); + this.uuid = API.sanitizeUUID(uuid); this.status = status; this.name = name; this.relation = relation; @@ -83,6 +83,7 @@ public String getDisplayName(String message) { if (!isSystem()) { return getName(); } + //noinspection DataFlowIssue return getSystem().getProxy(message).orElse(getName()); } diff --git a/common/src/main/java/io/github/axolotlclient/api/util/UUIDHelper.java b/common/src/main/java/io/github/axolotlclient/api/util/UUIDHelper.java index d1fd90a6e..79dabb718 100644 --- a/common/src/main/java/io/github/axolotlclient/api/util/UUIDHelper.java +++ b/common/src/main/java/io/github/axolotlclient/api/util/UUIDHelper.java @@ -40,7 +40,13 @@ public class UUIDHelper { private static CachedAPI create(String endpoint, String jsonKey, String log) { return new CachedAPI<>(val -> { - HttpRequest req = HttpRequest.newBuilder(URI.create(endpoint + val)) + URI uri; + try { + uri = new URI(endpoint+val); + } catch (Exception e) { + return CompletableFuture.completedFuture(Optional.empty()); + } + HttpRequest req = HttpRequest.newBuilder(uri) .GET() .build(); @@ -76,6 +82,9 @@ public static UUID fromUndashed(String uuid) { } public static CompletableFuture> ensureUuidOpt(String nameOrUuid) { + if (nameOrUuid == null || nameOrUuid.isBlank()) { + return CompletableFuture.completedFuture(Optional.empty()); + } try { return CompletableFuture.completedFuture(Optional.of(API.sanitizeUUID(nameOrUuid))); } catch (IllegalArgumentException e) { diff --git a/common/src/main/java/io/github/axolotlclient/bridge/AxoMinecraftClient.java b/common/src/main/java/io/github/axolotlclient/bridge/AxoMinecraftClient.java index 2fefdf5c3..a7e35d50d 100644 --- a/common/src/main/java/io/github/axolotlclient/bridge/AxoMinecraftClient.java +++ b/common/src/main/java/io/github/axolotlclient/bridge/AxoMinecraftClient.java @@ -120,4 +120,12 @@ static int getCurrentFps() { default AxoResourceManager br$getResourceManager() { throw BridgeUtil.noImpl(); } + + /* + * Return type is an opaque object because we do not have a gui bridge currently. + */ + @RequiresImpl + default Object br$getScreen() { + throw BridgeUtil.noImpl(); + } } diff --git a/common/src/main/java/io/github/axolotlclient/bridge/events/Events.java b/common/src/main/java/io/github/axolotlclient/bridge/events/Events.java index 66015d7a6..a68f6155b 100644 --- a/common/src/main/java/io/github/axolotlclient/bridge/events/Events.java +++ b/common/src/main/java/io/github/axolotlclient/bridge/events/Events.java @@ -28,6 +28,7 @@ import io.github.axolotlclient.bridge.commands.Commands; import io.github.axolotlclient.bridge.entity.AxoEntity; import io.github.axolotlclient.bridge.entity.AxoPlayer; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.events.types.ReceiveChatMessageEvent; import io.github.axolotlclient.bridge.events.types.ScoreboardRenderEvent; import io.github.axolotlclient.bridge.events.types.WorldLoadEvent; @@ -40,6 +41,7 @@ public class Events { public static final EventBus> PLAYER_ATTACK = EventBus.broadcast2(); public static final EventBus> PLAYER_HURT = EventBus.broadcast2(); + public static final EventBus> PLAYER_DIRECTION_CHANGE = EventBus.broadcast1(); public static final EventBus> UPDATE_TIME = EventBus.broadcast1(); public static final EventBus> KEY_INPUT = EventBus.broadcast1(); diff --git a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java b/common/src/main/java/io/github/axolotlclient/bridge/events/types/PlayerDirectionChangeEvent.java similarity index 84% rename from 1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java rename to common/src/main/java/io/github/axolotlclient/bridge/events/types/PlayerDirectionChangeEvent.java index 8396e1ccb..e6a6f3c89 100644 --- a/1.16_combat-6/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java +++ b/common/src/main/java/io/github/axolotlclient/bridge/events/types/PlayerDirectionChangeEvent.java @@ -20,13 +20,8 @@ * For more information, see the LICENSE file. */ -package io.github.axolotlclient.util.events.impl; +package io.github.axolotlclient.bridge.events.types; -import lombok.Data; - -@Data -public class PlayerDirectionChangeEvent { - - private final float prevPitch, prevYaw, pitch, yaw; +public record PlayerDirectionChangeEvent(float prevPitch, float prevYaw, float pitch, float yaw) { } diff --git a/common/src/main/java/io/github/axolotlclient/bridge/internal/PlatformImplInternal.java b/common/src/main/java/io/github/axolotlclient/bridge/internal/PlatformImplInternal.java index 5e61734c6..ac49c9363 100644 --- a/common/src/main/java/io/github/axolotlclient/bridge/internal/PlatformImplInternal.java +++ b/common/src/main/java/io/github/axolotlclient/bridge/internal/PlatformImplInternal.java @@ -98,7 +98,7 @@ public static AxoIdentifier createIdentifier(String ns, String path) { } @RequiresImpl - public static AxoKeybinding createKeyBinding(@Nullable AxoKey defaultKey, String name, String category) { + public static AxoKeybinding createKeyBinding(@Nullable AxoKey defaultKey, String name) { throw BridgeUtil.noImpl(); } diff --git a/common/src/main/java/io/github/axolotlclient/bridge/key/AxoKeybinding.java b/common/src/main/java/io/github/axolotlclient/bridge/key/AxoKeybinding.java index 806f346e0..d92aa38be 100644 --- a/common/src/main/java/io/github/axolotlclient/bridge/key/AxoKeybinding.java +++ b/common/src/main/java/io/github/axolotlclient/bridge/key/AxoKeybinding.java @@ -31,8 +31,8 @@ * An abstract representation of a keybind */ public interface AxoKeybinding { - static AxoKeybinding create(@Nullable AxoKey defaultKey, String name, String category) { - return PlatformImplInternal.createKeyBinding(defaultKey, name, category); + static AxoKeybinding create(@Nullable AxoKey defaultKey, String name) { + return PlatformImplInternal.createKeyBinding(defaultKey, name); } @RequiresImpl diff --git a/common/src/main/java/io/github/axolotlclient/bridge/render/AxoRenderContext.java b/common/src/main/java/io/github/axolotlclient/bridge/render/AxoRenderContext.java index 82cc2fa38..2636de268 100644 --- a/common/src/main/java/io/github/axolotlclient/bridge/render/AxoRenderContext.java +++ b/common/src/main/java/io/github/axolotlclient/bridge/render/AxoRenderContext.java @@ -30,6 +30,7 @@ import io.github.axolotlclient.modules.hud.util.Rectangle; import org.jetbrains.annotations.ApiStatus; +@SuppressWarnings("unused") public interface AxoRenderContext { // Matrix management @RequiresImpl @@ -95,26 +96,56 @@ public interface AxoRenderContext { throw BridgeUtil.noImpl(); } + @ApiStatus.NonExtendable + default int br$drawString(String value, int x, int y, int color) { + return br$drawString(value, x, y, color, true); + } + @RequiresImpl default int br$drawString(AxoText value, int x, int y, int color, boolean shadow) { throw BridgeUtil.noImpl(); } + @ApiStatus.NonExtendable + default int br$drawString(AxoText value, int x, int y, int color) { + return br$drawString(value, x, y, color, true); + } + + @ApiStatus.NonExtendable + default int br$drawString(AxoText value, int x, int y, Color color) { + return br$drawString(value, x, y, color, true); + } + @ApiStatus.NonExtendable default int br$drawString(String value, int x, int y, Color color, boolean shadow) { return br$drawString(value, x, y, color.toInt(), shadow); } + @ApiStatus.NonExtendable + default int br$drawString(String value, int x, int y, Color color) { + return br$drawString(value, x, y, color, true); + } + @ApiStatus.NonExtendable default void br$drawCenteredString(String value, int x, int y, int color, boolean shadow) { br$drawString(value, x - br$getFont().br$getWidth(value) / 2, y, color, shadow); } + @ApiStatus.NonExtendable + default void br$drawCenteredString(String value, int x, int y, int color) { + br$drawCenteredString(value, x, y, color, true); + } + @ApiStatus.NonExtendable default void br$drawCenteredString(String value, int x, int y, Color color, boolean shadow) { br$drawCenteredString(value, x, y, color.toInt(), shadow); } + @ApiStatus.NonExtendable + default void br$drawCenteredString(String value, int x, int y, Color color) { + br$drawCenteredString(value, x, y, color, true); + } + @ApiStatus.NonExtendable default int br$drawString(AxoText value, int x, int y, Color color, boolean shadow) { return br$drawString(value, x, y, color.toInt(), shadow); @@ -130,6 +161,11 @@ public interface AxoRenderContext { br$drawCenteredString(value, x, y, color.toInt(), shadow); } + @ApiStatus.NonExtendable + default void br$drawCenteredString(AxoText value, int x, int y, Color color) { + br$drawCenteredString(value, x, y, color, true); + } + // fillRect overloads @ApiStatus.NonExtendable default void br$fillRect(Rectangle rect, Color color) { diff --git a/common/src/main/java/io/github/axolotlclient/config/profiles/Profiles.java b/common/src/main/java/io/github/axolotlclient/config/profiles/Profiles.java index 448c675ff..24564df54 100644 --- a/common/src/main/java/io/github/axolotlclient/config/profiles/Profiles.java +++ b/common/src/main/java/io/github/axolotlclient/config/profiles/Profiles.java @@ -23,9 +23,13 @@ package io.github.axolotlclient.config.profiles; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -39,10 +43,18 @@ import io.github.axolotlclient.AxolotlClientCommon; import io.github.axolotlclient.bridge.util.AxoI18n; import io.github.axolotlclient.util.GsonHelper; +import io.github.axolotlclient.util.ThreadExecuter; import lombok.Setter; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.util.tinyfd.TinyFileDialogs; public class Profiles { private static final Path PROFILES_CONFIG = AxolotlClientCommon.resolveConfigFile("profiles").resolve("profiles.json"); + private static final String PROFILE_EXPORT_FILE_EXTENSION = ".axoprofile"; + private static final DateTimeFormatter EXPORT_TIME_FORMAT = new DateTimeFormatterBuilder().appendPattern("yyyy_MM_dd-HH_mm_ss").toFormatter(); + private static final String PROFILE_INFO_FILE = "profile_info.json"; public static Profiles getInstance() { return INSTANCE; @@ -131,6 +143,111 @@ public Profile duplicate(Profile profile) { return duplicate; } + public void exportProfile(Profile profile) { + ThreadExecuter.scheduleTask(() -> { + try (MemoryStack stack = MemoryStack.stackPush()) { + var pointers = stack.mallocPointer(1); + pointers.put(stack.UTF8("*" + PROFILE_EXPORT_FILE_EXTENSION)); + pointers.flip(); + var out = TinyFileDialogs.tinyfd_saveFileDialog("Choose export destination", + FabricLoader.getInstance().getGameDir() + .resolve(LocalDateTime.now().format(EXPORT_TIME_FORMAT) + "_" + profile.name() + PROFILE_EXPORT_FILE_EXTENSION).toString(), + pointers, null); + if (out == null) { + return; + } + if (!out.endsWith(PROFILE_EXPORT_FILE_EXTENSION)) { + AxolotlClientCommon.getInstance().getNotificationProvider() + .addStatus("profiles.profile.export.notification.failed", + "profiles.profile.export.notification.failed.invalid_destination"); + return; + } + var outPath = Path.of(out); + Files.deleteIfExists(outPath); + try (var fs = FileSystems.newFileSystem(outPath, Map.of("create", "true"))) { + var realRoot = profile.getPath(); + Files.walkFileTree(realRoot, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + var zipped = fs.getPath("profile").resolve(realRoot.relativize(file).toString()); + Files.createDirectories(zipped.getParent()); + Files.copy(file, zipped); + return super.visitFile(file, attrs); + } + }); + Files.writeString(fs.getPath(PROFILE_INFO_FILE), GsonHelper.GSON.toJson(new ProfileInfo(profile))); + } + AxolotlClientCommon.getInstance().getNotificationProvider() + .addStatus("profiles.profile.export.notification.success", + "profiles.profile.export.notification.success.desc", profile.name(), FabricLoader.getInstance().getGameDir().relativize(outPath)); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().info("Failed to export profile", e); + AxolotlClientCommon.getInstance().getNotificationProvider() + .addStatus("profiles.profile.export.notification.failed", + "profiles.profile.export.notification.failed.generic"); + } + }); + } + + public CompletableFuture> importProfiles() { + return CompletableFuture.supplyAsync(() -> { + try (MemoryStack stack = MemoryStack.stackPush()) { + var pointers = stack.mallocPointer(1); + pointers.put(stack.UTF8("*" + PROFILE_EXPORT_FILE_EXTENSION)); + pointers.flip(); + var files = TinyFileDialogs.tinyfd_openFileDialog("Import Profile", + FabricLoader.getInstance().getGameDir().toString(), + pointers, + null, true + ); + if (files == null) return Collections.emptyList(); + var imported = Arrays.stream(files.split("\\|")).map(Path::of) + .map(p -> { + try (var fs = FileSystems.newFileSystem(p)) { + var profileInfoPath = fs.getPath(PROFILE_INFO_FILE); + if (!Files.exists(profileInfoPath)) { + AxolotlClientCommon.getInstance().getLogger().warn("Skipping bad profile file at {}", p); + AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("profiles.profile.import.notification.failed", "profiles.profile.import.notification.malformed_profile", p.getFileName()); + return null; + } + var profileInfo = GsonHelper.GSON.fromJson(Files.readString(profileInfoPath), ProfileInfo.class); + var newProfile = newProfile(profileInfo.name()); + Files.createDirectories(newProfile.getPath()); + var fakeRoot = fs.getPath("/profile"); + Files.walkFileTree(fakeRoot, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + Files.copy(file, newProfile.getPath().resolve(fakeRoot.relativize(file).toString())); + return super.visitFile(file, attrs); + } + }); + return newProfile; + } catch (Exception e) { + AxolotlClientCommon.getInstance().getLogger().warn("Failed to import profile from {}", p, e); + AxolotlClientCommon.getInstance().getNotificationProvider() + .addStatus("profiles.profile.import.notification.failed", + "profiles.profile.import.notification.failed.generic"); + return null; + } + }).filter(Objects::nonNull).toList(); + saveProfiles(); + if (!imported.isEmpty()) { + var count = imported.size(); + if (count == 1) { + AxolotlClientCommon.getInstance().getNotificationProvider() + .addStatus("profiles.profile.import.notification.success", + "profiles.profile.import.notification.success.desc.one"); + } else { + AxolotlClientCommon.getInstance().getNotificationProvider() + .addStatus("profiles.profile.import.notification.success", + "profiles.profile.import.notification.success.desc.more", count); + } + } + return imported; + } + }, ThreadExecuter.service()); + } + public static final class Profile { @Setter private String name; @@ -153,20 +270,6 @@ public String id() { return id; } - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (Profile) obj; - return Objects.equals(this.name, that.name) && - Objects.equals(this.id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(name, id); - } - @Override public String toString() { return "Profile[" + @@ -235,4 +338,35 @@ public ProfileStorage read(JsonReader in) throws IOException { return new ProfileStorage(profiles.get((String) obj.get("current")), available); } } + + @JsonAdapter(ProfileInfo.ProfileInfoAdapter.class) + public record ProfileInfo(String name, String id) { + public ProfileInfo(Profile p) { + this(p.name(), p.id()); + } + + public static class ProfileInfoAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter jsonWriter, ProfileInfo profileInfo) throws IOException { + if (profileInfo == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("name").value(profileInfo.name()) + .name("id").value(profileInfo.id()); + jsonWriter.endObject(); + } + + @Override + public ProfileInfo read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) return null; + + @SuppressWarnings("unchecked") var map = (Map) GsonHelper.read(jsonReader); + if (map == null) return null; + return new ProfileInfo(map.get("name"), map.get("id")); + } + } + } } diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/Account.java b/common/src/main/java/io/github/axolotlclient/modules/auth/Account.java index f7e759496..e07ae64f9 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/auth/Account.java +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/Account.java @@ -24,7 +24,6 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import com.google.gson.JsonObject; @@ -83,8 +82,9 @@ public static Account deserialize(JsonObject object) { return new Account(uuid, name, authToken, msaToken, refreshToken, expiration); } - public CompletableFuture> refresh(MSAuth auth) { - return auth.refreshToken(refreshToken, this); + public CompletableFuture refresh(MSApi auth) { + if (isOffline()) return CompletableFuture.failedFuture(new UnsupportedOperationException()); + return auth.refresh(this); } public boolean isOffline() { diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/Accounts.java b/common/src/main/java/io/github/axolotlclient/modules/auth/Accounts.java index 1b9d8667d..2ff257eab 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/auth/Accounts.java +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/Accounts.java @@ -27,10 +27,12 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.util.GsonHelper; import io.github.axolotlclient.util.Logger; import lombok.Getter; @@ -38,9 +40,11 @@ @Getter public abstract class Accounts { + public final OptionCategory category = OptionCategory.create("auth"); + private final List accounts = new ArrayList<>(); protected Account current; - protected MSAuth auth; + protected MSApi msApi; public void load() { Path legacy = AxolotlClientCommon.resolveConfigFile("../accounts.json"); @@ -117,7 +121,7 @@ public boolean allowOfflineAccounts() { return !accounts.isEmpty() && !accounts.stream().allMatch(Account::isOffline); } - abstract void showAccountsExpiredScreen(Account account); + abstract CompletableFuture showAccountsExpiredScreen(Account account); abstract void displayDeviceCode(DeviceFlowData data); } diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/MSApi.java b/common/src/main/java/io/github/axolotlclient/modules/auth/MSApi.java new file mode 100644 index 000000000..3c98c7ec6 --- /dev/null +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/MSApi.java @@ -0,0 +1,532 @@ +/* + * Copyright © 2024 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth; + +import java.io.FileNotFoundException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Base64; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; +import java.util.function.Supplier; + +import com.github.mizosoft.methanol.FormBodyPublisher; +import com.github.mizosoft.methanol.MediaType; +import com.github.mizosoft.methanol.MultipartBodyPublisher; +import com.google.common.hash.Hashing; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.modules.auth.skin.Cape; +import io.github.axolotlclient.modules.auth.skin.Skin; +import io.github.axolotlclient.util.GsonHelper; +import io.github.axolotlclient.util.JsonBuilders; +import io.github.axolotlclient.util.Logger; +import io.github.axolotlclient.util.NetworkUtil; +import lombok.ToString; + +// Partly oriented on In-Game-Account-Switcher by The-Fireplace, VidTu +public class MSApi { + + private static final String CLIENT_ID = "938592fc-8e01-4c6d-b56d-428c7d9cf5ea"; // AxolotlClient MSA ClientID + private static final String SCOPES = "XboxLive.signin offline_access"; + private static final String XBL_AUTH_URL = "https://user.auth.xboxlive.com/user/authenticate"; + private static final String MS_DEVICE_CODE_LOGIN_URL = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode?mkt="; + private static final String MS_TOKEN_LOGIN_URL = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"; + private static final String XBL_XSTS_AUTH_URL = "https://xsts.auth.xboxlive.com/xsts/authorize"; + private static final String MC_LOGIN_WITH_XBOX_URL = "https://api.minecraftservices.com/authentication/login_with_xbox"; + + private final Supplier languageSupplier; + private final Logger logger; + private final Accounts accounts; + private final HttpClient client; + + public static MSApi INSTANCE; + + public MSApi(Accounts accounts, Supplier languageSupplier) { + this.logger = AxolotlClientCommon.getInstance().getLogger(); + this.client = NetworkUtil.createHttpClient(); + this.accounts = accounts; + this.languageSupplier = languageSupplier; + INSTANCE = this; + } + + public CompletableFuture startDeviceAuth() { + + String[] lang = languageSupplier.get().replace("_", "-").split("-"); + logger.debug("starting ms device auth flow"); + // https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-device-code#device-authorization-response + HttpRequest.Builder builder = HttpRequest.newBuilder() + .POST(FormBodyPublisher.newBuilder() + .query("client_id", CLIENT_ID) + .query("scope", SCOPES).build()) + .header("content-type", "application/x-www-form-urlencoded") + .uri(URI.create(MS_DEVICE_CODE_LOGIN_URL + lang[0] + "-" + lang[1].toUpperCase(Locale.ROOT))); + return requestJson(builder.build()) + .thenApplyAsync(object -> { + int expiresIn = object.get("expires_in").getAsInt(); + String deviceCode = object.get("device_code").getAsString(); + String userCode = object.get("user_code").getAsString(); + String verificationUri = object.get("verification_uri").getAsString(); + int interval = object.get("interval").getAsInt(); + String message = object.get("message").getAsString(); + logger.debug("displaying device code to user"); + DeviceFlowData data = new DeviceFlowData(message, verificationUri, deviceCode, userCode, expiresIn, interval); + accounts.displayDeviceCode(data); + return data; + }).thenComposeAsync(data -> { + logger.debug("waiting for user authorization..."); + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < data.getExpiresIn() * 1000L && !data.isCancelled()) { + if ((System.currentTimeMillis() - start) % data.getInterval() == 0) { + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder().POST( + FormBodyPublisher.newBuilder().query("client_id", CLIENT_ID) + .query("device_code", data.getDeviceCode()) + .query("grant_type", "urn:ietf:params:oauth:grant-type:device_code") + .build() + ) + .uri(URI.create(MS_TOKEN_LOGIN_URL)); + JsonObject response = requestJson(requestBuilder.build()).join(); + + if (response.has("refresh_token") && response.has("access_token")) { + data.setStatus("auth.working"); + return authenticateFromMSTokens(response.get("access_token").getAsString(), + response.get("refresh_token").getAsString()) + .thenApply(a -> { + int index = accounts.getAccounts().indexOf(a); + Account loginAccount; + if (index == -1) { + accounts.getAccounts().add(a); + loginAccount = a; + } else { + var prev = accounts.getAccounts().get(index); + prev.setAuthToken(a.getAuthToken()); + prev.setExpiration(a.getExpiration()); + prev.setMsaToken(a.getMsaToken()); + prev.setName(a.getName()); + prev.setRefreshToken(a.getRefreshToken()); + loginAccount = prev; + } + accounts.login(loginAccount); + accounts.save(); + data.setStatus("auth.finished"); + return loginAccount; + }); + } + + if (response.has("error")) { + String error = response.get("error").getAsString(); + switch (error) { + case "authorization_pending": + continue; + case "bad_verification_code": + throw new IllegalStateException("Bad verification code! " + response); + case "authorization_declined": + case "expired_token": + default: + break; + } + } + } + } + return CompletableFuture.failedStage(new TimeoutException()); + }); + } + + private CompletableFuture authenticateFromMSTokens(String accessToken, String refreshToken) { + return CompletableFuture.supplyAsync(() -> { + logger.debug("getting xbl token... "); + XblData xbl = authXbl(accessToken).join(); + logger.debug("getting xsts token..."); + XblData xsts = authXstsMC(xbl.token()).join(); + logger.debug("getting mc auth token..."); + MCXblData mc = authMC(xsts.displayClaims().uhs(), xsts.token()).join(); + + JsonObject profileJson = getMCProfile(mc.accessToken()).join(); + if (profileJson.has("error") && "NOT_FOUND".equals(profileJson.get("error").getAsString())) { + AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("auth.notif.login.failed", "auth.notif.login.failed.no_profile"); + throw new IllegalStateException(); + } + logger.debug("retrieving entitlements..."); + if (!checkOwnership(mc.accessToken()).join()) { + AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("auth.notif.login.failed", "auth.notif.login.failed.no_entitlement"); + logger.warn("Failed to check for game ownership!"); + throw new IllegalStateException(); + } + logger.debug("getting profile..."); + MCProfile profile = MCProfile.get(profileJson); + return new Account(profile.name(), profile.id(), mc.accessToken(), mc.expiration(), refreshToken, accessToken); + }); + } + + public record MCProfile(String id, String name, List skins, List capes) { + public static MCProfile get(JsonObject json) { + var skinList = GsonHelper.jsonArrayToStream(json.getAsJsonArray("skins")) + .map(s -> OnlineSkin.get(s.getAsJsonObject())) + .toList(); + var capesList = GsonHelper.jsonArrayToStream(json.getAsJsonArray("capes")) + .map(s -> OnlineCape.get(s.getAsJsonObject())) + .toList(); + CompletableFuture.allOf(skinList.toArray(CompletableFuture[]::new)); + CompletableFuture.allOf(capesList.toArray(CompletableFuture[]::new)); + return new MCProfile(json.get("id").getAsString(), json.get("name").getAsString(), + skinList.stream().map(CompletableFuture::join).toList(), + capesList.stream().map(CompletableFuture::join).toList()); + } + + @ToString + public static final class OnlineSkin implements Skin.Online { + public static final String VARIANT_CLASSIC = "CLASSIC"; + public static final String VARIANT_SLIM = "SLIM"; + public static final String STATE_ACTIVE = "ACTIVE"; + private final String id; + private final String state; + private final String url; + private boolean classicVariant; + private final byte[] image; + private final String textureKey; + + public OnlineSkin(String id, String state, String url, String variant, + byte[] image, String textureKey) { + this.id = id; + this.state = state; + this.url = url; + this.classicVariant = VARIANT_CLASSIC.equals(variant); + this.image = image; + this.textureKey = textureKey; + } + + @SuppressWarnings("UnstableApiUsage") + public static CompletableFuture get(JsonObject object) { + String url = object.get("url").getAsString(); + return INSTANCE.client.sendAsync(HttpRequest.newBuilder(URI.create(url)).GET().build(), HttpResponse.BodyHandlers.ofByteArray()) + .thenApplyAsync(res -> { + if (res.statusCode() == 200) { + return res.body(); + } + throw new IllegalArgumentException("abnormal status: " + res.statusCode()); + }).thenApply(bytes -> new OnlineSkin(object.get("id").getAsString(), + object.get("state").getAsString(), + url, + object.get("variant").getAsString(), bytes, + Hashing.sha256().hashBytes(bytes).toString())); + } + + public byte[] image() { + return image; + } + + public boolean classicVariant() { + return classicVariant; + } + + @Override + public void classicVariant(boolean classic) { + this.classicVariant = classic; + } + + public boolean active() { + return STATE_ACTIVE.equals(state()); + } + + @Override + public CompletableFuture equip(MSApi api, Account account) { + return api.setSkin(account, this); + } + + @Override + public boolean supportsDownload() { + return true; + } + + public String id() { + return id; + } + + public String state() { + return state; + } + + @Override + public String url() { + return url; + } + + @Override + public String sha256() { + return textureKey; + } + } + + public record OnlineCape(String id, String state, String url, String alias, byte[] image, + String sha256) implements Cape { + public static final String STATE_ACTIVE = "ACTIVE"; + + @SuppressWarnings("UnstableApiUsage") + public static CompletableFuture get(JsonObject object) { + String url = object.get("url").getAsString(); + return INSTANCE.client.sendAsync(HttpRequest.newBuilder(URI.create(url)).GET().build(), HttpResponse.BodyHandlers.ofByteArray()) + .thenApplyAsync(res -> { + if (res.statusCode() == 200) { + return res.body(); + } + throw new IllegalArgumentException("abnormal status: " + res.statusCode()); + }).thenApply(bytes -> new OnlineCape(object.get("id").getAsString(), object.get("state").getAsString(), + url, object.get("alias").getAsString(), bytes, Hashing.sha256().hashBytes(bytes).toString())); + } + + public boolean active() { + return STATE_ACTIVE.equals(state()); + } + + @Override + public CompletableFuture equip(MSApi api, Account account) { + return api.showCape(account, this); + } + } + } + + private CompletableFuture authXbl(String code) { + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(XBL_AUTH_URL)) + .POST(HttpRequest.BodyPublishers.ofString(JsonBuilders.JsonObject.create() + .field("Properties", JsonBuilders.JsonObject.create() + .field("AuthMethod", "RPS") + .field("SiteName", "user.auth.xboxlive.com") + .field("RpsTicket", "d=" + code)) + .field("RelyingParty", "http://auth.xboxlive.com") + .field("TokenType", "JWT").asString())) + .header("content-type", "application/json") + .header("accept", "application/json"); + + return requestJson(requestBuilder.build()).thenApply(response -> new XblData(Instant.parse(response.get("IssueInstant").getAsString()), Instant.parse(response.get("NotAfter").getAsString()), + response.get("Token").getAsString(), new XblData.DisplayClaims(response.get("DisplayClaims").getAsJsonObject().get("xui").getAsJsonArray().get(0).getAsJsonObject().get("uhs").getAsString()))); + } + + private record XblData(Instant issueInstant, Instant notAfter, String token, DisplayClaims displayClaims) { + private record DisplayClaims(String uhs) { + } + } + + private CompletableFuture authXstsMC(String xblToken) { + var body = JsonBuilders.JsonObject.create() + .field("Properties", JsonBuilders.JsonObject.create() + .field("SandboxId", "RETAIL") + .field("UserTokens", JsonBuilders.JsonArray.create().field(xblToken))) + .field("RelyingParty", "rp://api.minecraftservices.com/") + .field("TokenType", "JWT"); + return requestJson(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(body.asString())).uri(URI.create(XBL_XSTS_AUTH_URL)).build()) + .thenApply(response -> new XblData(Instant.parse(response.get("IssueInstant").getAsString()), Instant.parse(response.get("NotAfter").getAsString()), + response.get("Token").getAsString(), new XblData.DisplayClaims(response.get("DisplayClaims").getAsJsonObject().get("xui").getAsJsonArray().get(0).getAsJsonObject().get("uhs").getAsString()))); + } + + private CompletableFuture authMC(String userhash, String xsts) { + var body = JsonBuilders.JsonObject.create().field("identityToken", "XBL3.0 x=" + userhash + ";" + xsts); + return requestJson(HttpRequest.newBuilder(URI.create(MC_LOGIN_WITH_XBOX_URL)).POST(HttpRequest.BodyPublishers.ofString(body.asString())).build()) + .thenApply(response -> new MCXblData(response.get("username").getAsString(), + response.get("access_token").getAsString(), + Instant.now().plus(response.get("expires_in").getAsLong(), ChronoUnit.SECONDS))); + } + + private record MCXblData(String username, String accessToken, Instant expiration) { + } + + private CompletableFuture checkOwnership(String accessToken) { + return requestJson(HttpRequest + .newBuilder(URI.create("https://api.minecraftservices.com/entitlements/mcstore")) + .header("Authorization", "Bearer " + accessToken).build()) + .thenApply(res -> GsonHelper.jsonArrayToStream(res.get("items").getAsJsonArray()) + .anyMatch(e -> e.isJsonObject() && e.getAsJsonObject().has("name") + && "game_minecraft".equals(e.getAsJsonObject().get("name").getAsString()))); + } + + private CompletableFuture getMCProfile(String accessToken) { + return requestJson(HttpRequest.newBuilder().GET() + .uri(URI.create("https://api.minecraftservices.com/minecraft/profile")) + .header("Authorization", "Bearer " + accessToken).build()); + } + + public CompletableFuture refresh(Account account) { + logger.debug("refreshing auth code..."); + return requestJson(HttpRequest + .newBuilder(URI.create(MS_TOKEN_LOGIN_URL)) + .POST(FormBodyPublisher.newBuilder() + .query("client_id", CLIENT_ID) + .query("refresh_token", account.getRefreshToken()) + .query("scope", SCOPES) + .query("grant_type", "refresh_token").build()) + .header("Accept", "application/json").build()) + .thenCompose(response -> { + if (response.has("error_codes")) { + int errorCode = response.get("error_codes").getAsJsonArray().get(0).getAsInt(); + if (errorCode == 70000 || errorCode == 70012) { + return accounts.showAccountsExpiredScreen(account); + } else { + logger.warn("Login error, unexpected response: " + response); + AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("auth.notif.refresh.error", "auth.notif.refresh.error.unexpected_response"); + throw new IllegalArgumentException(); + } + } + logger.debug("authenticating..."); + return authenticateFromMSTokens(response.get("access_token").getAsString(), + response.get("refresh_token").getAsString()).thenApply(refreshed -> { + account.setRefreshToken(refreshed.getRefreshToken()); + account.setAuthToken(refreshed.getAuthToken()); + account.setName(refreshed.getName()); + account.setMsaToken(refreshed.getMsaToken()); + account.setExpiration(refreshed.getExpiration()); + accounts.save(); + return account; + }); + }); + } + + private CompletableFuture requestJson(HttpRequest request) { + return client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenApply(res -> GsonHelper.fromJson(res.body())); + } + + public CompletableFuture getProfile(Account account) { + return getMCProfile(account.getAuthToken()).thenApply(this::extractProfile); + } + + public record SkinBundle(String name, String id, CompletableFuture skin, String skinKey, + boolean classicModel) { + } + + public CompletableFuture getTextures(String uuid) { + return requestJson(HttpRequest.newBuilder().GET() + .uri(URI.create("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid)) + .build()).thenApply(json -> { + var name = json.get("name").getAsString(); + var id = json.get("id").getAsString(); + var properties = json.get("properties").getAsJsonArray(); + for (JsonElement e : properties) { + if (e.isJsonObject()) { + var obj = e.getAsJsonObject(); + if (obj.has("name") && "textures".equals(obj.get("name").getAsString())) { + var b64 = obj.get("value").getAsString(); + var props = GsonHelper.fromJson(new String(Base64.getDecoder().decode(b64), StandardCharsets.UTF_8)); + var textures = props.get("textures").getAsJsonObject(); + if (textures.has("SKIN")) { + var skinObj = textures.get("SKIN").getAsJsonObject(); + var skinUrl = skinObj.get("url").getAsString(); + var skin = client.sendAsync(HttpRequest.newBuilder().uri(URI.create(skinUrl)).GET().build(), HttpResponse.BodyHandlers.ofByteArray()) + .thenApply(HttpResponse::body); + var skinKey = skinUrl.substring(skinUrl.lastIndexOf("/") + 1); + var classicModel = true; + if (skinObj.has("metadata")) { + var metadata = skinObj.get("metadata").getAsJsonObject(); + var model = metadata.get("model").getAsString(); + classicModel = MCProfile.OnlineSkin.VARIANT_CLASSIC.toLowerCase(Locale.ROOT).equals(model.toLowerCase(Locale.ROOT)); + } + return new SkinBundle(name, id, skin, skinKey, classicModel); + } + } + } + } + return null; + }); + } + + private MCProfile extractProfile(JsonObject profileJson) { + if (profileJson.has("error") && "NOT_FOUND".equals(profileJson.get("error").getAsString())) { + throw new IllegalStateException("profile not found"); + } + if (!profileJson.has("id")) { + logger.warn("Unexpected profile response: {}", profileJson); + throw new IllegalStateException("unexpected error"); + } + return MCProfile.get(profileJson); + } + + + public CompletableFuture setSkin(Account account, Skin.Online skin) { + return setSkin(account, skin.classicVariant(), skin.url()); + } + + public CompletableFuture setSkin(Account account, boolean wide, String url) { + return requestJson(HttpRequest.newBuilder() + .uri(URI.create("https://api.minecraftservices.com/minecraft/profile/skins")) + .header("Authorization", "Bearer " + account.getAuthToken()) + .POST(HttpRequest.BodyPublishers.ofString(JsonBuilders.JsonObject.create() + .field("variant", wide ? MCProfile.OnlineSkin.VARIANT_CLASSIC : MCProfile.OnlineSkin.VARIANT_SLIM) + .field("url", url).asString())).build()) + .thenApply(this::extractProfile); + } + + public CompletableFuture uploadAndSetSkin(Account account, boolean wide, byte[] image) { + return uploadAndSetSkin(account, MultipartBodyPublisher.newBuilder() + .textPart("variant", wide ? "classic" : "slim") + .formPart("file", HttpRequest.BodyPublishers.ofByteArray(image)).build()); + } + + public CompletableFuture uploadAndSetSkin(Account account, Skin.LocalSkin skin) { + try { + return uploadAndSetSkin(account, MultipartBodyPublisher.newBuilder() + .textPart("variant", skin.classicVariant() ? "classic" : "slim") + .filePart("file", skin.file(), MediaType.IMAGE_PNG).build()); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + private CompletableFuture uploadAndSetSkin(Account account, MultipartBodyPublisher publisher) { + return requestJson(HttpRequest.newBuilder() + .uri(URI.create("https://api.minecraftservices.com/minecraft/profile/skins")) + .header("Authorization", "Bearer " + account.getAuthToken()) + .POST(publisher).build()) + .thenApply(this::extractProfile); + } + + public CompletableFuture resetSkin(Account account) { + return requestJson(HttpRequest.newBuilder().DELETE() + .uri(URI.create("https://api.minecraftservices.com/minecraft/profile/skins/active")) + .header("Authorization", "Bearer " + account.getAuthToken()) + .build()) + .thenApply(this::extractProfile); + } + + public CompletableFuture hideCape(Account account) { + return requestJson(HttpRequest.newBuilder().DELETE() + .uri(URI.create("https://api.minecraftservices.com/minecraft/profile/capes/active")) + .header("Authorization", "Bearer " + account.getAuthToken()) + .build()) + .thenApply(this::extractProfile); + } + + public CompletableFuture showCape(Account account, MCProfile.OnlineCape cape) { + return requestJson(HttpRequest.newBuilder() + .uri(URI.create("https://api.minecraftservices.com/minecraft/profile/capes/active")) + .header("Authorization", "Bearer " + account.getAuthToken()) + .PUT(HttpRequest.BodyPublishers.ofString(JsonBuilders.JsonObject.create().field("capeId", cape.id()).asString())).build()) + .thenApply(this::extractProfile); + } +} diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/MSAuth.java b/common/src/main/java/io/github/axolotlclient/modules/auth/MSAuth.java deleted file mode 100644 index 32d90b6bf..000000000 --- a/common/src/main/java/io/github/axolotlclient/modules/auth/MSAuth.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright © 2024 moehreag & Contributors - * - * This file is part of AxolotlClient. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * For more information, see the LICENSE file. - */ - -package io.github.axolotlclient.modules.auth; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; - -import com.github.mizosoft.methanol.FormBodyPublisher; -import com.google.gson.JsonObject; -import io.github.axolotlclient.AxolotlClientCommon; -import io.github.axolotlclient.util.GsonHelper; -import io.github.axolotlclient.util.Logger; -import io.github.axolotlclient.util.NetworkUtil; - -// Partly oriented on In-Game-Account-Switcher by The-Fireplace, VidTu -public class MSAuth { - - private static final String CLIENT_ID = "938592fc-8e01-4c6d-b56d-428c7d9cf5ea"; // AxolotlClient MSA ClientID - private static final String SCOPES = "XboxLive.signin offline_access"; - private static final String XBL_AUTH_URL = "https://user.auth.xboxlive.com/user/authenticate"; - private static final String MS_DEVICE_CODE_LOGIN_URL = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode?mkt="; - private static final String MS_TOKEN_LOGIN_URL = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"; - private static final String XBL_XSTS_AUTH_URL = "https://xsts.auth.xboxlive.com/xsts/authorize"; - private static final String MC_LOGIN_WITH_XBOX_URL = "https://api.minecraftservices.com/authentication/login_with_xbox"; - - private final Supplier languageSupplier; - private final Logger logger; - private final Accounts accounts; - private final HttpClient client; - - public static MSAuth INSTANCE; - - public MSAuth(Logger logger, Accounts accounts, Supplier languageSupplier) { - this.logger = logger; - this.accounts = accounts; - this.languageSupplier = languageSupplier; - this.client = getHttpClient(); - INSTANCE = this; - } - - public CompletableFuture startDeviceAuth() { - - String[] lang = languageSupplier.get().replace("_", "-").split("-"); - logger.debug("starting ms device auth flow"); - // https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-device-code#device-authorization-response - HttpRequest.Builder builder = HttpRequest.newBuilder() - .POST(FormBodyPublisher.newBuilder() - .query("client_id", CLIENT_ID) - .query("scope", SCOPES).build()) - .header("ContentType", "application/x-www-form-urlencoded") - .uri(URI.create(MS_DEVICE_CODE_LOGIN_URL + lang[0] + "-" + lang[1].toUpperCase(Locale.ROOT))); - return requestJson(builder.build()) - .thenApply(object -> { - int expiresIn = object.get("expires_in").getAsInt(); - String deviceCode = object.get("device_code").getAsString(); - String userCode = object.get("user_code").getAsString(); - String verificationUri = object.get("verification_uri").getAsString(); - int interval = object.get("interval").getAsInt(); - String message = object.get("message").getAsString(); - logger.debug("displaying device code to user"); - DeviceFlowData data = new DeviceFlowData(message, verificationUri, deviceCode, userCode, expiresIn, interval); - accounts.displayDeviceCode(data); - return data; - }) - .thenApply(data -> { - logger.debug("waiting for user authorization..."); - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < data.getExpiresIn() * 1000L && !data.isCancelled()) { - if ((System.currentTimeMillis() - start) % data.getInterval() == 0) { - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder().POST( - FormBodyPublisher.newBuilder().query("client_id", CLIENT_ID) - .query("device_code", data.getDeviceCode()) - .query("grant_type", "urn:ietf:params:oauth:grant-type:device_code") - .build() - ) - .uri(URI.create(MS_TOKEN_LOGIN_URL)); - JsonObject response = requestJson(requestBuilder.build()).join(); - - if (response.has("refresh_token") && response.has("access_token")) { - data.setStatus("auth.working"); - return authenticateFromMSTokens(response.get("access_token").getAsString(), - response.get("refresh_token").getAsString()) - .thenAccept(o -> { - o.ifPresent(a -> { - int index = accounts.getAccounts().indexOf(a); - if (index == -1) { - accounts.getAccounts().add(a); - } else { - accounts.getAccounts().set(index, a); - } - accounts.login(a); - accounts.save(); - data.setStatus("auth.finished"); - }); - }).join(); - } - - if (response.has("error")) { - String error = response.get("error").getAsString(); - switch (error) { - case "authorization_pending": - continue; - case "bad_verification_code": - throw new IllegalStateException("Bad verification code! " + response); - case "authorization_declined": - case "expired_token": - default: - break; - } - } - } - } - return null; - }); - } - - private CompletableFuture> authenticateFromMSTokens(String accessToken, String refreshToken) { - return CompletableFuture.supplyAsync(() -> { - logger.debug("getting xbl token... "); - XblData xbl = authXbl(accessToken).join(); - logger.debug("getting xsts token..."); - XblData xsts = authXstsMC(xbl.token()).join(); - logger.debug("getting mc auth token..."); - MCXblData mc = authMC(xsts.displayClaims().uhs(), xsts.token()).join(); - - JsonObject profileJson = getMCProfile(mc.accessToken()).join(); - if (profileJson.has("error") && "NOT_FOUND".equals(profileJson.get("error").getAsString())) { - AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("auth.notif.login.failed", "auth.notif.login.failed.no_profile"); - return Optional.empty(); - } - logger.debug("retrieving entitlements..."); - if (!checkOwnership(mc.accessToken()).join()) { - AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("auth.notif.login.failed", "auth.notif.login.failed.no_entitlement"); - logger.warn("Failed to check for game ownership!"); - return Optional.empty(); - } - logger.debug("getting profile..."); - MCProfile profile = MCProfile.get(profileJson); - return Optional.of(new Account(profile.name(), profile.id(), mc.accessToken(), mc.expiration(), refreshToken, accessToken)); - }); - } - - private record MCProfile(String id, String name, List skins, List capes) { - public static MCProfile get(JsonObject json) { - return new MCProfile(json.get("id").getAsString(), json.get("name").getAsString(), - GsonHelper.jsonArrayToStream(json.getAsJsonArray("skins")) - .map(s -> Skin.get(s.getAsJsonObject())) - .toList(), GsonHelper.jsonArrayToStream(json.getAsJsonArray("capes")) - .map(s -> Cape.get(s.getAsJsonObject())) - .toList()); - } - - public record Skin(String id, String state, String url, String variant, String textureKey) { - public static Skin get(JsonObject object) { - return new Skin(object.get("id").getAsString(), - object.get("state").getAsString(), - object.get("url").getAsString(), - object.get("variant").getAsString(), - object.get("textureKey").getAsString()); - } - } - - public record Cape(String id, String state, String url, String alias) { - public static Cape get(JsonObject object) { - return new Cape(object.get("id").getAsString(), object.get("state").getAsString(), object.get("url").getAsString(), object.get("alias").getAsString()); - } - } - - } - - private CompletableFuture authXbl(String code) { - JsonObject object = new JsonObject(); - JsonObject properties = new JsonObject(); - properties.addProperty("AuthMethod", "RPS"); - properties.addProperty("SiteName", "user.auth.xboxlive.com"); - properties.addProperty("RpsTicket", "d=" + code); - object.add("Properties", properties); - object.addProperty("RelyingParty", "http://auth.xboxlive.com"); - object.addProperty("TokenType", "JWT"); - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() - .uri(URI.create(XBL_AUTH_URL)) - .POST(HttpRequest.BodyPublishers.ofString(object.toString())) - .header("Content-Type", "application/json") - .header("Accept", "application/json"); - - return requestJson(requestBuilder.build()).thenApply(response -> new XblData(Instant.parse(response.get("IssueInstant").getAsString()), Instant.parse(response.get("NotAfter").getAsString()), - response.get("Token").getAsString(), new XblData.DisplayClaims(response.get("DisplayClaims").getAsJsonObject().get("xui").getAsJsonArray().get(0).getAsJsonObject().get("uhs").getAsString()))); - } - - private record XblData(Instant issueInstant, Instant notAfter, String token, DisplayClaims displayClaims) { - private record DisplayClaims(String uhs) { - } - } - - private CompletableFuture authXstsMC(String xblToken) { - String body = "{" + - " \"Properties\": {" + - " \"SandboxId\": \"RETAIL\"," + - " \"UserTokens\": [" + - " \"" + xblToken + "\"" + - " ]" + - " }," + - " \"RelyingParty\": \"rp://api.minecraftservices.com/\"," + - " \"TokenType\": \"JWT\"" + - " }"; - return requestJson(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(body)).uri(URI.create(XBL_XSTS_AUTH_URL)).build()) - .thenApply(response -> new XblData(Instant.parse(response.get("IssueInstant").getAsString()), Instant.parse(response.get("NotAfter").getAsString()), - response.get("Token").getAsString(), new XblData.DisplayClaims(response.get("DisplayClaims").getAsJsonObject().get("xui").getAsJsonArray().get(0).getAsJsonObject().get("uhs").getAsString()))); - } - - private CompletableFuture authMC(String userhash, String xsts) { - String body = "{\"identityToken\": \"XBL3.0 x=" + userhash + ";" + xsts + "\"\n}"; - return requestJson(HttpRequest.newBuilder(URI.create(MC_LOGIN_WITH_XBOX_URL)).POST(HttpRequest.BodyPublishers.ofString(body)).build()) - .thenApply(response -> new MCXblData(response.get("username").getAsString(), - response.get("access_token").getAsString(), - Instant.now().plus(response.get("expires_in").getAsLong(), ChronoUnit.SECONDS))); - } - - private record MCXblData(String username, String accessToken, Instant expiration) { - } - - private CompletableFuture checkOwnership(String accessToken) { - return requestJson(HttpRequest - .newBuilder(URI.create("https://api.minecraftservices.com/entitlements/mcstore")) - .header("Authorization", "Bearer " + accessToken).build()) - .thenApply(res -> GsonHelper.jsonArrayToStream(res.get("items").getAsJsonArray()) - .anyMatch(e -> e.isJsonObject() && e.getAsJsonObject().has("name") - && "game_minecraft".equals(e.getAsJsonObject().get("name").getAsString()))); - } - - private CompletableFuture getMCProfile(String accessToken) { - return requestJson(HttpRequest.newBuilder().GET() - .uri(URI.create("https://api.minecraftservices.com/minecraft/profile")) - .header("Authorization", "Bearer " + accessToken).build()); - } - - private HttpClient getHttpClient() { - return NetworkUtil.createHttpClient(); - } - - public CompletableFuture> refreshToken(String token, Account account) { - return CompletableFuture.supplyAsync(() -> { - logger.debug("refreshing auth code... "); - HttpRequest.Builder requestBuilder = HttpRequest - .newBuilder(URI.create(MS_TOKEN_LOGIN_URL)) - .POST(FormBodyPublisher.newBuilder() - .query("client_id", CLIENT_ID) - .query("refresh_token", token) - .query("scope", SCOPES) - .query("grant_type", "refresh_token").build()) - .header("Accept", "application/json"); - - JsonObject response = requestJson(requestBuilder.build()).join(); - - if (response.has("error_codes")) { - int errorCode = response.get("error_codes").getAsJsonArray().get(0).getAsInt(); - if (errorCode == 70000 || errorCode == 70012) { - accounts.showAccountsExpiredScreen(account); - } else { - logger.warn("Login error, unexpected response: " + response); - AxolotlClientCommon.getInstance().getNotificationProvider().addStatus("auth.notif.refresh.error", "auth.notif.refresh.error.unexpected_response"); - } - return Optional.empty(); - } - - logger.debug("authenticating..."); - Optional opt = authenticateFromMSTokens(response.get("access_token").getAsString(), - response.get("refresh_token").getAsString()).join(); - opt.ifPresent(refreshed -> { - account.setRefreshToken(refreshed.getRefreshToken()); - account.setAuthToken(refreshed.getAuthToken()); - account.setName(refreshed.getName()); - account.setMsaToken(refreshed.getMsaToken()); - account.setExpiration(refreshed.getExpiration()); - accounts.save(); - }); - return opt; - }); - } - - private CompletableFuture requestJson(HttpRequest request) { - return client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) - .thenApply(res -> GsonHelper.fromJson(res.body())); - } -} diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Asset.java b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Asset.java new file mode 100644 index 000000000..42c953c43 --- /dev/null +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Asset.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; + +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.MSApi; + +public interface Asset { + + byte[] image(); + + boolean active(); + + CompletableFuture equip(MSApi api, Account account); + + String sha256(); + + interface Local extends Asset { + Path file(); + } + + interface Online extends Asset { + String url(); + + default boolean supportsDownload() { + return false; + } + } +} diff --git a/1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Cape.java similarity index 78% rename from 1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java rename to common/src/main/java/io/github/axolotlclient/modules/auth/skin/Cape.java index 5b8aff747..d1e823236 100644 --- a/1.21.7/src/main/java/io/github/axolotlclient/util/events/impl/PlayerDirectionChangeEvent.java +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Cape.java @@ -1,5 +1,5 @@ /* - * Copyright © 2024 moehreag & Contributors + * Copyright © 2025 moehreag & Contributors * * This file is part of AxolotlClient. * @@ -20,13 +20,9 @@ * For more information, see the LICENSE file. */ -package io.github.axolotlclient.util.events.impl; - -import lombok.Data; - -@Data -public class PlayerDirectionChangeEvent { - - private final float prevPitch, prevYaw, pitch, yaw; +package io.github.axolotlclient.modules.auth.skin; +public interface Cape extends Asset.Online { + String id(); + String alias(); } diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Skin.java b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Skin.java new file mode 100644 index 000000000..ce7f8b9ed --- /dev/null +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/Skin.java @@ -0,0 +1,303 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +import com.google.common.hash.Hashing; +import io.github.axolotlclient.api.util.UUIDHelper; +import io.github.axolotlclient.modules.auth.Account; +import io.github.axolotlclient.modules.auth.MSApi; +import io.github.axolotlclient.util.GsonHelper; +import io.github.axolotlclient.util.NetworkUtil; +import org.jetbrains.annotations.NotNull; + +public interface Skin extends Asset { + boolean classicVariant(); + + void classicVariant(boolean classic); + + interface Local extends Skin, Asset.Local { + + } + + interface Online extends Skin, Asset.Online { + } + + final class LocalSkin implements Local { + public static final String META_DIR = ".meta"; + public static final String METADATA_SUFFIX = ".meta"; + public static final String CLASSIC_METADATA_KEY = "variant_classic"; + private boolean classic; + private final Path file; + private final byte[] data; + private final String textureKey; + + public LocalSkin(boolean classic, Path file, byte[] image, String textureKey) { + this.classic = classic; + this.file = file; + this.data = image; + this.textureKey = textureKey; + } + + @SuppressWarnings("unchecked") + public static Map readMetadata(Path skinFile) throws IOException { + var metadataFile = getMetadataFile(skinFile); + if (!Files.exists(metadataFile)) return null; + + try (var in = Files.newInputStream(metadataFile)) { + return (Map) GsonHelper.read(in); + } + } + + public static void writeMetadata(Path skinFile, Map metadata) throws IOException { + var metadataFile = getMetadataFile(skinFile); + Files.createDirectories(metadataFile.getParent()); + try (var out = Files.newOutputStream(metadataFile); + var writer = new OutputStreamWriter(out)) { + GsonHelper.GSON.toJson(metadata, writer); + } + } + + public static void deleteMetadata(Path skinFile) throws IOException { + Files.deleteIfExists(getMetadataFile(skinFile)); + } + + private static @NotNull Path getMetadataFile(Path skinFile) { + return skinFile.resolveSibling(META_DIR).resolve(skinFile.getFileName().toString() + METADATA_SUFFIX); + } + + @Override + public boolean classicVariant() { + return classic; + } + + @Override + public void classicVariant(boolean classic) { + if (classic != this.classic) { + try { + var metadata = readMetadata(file()); + if (metadata == null) metadata = new HashMap<>(); + metadata.put(CLASSIC_METADATA_KEY, classic); + writeMetadata(file(), metadata); + } catch (IOException ignored) { + } + } + this.classic = classic; + } + + @Override + public byte[] image() { + return data; + } + + @Override + public boolean active() { + return false; + } + + @Override + public CompletableFuture equip(MSApi api, Account account) { + return api.uploadAndSetSkin(account, this); + } + + @Override + public Path file() { + return file; + } + + @Override + public String sha256() { + return textureKey; + } + } + + record Shared(Skin.Local local, MSApi.MCProfile.OnlineSkin online) implements Local, Online { + + @Override + public boolean classicVariant() { + return local.classicVariant(); + } + + @Override + public void classicVariant(boolean classic) { + local.classicVariant(classic); + } + + @Override + public byte[] image() { + return local.image(); + } + + @Override + public boolean active() { + return online.active(); + } + + @Override + public CompletableFuture equip(MSApi api, Account account) { + return online.equip(api, account); + } + + @Override + public String sha256() { + return online.sha256(); + } + + @Override + public Path file() { + return local.file(); + } + + @Override + public String url() { + return online.url(); + } + + @Override + public boolean supportsDownload() { + return true; + } + } + + static Skin getDefaultSkin(Account account) { + return getDefaultSkin(UUIDHelper.fromUndashed(account.getUuid())); + } + + static Skin getDefaultSkin(UUID uuid) { + return DefaultSkin.get(uuid); + } +} + +record DefaultSkin(String name, String stringUrl, URI url, boolean wide) { + private static final HttpClient client = NetworkUtil.createHttpClient(); + private static final Map DEFAULT_SKIN_CACHE = new HashMap<>(); + + DefaultSkin(String name, String url, boolean wide) { + this(name, url, URI.create(url), wide); + } + + private static final DefaultSkin[] SKINS = new DefaultSkin[]{ + new DefaultSkin("alex", "https://minecraft.wiki/images/Alex_%28slim_texture%29_JE3.png", false), + new DefaultSkin("ari", "https://minecraft.wiki/images/Ari_%28slim_texture%29_JE1.png", false), + new DefaultSkin("efe", "https://minecraft.wiki/images/Efe_%28slim_texture%29_JE1.png", false), + new DefaultSkin("kai", "https://minecraft.wiki/images/Kai_%28slim_texture%29_JE1.png", false), + new DefaultSkin("makena", "https://minecraft.wiki/images/Makena_%28slim_texture%29_JE1.png", false), + new DefaultSkin("noor", "https://minecraft.wiki/images/Noor_%28slim_texture%29_JE1.png", false), + new DefaultSkin("steve", "https://minecraft.wiki/images/Steve_%28slim_texture%29_JE2.png", false), + new DefaultSkin("sunny", "https://minecraft.wiki/images/Sunny_%28slim_texture%29_JE1.png", false), + new DefaultSkin("zuri", "https://minecraft.wiki/images/Zuri_%28slim_texture%29_JE1.png", false), + new DefaultSkin("alex", "https://minecraft.wiki/images/Alex_%28classic_texture%29_JE2.png", true), + new DefaultSkin("ari", "https://minecraft.wiki/images/Ari_%28classic_texture%29_JE1.png", true), + new DefaultSkin("efe", "https://minecraft.wiki/images/Efe_%28classic_texture%29_JE1.png", true), + new DefaultSkin("kai", "https://minecraft.wiki/images/Kai_%28classic_texture%29_JE1.png", true), + new DefaultSkin("makena", "https://minecraft.wiki/images/Makena_%28classic_texture%29_JE1.png", true), + new DefaultSkin("noor", "https://minecraft.wiki/images/Noor_%28classic_texture%29_JE1.png", true), + new DefaultSkin("steve", "https://minecraft.wiki/images/Steve_%28classic_texture%29_JE6.png", true), + new DefaultSkin("sunny", "https://minecraft.wiki/images/Sunny_%28classic_texture%29_JE1.png", true), + new DefaultSkin("zuri", "https://minecraft.wiki/images/Zuri_%28classic_texture%29_JE1.png", true) + }; + + @SuppressWarnings("UnstableApiUsage") + public Skin getSkin() { + return DEFAULT_SKIN_CACHE.computeIfAbsent(this, unused -> { + var wrapper = new Skin.Online() { + private DefaultSkin wrapped = DefaultSkin.this; + private byte[] data = null; + private String hash = null; + + private void load() { + data = client.sendAsync(HttpRequest.newBuilder().GET().uri(wrapped.url()).build(), HttpResponse.BodyHandlers.ofByteArray()) + .thenApply(HttpResponse::body).join(); + hash = Hashing.sha256().hashBytes(data).toString(); + } + + @Override + public boolean classicVariant() { + return wrapped.wide(); + } + + @Override + public void classicVariant(boolean classic) { + int i = switch (name()) { + case "alex" -> 0; + case "ari" -> 1; + case "efe" -> 2; + case "kai" -> 3; + case "makena" -> 4; + case "noor" -> 5; + case "steve" -> 6; + case "sunny" -> 7; + case "zuri" -> 8; + default -> throw new IllegalStateException(); + }; + if (classic) i += 9; + wrapped = SKINS[i]; + load(); + } + + @Override + public byte[] image() { + return data; + } + + @Override + public boolean active() { + return false; + } + + @Override + public CompletableFuture equip(MSApi api, Account account) { + return api.setSkin(account, this); + } + + @Override + public String sha256() { + return hash; + } + + @Override + public String url() { + return wrapped.stringUrl(); + } + }; + wrapper.load(); + return wrapper; + }); + } + + static Skin get(UUID uuid) { + return SKINS[Math.floorMod(uuid.hashCode(), SKINS.length)].getSkin(); + } +} diff --git a/common/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinImportUtil.java b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinImportUtil.java new file mode 100644 index 000000000..a2a8fc8e4 --- /dev/null +++ b/common/src/main/java/io/github/axolotlclient/modules/auth/skin/SkinImportUtil.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.modules.auth.skin; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.loader.api.FabricLoader; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.util.tinyfd.TinyFileDialogs; + +public class SkinImportUtil { + public static CompletableFuture> openImportSkinDialog() { + return CompletableFuture.supplyAsync(() -> { + try (MemoryStack stack = MemoryStack.stackPush()) { + var pointers = stack.pointers(stack.UTF8("*.png")); + @SuppressWarnings("DataFlowIssue") var result = TinyFileDialogs.tinyfd_openFileDialog("Import Skins", + FabricLoader.getInstance().getGameDir().toString(), pointers, null, true); + if (result != null) { + return Arrays.stream(result.split("\\|")) + .map(Path::of).toList(); + } + return List.of(); + } + }); + } +} diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/HudManagerCommon.java b/common/src/main/java/io/github/axolotlclient/modules/hud/HudManagerCommon.java index 99a4999f9..c253a5cc3 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/HudManagerCommon.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/HudManagerCommon.java @@ -62,15 +62,15 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public abstract class HudManagerCommon extends AbstractCommonModule implements ProfileAware { @Getter private static HudManagerCommon instance; private final static String CUSTOM_MODULE_SAVE_FILE_NAME = "custom_hud.json"; - private final AxoKeybinding key = AxoKeybinding.create(AxoKeys.KEY_RSHIFT, "key.openHud", "category.axolotlclient"); - private final AxoKeybinding toggleHud = AxoKeybinding.create(AxoKeys.KEY_UNKNOWN, "key.toggle_hud", "category.axolotlclient"); + private final AxoKeybinding key = AxoKeybinding.create(AxoKeys.KEY_RSHIFT, "key.openHud"); + private final AxoKeybinding toggleHud = AxoKeybinding.create(AxoKeys.KEY_UNKNOWN, "key.toggle_hud"); private final OptionCategory hudCategory = OptionCategory.create("hud"); private final BooleanOption enabled = new BooleanOption("enabled", true); private final Map entries; @@ -216,6 +216,7 @@ public final HudManagerCommon add(AbstractHudEntry entry) { return this; } + @SuppressWarnings("UnusedReturnValue") public final HudManagerCommon addNonConfigured(AbstractHudEntry entry) { entries.put(entry.getId(), entry); return this; @@ -252,7 +253,7 @@ public boolean hudsEnabled() { public void render(AxoRenderContext context, float delta) { if (!hudsEnabled()) return; for (HudEntry hud : getEntries()) { - if (hud.isEnabled()) { + if (hud.isEnabled() && !hud.isHidden()) { hud.render(context, delta); } } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Configurable.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Configurable.java index 31c74ed57..7fafdc8b3 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Configurable.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Configurable.java @@ -31,7 +31,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public interface Configurable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/DynamicallyPositionable.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/DynamicallyPositionable.java index 3026d720e..202c64dd0 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/DynamicallyPositionable.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/DynamicallyPositionable.java @@ -28,7 +28,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*

* Represents an object that width/height can change and it can react accordingly */ diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/HudEntry.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/HudEntry.java index 01cdf1f9c..18a911edc 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/HudEntry.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/HudEntry.java @@ -28,7 +28,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public interface HudEntry extends Identifiable, Configurable, Positionable { @@ -66,4 +66,8 @@ default double getDefaultY() { void setHovered(boolean hovered); boolean isHovered(); + + boolean isHidden(); + + boolean supportsScaling(); } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Identifiable.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Identifiable.java index 608c68bf1..8a01b4622 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Identifiable.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Identifiable.java @@ -29,7 +29,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*

* An interface that represents an object that contains an Identifier, as well as ways to translate itself into a */ diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Positionable.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Positionable.java index cbcae933b..46962e8e6 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Positionable.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/component/Positionable.java @@ -29,7 +29,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public interface Positionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/AbstractHudEntry.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/AbstractHudEntry.java index 73b10fe70..67762dc84 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/AbstractHudEntry.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/AbstractHudEntry.java @@ -28,6 +28,7 @@ import io.github.axolotlclient.AxolotlClientConfig.api.options.Option; import io.github.axolotlclient.AxolotlClientConfig.api.options.OptionCategory; import io.github.axolotlclient.AxolotlClientConfig.api.util.Colors; +import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; import io.github.axolotlclient.AxolotlClientConfig.impl.options.DoubleOption; import io.github.axolotlclient.bridge.AxoMinecraftClient; import io.github.axolotlclient.bridge.render.AxoRenderContext; @@ -46,13 +47,14 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public abstract class AbstractHudEntry implements HudEntry { @Getter protected final ForceableBooleanOption enabled = DefaultOptions.getEnabled(); protected final DoubleOption scale = DefaultOptions.getScale(this); protected final AxoMinecraftClient client = AxoMinecraftClient.getInstance(); + protected final BooleanOption hide = new BooleanOption("hud.hide", false); private final DoubleOption x = DefaultOptions.getX(getDefaultX(), this); private final DoubleOption y = DefaultOptions.getY(getDefaultY(), this); @Setter @@ -64,6 +66,7 @@ public abstract class AbstractHudEntry implements HudEntry { @Setter @Getter protected boolean hovered = false; + protected boolean supportsScaling = true; @Getter private Rectangle trueBounds; private Rectangle renderBounds; @@ -146,7 +149,7 @@ public Rectangle getBounds() { return renderBounds; } - public void setBounds(float scale) { + public void setBounds() { final var window = AxoWindow.getWindow(); if (window == null) { @@ -212,10 +215,6 @@ public void onBoundsUpdate() { setBounds(); } - public void setBounds() { - setBounds(getScale()); - } - public OptionCategory getAllOptions() { if (category == null) { List> options = getSaveOptions(); @@ -266,4 +265,13 @@ public void setEnabled(boolean value) { enabled.set(value); } + @Override + public boolean isHidden() { + return hide.get(); + } + + @Override + public boolean supportsScaling() { + return supportsScaling; + } } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/BoxHudEntry.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/BoxHudEntry.java index 887fc3382..ad896bb9a 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/BoxHudEntry.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/BoxHudEntry.java @@ -35,7 +35,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public abstract class BoxHudEntry extends AbstractHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/SimpleTextHudEntry.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/SimpleTextHudEntry.java index ddb9b66eb..3962de185 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/SimpleTextHudEntry.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/SimpleTextHudEntry.java @@ -41,7 +41,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public abstract class SimpleTextHudEntry extends TextHudEntry implements DynamicallyPositionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/TextHudEntry.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/TextHudEntry.java index da2dc7d3c..756051de4 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/TextHudEntry.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/entry/TextHudEntry.java @@ -34,7 +34,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public abstract class TextHudEntry extends BoxHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CompassHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CompassHud.java index 21c13c280..f83fc1e0f 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CompassHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CompassHud.java @@ -41,7 +41,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CompassHud extends TextHudEntry implements DynamicallyPositionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CoordsHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CoordsHud.java index e9a54c45e..893784ab6 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CoordsHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/CoordsHud.java @@ -42,7 +42,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CoordsHud extends TextHudEntry implements DynamicallyPositionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IPHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IPHud.java index 86ba85cc2..521a1a76f 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IPHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IPHud.java @@ -42,7 +42,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class IPHud extends TextHudEntry implements DynamicallyPositionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IconHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IconHud.java index 5aa96e795..98fe988b1 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IconHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/IconHud.java @@ -22,13 +22,19 @@ package io.github.axolotlclient.modules.hud.gui.hud; +import java.util.List; +import java.util.Locale; + +import io.github.axolotlclient.AxolotlClientConfig.api.options.Option; +import io.github.axolotlclient.AxolotlClientConfig.impl.options.EnumOption; import io.github.axolotlclient.bridge.render.AxoRenderContext; import io.github.axolotlclient.bridge.render.AxoSprites; import io.github.axolotlclient.bridge.util.AxoIdentifier; import io.github.axolotlclient.modules.hud.gui.entry.BoxHudEntry; public class IconHud extends BoxHudEntry { - private static final AxoIdentifier ID = AxoIdentifier.of("axolotlclient", "iconhud"); + public static final AxoIdentifier ID = AxoIdentifier.of("axolotlclient", "iconhud"); + private final EnumOption mode = new EnumOption<>("iconhud.mode", Mode.class, Mode.BOTH); public IconHud() { super(16, 16, false); @@ -39,6 +45,19 @@ public AxoIdentifier getId() { return ID; } + @Override + public void render(AxoRenderContext ctx, float delta) { + if (client.br$getScreen() == null && mode.get().showsInGame()) { + super.render(ctx, delta); + } + } + + public void renderInGui(AxoRenderContext context, float delta) { + if (mode.get().showsInGui()) { + super.render(context, delta); + } + } + @Override public void renderComponent(AxoRenderContext ctx, float delta) { ctx.br$glColor4(1, 1, 1, 1); @@ -51,4 +70,41 @@ public void renderComponent(AxoRenderContext ctx, float delta) { public void renderPlaceholderComponent(AxoRenderContext ctx, float delta) { renderComponent(ctx, delta); } + + @Override + public List> getConfigurationOptions() { + var options = super.getConfigurationOptions(); + options.add(mode); + return options; + } + + private enum Mode { + IN_GAME(){ + @Override + public boolean showsInGui() { + return false; + } + }, + GUI(){ + @Override + public boolean showsInGame() { + return false; + } + }, + BOTH; + + public boolean showsInGame() { + return true; + } + + public boolean showsInGui() { + return true; + } + + + @Override + public String toString() { + return "iconhud.mode."+super.toString().toLowerCase(Locale.ROOT); + } + } } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MemoryHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MemoryHud.java index d4b18fb58..1078a836c 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MemoryHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MemoryHud.java @@ -44,7 +44,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class MemoryHud extends TextHudEntry implements DynamicallyPositionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MouseMovementHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MouseMovementHud.java index 84b36a6c2..3677c33fe 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MouseMovementHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/MouseMovementHud.java @@ -27,6 +27,8 @@ import io.github.axolotlclient.AxolotlClientConfig.api.options.Option; import io.github.axolotlclient.AxolotlClientConfig.impl.options.GraphicsOption; import io.github.axolotlclient.bridge.Platform; +import io.github.axolotlclient.bridge.events.Events; +import io.github.axolotlclient.bridge.events.types.PlayerDirectionChangeEvent; import io.github.axolotlclient.bridge.render.AxoRenderContext; import io.github.axolotlclient.bridge.util.AxoIdentifier; import io.github.axolotlclient.modules.hud.gui.entry.BoxHudEntry; @@ -64,39 +66,25 @@ public class MouseMovementHud extends BoxHudEntry { private float lastMouseX = 0; private float lastMouseY = 0; - private boolean hasPreviousPitchYaw = false; - private float prevPitch = 0; - private float prevYaw = 0; - public MouseMovementHud() { super(53, 35, true); + Events.PLAYER_DIRECTION_CHANGE.register(this::onPlayerDirectionChange); + } + + public void onPlayerDirectionChange(PlayerDirectionChangeEvent event) { + // Implementation credit goes to TheKodeToad + // This project has the author's approval to use this + // https://github.com/Sol-Client/Client/blob/main/game/src/main/java/io/github/solclient/client/mod/impl/hud/keystrokes/KeystrokesMod.java + mouseX += (event.yaw() - event.prevYaw()) / 7F; + mouseY += (event.pitch() - event.prevPitch()) / 7F; + // 0, 0 will be the center of the HUD element + float halfWidth = getWidth() / 2f; + mouseX = MathUtil.clamp(mouseX, -halfWidth + 4, halfWidth - 4); + mouseY = MathUtil.clamp(mouseY, -13, 13); } - // Implementation credit goes to TheKodeToad - // This project has the author's approval to use this - // https://github.com/Sol-Client/Client/blob/main/game/src/main/java/io/github/solclient/client/mod/impl/hud/keystrokes/KeystrokesMod.java - // Port to Bridge: removed event and poll pitch/yaw in renderComponent @Override public void renderComponent(AxoRenderContext context, float delta) { - final var player = client.br$getPlayer(); - - if(player != null) { - if (hasPreviousPitchYaw) { - mouseX = (player.br$getYaw() - prevYaw); - mouseY = (player.br$getPitch() - prevPitch); - prevPitch = player.br$getPitch(); - prevYaw = player.br$getYaw(); - - float halfWidth = getWidth() / 2f; - mouseX = MathUtil.clamp(mouseX, -halfWidth + 4, halfWidth - 4); - mouseY = MathUtil.clamp(mouseY, -13, 13); - } else { - hasPreviousPitchYaw = true; - prevPitch = player.br$getPitch(); - prevYaw = player.br$getYaw(); - } - } - context.br$glColor4(1, 1, 1, 1); context.br$glEnableBlend(); int spaceY = getRawY(); diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PotionsHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PotionsHud.java index 9f36373f0..69de20f45 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PotionsHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/PotionsHud.java @@ -46,7 +46,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class PotionsHud extends TextHudEntry implements DynamicallyPositionable { public static final AxoIdentifier ID = AxoIdentifier.of("kronhud", "potionshud"); diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArmorHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArmorHud.java index dd6016374..6fa522cea 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArmorHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArmorHud.java @@ -47,7 +47,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ArmorHud extends TextHudEntry implements DynamicallyPositionable { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArrowHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArrowHud.java index f19bc6287..e4ff6e3eb 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArrowHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ArrowHud.java @@ -43,7 +43,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ArrowHud extends TextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ItemUpdateHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ItemUpdateHud.java index 094886924..1596f4162 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ItemUpdateHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/item/ItemUpdateHud.java @@ -43,7 +43,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ItemUpdateHud extends TextHudEntry { public static final AxoIdentifier ID = AxoIdentifier.of("kronhud", "itemupdatehud"); diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/CPSHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/CPSHud.java index 17a4fff78..7a8a56e6d 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/CPSHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/CPSHud.java @@ -34,7 +34,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class CPSHud extends SimpleTextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ComboHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ComboHud.java index a27b33664..9e4974291 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ComboHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ComboHud.java @@ -32,7 +32,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ComboHud extends SimpleTextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/FPSHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/FPSHud.java index 04501d839..ed3e93e79 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/FPSHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/FPSHud.java @@ -30,7 +30,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class FPSHud extends SimpleTextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/IRLTimeHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/IRLTimeHud.java index e7fba7b8a..18581ac7c 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/IRLTimeHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/IRLTimeHud.java @@ -36,7 +36,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class IRLTimeHud extends SimpleTextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PingHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PingHud.java index 8d0ef8170..558ed9e3b 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PingHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PingHud.java @@ -29,13 +29,14 @@ import io.github.axolotlclient.bridge.PlatformDispatch; import io.github.axolotlclient.bridge.util.AxoIdentifier; import io.github.axolotlclient.modules.hud.gui.entry.SimpleTextHudEntry; +import io.github.axolotlclient.util.ThreadExecuter; import org.apache.commons.lang3.mutable.MutableInt; /** * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ // TODO: figure out how to implement this logic without exposing everything to bridge @@ -63,8 +64,8 @@ public boolean tickable() { @Override public void tick() { if (second >= refreshDelay.get() * 20) { - PlatformDispatch.pingHud$updatePing(currentServerPing); second = 0; + ThreadExecuter.scheduleTask(() -> PlatformDispatch.pingHud$updatePing(currentServerPing)); } else { second++; } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PlayerCountHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PlayerCountHud.java index 89b564096..ff2c0625b 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PlayerCountHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/PlayerCountHud.java @@ -30,7 +30,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class PlayerCountHud extends SimpleTextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/SpeedHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/SpeedHud.java index 26420b988..b5a6fb38b 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/SpeedHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/SpeedHud.java @@ -39,7 +39,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class SpeedHud extends SimpleTextHudEntry { private static final AxoIdentifier ID = AxoIdentifier.of("kronhud", "speedhud"); diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/TPSHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/TPSHud.java index b5ed4d093..caadf085b 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/TPSHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/TPSHud.java @@ -33,7 +33,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class TPSHud extends SimpleTextHudEntry { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ToggleSprintHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ToggleSprintHud.java index 134699808..0484a2fdd 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ToggleSprintHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/simple/ToggleSprintHud.java @@ -43,7 +43,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ public class ToggleSprintHud extends SimpleTextHudEntry { @@ -54,8 +54,8 @@ public class ToggleSprintHud extends SimpleTextHudEntry { private final BooleanOption randomPlaceholder = new BooleanOption("randomPlaceholder", false); private final StringOption placeholder = new StringOption("placeholder", "No keys pressed"); - private final AxoKeybinding sprintToggle = AxoKeybinding.create(AxoKeys.KEY_K, "key.toggleSprint", "category.axolotlclient"); - private final AxoKeybinding sneakToggle = AxoKeybinding.create(AxoKeys.KEY_I, "key.toggleSneak", "category.axolotlclient"); + private final AxoKeybinding sprintToggle = AxoKeybinding.create(AxoKeys.KEY_K, "key.toggleSprint"); + private final AxoKeybinding sneakToggle = AxoKeybinding.create(AxoKeys.KEY_I, "key.toggleSneak"); @Getter private final BooleanOption sprintToggled = new BooleanOption("sprintToggled", false); @@ -71,8 +71,8 @@ public ToggleSprintHud() { @Override public void init() { - sprintToggle.br$registerOnConsumeClick(sprintToggled::toggle); - sneakToggle.br$registerOnConsumeClick(sneakToggled::toggle); + sprintToggle.br$registerOnConsumeClick(() -> sprintToggled.set(toggleSprint.get() && !sprintToggled.get())); + sneakToggle.br$registerOnConsumeClick(() -> sneakToggled.set(toggleSneak.get() && !sneakToggled.get())); } @Override diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/InventoryHud.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/InventoryHud.java index 43a44658a..369411311 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/InventoryHud.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/hud/vanilla/InventoryHud.java @@ -22,11 +22,15 @@ package io.github.axolotlclient.modules.hud.gui.hud.vanilla; +import java.util.Collections; import java.util.List; import java.util.stream.IntStream; import java.util.stream.Stream; import io.github.axolotlclient.AxolotlClientCommon; +import io.github.axolotlclient.AxolotlClientConfig.api.options.Option; +import io.github.axolotlclient.AxolotlClientConfig.impl.options.BooleanOption; +import io.github.axolotlclient.AxolotlClientConfig.impl.options.ColorOption; import io.github.axolotlclient.bridge.item.AxoItemStack; import io.github.axolotlclient.bridge.item.AxoItems; import io.github.axolotlclient.bridge.render.AxoRenderContext; @@ -54,6 +58,11 @@ public class InventoryHud extends BoxHudEntry implements DynamicallyPositionable private static final int ITEM_SIZE = 18; private static final int ITEM_TILE_SIZE = 16; + private final BooleanOption dynamic = new BooleanOption("dynamic", false); + private final BooleanOption itemBackground = new BooleanOption("inventoryhud.item_background", true); + private final ColorOption itemBackgroundColor = new ColorOption("inventoryhud.item_background_color", backgroundColor.getDefault()); + private final BooleanOption alwaysShowItemBackgrounds = new BooleanOption("inventoryhud.always_show_item_backgrounds", false); + public InventoryHud() { super(164, 56, true); } @@ -68,6 +77,22 @@ public double getDefaultY() { return 0.76; } + @Override + public void render(AxoRenderContext ctx, float delta) { + if (dynamic.get()) { + boolean render = false; + for (AxoItemStack stack : client.br$getPlayer().br$getInventory().br$getNonEquipmentItems()) { + if (stack != null && !stack.br$isEmpty()) { + render = true; + break; + } + } + + if (!render) return; + } + super.render(ctx, delta); + } + @Override public void renderComponent(AxoRenderContext graphics, float delta) { render(graphics, client.br$getPlayer().br$getInventory().br$getNonEquipmentItems()); @@ -85,17 +110,18 @@ private void render(AxoRenderContext graphics, List inve for (int i = 0, inventorySlotsLength = inventorySlots.size(); i < inventorySlotsLength; i++) { AxoItemStack stack = inventorySlots.get(i); - if (stack != null && !stack.br$isEmpty()) { - renderStack(graphics, x + (i % 9) * ITEM_SIZE, y + (i / 9) * ITEM_SIZE, stack); - } + //if (stack != null && !stack.br$isEmpty()) { + renderStack(graphics, x + (i % 9) * ITEM_SIZE, y + (i / 9) * ITEM_SIZE, stack); + //} } } - private void renderStack(AxoRenderContext graphics, int x, int y, AxoItemStack itemStack) { - if (background.get() && backgroundColor.get().getAlpha() > 0) { - graphics.br$fillRect(x, y, ITEM_TILE_SIZE, ITEM_TILE_SIZE, backgroundColor.get().toInt()); + var empty = itemStack == null || itemStack.br$isEmpty(); + if ((!empty || alwaysShowItemBackgrounds.get()) && itemBackground.get() && itemBackgroundColor.get().getAlpha() > 0) { + graphics.br$fillRect(x, y, ITEM_TILE_SIZE, ITEM_TILE_SIZE, itemBackgroundColor.get().toInt()); } + if (empty) return; graphics.br$renderGuiItemModel(itemStack, x, y); graphics.br$renderGuiItemOverlay(itemStack, x, y, null); @@ -110,4 +136,11 @@ public AxoIdentifier getId() { public AnchorPoint getAnchor() { return AnchorPoint.MIDDLE_MIDDLE; } + + @Override + public List> getConfigurationOptions() { + var options = super.getConfigurationOptions(); + Collections.addAll(options, hide, dynamic, itemBackground, itemBackgroundColor, alwaysShowItemBackgrounds); + return options; + } } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/AnchorPoint.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/AnchorPoint.java index eb9ad92e5..59cc17e67 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/AnchorPoint.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/AnchorPoint.java @@ -29,7 +29,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @AllArgsConstructor diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/CardinalOrder.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/CardinalOrder.java index 62da00834..736b2b335 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/CardinalOrder.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/CardinalOrder.java @@ -28,7 +28,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @Getter diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/Justification.java b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/Justification.java index b7ed4db66..281b79c1b 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/Justification.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/gui/layout/Justification.java @@ -30,7 +30,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @AllArgsConstructor diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/util/DefaultOptions.java b/common/src/main/java/io/github/axolotlclient/modules/hud/util/DefaultOptions.java index e4890c03f..77acb5e30 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/util/DefaultOptions.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/util/DefaultOptions.java @@ -34,7 +34,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @UtilityClass diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/util/DrawPosition.java b/common/src/main/java/io/github/axolotlclient/modules/hud/util/DrawPosition.java index eb55770de..93140635c 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/util/DrawPosition.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/util/DrawPosition.java @@ -29,7 +29,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ @Data diff --git a/common/src/main/java/io/github/axolotlclient/modules/hud/util/Rectangle.java b/common/src/main/java/io/github/axolotlclient/modules/hud/util/Rectangle.java index 4e57ff7ec..77913fdf6 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hud/util/Rectangle.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hud/util/Rectangle.java @@ -30,7 +30,7 @@ * This implementation of Hud modules is based on KronHUD. * Github Link. * - * @license GPL-3.0 + *

License: GPL-3.0

*/ /* diff --git a/common/src/main/java/io/github/axolotlclient/modules/hypixel/AutoGG.java b/common/src/main/java/io/github/axolotlclient/modules/hypixel/AutoGG.java index b6bb7200d..93383ec6c 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hypixel/AutoGG.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hypixel/AutoGG.java @@ -38,7 +38,7 @@ /** * Based on DragonEggBedrockBreaking's AutoGG Mod * - * @license MPL-2.0 + *

License: MPL-2.0

*/ public class AutoGG implements AbstractHypixelMod { @@ -159,7 +159,7 @@ private List addToList(String... strings) { private void onMessage(ReceiveChatMessageEvent event) { String message = event.getOriginalMessage(); - if (client.br$isLocalServer()) { + if (!client.br$isLocalServer()) { serverMap.keySet().forEach(s -> { if (serverMap.get(s).get() && client.br$getServerAddress().contains(s)) { if (gf.get()) { diff --git a/common/src/main/java/io/github/axolotlclient/modules/hypixel/ExpCalculator.java b/common/src/main/java/io/github/axolotlclient/modules/hypixel/ExpCalculator.java index 4d43e5758..69d2c4bd9 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hypixel/ExpCalculator.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hypixel/ExpCalculator.java @@ -78,7 +78,7 @@ public static int getTotalExpForLevel(float level) { if (level > easyLevelsCount) { float extraLevels = level - easyLevelsCount; - totalExp += (extraLevels * EXP_PER_LEVEL); + totalExp += (int) (extraLevels * EXP_PER_LEVEL); } return totalExp; } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hypixel/Skyblock.java b/common/src/main/java/io/github/axolotlclient/modules/hypixel/Skyblock.java index c7bc8f17e..055d69d84 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hypixel/Skyblock.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hypixel/Skyblock.java @@ -36,7 +36,7 @@ public class Skyblock implements AbstractHypixelMod { @Override public void init() { - AxoKeybinding.create(null, "lockRotation", "category.axolotlclient") + AxoKeybinding.create(null, "lockRotation") .br$registerOnConsumeClick(rotationLocked::toggle); } diff --git a/common/src/main/java/io/github/axolotlclient/modules/hypixel/bedwars/StatsOverlay.java b/common/src/main/java/io/github/axolotlclient/modules/hypixel/bedwars/StatsOverlay.java index b2e3a4e22..509e3d23d 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/hypixel/bedwars/StatsOverlay.java +++ b/common/src/main/java/io/github/axolotlclient/modules/hypixel/bedwars/StatsOverlay.java @@ -170,7 +170,7 @@ private static PlayerData.Bedwars createFake(int level, int winstreak, CombinedG private Map stats = new HashMap<>(); private final Map> playersByTeam = new EnumMap<>(BedwarsTeam.class); - private final AxoKeybinding toggle = AxoKeybinding.create(AxoKeys.KEY_UNKNOWN, "bedwars_stats_overlay", "category.axolotlclient"); + private final AxoKeybinding toggle = AxoKeybinding.create(AxoKeys.KEY_UNKNOWN, "bedwars_stats_overlay"); private boolean shouldRender = false; @Nullable private String errorMessage = null; diff --git a/common/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotCopying.java b/common/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotCopying.java index 3ba5f40fc..bd7f1eb47 100644 --- a/common/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotCopying.java +++ b/common/src/main/java/io/github/axolotlclient/modules/screenshotUtils/ScreenshotCopying.java @@ -29,41 +29,57 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import io.github.axolotlclient.AxolotlClientCommon; -import lombok.AllArgsConstructor; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; +import org.lwjgl.sdl.SDLClipboard; +import org.lwjgl.sdl.SDL_ClipboardCleanupCallback; +import org.lwjgl.sdl.SDL_ClipboardDataCallback; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; @UtilityClass public class ScreenshotCopying { static { - boolean wayland = false; + boolean sdl = false; try { - wayland = GLFW.glfwGetPlatform() == GLFW.GLFW_PLATFORM_WAYLAND; - } catch (Throwable ignored) { + Class.forName("org.lwjgl.sdl.SDL"); + sdl = true; + } catch (Throwable ignored) {} + SDL_AVAILABLE = sdl; + boolean wayland = false; + if (!sdl) { + try { + wayland = GLFW.glfwGetPlatform() == GLFW.GLFW_PLATFORM_WAYLAND; + } catch (Throwable ignored) { + } } IS_WAYLAND = wayland; } + private static final boolean SDL_AVAILABLE; private static final boolean IS_WAYLAND; public void copy(Path file) { - if (IS_WAYLAND) { - copyWayland(file); - } else { - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new FileTransferable(file.toFile()), null); + if (!SDL_AVAILABLE || !copySdl(file)) { + if (IS_WAYLAND) { + copyWayland(file); + } else { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new FileTransferable(file.toFile()), null); + } } } private void copyWayland(Path f) { try { - ProcessBuilder builder = new ProcessBuilder("bash", "-c", "wl-copy -t image/png < '" + f.toAbsolutePath()+"'"); + ProcessBuilder builder = new ProcessBuilder("bash", "-c", "wl-copy -t image/png < '" + f.toAbsolutePath() + "'"); Process p = builder.start(); p.waitFor(); } catch (IOException | InterruptedException ignored) { @@ -72,24 +88,50 @@ private void copyWayland(Path f) { } public void copy(byte[] image) { - if (IS_WAYLAND) { - try { - Path i = Files.createTempFile("axolotlclient_screenshot", ".png"); - Files.write(i, image); - copyWayland(i); - Files.delete(i); - } catch (IOException e) { - AxolotlClientCommon.getInstance().getLogger().error("Failed to copy image using temporary file!"); + if (!SDL_AVAILABLE || !SDLFence.copySdl(image)) { + if (IS_WAYLAND) { + try { + Path i = Files.createTempFile("axolotlclient_screenshot", ".png"); + Files.write(i, image); + copyWayland(i); + Files.delete(i); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().error("Failed to copy image using temporary file!"); + } + } else { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new ImageTransferable(image), null); } - } else { - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new ImageTransferable(image), null); } } - @AllArgsConstructor - protected static class ImageTransferable implements Transferable { - private final byte[] image; + private boolean copySdl(Path p) { + try { + return SDLFence.copySdl(Files.readAllBytes(p)); + } catch (IOException e) { + AxolotlClientCommon.getInstance().getLogger().error("Failed to read screenshot!", e); + } + return false; + } + + // Classloading fence... + static class SDLFence { + private static boolean copySdl(byte[] data) { + try (MemoryStack stack = MemoryStack.stackPush()) { + var mimetypesBuf = stack.UTF8("image/png"); + var mimetypes = stack.pointers(mimetypesBuf); + var dataBuf = ByteBuffer.allocateDirect(data.length).put(data).flip(); + var pointer = MemoryUtil.memAddress(dataBuf); + return SDLClipboard.SDL_SetClipboardData(SDL_ClipboardDataCallback.create((userdata, mime_type, size) -> { + var sizeBuf = MemoryUtil.memLongBuffer(size, 8); + sizeBuf.put(0, data.length); + return userdata; + }), + SDL_ClipboardCleanupCallback.create(userdata -> MemoryUtil.memFree(dataBuf)), pointer, mimetypes); + } + } + } + protected record ImageTransferable(byte[] image) implements Transferable { @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[]{DataFlavor.imageFlavor}; @@ -107,10 +149,7 @@ public Object getTransferData(DataFlavor flavor) throws IOException { } } - @AllArgsConstructor - protected static class FileTransferable implements Transferable { - private final File file; - + protected record FileTransferable(File file) implements Transferable { @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[]{DataFlavor.javaFileListFlavor}; @@ -122,7 +161,7 @@ public boolean isDataFlavorSupported(DataFlavor flavor) { } @Override - public Object getTransferData(DataFlavor flavor) { + public @NotNull Object getTransferData(DataFlavor flavor) { final ArrayList files = new ArrayList<>(); files.add(file); return files; diff --git a/common/src/main/java/io/github/axolotlclient/util/JsonBuilders.java b/common/src/main/java/io/github/axolotlclient/util/JsonBuilders.java new file mode 100644 index 000000000..157dc3cc3 --- /dev/null +++ b/common/src/main/java/io/github/axolotlclient/util/JsonBuilders.java @@ -0,0 +1,132 @@ +/* + * Copyright © 2025 moehreag & Contributors + * + * This file is part of AxolotlClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.util; + +import com.google.gson.JsonElement; + +public final class JsonBuilders { + public static final class JsonArray { + private final com.google.gson.JsonArray arr = new com.google.gson.JsonArray(); + + public static JsonArray create() { + return new JsonArray(); + } + + private JsonArray() { + } + + public JsonArray field(JsonElement ele) { + arr.add(ele); + return this; + } + + public JsonArray field(JsonArray builder) { + return field(builder.build()); + } + + public JsonArray field(JsonObject builder) { + return field(builder.build()); + } + + public JsonArray field(Number prop) { + arr.add(prop); + return this; + } + + public JsonArray field(String prop) { + arr.add(prop); + return this; + } + + public JsonArray field(Boolean prop) { + arr.add(prop); + return this; + } + + public JsonArray field(Character prop) { + arr.add(prop); + return this; + } + + public com.google.gson.JsonArray build() { + return arr; + } + + public String asString() { + return arr.toString(); + } + } + + public static final class JsonObject { + + private final com.google.gson.JsonObject obj = new com.google.gson.JsonObject(); + + public static JsonObject create() { + return new JsonObject(); + } + + private JsonObject() { + } + + public JsonObject field(String name, JsonElement ele) { + obj.add(name, ele); + return this; + } + + public JsonObject field(String name, JsonObject builder) { + return field(name, builder.build()); + } + + public JsonObject field(String name, JsonArray builder) { + return field(name, builder.build()); + } + + public JsonObject field(String name, Number prop) { + obj.addProperty(name, prop); + return this; + } + + public JsonObject field(String name, String prop) { + obj.addProperty(name, prop); + return this; + } + + public JsonObject field(String name, Boolean prop) { + obj.addProperty(name, prop); + return this; + } + + public JsonObject field(String name, Character prop) { + obj.addProperty(name, prop); + return this; + } + + public com.google.gson.JsonObject build() { + return obj; + } + + public String asString() { + return obj.toString(); + } + } +} diff --git a/common/src/main/java/io/github/axolotlclient/util/Watcher.java b/common/src/main/java/io/github/axolotlclient/util/Watcher.java index e01b81bbd..fd450696e 100644 --- a/common/src/main/java/io/github/axolotlclient/util/Watcher.java +++ b/common/src/main/java/io/github/axolotlclient/util/Watcher.java @@ -27,6 +27,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import io.github.axolotlclient.AxolotlClientCommon; import org.jetbrains.annotations.Nullable; @@ -36,21 +37,15 @@ public class Watcher implements AutoCloseable { private static final ScheduledExecutorService thread = Executors.newSingleThreadScheduledExecutor(); private final WatchService watcher; private final Path path; + private final Predicate fileFilter; - public Watcher(Path root) throws IOException { + public Watcher(Path root, Predicate fileFilter) throws IOException { this.path = root; + this.fileFilter = fileFilter; this.watcher = path.getFileSystem().newWatchService(); try { this.watchDir(path); - try (DirectoryStream directoryStream = Files.newDirectoryStream(path)) { - - for (Path path : directoryStream) { - if (Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) { - this.watchDir(path); - } - } - } } catch (Exception e) { this.watcher.close(); throw e; @@ -58,10 +53,10 @@ public Watcher(Path root) throws IOException { } @Nullable - public static Watcher create(Path path) { + public static Watcher create(Path path, Predicate fileFilter) { try { Files.createDirectories(path); - return new Watcher(path); + return new Watcher(path, fileFilter); } catch (IOException var2) { AxolotlClientCommon.getInstance().getLogger().warn("Failed to initialize directory {} monitoring", path, var2); return null; @@ -69,7 +64,11 @@ public static Watcher create(Path path) { } public static Watcher createSelfTicking(Path path, Runnable onUpdate) { - var watcher = create(path); + return createSelfTicking(path, s -> true, onUpdate); + } + + public static Watcher createSelfTicking(Path path, Predicate fileFilter, Runnable onUpdate) { + var watcher = create(path, fileFilter); if (watcher != null) { thread.scheduleAtFixedRate(() -> { try { @@ -97,12 +96,8 @@ public boolean pollForChanges() throws IOException { WatchKey watchKey; while ((watchKey = this.watcher.poll()) != null) { for (WatchEvent watchEvent : watchKey.pollEvents()) { - bl = true; - if (watchKey.watchable() == this.path && watchEvent.kind() == StandardWatchEventKinds.ENTRY_CREATE) { - Path path = this.path.resolve((Path) watchEvent.context()); - if (Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) { - this.watchDir(path); - } + if (watchKey.watchable() == this.path && watchEvent.context() != null) { + bl |= this.fileFilter.test(((Path)watchEvent.context()).toString()); } } diff --git a/common/src/main/resources/assets/axolotlclient/lang/en_us.json b/common/src/main/resources/assets/axolotlclient/lang/en_us.json index 8c0e6c7fa..41d50834b 100644 --- a/common/src/main/resources/assets/axolotlclient/lang/en_us.json +++ b/common/src/main/resources/assets/axolotlclient/lang/en_us.json @@ -139,6 +139,7 @@ "cardinalcolor": "Cardinal Direction Color", "cardinalorder": "Cardinal Order", "category.axolotlclient": "AxolotlClient", + "key.category.axolotlclient.title": "AxolotlClient", "chathud": "Chat HUD", "chromaSpeed": "Chroma Speed", "clear": "Clear", @@ -808,5 +809,60 @@ "bedwars.stats_overlay.column.ws": "Show Winstreaks", "bedwars.stats_overlay.toggle": "Whether the key toggles the overlay.", "bedwars.stats_overlay.auto_activate": "Automatic Activation", - "bedwars.stats_overlay.auto_activate.tooltip": "Automatically activate on game start. Requires the overlay to be in toggle mode." + "bedwars.stats_overlay.auto_activate.tooltip": "Automatically activate on game start. Requires the overlay to be in toggle mode.", + "inventoryhud.item_background": "Item Background", + "inventoryhud.item_background_color": "Item Background Color", + "inventoryhud.always_show_item_backgrounds": "Always Show Item Backgrounds", + "skins.manage": "Manage Skins", + "skins.nav.skins": "Skins", + "skins.nav.capes": "Capes", + "skins.error.failed_to_load": "Failed to load skins", + "skins.error.failed_to_load_desc": "Your log file may include more information.", + "skins.capes.no_cape": "No Cape", + "skins.manage.equipped": "Equipped", + "skins.manage.equip": "Equip", + "skins.loading": "Loading Skins...", + "skins.manage.equipping": "Equipping...", + "skins.manage.delete": "Delete Skin", + "skins.manage.delete.confirm": "Confirm Deletion", + "skins.manage.delete.confirm.desc": "This Skin's file will be deleted permanently!\n Are you sure?", + "skins.manage.delete.confirm.desc_active": "This Skin's file will be deleted permanently!\n Are you sure? The skin will not be un-equipped.", + "skins.manage.animations": "Skin Manger Animations", + "skins.manage.download": "Download Skin", + "skins.manage.import.local": "Import Skins", + "skins.manage.import.online": "Download Skin", + "skins.notification.title": "Skin Management", + "skins.notification.not_copied": "Skipped file %s because it does not seem like a valid skin file!", + "skins.manage.variant.classic": "Use Classic (Wide) Variant", + "skins.manage.variant.slim": "Use Slim Variant", + "skins.manage.import.online.input": "Enter Name or UUID:", + "skins.notification.import.online.failed_to_download": "Failed to download Skin of %s!", + "skins.notification.import.online.downloaded": "Downloaded Skin of %s!", + "skins.notification.import.online.failed_to_save": "Failed to save Skin of %s!", + "skins.notification.import.online.not_found": "Could not find user %s!", + "profiles.profile.import": "Import Profiles", + "profiles.profile.export": "Export", + "profiles.profile.export.notification.failed": "Export Failed", + "profiles.profile.export.notification.malformed_profile": "Malformed profile: %s. See the log for more information.", + "profiles.profile.export.notification.failed.invalid_destination": "Invalid export destination file.", + "profiles.profile.export.notification.failed.generic": "See the log for more information.", + "profiles.profile.export.notification.success": "Export Complete", + "profiles.profile.export.notification.success.desc": "Exported profile %s to %s.", + "profiles.profile.import.notification.failed": "Import Failed", + "profiles.profile.import.notification.failed.generic": "See the log for more information.", + "profiles.profile.import.notification.success": "Import Complete", + "profiles.profile.import.notification.success.desc.one": "Imported 1 profile", + "profiles.profile.import.notification.success.desc.more": "Imported %s profiles", + "skins.manage.equip.confirm": "Confirm Equipping", + "skins.manage.equip.download_current": "Your current skin is not downloaded and will get overridden by equipping a different one. Do you want to download your current skin before equipping this one?", + "gallery.error.loading": "Failed to load Gallery", + "gallery.reload": "Reload", + "iconhud.mode": "Icon Display Mode", + "iconhud.mode.in_game": "Only in-game", + "iconhud.mode.gui": "Only in GUIs", + "iconhud.mode.both": "In-game and in GUIs", + "hud.hide": "Hide HUD", + "hud.hide.tooltip": "Prevents this HUD from rendering completely.", + "keystrokes.stroke.move": "Edit Keystroke Positions", + "screenshot.gallery.view.error": "Failed to open image in gallery!" } diff --git a/common/src/main/resources/assets/axolotlclient/lang/fr_fr.json b/common/src/main/resources/assets/axolotlclient/lang/fr_fr.json index 097134e7b..c03958e57 100644 --- a/common/src/main/resources/assets/axolotlclient/lang/fr_fr.json +++ b/common/src/main/resources/assets/axolotlclient/lang/fr_fr.json @@ -139,6 +139,7 @@ "cardinalcolor": "Couleur Cardinale", "cardinalorder": "Ordre Cardinal", "category.axolotlclient": "AxolotlClient", + "key.category.axolotlclient.title": "AxolotlClient", "chathud": "Tchat HUD", "chromaSpeed": "Vitesse du Chroma", "clear": "Effacer", diff --git a/common/src/main/resources/assets/axolotlclient/lang/pt_pt.json b/common/src/main/resources/assets/axolotlclient/lang/pt_pt.json index bd71c3615..5b8018262 100644 --- a/common/src/main/resources/assets/axolotlclient/lang/pt_pt.json +++ b/common/src/main/resources/assets/axolotlclient/lang/pt_pt.json @@ -139,6 +139,7 @@ "cardinalcolor": "Cardinal Direction Color", "cardinalorder": "Cardinal Order", "category.axolotlclient": "AxolotlClient", + "key.category.axolotlclient.title": "AxolotlClient", "chathud": "Chat HUD", "chromaSpeed": "Chroma Speed", "clear": "Limpar", diff --git a/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/delete.png b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/delete.png new file mode 100644 index 000000000..cd0b75860 Binary files /dev/null and b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/delete.png differ diff --git a/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/download.png b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/download.png new file mode 100644 index 000000000..f425b2471 Binary files /dev/null and b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/download.png differ diff --git a/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/folder.png b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/folder.png new file mode 100644 index 000000000..08fc56bbc Binary files /dev/null and b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/folder.png differ diff --git a/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/slim.png b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/slim.png new file mode 100644 index 000000000..ee507a885 Binary files /dev/null and b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/slim.png differ diff --git a/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/wide.png b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/wide.png new file mode 100644 index 000000000..63ed18ae2 Binary files /dev/null and b/common/src/main/resources/assets/axolotlclient/textures/gui/sprites/wide.png differ diff --git a/gradle.properties b/gradle.properties index 74aa5f0e8..ecdc1d079 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ fabric.loom.disableMinecraftVerification=true axolotlclient.modules.all=true # Mod Properties -version=3.1.5 +version=3.1.6-beta.3 maven_group=io.github.axolotlclient @@ -23,13 +23,13 @@ mappings_cts8=1.16_combat-6+build.2 mappings_120=1.20.1+build.23 mappings_121=1.21.1+build.9 -fabric_loader=0.17.0 +fabric_loader=0.17.2 fapi_120=0.92.2 fapi_121=0.116.6 fabric_cts8=0.42.0+1.16 osl=0.16.3 -legacy_lwgjl3=1.2.5+1.8.9 +legacy_lwgjl3=1.2.10+1.8.9 -config=3.0.17 +config=3.0.22 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d4081da47..2e1113280 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index e06b04f2b..6798bfa65 100644 --- a/settings.gradle +++ b/settings.gradle @@ -37,5 +37,5 @@ optional '1.8.9' optional '1.16_combat-6' optional '1.20' optional '1.21' -optional '1.21.7' +optional '1.latest'