From 065df6054373251b4c9e145f584f44888987d903 Mon Sep 17 00:00:00 2001 From: oneachina Date: Mon, 6 Apr 2026 17:26:25 +0800 Subject: [PATCH 01/45] perf: port mojang mappings --- build.gradle | 2 +- gradle.properties | 1 - .../java/cn/pupperclient/PupperClient.java | 2 +- .../cn/pupperclient/PupperEventHandle.java | 3 - .../event/client/ReceivePacketEvent.java | 3 +- .../event/client/RenderGameOverlayEvent.java | 9 +- .../event/client/SendPacketEvent.java | 3 +- .../pupperclient/event/client/TotemEvent.java | 8 +- .../event/server/PacketHandler.java | 43 ++++----- .../gui/GuiResourcePackConvert.java | 25 +++-- .../java/cn/pupperclient/gui/MainMenuGui.java | 20 ++-- .../pupperclient/gui/api/SimpleSoarGui.java | 38 ++++---- .../java/cn/pupperclient/gui/api/SoarGui.java | 2 +- .../pupperclient/gui/edithud/GuiEditHUD.java | 5 +- .../gui/edithud/api/SnappingLine.java | 10 +- .../gui/modmenu/component/SettingBar.java | 5 +- .../gui/modmenu/pages/CosmeticsPage.java | 8 +- .../modmenu/pages/profile/ProfileAddPage.java | 5 +- .../gui/welcomegui/TermsScreen.java | 8 +- .../management/cape/CapeManager.java | 33 ++++--- .../management/cape/CapeRenderer.java | 12 +-- .../management/command/PupperCommand.java | 53 +++++----- .../management/command/impl/BindCommand.java | 16 ++-- .../management/command/impl/IRCCommand.java | 6 +- .../management/command/impl/LoginCommand.java | 15 ++- .../management/command/impl/MusicCommand.java | 39 ++++---- .../management/config/impl/ModConfig.java | 25 +++-- .../management/keybind/KeybindManager.java | 4 +- .../management/mod/api/Position.java | 6 +- .../management/mod/impl/fun/FakeFpsMod.java | 5 +- .../management/mod/impl/fun/HeypixelMod.java | 6 +- .../management/mod/impl/fun/TotemTracker.java | 38 ++++---- .../mod/impl/hud/BedwarsStatsOverlayMod.java | 26 ++--- .../mod/impl/hud/ComboCounterMod.java | 2 +- .../mod/impl/hud/CooldownHudMod.java | 4 +- .../management/mod/impl/hud/CoordsMod.java | 6 +- .../mod/impl/hud/DayCounterMod.java | 2 +- .../mod/impl/hud/DynamicIsland.java | 14 +-- .../mod/impl/hud/FPSDisplayMod.java | 2 +- .../mod/impl/hud/FallDamageHelp.java | 32 +++---- .../mod/impl/hud/GameModeDisplayMod.java | 4 +- .../mod/impl/hud/HealthDisplayMod.java | 4 +- .../mod/impl/hud/KeystrokesMod.java | 26 +++-- .../mod/impl/hud/MouseStrokesMod.java | 7 +- .../mod/impl/hud/NameDisplayMod.java | 2 +- .../mod/impl/hud/PingDisplayMod.java | 8 +- .../mod/impl/hud/PitchDisplayMod.java | 2 +- .../mod/impl/hud/PlayerCounterMod.java | 5 +- .../management/mod/impl/hud/PotionHudMod.java | 25 +++-- .../mod/impl/hud/ReachDisplayMod.java | 21 ++-- .../management/mod/impl/hud/Scoreboard.java | 50 +++++----- .../mod/impl/hud/SpeedometerMod.java | 16 ++-- .../management/mod/impl/hud/StopwatchMod.java | 5 +- .../management/mod/impl/hud/TargetHUDMod.java | 38 ++++---- .../mod/impl/hud/WeatherDisplayMod.java | 32 +++---- .../mod/impl/hud/YawDisplayMod.java | 2 +- .../management/mod/impl/misc/HypixelMod.java | 4 +- .../management/mod/impl/misc/IRCChatMod.java | 29 +++--- .../management/mod/impl/player/AutoGGMod.java | 8 +- .../mod/impl/player/AutoTextMod.java | 16 ++-- .../mod/impl/player/FreelookMod.java | 20 ++-- .../management/mod/impl/player/Sprint.java | 2 +- .../mod/impl/player/TaplookMod.java | 20 ++-- .../management/mod/impl/player/ZoomMod.java | 15 ++- .../mod/impl/render/BloodParticleMod.java | 33 ++++--- .../mod/impl/render/ClickEffectMod.java | 28 +++--- .../mod/impl/render/MusicWaveformMod.java | 4 +- .../mod/impl/render/ParticlesMod.java | 37 +++---- .../mod/impl/render/ProjectileTrailMod.java | 30 +++--- .../mod/impl/settings/ModMenuSettings.java | 14 ++- .../mod/settings/impl/KeybindSetting.java | 15 ++- .../management/quickplay/QuickPlay.java | 9 +- .../quickplay/impl/ArcadeQuickPlay.java | 5 +- .../websocket/WebSocketManager.java | 16 ++-- .../mixin/interfaces/IMixinLivingEntity.java | 4 +- .../minecraft/client/MixinKeyboard.java | 21 ++-- .../client/MixinMinecraftClient.java | 90 +++++++++-------- .../mixins/minecraft/client/MixinMouse.java | 35 ++++--- .../minecraft/client/gui/MixinBossBarHud.java | 46 +++++---- .../minecraft/client/gui/MixinChatHud.java | 10 +- .../client/gui/MixinLanguageScreen.java | 15 +-- .../client/gui/MixinMultiplayerScreen.java | 15 ++- .../minecraft/client/gui/MixinPackScreen.java | 25 +++-- .../client/gui/MixinSplashScreen.java | 72 +++++++------- .../client/gui/MixinTitleScreen.java | 13 ++- .../client/option/MixinKeyBinding.java | 41 ++++---- .../client/render/BufferRendererAccessor.java | 9 +- .../minecraft/client/render/MixinCamera.java | 27 +++--- .../client/render/MixinEntityRenderer.java | 51 +++++----- .../client/render/MixinGameRenderer.java | 21 ++-- .../client/render/MixinHeldItemRenderer.java | 71 +++++++------- .../client/render/MixinInGameHud.java | 19 ++-- .../render/MixinInGameOverlayRenderer.java | 21 ++-- .../render/MixinLightmapTextureManager.java | 7 +- .../client/render/PupperInGameHud.java | 96 +++++++++---------- .../client/render/PupperScoreboard.java | 4 +- .../client/sound/MixinSoundSystem.java | 24 +++-- .../minecraft/client/util/MixinWindow.java | 7 +- .../MixinAbstractClientPlayerEntity.java | 44 ++++----- .../mixins/minecraft/entity/MixinEntity.java | 43 ++++----- .../minecraft/entity/MixinLivingEntity.java | 59 ++++++------ .../minecraft/entity/MixinPlayerEntity.java | 21 ++-- .../network/MixinClientConnection.java | 35 ++++--- ...PlayerInteractEntityC2SPacketAccessor.java | 9 +- .../mixins/minecraft/world/MixinBiome.java | 7 +- .../world/MixinClientWorldProperties.java | 7 +- .../mixins/minecraft/world/MixinWorld.java | 9 +- .../viafabricplus/MixinMinecraftClient.java | 15 ++- .../cn/pupperclient/shader/Framebuffer.java | 14 ++- .../shader/PostProcessRenderer.java | 9 +- .../java/cn/pupperclient/shader/Shader.java | 10 +- .../cn/pupperclient/shader/ShaderHelper.java | 13 ++- .../pupperclient/shader/impl/Kawaseblur.java | 6 +- src/main/java/cn/pupperclient/skia/Skia.java | 17 ++-- .../skia/context/SkiaContext.java | 10 +- .../pupperclient/skia/image/ImageHelper.java | 15 ++- .../pupperclient/ui/component/Component.java | 5 +- .../handler/impl/KeybindHandler.java | 3 +- .../ui/component/impl/Keybind.java | 19 ++-- .../component/impl/text/TextInputHelper.java | 17 ++-- .../cn/pupperclient/utils/chat/ChatUtils.java | 48 +++++----- .../pupperclient/utils/file/FileLocation.java | 5 +- .../minecraft/interfaces/IMinecraft.java | 4 +- .../utils/minecraft/player/HealthUtils.java | 24 ++--- .../utils/minecraft/player/SkinUtils.java | 10 +- .../utils/misc/SoundEventHelper.java | 4 +- .../utils/server/ServerUtils.java | 11 +-- .../utils/thread/Multithreading.java | 5 +- src/main/resources/pupper.accesswidener | 68 ++++++------- 129 files changed, 1151 insertions(+), 1257 deletions(-) diff --git a/build.gradle b/build.gradle index c29ab05..8788e0e 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,7 @@ configurations { dependencies { minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" diff --git a/gradle.properties b/gradle.properties index 172ab04..487c93e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,6 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop minecraft_version=1.21.4 -yarn_mappings=1.21.4+build.8 loader_version=0.18.2 # Mod Properties diff --git a/src/main/java/cn/pupperclient/PupperClient.java b/src/main/java/cn/pupperclient/PupperClient.java index 2ed43ad..7555c16 100644 --- a/src/main/java/cn/pupperclient/PupperClient.java +++ b/src/main/java/cn/pupperclient/PupperClient.java @@ -130,7 +130,7 @@ private void createConfigFile(Path configFile) throws IOException { private void registerTermsScreenCheck() { ClientTickEvents.END_CLIENT_TICK.register(client -> { - if (firstLaunch && client.world != null && !hasAcceptedTerms) { + if (firstLaunch && client.level != null && !hasAcceptedTerms) { TermsScreen termsScreen = new TermsScreen(); client.setScreen(termsScreen); } diff --git a/src/main/java/cn/pupperclient/PupperEventHandle.java b/src/main/java/cn/pupperclient/PupperEventHandle.java index 4e776d5..f874577 100644 --- a/src/main/java/cn/pupperclient/PupperEventHandle.java +++ b/src/main/java/cn/pupperclient/PupperEventHandle.java @@ -3,12 +3,9 @@ import java.util.List; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.EventType; import cn.pupperclient.event.client.*; import cn.pupperclient.event.server.impl.GameJoinEvent; import cn.pupperclient.management.profile.Profile; -import net.minecraft.client.MinecraftClient; public class PupperEventHandle { public final EventBus.EventListener onClientTick = event -> { diff --git a/src/main/java/cn/pupperclient/event/client/ReceivePacketEvent.java b/src/main/java/cn/pupperclient/event/client/ReceivePacketEvent.java index 78537b5..280b59c 100644 --- a/src/main/java/cn/pupperclient/event/client/ReceivePacketEvent.java +++ b/src/main/java/cn/pupperclient/event/client/ReceivePacketEvent.java @@ -1,8 +1,7 @@ package cn.pupperclient.event.client; import cn.pupperclient.event.Event; - -import net.minecraft.network.packet.Packet; +import net.minecraft.network.protocol.Packet; public class ReceivePacketEvent extends Event { diff --git a/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java b/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java index 7934144..27e6c9f 100644 --- a/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java +++ b/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java @@ -1,18 +1,17 @@ package cn.pupperclient.event.client; import cn.pupperclient.event.Event; - -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; public class RenderGameOverlayEvent extends Event { - private final DrawContext context; + private final GuiGraphics context; - public RenderGameOverlayEvent(DrawContext context) { + public RenderGameOverlayEvent(GuiGraphics context) { this.context = context; } - public DrawContext getContext() { + public GuiGraphics getContext() { return context; } } diff --git a/src/main/java/cn/pupperclient/event/client/SendPacketEvent.java b/src/main/java/cn/pupperclient/event/client/SendPacketEvent.java index 4cf477d..210dda5 100644 --- a/src/main/java/cn/pupperclient/event/client/SendPacketEvent.java +++ b/src/main/java/cn/pupperclient/event/client/SendPacketEvent.java @@ -1,8 +1,7 @@ package cn.pupperclient.event.client; import cn.pupperclient.event.Event; - -import net.minecraft.network.packet.Packet; +import net.minecraft.network.protocol.Packet; public class SendPacketEvent extends Event { diff --git a/src/main/java/cn/pupperclient/event/client/TotemEvent.java b/src/main/java/cn/pupperclient/event/client/TotemEvent.java index 5053d45..5ef7f2e 100644 --- a/src/main/java/cn/pupperclient/event/client/TotemEvent.java +++ b/src/main/java/cn/pupperclient/event/client/TotemEvent.java @@ -1,16 +1,16 @@ package cn.pupperclient.event.client; import cn.pupperclient.event.Event; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.world.entity.player.Player; public class TotemEvent extends Event { - private final PlayerEntity player; + private final Player player; - public TotemEvent(PlayerEntity entity) { + public TotemEvent(Player entity) { player = entity; } - public PlayerEntity getPlayer() { + public Player getPlayer() { return player; } } diff --git a/src/main/java/cn/pupperclient/event/server/PacketHandler.java b/src/main/java/cn/pupperclient/event/server/PacketHandler.java index 1da2921..5773dd1 100644 --- a/src/main/java/cn/pupperclient/event/server/PacketHandler.java +++ b/src/main/java/cn/pupperclient/event/server/PacketHandler.java @@ -9,14 +9,13 @@ import cn.pupperclient.event.server.impl.ReceiveChatEvent; import cn.pupperclient.event.server.impl.SendChatEvent; import cn.pupperclient.mixin.mixins.minecraft.network.packet.PlayerInteractEntityC2SPacketAccessor; - -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; -import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; -import net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityDamageS2CPacket; -import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; -import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundDamageEventPacket; +import net.minecraft.network.protocol.game.ClientboundLoginPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.ServerboundChatPacket; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; public class PacketHandler { @@ -24,22 +23,22 @@ public class PacketHandler { Packet basePacket = packetEvent.getPacket(); - if (basePacket instanceof PlayerInteractEntityC2SPacket) { + if (basePacket instanceof ServerboundInteractPacket) { - PlayerInteractEntityC2SPacket packet = (PlayerInteractEntityC2SPacket) basePacket; - PlayerInteractEntityC2SPacket.InteractType type = ((PlayerInteractEntityC2SPacketAccessor) packet) + ServerboundInteractPacket packet = (ServerboundInteractPacket) basePacket; + ServerboundInteractPacket.ActionType type = ((PlayerInteractEntityC2SPacketAccessor) packet) .getInteractTypeHandler().getType(); - if (type.equals(PlayerInteractEntityC2SPacket.InteractType.ATTACK)) { + if (type.equals(ServerboundInteractPacket.ActionType.ATTACK)) { EventBus.getInstance() .post(new AttackEntityEvent(((PlayerInteractEntityC2SPacketAccessor) packet).entityId())); } } - if (basePacket instanceof ChatMessageC2SPacket) { + if (basePacket instanceof ServerboundChatPacket) { - ChatMessageC2SPacket packet = (ChatMessageC2SPacket) basePacket; - SendChatEvent event = new SendChatEvent(packet.chatMessage()); + ServerboundChatPacket packet = (ServerboundChatPacket) basePacket; + SendChatEvent event = new SendChatEvent(packet.message()); EventBus.getInstance().post(event); @@ -53,16 +52,16 @@ public class PacketHandler { Packet basePacket = packetEvent.getPacket(); - if (basePacket instanceof EntityDamageS2CPacket) { + if (basePacket instanceof ClientboundDamageEventPacket) { - EntityDamageS2CPacket packet = (EntityDamageS2CPacket) basePacket; + ClientboundDamageEventPacket packet = (ClientboundDamageEventPacket) basePacket; EventBus.getInstance().post(new DamageEntityEvent(packet.entityId())); } - if (basePacket instanceof ChatMessageS2CPacket) { + if (basePacket instanceof ClientboundPlayerChatPacket) { - ChatMessageS2CPacket packet = (ChatMessageS2CPacket) basePacket; + ClientboundPlayerChatPacket packet = (ClientboundPlayerChatPacket) basePacket; ReceiveChatEvent event = new ReceiveChatEvent(packet.body().content()); EventBus.getInstance().post(event); @@ -72,9 +71,9 @@ public class PacketHandler { } } - if (basePacket instanceof GameMessageS2CPacket) { + if (basePacket instanceof ClientboundSystemChatPacket) { - GameMessageS2CPacket packet = (GameMessageS2CPacket) basePacket; + ClientboundSystemChatPacket packet = (ClientboundSystemChatPacket) basePacket; ReceiveChatEvent event = new ReceiveChatEvent(packet.content().getString()); EventBus.getInstance().post(event); @@ -84,7 +83,7 @@ public class PacketHandler { } } - if (basePacket instanceof GameJoinS2CPacket) { + if (basePacket instanceof ClientboundLoginPacket) { EventBus.getInstance().post(new GameJoinEvent()); } }; diff --git a/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java b/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java index 7a32b25..cd58706 100644 --- a/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java +++ b/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java @@ -13,6 +13,7 @@ import java.util.zip.ZipInputStream; import cn.pupperclient.PupperClient; +import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import cn.pupperclient.libraries.resourcepack.ResourcePackConverter; @@ -21,18 +22,18 @@ import cn.pupperclient.utils.file.FileLocation; import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; -import net.minecraft.util.Colors; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.util.CommonColors; -public class GuiResourcePackConvert extends Screen { +public class GuiResourcePackConvert extends Screen implements IMinecraft { private String progress = "Converting..."; private Screen prevScreen; public GuiResourcePackConvert(Screen prevScreen) { - super(Text.of("PackConvert")); + super(Component.literal("PackConvert")); this.prevScreen = prevScreen; } @@ -45,17 +46,15 @@ public void init() { } catch (Exception e) { PupperClient.LOGGER.error("converter error: {}", e.getMessage()); } - if (client != null) { - client.setScreen(prevScreen); - } + client.setScreen(prevScreen); }); super.init(); } @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); - context.drawCenteredTextWithShadow(this.textRenderer, Text.of(progress), this.width / 2, this.height / 2 - 50, Colors.WHITE); + context.drawCenteredString(this.font, Component.literal(progress), this.width / 2, this.height / 2 - 50, CommonColors.WHITE); } private ResourcePackConverter createConverter() { @@ -74,7 +73,7 @@ private ResourcePackConverter createConverter() { try { File targetFile = new File(cacheDir, f.getName()); - File packDir = new File(client.runDirectory, "resourcepacks"); + File packDir = new File(client.gameDirectory, "resourcepacks"); File outputFile = new File(packDir, f.getName()); Files.move(f.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); @@ -132,7 +131,7 @@ private List detectPacks() { private List getOldResourcePacks() { List files = new ArrayList<>(); - File packDir = new File(client.runDirectory, "resourcepacks"); + File packDir = new File(client.gameDirectory, "resourcepacks"); File[] packFiles = packDir.listFiles(); if (packFiles != null) { diff --git a/src/main/java/cn/pupperclient/gui/MainMenuGui.java b/src/main/java/cn/pupperclient/gui/MainMenuGui.java index d922215..10fdd89 100644 --- a/src/main/java/cn/pupperclient/gui/MainMenuGui.java +++ b/src/main/java/cn/pupperclient/gui/MainMenuGui.java @@ -33,11 +33,11 @@ import com.terraformersmc.modmenu.gui.ModsScreen; import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; -import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; -import net.minecraft.client.gui.screen.option.OptionsScreen; -import net.minecraft.client.gui.screen.world.SelectWorldScreen; -import net.minecraft.client.realms.gui.screen.RealmsMainScreen; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; +import net.minecraft.client.gui.screens.options.OptionsScreen; +import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; +import com.mojang.realmsclient.RealmsMainScreen; +import net.minecraft.client.Minecraft; import ru.vidtu.ias.screen.AccountScreen; public class MainMenuGui extends SimpleSoarGui { @@ -69,7 +69,7 @@ public void init() { } @Override - public void resize(MinecraftClient client, int width, int height) { + public void resize(Minecraft client, int width, int height) { super.resize(client, width, height); rebuildLayout(); } @@ -105,7 +105,7 @@ private void rebuildLayout() { buttons.add(new MainMenuButton("menu.multiplayer", Icon.GROUPS, centerX - buttonWidth / 2, centerY - (60 * scaleFactor), buttonWidth, scaleFactor, () -> { - client.setScreen(new MultiplayerScreen(this)); + client.setScreen(new JoinMultiplayerScreen(this)); })); buttons.add(new MainMenuButton("menu.realms", Icon.DNS, @@ -121,7 +121,7 @@ private void rebuildLayout() { centerX - buttonWidth / 2, centerY + (180 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new OptionsScreen(this, client.options)))); buttons.add(new MainMenuButton("menu.quit", Icon.CLOSE, - centerX - buttonWidth / 2, centerY + (240 * scaleFactor), buttonWidth, scaleFactor, () -> client.scheduleStop())); + centerX - buttonWidth / 2, centerY + (240 * scaleFactor), buttonWidth, scaleFactor, client::stop)); float buttonSize = 40 * scaleFactor; float buttonSpacing = 10 * scaleFactor; @@ -402,8 +402,8 @@ private void drawBackgroundWindow(double mouseX, double mouseY, ColorPalette pal private void drawCustomBackground() { float parallaxStrength = 40; - float targetParallaxX = (float) (client.mouse.getX() - client.getWindow().getWidth() / 2F) / client.getWindow().getWidth() * parallaxStrength; - float targetParallaxY = (float) (client.mouse.getY() - client.getWindow().getHeight() / 2F) / client.getWindow().getHeight() * parallaxStrength; + float targetParallaxX = (float) (client.mouseHandler.xpos() - client.getWindow().getWidth() / 2F) / client.getWindow().getWidth() * parallaxStrength; + float targetParallaxY = (float) (client.mouseHandler.ypos() - client.getWindow().getHeight() / 2F) / client.getWindow().getHeight() * parallaxStrength; parallaxX += (targetParallaxX - parallaxX) * 0.1f; parallaxY += (targetParallaxY - parallaxY) * 0.1f; diff --git a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java index eb05431..5686a4c 100644 --- a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java @@ -2,11 +2,10 @@ import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.context.SkiaContext; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; /** * Base class for all PupperClient GUIs. @@ -14,11 +13,11 @@ */ public abstract class SimpleSoarGui extends Screen { - protected final MinecraftClient client = MinecraftClient.getInstance(); + protected final Minecraft client = Minecraft.getInstance(); protected final boolean mcScale; protected SimpleSoarGui(boolean mcScale) { - super(Text.empty()); + super(Component.empty()); this.mcScale = mcScale; } @@ -33,17 +32,16 @@ protected void init() { public abstract void draw(double mouseX, double mouseY); @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { SkiaContext.draw((skiaContext) -> { Skia.save(); if (mcScale) { - Skia.scale((float) client.getWindow().getScaleFactor()); + Skia.scale((float) client.getWindow().getGuiScale()); } - - // Standardize mouse coordinates based on scaling - double finalMouseX = mcScale ? mouseX : client.mouse.getX(); - double finalMouseY = mcScale ? mouseY : client.mouse.getY(); + + double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); + double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); draw(finalMouseX, finalMouseY); @@ -53,22 +51,22 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - double finalMouseX = mcScale ? mouseX : client.mouse.getX(); - double finalMouseY = mcScale ? mouseY : client.mouse.getY(); + double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); + double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); return onMousePressed(finalMouseX, finalMouseY, button); } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { - double finalMouseX = mcScale ? mouseX : client.mouse.getX(); - double finalMouseY = mcScale ? mouseY : client.mouse.getY(); + double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); + double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); return onMouseReleased(finalMouseX, finalMouseY, button); } @Override public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - double finalMouseX = mcScale ? mouseX : client.mouse.getX(); - double finalMouseY = mcScale ? mouseY : client.mouse.getY(); + double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); + double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); return onMouseScrolled(finalMouseX, finalMouseY, horizontalAmount, verticalAmount); } @@ -91,7 +89,7 @@ public boolean charTyped(char chr, int modifiers) { public boolean onCharTyped(char chr, int modifiers) { return super.charTyped(chr, modifiers); } @Override - public boolean shouldPause() { + public boolean isPauseScreen() { return false; } } diff --git a/src/main/java/cn/pupperclient/gui/api/SoarGui.java b/src/main/java/cn/pupperclient/gui/api/SoarGui.java index 6127782..ee0f31c 100644 --- a/src/main/java/cn/pupperclient/gui/api/SoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SoarGui.java @@ -19,7 +19,7 @@ import cn.pupperclient.ui.component.Component; import io.github.humbleui.skija.SurfaceOrigin; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screens.Screen; public abstract class SoarGui extends SimpleSoarGui { diff --git a/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java b/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java index 264d461..be24eee 100644 --- a/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java +++ b/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java @@ -4,7 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; - +import net.minecraft.client.gui.screens.Screen; import cn.pupperclient.PupperClient; import org.lwjgl.glfw.GLFW; @@ -17,7 +17,6 @@ import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; -import net.minecraft.client.gui.screen.Screen; public class GuiEditHUD extends SimpleSoarGui { @@ -195,7 +194,7 @@ private FloatArrayList getSnappingLines(boolean isHorizontal) { FloatArrayList lines = new FloatArrayList(); - lines.add(isHorizontal ? client.getWindow().getScaledWidth() / 2F : client.getWindow().getScaledHeight() / 2F); + lines.add(isHorizontal ? client.getWindow().getGuiScaledWidth() / 2F : client.getWindow().getGuiScaledHeight() / 2F); mods.stream().filter( mod -> isModInteractable(mod) && !selectedMod.map(pair -> pair.left().equals(mod)).orElse(false)) diff --git a/src/main/java/cn/pupperclient/gui/edithud/api/SnappingLine.java b/src/main/java/cn/pupperclient/gui/edithud/api/SnappingLine.java index b175c8f..2a8ec7d 100644 --- a/src/main/java/cn/pupperclient/gui/edithud/api/SnappingLine.java +++ b/src/main/java/cn/pupperclient/gui/edithud/api/SnappingLine.java @@ -1,11 +1,9 @@ package cn.pupperclient.gui.edithud.api; import java.awt.Color; - +import net.minecraft.client.Minecraft; import cn.pupperclient.skia.Skia; -import net.minecraft.client.MinecraftClient; - public class SnappingLine { private float line; @@ -35,15 +33,15 @@ public SnappingLine(float line, float left, float size, boolean multipleSides) { public void drawLine(float lineWidth, boolean isX) { - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); Color color = Color.WHITE; float pos = (float) (line - lineWidth / 2f); if (isX) { - Skia.drawLine(pos, 0, pos, client.getWindow().getScaledHeight(), lineWidth, color); + Skia.drawLine(pos, 0, pos, client.getWindow().getGuiScaledHeight(), lineWidth, color); } else { - Skia.drawLine(0, pos, client.getWindow().getScaledWidth(), pos, lineWidth, color); + Skia.drawLine(0, pos, client.getWindow().getGuiScaledWidth(), pos, lineWidth, color); } } diff --git a/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java b/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java index 3d78956..67e10e5 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java @@ -35,8 +35,7 @@ import cn.pupperclient.ui.component.impl.Switch; import cn.pupperclient.ui.component.impl.text.TextField; import cn.pupperclient.utils.language.I18n; - -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class SettingBar extends Component { @@ -93,7 +92,7 @@ public void onChanged(String option) { Keybind bind = new Keybind(0, 0, kSetting.getKey()); bind.setHandler(new KeybindHandler() { @Override - public void onBinded(InputUtil.Key key) { + public void onBinded(InputConstants.Key key) { kSetting.setKey(key); } }); diff --git a/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java b/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java index 1a6c11e..f647649 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java @@ -20,12 +20,12 @@ import cn.pupperclient.utils.file.FileDialog; import cn.pupperclient.utils.language.I18n; import cn.pupperclient.utils.mouse.MouseUtils; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.Identifier; import org.lwjgl.glfw.GLFW; import io.github.humbleui.skija.Font; import javax.imageio.ImageIO; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; @@ -114,7 +114,7 @@ private void uploadCape() { try { Files.copy(selectedFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - MinecraftClient.getInstance().execute(this::loadExistingCapes); + Minecraft.getInstance().execute(this::loadExistingCapes); } catch (IOException e) { cn.pupperclient.PupperLogger.error("CosmeticsPage", "Failed to copy uploaded cape", e); } @@ -213,7 +213,7 @@ private void drawMd3Style(double mouseX, double mouseY) { } if (item.capeFile.exists()) { - Identifier capeTexture = PupperClient.getInstance().getCapeManager().getLoadedCape(item.capeId); + ResourceLocation capeTexture = PupperClient.getInstance().getCapeManager().getLoadedCape(item.capeId); if (capeTexture != null) { CapeRenderer.renderRoundedCapePreview(capeTexture, itemX + 5, itemY + 5, itemWidth - 10, itemHeight - 10, 8); diff --git a/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java b/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java index 602e1c5..f1c04eb 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java @@ -3,7 +3,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; - +import net.minecraft.client.Minecraft; import cn.pupperclient.PupperClient; import org.lwjgl.glfw.GLFW; @@ -27,7 +27,6 @@ import cn.pupperclient.utils.mouse.MouseUtils; import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; -import net.minecraft.client.MinecraftClient; public class ProfileAddPage extends SimplePage { @@ -46,7 +45,7 @@ public ProfileAddPage(SoarGui parent, Class prevPage) { @Override public void init() { - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); components.clear(); super.init(); diff --git a/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java b/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java index 2d3440a..a8da9be 100644 --- a/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java +++ b/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java @@ -6,9 +6,9 @@ import cn.pupperclient.skia.font.Fonts; import cn.pupperclient.ui.component.handler.impl.ButtonHandler; import cn.pupperclient.ui.component.impl.Button; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.sound.SoundEvents; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.sounds.SoundEvents; import java.awt.Color; @@ -51,7 +51,7 @@ public void onAction() { } @Override - public void resize(MinecraftClient client, int width, int height) { + public void resize(Minecraft client, int width, int height) { super.resize(client, width, height); rebuildLayout(); } diff --git a/src/main/java/cn/pupperclient/management/cape/CapeManager.java b/src/main/java/cn/pupperclient/management/cape/CapeManager.java index 17b6c9b..0240655 100644 --- a/src/main/java/cn/pupperclient/management/cape/CapeManager.java +++ b/src/main/java/cn/pupperclient/management/cape/CapeManager.java @@ -1,22 +1,21 @@ package cn.pupperclient.management.cape; +import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.NativeImageBackedTexture; -import net.minecraft.util.Identifier; - import java.io.Closeable; import java.io.IOException; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.resources.ResourceLocation; public class CapeManager implements Closeable { private static CapeManager instance; - private final Map loadedCapes = Collections.synchronizedMap(new HashMap<>()); - private final Map loadedCapeTextures = Collections.synchronizedMap(new HashMap<>()); + private final Map loadedCapes = Collections.synchronizedMap(new HashMap<>()); + private final Map loadedCapeTextures = Collections.synchronizedMap(new HashMap<>()); private String selectedCapeId = null; @@ -39,7 +38,7 @@ public String getSelectedCapeId() { return selectedCapeId; } - public Identifier getSelectedCapeTexture() { + public ResourceLocation getSelectedCapeTexture() { if (selectedCapeId == null) return null; return getLoadedCape(selectedCapeId); } @@ -53,10 +52,10 @@ public void loadCape(String id, byte[] textureData) { executorService.submit(() -> { RenderSystem.recordRenderCall(() -> { - NativeImageBackedTexture nativeImage = createNativeTexture(textureData); + DynamicTexture nativeImage = createNativeTexture(textureData); if (nativeImage != null) { - Identifier identifier = Identifier.of("pupper", namespace + "/" + id); - MinecraftClient.getInstance().getTextureManager().registerTexture(identifier, nativeImage); + ResourceLocation identifier = ResourceLocation.fromNamespaceAndPath("pupper", namespace + "/" + id); + Minecraft.getInstance().getTextureManager().register(identifier, nativeImage); loadedCapes.put(id, identifier); loadedCapeTextures.put(identifier, nativeImage); } @@ -71,17 +70,17 @@ public void unloadCape(String id) { selectedCapeId = null; } - Identifier cape = loadedCapes.remove(id); + ResourceLocation cape = loadedCapes.remove(id); if (cape != null) { - NativeImageBackedTexture texture = loadedCapeTextures.remove(cape); + DynamicTexture texture = loadedCapeTextures.remove(cape); if (texture != null) { texture.close(); } - MinecraftClient.getInstance().getTextureManager().destroyTexture(cape); + Minecraft.getInstance().getTextureManager().release(cape); } } - public Identifier getLoadedCape(String id) { + public ResourceLocation getLoadedCape(String id) { return id != null ? loadedCapes.get(id) : null; } @@ -89,10 +88,10 @@ public Set getLoadedCapeIds() { return new HashSet<>(loadedCapes.keySet()); } - private static NativeImageBackedTexture createNativeTexture(byte[] bytes) { + private static DynamicTexture createNativeTexture(byte[] bytes) { if (bytes == null) return null; try { - return new NativeImageBackedTexture(NativeImage.read(bytes)); + return new DynamicTexture(NativeImage.read(bytes)); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java b/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java index 1fc227d..ef1783f 100644 --- a/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java +++ b/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java @@ -1,21 +1,21 @@ package cn.pupperclient.management.cape; import cn.pupperclient.skia.Skia; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.Identifier; import io.github.humbleui.skija.ClipMode; import io.github.humbleui.skija.Path; import io.github.humbleui.skija.SurfaceOrigin; import io.github.humbleui.types.RRect; import io.github.humbleui.types.Rect; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; public class CapeRenderer { - public static void renderCapePreview(Identifier capeTexture, float x, float y, float width, float height) { + public static void renderCapePreview(ResourceLocation capeTexture, float x, float y, float width, float height) { if (capeTexture == null) return; try { - int textureId = MinecraftClient.getInstance().getTextureManager().getTexture(capeTexture).getGlId(); + int textureId = Minecraft.getInstance().getTextureManager().getTexture(capeTexture).getId(); // 尝试不同的纹理尺寸 boolean loaded = Skia.getImageHelper().load(textureId, 64, 32, SurfaceOrigin.TOP_LEFT) || @@ -47,12 +47,12 @@ public static void renderCapePreview(Identifier capeTexture, float x, float y, f } } - public static void renderRoundedCapePreview(Identifier capeTexture, float x, float y, + public static void renderRoundedCapePreview(ResourceLocation capeTexture, float x, float y, float width, float height, float radius) { if (capeTexture == null) return; try { - int textureId = MinecraftClient.getInstance().getTextureManager().getTexture(capeTexture).getGlId(); + int textureId = Minecraft.getInstance().getTextureManager().getTexture(capeTexture).getId(); // 尝试不同的纹理尺寸 boolean loaded = Skia.getImageHelper().load(textureId, 64, 32, SurfaceOrigin.TOP_LEFT) || diff --git a/src/main/java/cn/pupperclient/management/command/PupperCommand.java b/src/main/java/cn/pupperclient/management/command/PupperCommand.java index 18a33a7..bb7236c 100644 --- a/src/main/java/cn/pupperclient/management/command/PupperCommand.java +++ b/src/main/java/cn/pupperclient/management/command/PupperCommand.java @@ -8,12 +8,11 @@ import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import cn.pupperclient.utils.language.I18n; import net.fabricmc.fabric.api.client.message.v1.ClientSendMessageEvents; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; import java.io.IOException; public class PupperCommand implements IMinecraft { @@ -123,16 +122,16 @@ private static void showHelp() { private static void listMods() { if (modManager == null) { - ChatUtils.addChatMessage(Text.literal("§c" + I18n.get("modManager.notInitialized"))); + ChatUtils.addChatMessage(Component.literal("§c" + I18n.get("modManager.notInitialized"))); return; } // 创建标题和刷新按钮 - MutableText title = Text.literal("=== " + I18n.get("command.help.modlist.title") + " ===") - .formatted(Formatting.GOLD); + MutableComponent title = Component.literal("=== " + I18n.get("command.help.modlist.title") + " ===") + .withStyle(ChatFormatting.GOLD); - MutableText refreshButton = createClickableText(" [" + I18n.get("command.help.modlist.refresh") + "]", ".list", - I18n.get("command.help.modlist.refresh.tip"), Formatting.GREEN); + MutableComponent refreshButton = createClickableText(" [" + I18n.get("command.help.modlist.refresh") + "]", ".list", + I18n.get("command.help.modlist.refresh.tip"), ChatFormatting.GREEN); title.append(refreshButton); ChatUtils.addChatMessage(title); @@ -150,44 +149,44 @@ private static void listMods() { boolean isEnabled = mod.isEnabled(); String shortModName = getShortModName(mod.getName()); - MutableText modNameText = Text.literal("• " + modDisplayName) - .formatted(Formatting.AQUA); + MutableComponent modNameText = Component.literal("• " + modDisplayName) + .withStyle(ChatFormatting.AQUA); - MutableText statusText; + MutableComponent statusText; if (isEnabled) { statusText = createClickableText(I18n.get("mod.enabled"), ".toggle " + shortModName, - I18n.get("modNameText.c") + " " + modDisplayName, Formatting.GREEN); + I18n.get("modNameText.c") + " " + modDisplayName, ChatFormatting.GREEN); } else { statusText = createClickableText(I18n.get("mod.disabled"), ".toggle " + shortModName, - I18n.get("modNameText.d") + " " + modDisplayName, Formatting.RED); + I18n.get("modNameText.d") + " " + modDisplayName, ChatFormatting.RED); } - MutableText modLine = Text.empty() + MutableComponent modLine = Component.empty() .append(modNameText) - .append(Text.literal(" - ").formatted(Formatting.GRAY)) + .append(Component.literal(" - ").withStyle(ChatFormatting.GRAY)) .append(statusText); ChatUtils.addChatMessage(modLine); } // 统计信息行 - MutableText stats = Text.literal(I18n.get("command.help.modlist.stats") + ": ") - .formatted(Formatting.GRAY) - .append(Text.literal(enabledCount + "/" + totalCount + " " + I18n.get("mod.enabled")) - .formatted(enabledCount > 0 ? Formatting.GREEN : Formatting.RED)); + MutableComponent stats = Component.literal(I18n.get("command.help.modlist.stats") + ": ") + .withStyle(ChatFormatting.GRAY) + .append(Component.literal(enabledCount + "/" + totalCount + " " + I18n.get("mod.enabled")) + .withStyle(enabledCount > 0 ? ChatFormatting.GREEN : ChatFormatting.RED)); ChatUtils.addChatMessage(stats); } - private static MutableText createClickableText(String displayText, String command, String hoverText, Formatting color) { - return Text.literal(displayText) - .formatted(color) - .styled(style -> style + private static MutableComponent createClickableText(String displayText, String command, String hoverText, ChatFormatting color) { + return Component.literal(displayText) + .withStyle(color) + .withStyle(style -> style .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal(hoverText).formatted(Formatting.GRAY)))); + Component.literal(hoverText).withStyle(ChatFormatting.GRAY)))); } private static String getShortModName(String fullName) { diff --git a/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java b/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java index d3ae292..20fd423 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java @@ -9,16 +9,16 @@ import cn.pupperclient.management.mod.ModManager; import cn.pupperclient.utils.chat.ChatUtils; import cn.pupperclient.utils.language.I18n; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.List; import java.util.Map; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; public class BindCommand { private static final ModManager modManager = PupperClient.getInstance().getModManager(); @@ -138,11 +138,11 @@ private static void listKeybinds() { String keyName = getKeyName(keyCode); for (Mod mod : mods) { - MutableText message = Text.literal("§b• " + mod.getName() + " §7→ §a" + keyName + " §7(keycode: " + keyCode + ")") - .styled(style -> style + MutableComponent message = Component.literal("§b• " + mod.getName() + " §7→ §a" + keyName + " §7(keycode: " + keyCode + ")") + .withStyle(style -> style .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ".bind " + mod.getName() + " none")) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal("Click to clear this keybind").formatted(Formatting.GRAY)))); + Component.literal("Click to clear this keybind").withStyle(ChatFormatting.GRAY)))); ChatUtils.addChatMessage(message); boundCount++; diff --git a/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java b/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java index dbdb2ec..8abe16b 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java @@ -3,7 +3,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.impl.misc.IRCChatMod; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; public class IRCCommand implements IMinecraft { @@ -64,8 +64,8 @@ private static void sendHelp() { } private static void sendMessage(String message) { - if (mc.player != null) { - mc.player.sendMessage(Text.of(message), false); + if (client.player != null) { + client.player.displayClientMessage(Component.nullToEmpty(message), false); } } } diff --git a/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java b/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java index e955d57..eb21222 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java @@ -6,15 +6,14 @@ import cn.pupperclient.utils.thread.Multithreading; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; - import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; public class LoginCommand { @@ -139,11 +138,11 @@ private static void phoneLoginWithCaptcha(String phone, String captcha) { ChatUtils.addChatMessage("§c验证码登录失败: " + errorMsg); // 提供重新发送验证码的快捷方式 - MutableText retryText = Text.literal("§7[重新发送验证码]") - .styled(style -> style + MutableComponent retryText = Component.literal("§7[重新发送验证码]") + .withStyle(style -> style .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ".login send " + phone)) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal("点击重新发送验证码")))); + Component.literal("点击重新发送验证码")))); ChatUtils.addChatMessage(retryText); }); return; diff --git a/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java b/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java index 46efbda..d5326f5 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java @@ -7,12 +7,6 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.utils.chat.ChatUtils; import cn.pupperclient.utils.thread.Multithreading; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - import java.io.*; import java.net.HttpURLConnection; import java.net.URL; @@ -20,6 +14,11 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; public class MusicCommand { @@ -157,18 +156,18 @@ private static void searchMusic(String keyword, int limit) { } // 格式化显示 - MutableText songText = Text.literal("§b" + (i + 1) + ". §f" + songName) - .styled(style -> style + MutableComponent songText = Component.literal("§b" + (i + 1) + ". §f" + songName) + .withStyle(style -> style .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ".music download " + songId)) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal("§6点击快速下载\n§7歌手: " + artistsStr + "\n§7专辑: " + albumName)))); + Component.literal("§6点击快速下载\n§7歌手: " + artistsStr + "\n§7专辑: " + albumName)))); - MutableText artistText = Text.literal(" §7- " + artistsStr); - MutableText downloadBtn = createClickableText( + MutableComponent artistText = Component.literal(" §7- " + artistsStr); + MutableComponent downloadBtn = createClickableText( ".music download " + songId, "下载 " + songName); - MutableText fullLine = Text.empty() + MutableComponent fullLine = Component.empty() .append(songText) .append(artistText) .append(downloadBtn); @@ -348,10 +347,10 @@ private static void listDownloadedMusic() { String fileName = musicFile.getName(); String displayName = fileName.substring(0, fileName.lastIndexOf('.')); - MutableText fileText = Text.literal("§b" + (i + 1) + ". §f" + displayName) - .styled(style -> style + MutableComponent fileText = Component.literal("§b" + (i + 1) + ". §f" + displayName) + .withStyle(style -> style .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal("§6文件: " + fileName + "\n§7大小: " + formatFileSize(musicFile.length()))))); + Component.literal("§6文件: " + fileName + "\n§7大小: " + formatFileSize(musicFile.length()))))); ChatUtils.addChatMessage(fileText); } @@ -481,12 +480,12 @@ private static String formatFileSize(long size) { } } - private static MutableText createClickableText(String command, String hoverText) { - return Text.literal(" [下载]") - .formatted(Formatting.GREEN) - .styled(style -> style + private static MutableComponent createClickableText(String command, String hoverText) { + return Component.literal(" [下载]") + .withStyle(ChatFormatting.GREEN) + .withStyle(style -> style .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Text.literal(hoverText).formatted(Formatting.GRAY)))); + Component.literal(hoverText).withStyle(ChatFormatting.GRAY)))); } } diff --git a/src/main/java/cn/pupperclient/management/config/impl/ModConfig.java b/src/main/java/cn/pupperclient/management/config/impl/ModConfig.java index 9784179..918d3b1 100644 --- a/src/main/java/cn/pupperclient/management/config/impl/ModConfig.java +++ b/src/main/java/cn/pupperclient/management/config/impl/ModConfig.java @@ -6,6 +6,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.impl.hud.DynamicIsland; import com.google.gson.JsonObject; +import com.mojang.blaze3d.platform.InputConstants; import cn.pupperclient.libraries.material3.hct.Hct; import cn.pupperclient.management.config.Config; import cn.pupperclient.management.config.ConfigType; @@ -19,8 +20,6 @@ import cn.pupperclient.utils.color.ColorUtils; import cn.pupperclient.utils.misc.JsonUtils; -import net.minecraft.client.util.InputUtil; - public class ModConfig extends Config { public ModConfig() { @@ -160,10 +159,10 @@ private void loadKeybindSetting(KeybindSetting setting, JsonObject settingsJson) String inputType = JsonUtils.getStringProperty(keybindJson, "type", ""); int keyCode = JsonUtils.getIntProperty(keybindJson, "code", -1); - InputUtil.Type type = determineInputType(inputType); + InputConstants.Type type = determineInputType(inputType); if (!inputType.isEmpty() && keyCode != -1) { - setting.setKey(type.createFromCode(keyCode)); + setting.setKey(type.getOrCreate(keyCode)); } else { setting.setKey(setting.getDefaultKey()); } @@ -264,11 +263,11 @@ private void saveHctColorSetting(HctColorSetting setting, JsonObject settingsJso private void saveKeybindSetting(KeybindSetting setting, JsonObject settingsJson) { JsonObject keybindJson = new JsonObject(); - InputUtil.Type type = setting.getKey().getCategory(); + InputConstants.Type type = setting.getKey().getType(); String saveType = getInputTypeString(type); keybindJson.addProperty("type", saveType); - keybindJson.addProperty("code", setting.getKey().getCode()); + keybindJson.addProperty("code", setting.getKey().getValue()); settingsJson.add(setting.getName(), keybindJson); } @@ -287,18 +286,18 @@ private void saveFileSetting(FileSetting setting, JsonObject settingsJson) { settingsJson.addProperty(setting.getName(), filePath); } - private InputUtil.Type determineInputType(String inputType) { + private InputConstants.Type determineInputType(String inputType) { return switch (inputType) { - case "key" -> InputUtil.Type.KEYSYM; - case "mouse" -> InputUtil.Type.MOUSE; - default -> InputUtil.Type.SCANCODE; + case "key" -> InputConstants.Type.KEYSYM; + case "mouse" -> InputConstants.Type.MOUSE; + default -> InputConstants.Type.SCANCODE; }; } - private String getInputTypeString(InputUtil.Type type) { - if (type.equals(InputUtil.Type.KEYSYM)) { + private String getInputTypeString(InputConstants.Type type) { + if (type.equals(InputConstants.Type.KEYSYM)) { return "key"; - } else if (type.equals(InputUtil.Type.MOUSE)) { + } else if (type.equals(InputConstants.Type.MOUSE)) { return "mouse"; } else { return "scancode"; diff --git a/src/main/java/cn/pupperclient/management/keybind/KeybindManager.java b/src/main/java/cn/pupperclient/management/keybind/KeybindManager.java index 3045dec..1a7a8fe 100644 --- a/src/main/java/cn/pupperclient/management/keybind/KeybindManager.java +++ b/src/main/java/cn/pupperclient/management/keybind/KeybindManager.java @@ -114,8 +114,7 @@ public int getPriority() { private void handleGlobalKeyEvent(KeyEvent event) { if (!event.isState()) return; - // 防止在GUI界面中误触发 - if (mc != null && mc.currentScreen != null) return; + if (client.screen != null) return; int keyCode = event.getKeybind(); List mods = getModsByKey(keyCode); @@ -123,7 +122,6 @@ private void handleGlobalKeyEvent(KeyEvent event) { if (!mods.isEmpty()) { LOGGER.debug("Keybind triggered: {} for {} mod(s)", keyCode, mods.size()); - // 触发所有绑定到此按键的Mod for (Mod mod : mods) { LOGGER.debug("Toggling mod: {}", mod.getName()); mod.toggle(); diff --git a/src/main/java/cn/pupperclient/management/mod/api/Position.java b/src/main/java/cn/pupperclient/management/mod/api/Position.java index e863ed2..41eadf8 100644 --- a/src/main/java/cn/pupperclient/management/mod/api/Position.java +++ b/src/main/java/cn/pupperclient/management/mod/api/Position.java @@ -1,6 +1,6 @@ package cn.pupperclient.management.mod.api; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public class Position { @@ -121,11 +121,11 @@ private float getAnchorY(float value) { } private float getScreenWidth() { - return MinecraftClient.getInstance().getWindow().getScaledWidth(); + return Minecraft.getInstance().getWindow().getGuiScaledWidth(); } private float getScreenHeight() { - return MinecraftClient.getInstance().getWindow().getScaledHeight(); + return Minecraft.getInstance().getWindow().getGuiScaledHeight(); } public float getScale() { diff --git a/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java b/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java index 83fd095..fcb3707 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java @@ -6,11 +6,10 @@ import cn.pupperclient.management.mod.settings.impl.ComboSetting; import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; -import net.minecraft.client.MinecraftClient; - import java.util.Arrays; import java.util.List; import java.util.Random; +import net.minecraft.client.Minecraft; public class FakeFpsMod extends SimpleHUDMod { private final ComboSetting modeSetting; @@ -79,7 +78,7 @@ public FakeFpsMod() { @Override public String getText() { - int realFps = MinecraftClient.getInstance().getCurrentFps(); + int realFps = Minecraft.getInstance().getFps(); String mode = modeSetting.getOption(); switch (mode) { diff --git a/src/main/java/cn/pupperclient/management/mod/impl/fun/HeypixelMod.java b/src/main/java/cn/pupperclient/management/mod/impl/fun/HeypixelMod.java index ac82b86..667e225 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/fun/HeypixelMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/fun/HeypixelMod.java @@ -9,7 +9,7 @@ import cn.pupperclient.management.mod.settings.impl.BooleanSetting; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.chat.ChatUtils; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public class HeypixelMod extends Mod { private static HeypixelMod instance; @@ -55,9 +55,9 @@ public void onChatMessage(ChatEvent event) { ChatUtils.addChatMessage("checked! try to send /again command"); } EventBus.getInstance().post(new AutoAgainEvent()); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); if (client.player != null) { - client.player.networkHandler.sendChatCommand("again"); + client.player.connection.sendCommand("again"); if (Logging.isEnabled()) { ChatUtils.addChatMessage("Done"); } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java b/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java index b8a3b29..e400185 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java @@ -8,14 +8,13 @@ import cn.pupperclient.management.mod.ModCategory; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.chat.ChatUtils; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityStatuses; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - import java.util.HashMap; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityEvent; +import net.minecraft.world.entity.player.Player; public class TotemTracker extends Mod { private static TotemTracker instance; @@ -42,40 +41,41 @@ public void onDisable() { @EventListener public void onTotem(TotemEvent event) { - PlayerEntity player = event.getPlayer(); + Player player = event.getPlayer(); char ch = 0; int l_Count = 1; if (popContainer.containsKey(player.getName().getString())) { l_Count = popContainer.get(player.getName().getString()); } if (l_Count == 1) { - if (player.equals(mc.player)) { - ChatUtils.addChatMessage(Text.of(String.format(Formatting.WHITE + "You(%s)" + Formatting.RESET + " popped " + Formatting.GRAY + "%d" + Formatting.RESET + " totem.", player.getName().getString(), l_Count))); + if (player.equals(client.player)) { + ChatUtils.addChatMessage(Component.nullToEmpty(String.format(ChatFormatting.WHITE + "You(%s)" + ChatFormatting.RESET + " popped " + ChatFormatting.GRAY + "%d" + ChatFormatting.RESET + " totem.", player.getName().getString(), l_Count))); } else { - ChatUtils.addChatMessage(Text.of(String.format(Formatting.WHITE + "%s" + Formatting.RESET + " popped " + Formatting.GRAY + "%d" + Formatting.RESET + " totem.", player.getName().getString().replace(String.valueOf(Formatting.FORMATTING_CODE_PREFIX), ""), l_Count))); + ChatUtils.addChatMessage(Component.nullToEmpty(String.format(ChatFormatting.WHITE + "%s" + ChatFormatting.RESET + " popped " + ChatFormatting.GRAY + "%d" + ChatFormatting.RESET + " totem.", player.getName().getString().replace(String.valueOf(ChatFormatting.PREFIX_CODE), ""), l_Count))); } } else { - if (player.equals(mc.player)) { - ChatUtils.addChatMessage(Text.of(String.format(Formatting.WHITE + "You(%s)" + Formatting.RESET + " popped " + Formatting.GRAY + "%d" + Formatting.RESET + " totem.", player.getName().getString().replace(String.valueOf(Formatting.FORMATTING_CODE_PREFIX), ""), l_Count))); + if (player.equals(client.player)) { + ChatUtils.addChatMessage(Component.nullToEmpty(String.format(ChatFormatting.WHITE + "You(%s)" + ChatFormatting.RESET + " popped " + ChatFormatting.GRAY + "%d" + ChatFormatting.RESET + " totem.", player.getName().getString().replace(String.valueOf(ChatFormatting.PREFIX_CODE), ""), l_Count))); } else { - ChatUtils.addChatMessage(Text.of(String.format(Formatting.WHITE + "%s" + Formatting.RESET + " has popped " + Formatting.GRAY + "%d" + Formatting.RESET + " totems.", player.getName().getString(), l_Count))); + ChatUtils.addChatMessage(Component.nullToEmpty(String.format(ChatFormatting.WHITE + "%s" + ChatFormatting.RESET + " has popped " + ChatFormatting.GRAY + "%d" + ChatFormatting.RESET + " totems.", player.getName().getString(), l_Count))); } } } @EventListener(priority = 1001) public void onPacketReceive(ReceivePacketEvent event) { - if (event.getPacket() instanceof EntityStatusS2CPacket packet) { - if (packet.getStatus() == EntityStatuses.USE_TOTEM_OF_UNDYING) { - Entity entity = packet.getEntity(mc.world); - if(entity instanceof PlayerEntity player) { + if (event.getPacket() instanceof ClientboundEntityEventPacket packet) { + if (packet.getEventId() == EntityEvent.PROTECTED_FROM_DEATH) { + assert client.level != null; + Entity entity = packet.getEntity(client.level); + if(entity instanceof Player player) { onTotemPop(player); } } } } - public void onTotemPop(PlayerEntity player) { + public void onTotemPop(Player player) { int l_Count = 1; if (popContainer.containsKey(player.getName().getString())) { l_Count = popContainer.get(player.getName().getString()); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java index 2f0e437..d3d7ec7 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java @@ -1,7 +1,9 @@ package cn.pupperclient.management.mod.impl.hud; import java.io.File; +import java.util.Objects; +import net.minecraft.client.multiplayer.PlayerInfo; import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.RenderSkiaEvent; @@ -15,8 +17,6 @@ import cn.pupperclient.utils.server.Server; import cn.pupperclient.utils.server.ServerUtils; -import net.minecraft.client.network.PlayerListEntry; - public class BedwarsStatsOverlayMod extends HUDMod { private NumberSetting maxSetting = new NumberSetting("setting.max", "setting.max.description", Icon.MAXIMIZE, this, @@ -46,28 +46,22 @@ public BedwarsStatsOverlayMod() { if (ServerUtils.isJoin(Server.HYPIXEL)) { - for (PlayerListEntry player : mc.getNetworkHandler().getPlayerList()) { - - if (player.getProfile() == null) { - continue; - } + for (PlayerInfo player : Objects.requireNonNull(client.getConnection()).getOnlinePlayers()) { - String name = player.getProfile().getName(); + String name = player.getProfile().getName(); String uuid = player.getProfile().getId().toString().replace("-", ""); HypixelUser hypixelUser = PupperClient.getInstance().getHypixelManager().getByUuid(uuid); if (hypixelUser != null) { - if (player.getSkinTextures() != null) { + player.getSkin(); + File file = SkinUtils.getSkin(player.getSkin().texture()); - File file = SkinUtils.getSkin(player.getSkinTextures().texture()); - - if (file.exists()) { - Skia.drawPlayerHead(file, getX() + 5.5F, getY() + offsetY, 12, 12, 2.5F); - } - } + if (file.exists()) { + Skia.drawPlayerHead(file, getX() + 5.5F, getY() + offsetY, 12, 12, 2.5F); + } - Skia.drawHeightCenteredText(name, getX() + 21, getY() + offsetY + 6F, + Skia.drawHeightCenteredText(name, getX() + 21, getY() + offsetY + 6F, this.getDesign().getTextColor(), Fonts.getRegular(9)); Skia.drawFullCenteredText(hypixelUser.getBedwarsLevel(), getX() + 120, getY() + offsetY + 6F, diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java index 0968b1e..cf987bd 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java @@ -31,7 +31,7 @@ public ComboCounterMod() { combo++; possibleTarget = -1; hitTime = System.currentTimeMillis(); - } else if (event.getEntityId() == mc.player.getId()) { + } else if (event.getEntityId() == client.player.getId()) { combo = 0; } }; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java index becc135..5eee548 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java @@ -27,8 +27,8 @@ public void onSkiaRender(RenderSkiaEvent event) { @Override public String getText() { float cooldownProgress = 0; - if (mc.player != null) { - cooldownProgress = mc.player.getAttackCooldownProgress(0.0F); + if (client.player != null) { + cooldownProgress = client.player.getAttackStrengthScale(0.0F); } boolean isCooldown = cooldownProgress < 1.0f; return isCooldown ? ("Cooldown: " + cooldownProgress) : "Done"; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java index 7f58544..e744c28 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java @@ -17,9 +17,9 @@ public CoordsMod() { @Override public String getText() { - if (mc.player != null) { - return "X: " + (int) mc.player.getX() + " Y: " + (int) mc.player.getY() + " Z: " - + (int) mc.player.getZ(); + if (client.player != null) { + return "X: " + (int) client.player.getX() + " Y: " + (int) client.player.getY() + " Z: " + + (int) client.player.getZ(); } return ""; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java index 21b570c..2388303 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java @@ -17,7 +17,7 @@ public DayCounterMod() { @Override public String getText() { - long time = mc.world.getTime() / 24000L; + long time = client.level.getGameTime() / 24000L; return time + " Day" + (time > 1L ? "s" : ""); } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java index b001f60..8679f23 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java @@ -205,7 +205,7 @@ private void drawNormalTextWithIcons(float startX, float startY, float fontSize, drawTextWithAlpha(playerIcon, currentX, startY, Fonts.getIcon(iconSize), (float) 1.0); currentX += Skia.getTextBounds(playerIcon, Fonts.getIcon(iconSize)).getWidth() + 2; - String playerName = mc.player != null ? mc.player.getName().getString() : "NULL"; + String playerName = client.player != null ? client.player.getName().getString() : "NULL"; drawTextWithAlpha(playerName + " · ", currentX, startY, Fonts.getGoogleSansRegular(fontSize), (float) 1.0); currentX += Skia.getTextBounds(playerName + " · ", Fonts.getGoogleSansRegular(fontSize)).getWidth() + 5; @@ -223,7 +223,7 @@ private void drawNormalTextWithIcons(float startX, float startY, float fontSize, drawTextWithAlpha(fpsIcon, currentX, startY - 1F, Fonts.getIcon(iconSize), (float) 1.0); currentX += Skia.getTextBounds(fpsIcon, Fonts.getIcon(iconSize)).getWidth() + 2; - String fpsText = mc.getCurrentFps() + " FPS"; + String fpsText = client.getFps() + " FPS"; drawTextWithAlpha(fpsText, currentX, startY, Fonts.getGoogleSansRegular(fontSize), (float) 1.0); } @@ -236,7 +236,7 @@ private float calculateNormalTextWidth(float fontSize, float iconSize) { // 玩家图标和名称 String playerIcon = Icon.PERSON; totalWidth += Skia.getTextBounds(playerIcon, Fonts.getIcon(iconSize)).getWidth() + 2; - String playerName = mc.player != null ? mc.player.getName().getString() : "NULL"; + String playerName = client.player != null ? client.player.getName().getString() : "NULL"; totalWidth += Skia.getTextBounds(playerName + " · ", Fonts.getGoogleSansRegular(fontSize)).getWidth() + 5; // 服务器信息和延迟 @@ -248,7 +248,7 @@ private float calculateNormalTextWidth(float fontSize, float iconSize) { // FPS图标和数值 String fpsIcon = Icon.DESKTOP_WINDOWS; totalWidth += Skia.getTextBounds(fpsIcon, Fonts.getIcon(iconSize)).getWidth() + 2; - String fpsText = mc.getCurrentFps() + " FPS"; + String fpsText = client.getFps() + " FPS"; totalWidth += Skia.getTextBounds(fpsText, Fonts.getGoogleSansRegular(fontSize)).getWidth() + 5; return totalWidth; @@ -329,9 +329,9 @@ private float easeInCubic(float x) { } private @NotNull String getServerInfo() { - if (mc.getCurrentServerEntry() != null && mc.player != null) { - String serverAddress = mc.getCurrentServerEntry().address; - long ping = mc.getCurrentServerEntry().ping; + if (client.getCurrentServer() != null && client.player != null) { + String serverAddress = client.getCurrentServer().ip; + long ping = client.getCurrentServer().ping; return ping + "ms to " + serverAddress; } return "Singleplayer"; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java index 6b0322e..326ea77 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java @@ -17,7 +17,7 @@ public FPSDisplayMod() { @Override public String getText() { - return mc.getCurrentFps() + " FPS"; + return client.getFps() + " FPS"; } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java index 3e0c10f..abb00c9 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java @@ -4,14 +4,14 @@ import cn.pupperclient.event.client.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.World; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; public class FallDamageHelp extends SimpleHUDMod { public FallDamageHelp() { @@ -23,19 +23,19 @@ public FallDamageHelp() { }; public static boolean willFallToDeath() { - MinecraftClient client = MinecraftClient.getInstance(); - ClientPlayerEntity player = client.player; + Minecraft client = Minecraft.getInstance(); + LocalPlayer player = client.player; if (player == null) { return false; } - World world = player.getEntityWorld(); + Level world = player.getCommandSenderWorld(); double currentY = player.getY(); - BlockPos playerBlockPos = player.getBlockPos(); + BlockPos playerBlockPos = player.blockPosition(); for (int offset = 1; offset < 256; offset++) { int y = playerBlockPos.getY() - offset; - if (y < world.getBottomY()) { + if (y < world.getMinY()) { break; } @@ -43,14 +43,14 @@ public static boolean willFallToDeath() { BlockState state = world.getBlockState(checkPos); VoxelShape collisionShape = state.getCollisionShape(world, checkPos); - if (!collisionShape.isEmpty() && collisionShape != VoxelShapes.empty()) { - double blockTopY = y + collisionShape.getMax(Direction.Axis.Y); + if (!collisionShape.isEmpty() && collisionShape != Shapes.empty()) { + double blockTopY = y + collisionShape.max(Direction.Axis.Y); double fallDistance = currentY - blockTopY; return fallDistance >= 23; } } - double fallDistance = currentY - world.getBottomY(); + double fallDistance = currentY - world.getMinY(); return fallDistance >= 23; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java index 23ff1a1..b472c05 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java @@ -20,9 +20,9 @@ public String getText() { String prefix = "Mode: "; - if (mc.player.isCreative()) { + if (client.player.isCreative()) { return prefix + "Creative"; - } else if (mc.player.isSpectator()) { + } else if (client.player.isSpectator()) { return prefix + "Spectator"; } else { return prefix + "Survival"; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java index f703d7d..b0c4831 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java @@ -17,8 +17,8 @@ public HealthDisplayMod() { @Override public String getText() { - if (mc.player != null) { - return (int) mc.player.getHealth() + " Health"; + if (client.player != null) { + return (int) client.player.getHealth() + " Health"; } return ""; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java index ee4a86e..dfdbfc0 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java @@ -2,7 +2,7 @@ import java.util.ArrayList; import java.util.List; - +import net.minecraft.client.KeyMapping; import cn.pupperclient.animation.Animation; import cn.pupperclient.animation.Duration; import cn.pupperclient.animation.cubicbezier.impl.EaseStandard; @@ -18,8 +18,6 @@ import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.color.ColorUtils; -import net.minecraft.client.option.KeyBinding; - public class KeystrokesMod extends HUDMod { private List panels = new ArrayList<>(); @@ -34,11 +32,11 @@ public class KeystrokesMod extends HUDMod { public KeystrokesMod() { super("mod.keystrokes.name", "mod.keystrokes.description", Icon.KEYBOARD); - panels.add(new Panel(mc.options.forwardKey, 32, 0)); - panels.add(new Panel(mc.options.leftKey, 0, 32)); - panels.add(new Panel(mc.options.backKey, 32, 32)); - panels.add(new Panel(mc.options.rightKey, 64, 32)); - panels.add(new Panel(mc.options.jumpKey, 0, 64, 92, 22, true)); + panels.add(new Panel(client.options.keyUp, 32, 0)); + panels.add(new Panel(client.options.keyLeft, 0, 32)); + panels.add(new Panel(client.options.keyDown, 32, 32)); + panels.add(new Panel(client.options.keyRight, 64, 32)); + panels.add(new Panel(client.options.keyJump, 0, 64, 92, 22, true)); } @Override @@ -88,11 +86,11 @@ public float getRadius() { private class Panel { private float x, y, width, height; - private KeyBinding keyBinding; + private KeyMapping keyBinding; private boolean jumpKey; private Animation animation; - private Panel(KeyBinding keyBinding, float x, float y, float width, float height, boolean jumpKey) { + private Panel(KeyMapping keyBinding, float x, float y, float width, float height, boolean jumpKey) { this.x = x; this.y = y; this.width = width; @@ -102,7 +100,7 @@ private Panel(KeyBinding keyBinding, float x, float y, float width, float height this.animation = new DummyAnimation(0); } - private Panel(KeyBinding keyBinding, float x, float y) { + private Panel(KeyMapping keyBinding, float x, float y) { this(keyBinding, x, y, 28, 28, false); } @@ -111,7 +109,7 @@ private void draw() { KeystrokesMod.this.drawBackground(getX() + x, getY() + y, width, height); if (!jumpKey && !unmarkSetting.isEnabled()) { - Skia.drawFullCenteredText(keyBinding.getBoundKeyLocalizedText().getString(), getX() + x + (width / 2), + Skia.drawFullCenteredText(keyBinding.getTranslatedKeyMessage().getString(), getX() + x + (width / 2), getY() + y + (height / 2), KeystrokesMod.this.getDesign().getTextColor(), Fonts.getRegular(12)); } @@ -138,10 +136,10 @@ private void drawBlur() { private void update() { - boolean isKeyDown = snapTapSetting.isEnabled() ? keyBinding.isPressed() + boolean isKeyDown = snapTapSetting.isEnabled() ? keyBinding.isDown() : ((IMixinKeyBinding) keyBinding).getRealIsPressed(); - if (isKeyDown && animation.getEnd() != 1 && mc.currentScreen == null) { + if (isKeyDown && animation.getEnd() != 1 && client.screen == null) { animation = new EaseStandard(Duration.MEDIUM_3, animation.getValue(), 1); } else if (!isKeyDown && animation.getEnd() != 0) { animation = new EaseStandard(Duration.MEDIUM_3, animation.getValue(), 0); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java index b81dd66..5de86d7 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java @@ -8,8 +8,7 @@ import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.font.Icon; - -import net.minecraft.util.math.MathHelper; +import net.minecraft.util.Mth; public class MouseStrokesMod extends HUDMod { @@ -47,8 +46,8 @@ public MouseStrokesMod() { public final EventBus.EventListener onPlayerDirectionChange = event -> { mouseX += (event.getYaw() - event.getPrevYaw()) / 7F; mouseY += (event.getPitch() - event.getPrevPitch()) / 7F; - mouseX = MathHelper.clamp(mouseX, -20, 20); - mouseY = MathHelper.clamp(mouseY, -20, 20); + mouseX = Mth.clamp(mouseX, -20, 20); + mouseY = Mth.clamp(mouseY, -20, 20); }; @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java index dd8cdbc..fd4b1c6 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java @@ -17,7 +17,7 @@ public NameDisplayMod() { @Override public String getText() { - return "Name: " + mc.player.getGameProfile().getName(); + return "Name: " + client.player.getGameProfile().getName(); } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java index 70fdb24..5d736e4 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java @@ -35,16 +35,16 @@ private void updatePing() { if (timer.delay((long) (1000 * refreshTimeSetting.getValue()))) { if (ServerUtils.isMultiplayer()) { - if (Objects.requireNonNull(mc.getCurrentServerEntry()).ping <= 1 && !pinging) { + if (Objects.requireNonNull(client.getCurrentServer()).ping <= 1 && !pinging) { Multithreading.runAsync(() -> { pinging = true; - ping = MCPing.pingModern().address(mc.getCurrentServerEntry().address).getSync().getPing(); + ping = MCPing.pingModern().address(client.getCurrentServer().ip).getSync().getPing(); pinging = false; }); } else { - ping = mc.getCurrentServerEntry().ping; + ping = Objects.requireNonNull(client.getCurrentServer()).ping; } - } else if (mc.isIntegratedServerRunning()) { + } else if (client.hasSingleplayerServer()) { ping = 0; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java index 30a4947..fde5591 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java @@ -21,7 +21,7 @@ public PitchDisplayMod() { @Override public String getText() { - return "Pitch: " + df.format(mc.player.getPitch()); + return "Pitch: " + df.format(client.player.getViewXRot(0.0f)); } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java index afa2204..4c12255 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java @@ -5,6 +5,8 @@ import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; +import java.util.Objects; + public class PlayerCounterMod extends SimpleHUDMod { public PlayerCounterMod() { @@ -17,7 +19,8 @@ public PlayerCounterMod() { @Override public String getText() { - return "Player: " + mc.world.getPlayers().size(); + assert client.level != null; + return "Player: " + Objects.requireNonNull(client.level.getServer()).getPlayerCount(); } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java index ee8b89b..1444de1 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java @@ -10,15 +10,14 @@ import cn.pupperclient.skia.font.Fonts; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.misc.RomanConverter; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.effect.StatusEffect; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.registry.entry.RegistryEntry; - import java.awt.*; import java.util.*; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Holder; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; import static cn.pupperclient.management.mod.impl.hud.ArrayListMod.ICON_TEXT_SPACING; @@ -265,18 +264,18 @@ private void drawRoundedBackground(float x, float y, float width, int alpha) { private List getActivePotions() { List activePotions = new ArrayList<>(); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); if (client.player == null) return activePotions; // Get all active status effects - Collection effects = client.player.getStatusEffects(); + Collection effects = client.player.getActiveEffects(); - for (StatusEffectInstance effect : effects) { - RegistryEntry statusEffect = effect.getEffectType(); - String effectkey = statusEffect.value().getTranslationKey(); + for (MobEffectInstance effect : effects) { + Holder statusEffect = effect.getEffect(); + String effectkey = statusEffect.value().getDescriptionId(); String roman_converter = RomanConverter.intToRomanByPlace(effect.getAmplifier()); String amplifier = roman_converter.equals("0") ? " " : " " + roman_converter; - String effectName = statusEffect.value().getName().getString() + amplifier; + String effectName = statusEffect.value().getDisplayName().getString() + amplifier; String timeText = formatDuration(effect); // Calculate widths for layout @@ -295,8 +294,8 @@ private List getActivePotions() { return activePotions; } - private String formatDuration(StatusEffectInstance effect) { - if (effect.isInfinite()) { + private String formatDuration(MobEffectInstance effect) { + if (effect.isInfiniteDuration()) { return "inf"; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java index 2a4b017..e41baf6 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java @@ -1,7 +1,9 @@ package cn.pupperclient.management.mod.impl.hud; import java.text.DecimalFormat; - +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.RenderSkiaEvent; import cn.pupperclient.event.server.impl.AttackEntityEvent; @@ -9,10 +11,6 @@ import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Vec3d; - public class ReachDisplayMod extends SimpleHUDMod { private DecimalFormat df = new DecimalFormat("0.##"); @@ -33,11 +31,14 @@ public ReachDisplayMod() { if (event.getEntityId() == possibleTarget) { - Entity entity = mc.world.getEntityById(event.getEntityId()); + assert client.level != null; + Entity entity = client.level.getEntity(event.getEntityId()); possibleTarget = -1; - distance = mc.player.getEyePos() - .distanceTo(closestPointToBox(mc.player.getEyePos(), entity.getBoundingBox())); + assert client.player != null; + assert entity != null; + distance = client.player.getEyePosition() + .distanceTo(closestPointToBox(client.player.getEyePosition(), entity.getBoundingBox())); hitTime = System.currentTimeMillis(); } }; @@ -46,8 +47,8 @@ public ReachDisplayMod() { possibleTarget = event.getEntityId(); }; - private Vec3d closestPointToBox(Vec3d start, Box box) { - return new Vec3d(coerceIn(start.x, box.minX, box.maxX), coerceIn(start.y, box.minY, box.maxY), + private Vec3 closestPointToBox(Vec3 start, AABB box) { + return new Vec3(coerceIn(start.x, box.minX, box.maxX), coerceIn(start.y, box.minY, box.maxY), coerceIn(start.z, box.minZ, box.maxZ)); } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java index 9e9b1eb..7f32573 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java @@ -4,23 +4,21 @@ import cn.pupperclient.event.client.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleListHUDMod; import cn.pupperclient.skia.font.Icon; -import net.minecraft.client.MinecraftClient; -import net.minecraft.scoreboard.ScoreboardDisplaySlot; -import net.minecraft.scoreboard.ScoreboardEntry; -import net.minecraft.scoreboard.ScoreboardObjective; -import net.minecraft.scoreboard.Team; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - import java.util.ArrayList; import java.util.Collection; import java.util.List; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerScoreEntry; +import net.minecraft.world.scores.PlayerTeam; public class Scoreboard extends SimpleListHUDMod { private static Scoreboard instance; - private final MinecraftClient client = MinecraftClient.getInstance(); + private final Minecraft client = Minecraft.getInstance(); private List displayLines = new ArrayList<>(); public Scoreboard() { @@ -52,26 +50,26 @@ public void draw() { private void updateDisplayLines() { displayLines.clear(); - ScoreboardObjective scoreboardObjective = client.world.getScoreboard().getObjectiveForSlot(ScoreboardDisplaySlot.SIDEBAR); + Objective scoreboardObjective = client.level.getScoreboard().getDisplayObjective(DisplaySlot.SIDEBAR); if (scoreboardObjective == null) { return; } - net.minecraft.scoreboard.Scoreboard scoreboard = scoreboardObjective.getScoreboard(); - Collection scores = scoreboard.getScoreboardEntries(scoreboardObjective); + net.minecraft.world.scores.Scoreboard scoreboard = scoreboardObjective.getScoreboard(); + Collection scores = scoreboard.listPlayerScores(scoreboardObjective); if (scores.isEmpty()) { return; } // 添加标题 - 保留格式化字符 - Text titleText = scoreboardObjective.getDisplayName(); + Component titleText = scoreboardObjective.getDisplayName(); String formattedTitle = convertTextToFormattedString(titleText); displayLines.add(formattedTitle); // 过滤和排序 - List sortedScores = new ArrayList<>(); - for (ScoreboardEntry entry : scores) { - if (!entry.hidden()) { + List sortedScores = new ArrayList<>(); + for (PlayerScoreEntry entry : scores) { + if (!entry.isHidden()) { sortedScores.add(entry); } } @@ -80,19 +78,19 @@ private void updateDisplayLines() { // 添加积分项 int maxLines = Math.min(sortedScores.size(), 199); for (int i = 0; i < maxLines; i++) { - ScoreboardEntry entry = sortedScores.get(i); + PlayerScoreEntry entry = sortedScores.get(i); String line = getFormattedScoreText(entry, scoreboard); displayLines.add(line); } } - private String getFormattedScoreText(ScoreboardEntry entry, net.minecraft.scoreboard.Scoreboard scoreboard) { + private String getFormattedScoreText(PlayerScoreEntry entry, net.minecraft.world.scores.Scoreboard scoreboard) { String playerName = entry.owner(); - Team team = scoreboard.getScoreHolderTeam(playerName); + PlayerTeam team = scoreboard.getPlayersTeam(playerName); String displayName; if (team != null) { - Text formattedName = entry.name(); + Component formattedName = entry.ownerName(); // 使用新的格式化方法 displayName = convertTextToFormattedString(formattedName); } else { @@ -106,7 +104,7 @@ private String getFormattedScoreText(ScoreboardEntry entry, net.minecraft.scoreb * 将 Minecraft Text 对象转换为包含格式化字符的字符串 * 保留颜色代码和格式化信息 */ - private String convertTextToFormattedString(Text text) { + private String convertTextToFormattedString(Component text) { StringBuilder result = new StringBuilder(); convertTextRecursive(text, result); return result.toString(); @@ -115,14 +113,14 @@ private String convertTextToFormattedString(Text text) { /** * 递归处理 Text 对象及其子组件 */ - private void convertTextRecursive(Text text, StringBuilder result) { + private void convertTextRecursive(Component text, StringBuilder result) { // 处理当前文本的样式 if (text.getStyle() != null) { // 添加颜色代码 if (text.getStyle().getColor() != null) { - Formatting formatting = Formatting.byName(text.getStyle().getColor().getName()); + ChatFormatting formatting = ChatFormatting.getByName(text.getStyle().getColor().serialize()); if (formatting != null && formatting.isColor()) { - result.append("§").append(formatting.getCode()); + result.append("§").append(formatting.getChar()); } } @@ -151,7 +149,7 @@ private void convertTextRecursive(Text text, StringBuilder result) { } // 递归处理子组件 - for (Text sibling : text.getSiblings()) { + for (Component sibling : text.getSiblings()) { convertTextRecursive(sibling, result); } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java index 3ef0bf5..93856e3 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java @@ -1,15 +1,13 @@ package cn.pupperclient.management.mod.impl.hud; import java.text.DecimalFormat; - +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.Vec3d; - public class SpeedometerMod extends SimpleHUDMod { private DecimalFormat speedFormat = new DecimalFormat("0.00"); @@ -27,13 +25,13 @@ public String getText() { String suffix = " m/s"; - if (mc.player != null) { + if (client.player != null) { - Entity entity = mc.player.getVehicle() == null ? mc.player : mc.player.getVehicle(); - Vec3d vec = entity.getMovement(); + Entity entity = client.player.getVehicle() == null ? client.player : client.player.getVehicle(); + Vec3 vec = entity.getKnownMovement(); - if (entity.isOnGround() && vec.y < 0) { - vec = new Vec3d(vec.x, 0, vec.z); + if (entity.onGround() && vec.y < 0) { + vec = new Vec3(vec.x, 0, vec.z); } return speedFormat.format(vec.length() * 20) + suffix; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java index 762618f..acb8fda 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java @@ -11,8 +11,7 @@ import cn.pupperclient.management.mod.settings.impl.KeybindSetting; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.time.TimerUtils; - -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class StopwatchMod extends SimpleHUDMod { @@ -22,7 +21,7 @@ public class StopwatchMod extends SimpleHUDMod { private DecimalFormat timeFormat = new DecimalFormat("0.00"); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputUtil.fromKeyCode(GLFW.GLFW_KEY_P, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_P, 0)); public StopwatchMod() { super("mod.stopwatch.name", "mod.stopwatch.description", Icon.TIMER); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java index a038a02..2181543 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java @@ -20,16 +20,16 @@ import cn.pupperclient.utils.minecraft.player.SkinUtils; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.ActionResult; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; public class TargetHUDMod extends HUDMod { private static TargetHUDMod instance; - private PlayerEntity targetPlayer; + private Player targetPlayer; private long lastAttackTime = 0; private static final long DISPLAY_DURATION = 10000; @@ -72,14 +72,14 @@ public void onDisable() { private void registerFabricCallbacks() { AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { - if (world.isClient && player instanceof ClientPlayerEntity && entity instanceof PlayerEntity newTarget) { + if (world.isClientSide && player instanceof LocalPlayer && entity instanceof Player newTarget) { updateTarget(newTarget); } - return ActionResult.PASS; + return InteractionResult.PASS; }); } - private void updateTarget(PlayerEntity newTarget) { + private void updateTarget(Player newTarget) { if (targetPlayer == null || !targetPlayer.equals(newTarget)) { targetPlayer = newTarget; lastAttackTime = System.currentTimeMillis(); @@ -139,10 +139,10 @@ private boolean shouldShowTarget() { private void drawTargetInfo(float width, float height) { boolean isEditing = HUDCore.isEditing; - PlayerEntity displayPlayer; + Player displayPlayer; if (isEditing) { - displayPlayer = MinecraftClient.getInstance().player; + displayPlayer = Minecraft.getInstance().player; } else { displayPlayer = targetPlayer; } @@ -152,8 +152,8 @@ private void drawTargetInfo(float width, float height) { } if (!isEditing) { - MinecraftClient client = MinecraftClient.getInstance(); - if (client.world == null || client.world.getEntityById(displayPlayer.getId()) == null) { + Minecraft client = Minecraft.getInstance(); + if (client.level == null || client.level.getEntity(displayPlayer.getId()) == null) { targetPlayer = null; return; } @@ -260,7 +260,7 @@ private Color blendColors(Color color1, Color color2, float factor) { return new Color(red, green, blue, alpha); } - private void drawPlayerAvatar(PlayerEntity player, float x, float y, float size) { + private void drawPlayerAvatar(Player player, float x, float y, float size) { Skia.save(); try { @@ -283,10 +283,10 @@ private void drawPlayerAvatar(PlayerEntity player, float x, float y, float size) } } - private File getSkinFile(PlayerEntity player) { - if (player instanceof AbstractClientPlayerEntity clientPlayer) { - if (clientPlayer.getSkinTextures() != null) { - File skinFile = SkinUtils.getSkin(clientPlayer.getSkinTextures().texture()); + private File getSkinFile(Player player) { + if (player instanceof AbstractClientPlayer clientPlayer) { + if (clientPlayer.getSkin() != null) { + File skinFile = SkinUtils.getSkin(clientPlayer.getSkin().texture()); if (skinFile.exists()) { return skinFile; } @@ -295,7 +295,7 @@ private File getSkinFile(PlayerEntity player) { return null; } - private float getPlayerHealth(PlayerEntity player) { + private float getPlayerHealth(Player player) { if (player == null) { return 20.0f; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java index c156c26..7813554 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java @@ -4,12 +4,11 @@ import cn.pupperclient.event.client.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; - -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.biome.Biome; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.world.level.biome.Biome; public class WeatherDisplayMod extends SimpleHUDMod { @@ -25,17 +24,17 @@ public WeatherDisplayMod() { public String getText() { String prefix = "Weather: "; - ClientWorld world = mc.world; - ClientPlayerEntity player = mc.player; - BlockPos playerPos = player.getBlockPos(); - RegistryEntry biomeEntry = world.getBiome(playerPos); + ClientLevel world = client.level; + LocalPlayer player = client.player; + BlockPos playerPos = player.blockPosition(); + Holder biomeEntry = world.getBiome(playerPos); if (world.isThundering()) { return prefix + "Thundering"; } if (world.isRaining()) { - if (biomeEntry.value().getPrecipitation(playerPos, world.getSeaLevel()).equals(Biome.Precipitation.SNOW)) { + if (biomeEntry.value().getPrecipitationAt(playerPos, world.getSeaLevel()).equals(Biome.Precipitation.SNOW)) { return prefix + "Snowing"; } else { return prefix + "Raining"; @@ -47,11 +46,10 @@ public String getText() { @Override public String getIcon() { - - ClientWorld world = mc.world; - ClientPlayerEntity player = mc.player; - BlockPos playerPos = player.getBlockPos(); - RegistryEntry biomeEntry = world.getBiome(playerPos); + ClientLevel world = client.level; + LocalPlayer player = client.player; + BlockPos playerPos = player.blockPosition(); + Holder biomeEntry = world.getBiome(playerPos); String iconFont = Icon.SUNNY; @@ -60,7 +58,7 @@ public String getIcon() { } if (world.isRaining()) { - if (biomeEntry.value().getPrecipitation(playerPos, world.getSeaLevel()).equals(Biome.Precipitation.SNOW)) { + if (biomeEntry.value().getPrecipitationAt(playerPos, world.getSeaLevel()).equals(Biome.Precipitation.SNOW)) { iconFont = Icon.WEATHER_SNOWY; } else { iconFont = Icon.RAINY; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java index 0f46916..ffcf1f1 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java @@ -21,7 +21,7 @@ public YawDisplayMod() { @Override public String getText() { - return "Yaw: " + df.format(Math.abs(mc.player.getYaw() % 90)); + return "Yaw: " + df.format(Math.abs(client.player.getViewYRot(0.0f) % 90)); } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/misc/HypixelMod.java b/src/main/java/cn/pupperclient/management/mod/impl/misc/HypixelMod.java index 6b980f9..f5287a0 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/misc/HypixelMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/misc/HypixelMod.java @@ -27,9 +27,9 @@ public HypixelMod() { } public final EventBus.EventListener onClientTick = event -> { - if (autoTipSetting.isEnabled() && mc.player != null && ServerUtils.isJoin(Server.HYPIXEL)) { + if (autoTipSetting.isEnabled() && client.player != null && ServerUtils.isJoin(Server.HYPIXEL)) { if (tipTimer.delay(1200000)) { - mc.player.networkHandler.sendChatCommand("tip all"); + client.player.connection.sendCommand("tip all"); tipTimer.reset(); } } else { diff --git a/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java b/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java index 8f79c46..09b710e 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java @@ -12,9 +12,8 @@ import cn.pupperclient.management.mod.settings.impl.StringSetting; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; -import net.minecraft.text.Text; - import java.io.IOException; +import net.minecraft.network.chat.Component; public class IRCChatMod extends Mod implements IMinecraft, IRCHandler { @@ -69,9 +68,9 @@ public void onDisable() { // IRCHandler implementation @Override public void onMessage(String sender, String message) throws IOException { - if (showMessagesSetting.isEnabled() && mc.player != null) { + if (showMessagesSetting.isEnabled() && client.player != null) { String formattedMessage = String.format("§9[IRC] §b%s§f: %s", sender, message); - mc.player.sendMessage(Text.of(formattedMessage), false); + client.player.displayClientMessage(Component.nullToEmpty(formattedMessage), false); } } @@ -81,8 +80,8 @@ public void onDisconnected(String message) { lastError = message; PupperClient.LOGGER.warn("IRC disconnected: {}", message); - if (mc.player != null) { - mc.player.sendMessage(Text.of("§cIRC disconnected: " + message), false); + if (client.player != null) { + client.player.displayClientMessage(Component.nullToEmpty("§cIRC disconnected: " + message), false); } // Schedule reconnect if auto-connect is enabled @@ -97,16 +96,16 @@ public void onConnected() { lastError = ""; PupperClient.LOGGER.info("IRC connected successfully"); - if (mc.player != null) { - mc.player.sendMessage(Text.of("§aConnected to IRC server!"), false); + if (client.player != null) { + client.player.displayClientMessage(Component.nullToEmpty("§aConnected to IRC server!"), false); } } @Override public String getInGameUsername() { // Use Minecraft username if available, otherwise use setting - if (mc.player != null) { - return mc.player.getGameProfile().getName(); + if (client.player != null) { + return client.player.getGameProfile().getName(); } return usernameSetting.getValue(); } @@ -124,7 +123,7 @@ public String getInGameUsername() { } // Update in-game name periodically if connected - if (isConnected && transport != null && mc.player != null) { + if (isConnected && transport != null && client.player != null) { // This will be handled by the transport's scheduled task } }; @@ -153,8 +152,8 @@ public void connectToIRC() { lastError = e.getMessage(); PupperClient.LOGGER.error("Failed to create IRC transport", e); - if (mc.player != null) { - mc.player.sendMessage(Text.of("§cFailed to connect to IRC: " + e.getMessage()), false); + if (client.player != null) { + client.player.displayClientMessage(Component.nullToEmpty("§cFailed to connect to IRC: " + e.getMessage()), false); } transport = null; @@ -210,8 +209,8 @@ public String getServerInfo() { } private void sendChatMessage(String message) { - if (mc.player != null) { - mc.player.sendMessage(Text.of(message), false); + if (client.player != null) { + client.player.displayClientMessage(Component.nullToEmpty(message), false); } } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/AutoGGMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/AutoGGMod.java index cb02e6d..0b3e961 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/AutoGGMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/AutoGGMod.java @@ -64,12 +64,12 @@ private void processChat(List options, String message) { private void sendMessage(boolean hypixel) { Multithreading.schedule(() -> { if (hypixel) { - if (mc.player != null) { - mc.player.networkHandler.sendChatCommand("achat " + messageSetting.getValue()); + if (client.player != null) { + client.player.connection.sendCommand("achat " + messageSetting.getValue()); } } else { - if (mc.player != null) { - mc.player.networkHandler.sendChatMessage(messageSetting.getValue()); + if (client.player != null) { + client.player.connection.sendChat(messageSetting.getValue()); } } }, (long) delaySetting.getValue(), TimeUnit.SECONDS); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/AutoTextMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/AutoTextMod.java index dd93e02..7066382 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/AutoTextMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/AutoTextMod.java @@ -7,14 +7,14 @@ import cn.pupperclient.management.mod.settings.impl.KeybindSetting; import cn.pupperclient.management.mod.settings.impl.StringSetting; import cn.pupperclient.skia.font.Icon; -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class AutoTextMod extends Mod { - private KeybindSetting text1KeybindSetting = new KeybindSetting("setting.text1key", "setting.text1key.description", Icon.KEYBOARD, this, InputUtil.UNKNOWN_KEY); + private KeybindSetting text1KeybindSetting = new KeybindSetting("setting.text1key", "setting.text1key.description", Icon.KEYBOARD, this, InputConstants.UNKNOWN); private StringSetting text1Setting = new StringSetting("setting.text1", "setting.text1.description", Icon.TEXT_FORMAT, this, ""); - private KeybindSetting text2KeybindSetting = new KeybindSetting("setting.text2key", "setting.text2key.description", Icon.KEYBOARD, this, InputUtil.UNKNOWN_KEY); + private KeybindSetting text2KeybindSetting = new KeybindSetting("setting.text2key", "setting.text2key.description", Icon.KEYBOARD, this, InputConstants.UNKNOWN); private StringSetting text2Setting = new StringSetting("setting.text2", "setting.text2.description", Icon.TEXT_FORMAT, this, ""); - private KeybindSetting text3KeybindSetting = new KeybindSetting("setting.text3key", "setting.text3key.description", Icon.KEYBOARD, this, InputUtil.UNKNOWN_KEY); + private KeybindSetting text3KeybindSetting = new KeybindSetting("setting.text3key", "setting.text3key.description", Icon.KEYBOARD, this, InputConstants.UNKNOWN); private StringSetting text3Setting = new StringSetting("setting.text3", "setting.text3.description", Icon.TEXT_FORMAT, this, ""); @Override @@ -32,20 +32,20 @@ public AutoTextMod() { } public final EventBus.EventListener onClientTick = event -> { - if (mc.player != null) { + if (client.player != null) { return; } if(text1KeybindSetting.isPressed()) { - mc.player.networkHandler.sendChatMessage(text1Setting.getValue()); + client.player.connection.sendChat(text1Setting.getValue()); } if(text2KeybindSetting.isPressed()) { - mc.player.networkHandler.sendChatMessage(text2Setting.getValue()); + client.player.connection.sendChat(text2Setting.getValue()); } if(text3KeybindSetting.isPressed()) { - mc.player.networkHandler.sendChatMessage(text3Setting.getValue()); + client.player.connection.sendChat(text3Setting.getValue()); } }; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java index 9805c7c..5c01b91 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.player; import java.util.Arrays; - +import net.minecraft.client.CameraType; import org.lwjgl.glfw.GLFW; import cn.pupperclient.event.EventBus; @@ -12,23 +12,21 @@ import cn.pupperclient.management.mod.settings.impl.ComboSetting; import cn.pupperclient.management.mod.settings.impl.KeybindSetting; import cn.pupperclient.skia.font.Icon; - -import net.minecraft.client.option.Perspective; -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class FreelookMod extends Mod { private static FreelookMod instance; private boolean active; private boolean toggled; - private Perspective prevPerspective; + private CameraType prevPerspective; private ComboSetting perspectiveSetting = new ComboSetting("setting.perspective", "setting.perspective.description", Icon.CAMERASWITCH, this, Arrays.asList("setting.front", "setting.behind"), "setting.behind"); private BooleanSetting toggleSetting = new BooleanSetting("setting.toggle", "setting.toggle.description", Icon.SWITCH, this, false); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputUtil.fromKeyCode(GLFW.GLFW_KEY_B, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_B, 0)); public FreelookMod() { super("mod.freelook.name", "mod.freelook.description", Icon._360, ModCategory.PLAYER); @@ -68,17 +66,17 @@ public FreelookMod() { private void start() { String option = perspectiveSetting.getOption(); - Perspective perspective = option.equals("setting.front") ? Perspective.THIRD_PERSON_FRONT - : Perspective.THIRD_PERSON_BACK; + CameraType perspective = option.equals("setting.front") ? CameraType.THIRD_PERSON_FRONT + : CameraType.THIRD_PERSON_BACK; active = true; - prevPerspective = mc.options.getPerspective(); - mc.options.setPerspective(perspective); + prevPerspective = client.options.getCameraType(); + client.options.setCameraType(perspective); } private void stop() { active = false; - mc.options.setPerspective(prevPerspective); + client.options.setCameraType(prevPerspective); } public static FreelookMod getInstance() { diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/Sprint.java b/src/main/java/cn/pupperclient/management/mod/impl/player/Sprint.java index 88ee19e..94bbde2 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/Sprint.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/Sprint.java @@ -23,6 +23,6 @@ public void onDisable() { @EventListener public void onTick(ClientTickEvent event) { - mc.options.sprintKey.setPressed(true); + client.options.keySprint.setDown(true); } } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java index 1581b09..09b0381 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.player; import java.util.Arrays; - +import net.minecraft.client.CameraType; import org.lwjgl.glfw.GLFW; import cn.pupperclient.event.EventBus; @@ -12,14 +12,12 @@ import cn.pupperclient.management.mod.settings.impl.ComboSetting; import cn.pupperclient.management.mod.settings.impl.KeybindSetting; import cn.pupperclient.skia.font.Icon; - -import net.minecraft.client.option.Perspective; -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class TaplookMod extends Mod { private boolean active; - private Perspective prevPerspective; + private CameraType prevPerspective; private boolean toggled; private ComboSetting perspectiveSetting = new ComboSetting("setting.perspective", "setting.perspective.description", @@ -27,7 +25,7 @@ public class TaplookMod extends Mod { private BooleanSetting toggleSetting = new BooleanSetting("setting.toggle", "setting.toggle.description", Icon.SWITCH, this, false); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputUtil.fromKeyCode(GLFW.GLFW_KEY_V, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_V, 0)); public TaplookMod() { super("mod.taplook.name", "mod.taplook.description", Icon.TOUCH_APP, ModCategory.PLAYER); @@ -64,16 +62,16 @@ public TaplookMod() { private void start() { String option = perspectiveSetting.getOption(); - Perspective perspective = option.equals("setting.front") ? Perspective.THIRD_PERSON_FRONT - : Perspective.THIRD_PERSON_BACK; + CameraType perspective = option.equals("setting.front") ? CameraType.THIRD_PERSON_FRONT + : CameraType.THIRD_PERSON_BACK; active = true; - prevPerspective = mc.options.getPerspective(); - mc.options.setPerspective(perspective); + prevPerspective = client.options.getCameraType(); + client.options.setCameraType(perspective); } private void stop() { active = false; - mc.options.setPerspective(prevPerspective); + client.options.setCameraType(prevPerspective); } } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java index f6be745..d30607a 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java @@ -13,8 +13,7 @@ import cn.pupperclient.management.mod.settings.impl.KeybindSetting; import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; - -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class ZoomMod extends Mod { @@ -38,7 +37,7 @@ public class ZoomMod extends Mod { private BooleanSetting smoothCameraSetting = new BooleanSetting("setting.smoothcamera", "setting.smoothcamera.description", Icon.MOTION_BLUR, this, true); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputUtil.fromKeyCode(GLFW.GLFW_KEY_C, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_C, 0)); public ZoomMod() { super("mod.zoom.name", "mod.zoom.description", Icon.ZOOM_IN, ModCategory.PLAYER); @@ -51,13 +50,13 @@ public ZoomMod() { if (!active) { active = true; resetFactor(); - wasSmooth = mc.options.smoothCameraEnabled; - mc.options.smoothCameraEnabled = smoothCameraSetting.isEnabled(); + wasSmooth = client.options.smoothCamera; + client.options.smoothCamera = smoothCameraSetting.isEnabled(); } } else if (active) { active = false; setFactor(1); - mc.options.smoothCameraEnabled = wasSmooth; + client.options.smoothCamera = wasSmooth; } }; @@ -66,11 +65,11 @@ public ZoomMod() { event.setCancelled(true); if (event.getAmount() < 0) { if (currentFactor < 0.98) { - currentFactor += 0.03; + currentFactor += 0.03F; } } else if (event.getAmount() > 0) { if (currentFactor > 0.06) { - currentFactor -= 0.03; + currentFactor -= 0.03F; } } } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/BloodParticleMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/BloodParticleMod.java index 6872ab1..8b436ab 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/BloodParticleMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/BloodParticleMod.java @@ -7,16 +7,15 @@ import cn.pupperclient.management.mod.settings.impl.BooleanSetting; import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; - -import net.minecraft.block.Blocks; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.sound.SoundInstance; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.particle.BlockStateParticleEffect; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.sound.SoundCategory; -import net.minecraft.sound.SoundEvents; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.block.Blocks; public class BloodParticleMod extends Mod { @@ -32,21 +31,21 @@ public BloodParticleMod() { public final EventBus.EventListener onAttackEntity = event -> { Entity target = null; - if (mc.world != null) { - target = mc.world.getEntityById(event.getEntityId()); + if (client.level != null) { + target = client.level.getEntity(event.getEntityId()); } if (target instanceof LivingEntity) { for (int i = 0; i < multiplierSetting.getValue(); i++) { - mc.particleManager.addEmitter(target, - new BlockStateParticleEffect(ParticleTypes.BLOCK, Blocks.REDSTONE_BLOCK.getDefaultState())); + client.particleEngine.createTrackingEmitter(target, + new BlockParticleOption(ParticleTypes.BLOCK, Blocks.REDSTONE_BLOCK.defaultBlockState())); } } if (soundSetting.isEnabled() && target != null) { - mc.getSoundManager() - .play(new PositionedSoundInstance(SoundEvents.BLOCK_STONE_BREAK.id(), SoundCategory.BLOCKS, 4.0F, - 1.2F, SoundInstance.createRandom(), false, 0, SoundInstance.AttenuationType.LINEAR, + client.getSoundManager() + .play(new SimpleSoundInstance(SoundEvents.STONE_BREAK.location(), SoundSource.BLOCKS, 4.0F, + 1.2F, SoundInstance.createUnseededRandom(), false, 0, SoundInstance.Attenuation.LINEAR, target.getX(), target.getY(), target.getZ(), false)); } }; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java index c874ac5..c2fe378 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java @@ -10,10 +10,7 @@ import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.render.RippleEffect; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; -import net.minecraft.client.util.Window; +import com.mojang.blaze3d.platform.Window; import io.github.humbleui.skija.Canvas; import io.github.humbleui.skija.Paint; import io.github.humbleui.skija.Shader; @@ -24,6 +21,9 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; public class ClickEffectMod extends Mod { @@ -73,9 +73,9 @@ public void onEnable() { super.onEnable(); // 注册事件监听器 EventBus.getInstance().register(this); - Window window = MinecraftClient.getInstance().getWindow(); - windowWidth = window.getScaledWidth(); - windowHeight = window.getScaledHeight(); + Window window = Minecraft.getInstance().getWindow(); + windowWidth = window.getGuiScaledWidth(); + windowHeight = window.getGuiScaledHeight(); } @Override @@ -86,8 +86,8 @@ public void onDisable() { } public final EventBus.EventListener onMouseClick = event -> { - if ((mc.currentScreen instanceof TitleScreen - || mc.currentScreen instanceof MultiplayerScreen) + if ((client.screen instanceof TitleScreen + || client.screen instanceof JoinMultiplayerScreen) && (event.getButton() == GLFW.GLFW_MOUSE_BUTTON_LEFT || event.getButton() == GLFW.GLFW_MOUSE_BUTTON_RIGHT) ) { @@ -101,9 +101,9 @@ public void onDisable() { }; public final EventBus.EventListener onRenderSkia = event -> { - Window window = MinecraftClient.getInstance().getWindow(); - windowWidth = window.getScaledWidth(); - windowHeight = window.getScaledHeight(); + Window window = Minecraft.getInstance().getWindow(); + windowWidth = window.getGuiScaledWidth(); + windowHeight = window.getGuiScaledHeight(); Iterator iterator = ripples.iterator(); while (iterator.hasNext()) { @@ -118,8 +118,8 @@ public void onDisable() { }; private void renderRipple(Canvas canvas, RippleEffect ripple, Color baseColor) { - Window window = MinecraftClient.getInstance().getWindow(); - float windowHeight = window.getScaledHeight(); + Window window = Minecraft.getInstance().getWindow(); + float windowHeight = window.getGuiScaledHeight(); float flippedY = windowHeight - ripple.getY(); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java index 4f364d7..9a1243d 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java @@ -30,8 +30,8 @@ public MusicWaveformMod() { for (int i = 0; i < MusicPlayer.SPECTRUM_BANDS; i++) { MusicPlayer.ANIMATIONS[i].onTick(MusicPlayer.VISUALIZER[i], 10); - Skia.drawRect(offsetX, mc.getWindow().getScaledHeight() + MusicPlayer.ANIMATIONS[i].getValue(), 10, - mc.getWindow().getScaledHeight(), ColorUtils.applyAlpha(m.getColor(), 80)); + Skia.drawRect(offsetX, client.getWindow().getGuiScaledHeight() + MusicPlayer.ANIMATIONS[i].getValue(), 10, + client.getWindow().getGuiScaledHeight(), ColorUtils.applyAlpha(m.getColor(), 80)); offsetX += 10; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/ParticlesMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/ParticlesMod.java index 25cc181..b0718c4 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/ParticlesMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/ParticlesMod.java @@ -7,15 +7,16 @@ import cn.pupperclient.management.mod.settings.impl.BooleanSetting; import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.enchantment.Enchantments; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.registry.RegistryKeys; +import java.util.Objects; public class ParticlesMod extends Mod { @@ -40,27 +41,29 @@ public ParticlesMod() { int sharpnessAmount = (int) sharpnessAmountSetting.getValue(); int criticalsAmount = (int) criticalsAmountSetting.getValue(); - Entity target = mc.world.getEntityById(event.getEntityId()); - ClientPlayerEntity player = mc.player; + Entity target = client.level.getEntity(event.getEntityId()); + LocalPlayer player = client.player; - boolean critical = criticalsSetting.isEnabled() && player.getAttackCooldownProgress(0.5F) > 0.9F - && !player.isOnGround() && !player.isClimbing() && !player.isTouchingWater() - && !player.hasStatusEffect(StatusEffects.BLINDNESS) && !player.hasVehicle() + boolean critical = criticalsSetting.isEnabled() && player.getAttackStrengthScale(0.5F) > 0.9F + && !player.onGround() && !player.onClimbable() && !player.isInWater() + && !player.hasEffect(MobEffects.BLINDNESS) && !player.isPassenger() && target instanceof LivingEntity && !player.isSprinting(); boolean alwaysSharpness = alwaysSharpnessSetting.isEnabled(); - boolean sharpness = sharpnessSetting.isEnabled() && EnchantmentHelper.getLevel(mc.world.getRegistryManager() - .getOrThrow(RegistryKeys.ENCHANTMENT).getOrThrow(Enchantments.SHARPNESS), player.getWeaponStack()) > 0; + boolean sharpness = sharpnessSetting.isEnabled() && EnchantmentHelper.getItemEnchantmentLevel(client.level.registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(Enchantments.SHARPNESS), Objects.requireNonNull(player).getWeaponItem()) > 0; boolean alwaysCriticals = alwaysCriticalsSetting.isEnabled(); if (critical || alwaysCriticals) { for (int i = 0; i < criticalsAmount - 1; i++) { - mc.particleManager.addEmitter(target, ParticleTypes.CRIT); + assert target != null; + client.particleEngine.createTrackingEmitter(target, ParticleTypes.CRIT); } } if (alwaysSharpness || sharpness) { for (int i = 0; i < sharpnessAmount - 1; i++) { - mc.particleManager.addEmitter(target, ParticleTypes.ENCHANTED_HIT); + assert target != null; + client.particleEngine.createTrackingEmitter(target, ParticleTypes.ENCHANTED_HIT); } } }; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/ProjectileTrailMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/ProjectileTrailMod.java index 670bd13..daf4bec 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/ProjectileTrailMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/ProjectileTrailMod.java @@ -2,7 +2,11 @@ import java.util.Arrays; import java.util.Objects; - +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.phys.AABB; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; import cn.pupperclient.management.mod.Mod; @@ -10,12 +14,6 @@ import cn.pupperclient.management.mod.settings.impl.ComboSetting; import cn.pupperclient.skia.font.Icon; -import net.minecraft.entity.projectile.ProjectileEntity; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.ParticleType; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.util.math.Box; - public class ProjectileTrailMod extends Mod { private ComboSetting effectSetting = new ComboSetting("setting.effect", "setting.effect.description", @@ -30,24 +28,24 @@ public ProjectileTrailMod() { public final EventBus.EventListener onClientTick = event -> { - if (mc.player != null && mc.world != null) { + if (client.player != null && client.level != null) { - Box box = new Box(mc.player.getPos().add(-150.0, -150.0, -150.0), - mc.player.getPos().add(150.0, 150.0, 150.0)); + AABB box = new AABB(client.player.position().add(-150.0, -150.0, -150.0), + client.player.position().add(150.0, 150.0, 150.0)); - for (ProjectileEntity projectile : mc.world.getEntitiesByClass(ProjectileEntity.class, box, + for (Projectile projectile : client.level.getEntitiesOfClass(Projectile.class, box, entity -> true)) { - if (!(projectile.getVelocity().lengthSquared() > 0.01) || projectile.isOnGround() - || mc.world.getBlockState(projectile.getBlockPos()).isSolidBlock(mc.world, - projectile.getBlockPos()) && Objects.requireNonNull(projectile.getOwner()).getId() != mc.player.getId()) { + if (!(projectile.getDeltaMovement().lengthSqr() > 0.01) || projectile.onGround() + || client.level.getBlockState(projectile.blockPosition()).isRedstoneConductor(client.level, + projectile.blockPosition()) && Objects.requireNonNull(projectile.getOwner()).getId() != client.player.getId()) { continue; } ParticleType type = getCurrentType(); - if (type != null && type instanceof ParticleEffect) { - mc.world.addParticle((ParticleEffect) type, projectile.getX(), projectile.getY(), + if (type instanceof ParticleOptions) { + client.level.addParticle((ParticleOptions) type, projectile.getX(), projectile.getY(), projectile.getZ(), 0.0, 0.0, 0.0); } } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java b/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java index 30d8722..6ccbda7 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java @@ -2,7 +2,7 @@ import java.util.Arrays; import java.util.Objects; - +import net.minecraft.client.gui.screens.Screen; import cn.pupperclient.PupperClient; import cn.pupperclient.gui.MusicPlayGui; import org.lwjgl.glfw.GLFW; @@ -22,9 +22,7 @@ import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.language.I18n; import cn.pupperclient.utils.language.Language; - -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class ModMenuSettings extends Mod { @@ -33,9 +31,9 @@ public class ModMenuSettings extends Mod { private boolean languageInitialized = false; private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputUtil.fromKeyCode(GLFW.GLFW_KEY_RIGHT_SHIFT, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_RIGHT_SHIFT, 0)); private KeybindSetting keybindSetting_music = new KeybindSetting("setting.keybind_music", "setting.keybind_music.description", - Icon.KEYBOARD, this, InputUtil.fromKeyCode(GLFW.GLFW_KEY_M, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_M, 0)); private BooleanSetting darkModeSetting = new BooleanSetting("setting.darkmode", "setting.darkmode.description", Icon.DARK_MODE, this, false); private HctColorSetting hctColorSetting = new HctColorSetting("setting.color", "setting.color.description", @@ -97,11 +95,11 @@ private Language getLanguageEnumFromOption(String option) { } if (keybindSetting.isPressed()) { - mc.setScreen(new GuiModMenu()); + client.setScreen(new GuiModMenu()); } if (keybindSetting_music.isPressed()) { - mc.setScreen(new MusicPlayGui()); + client.setScreen(new MusicPlayGui()); } handleLanguageChange(); diff --git a/src/main/java/cn/pupperclient/management/mod/settings/impl/KeybindSetting.java b/src/main/java/cn/pupperclient/management/mod/settings/impl/KeybindSetting.java index d5df79c..06636fd 100644 --- a/src/main/java/cn/pupperclient/management/mod/settings/impl/KeybindSetting.java +++ b/src/main/java/cn/pupperclient/management/mod/settings/impl/KeybindSetting.java @@ -3,16 +3,15 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.Mod; import cn.pupperclient.management.mod.settings.Setting; - -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class KeybindSetting extends Setting { - private final InputUtil.Key defaultKey; - private InputUtil.Key key; + private final InputConstants.Key defaultKey; + private InputConstants.Key key; private boolean keyDown; private int pressTime; - public KeybindSetting(String name, String description, String icon, Mod parent, InputUtil.Key key) { + public KeybindSetting(String name, String description, String icon, Mod parent, InputConstants.Key key) { super(name, description, icon, parent); this.defaultKey = key; @@ -26,15 +25,15 @@ public void reset() { this.key = this.defaultKey; } - public InputUtil.Key getKey() { + public InputConstants.Key getKey() { return key; } - public void setKey(InputUtil.Key key) { + public void setKey(InputConstants.Key key) { this.key = key; } - public InputUtil.Key getDefaultKey() { + public InputConstants.Key getDefaultKey() { return defaultKey; } diff --git a/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java b/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java index f1cf945..a7600e4 100644 --- a/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java +++ b/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java @@ -1,17 +1,16 @@ package cn.pupperclient.management.quickplay; import java.util.ArrayList; - -import net.minecraft.util.Identifier; +import net.minecraft.resources.ResourceLocation; public class QuickPlay { private ArrayList commands = new ArrayList(); private final String name; - private final Identifier icon; + private final ResourceLocation icon; - public QuickPlay(String name, Identifier icon) { + public QuickPlay(String name, ResourceLocation icon) { this.name = name; this.icon = icon; this.addCommands(); @@ -27,7 +26,7 @@ public ArrayList getCommands() { return commands; } - public Identifier getIcon() { + public ResourceLocation getIcon() { return icon; } diff --git a/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java b/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java index 499d344..07ad353 100644 --- a/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java +++ b/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java @@ -2,13 +2,12 @@ import cn.pupperclient.management.quickplay.QuickPlay; import cn.pupperclient.management.quickplay.QuickPlayCommand; -import net.minecraft.util.Identifier; - import java.util.ArrayList; +import net.minecraft.resources.ResourceLocation; public class ArcadeQuickPlay extends QuickPlay { public ArcadeQuickPlay() { - super("Arcade", Identifier.of("pupper/icons/hypixel/", "Arcade.png")); + super("Arcade", ResourceLocation.fromNamespaceAndPath("pupper/icons/hypixel/", "Arcade.png")); } @Override diff --git a/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java b/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java index 522584c..da11d1f 100644 --- a/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java +++ b/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java @@ -6,15 +6,13 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.User; import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import cn.pupperclient.management.websocket.client.SoarWebSocketClient; import cn.pupperclient.management.websocket.packet.SoarPacket; import cn.pupperclient.utils.http.HttpUtils; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.session.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +22,7 @@ public class WebSocketManager { private static final int MAX_RETRY_ATTEMPTS = 3; private static final int CONNECTION_CHECK_INTERVAL_SECONDS = 10; - private final MinecraftClient minecraftClient; + private final Minecraft minecraftClient; private final ScheduledExecutorService scheduler; private GameProfile currentGameProfile; @@ -33,7 +31,7 @@ public class WebSocketManager { private final boolean isShuttingDown = false; public WebSocketManager() { - this.minecraftClient = MinecraftClient.getInstance(); + this.minecraftClient = Minecraft.getInstance(); this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> { Thread thread = new Thread(r, "WebSocket-Manager"); thread.setDaemon(true); @@ -135,15 +133,15 @@ private void closeExistingConnection() { private boolean authenticateWithMojang() { - Session session = minecraftClient.getSession(); - if (session == null || session.getAccessToken() == null || session.getUuidOrNull() == null) { + User session = minecraftClient.getUser(); + if (session == null || session.getAccessToken() == null || session.getProfileId() == null) { LOGGER.error("Invalid Minecraft session"); return false; } JsonObject authRequest = new JsonObject(); authRequest.addProperty("accessToken", session.getAccessToken()); - authRequest.addProperty("selectedProfile", session.getUuidOrNull().toString().replace("-", "")); + authRequest.addProperty("selectedProfile", session.getProfileId().toString().replace("-", "")); authRequest.addProperty("serverId", "cbd2c3f65d7ba5cceba0cc9647ff9a85c371f4"); try { diff --git a/src/main/java/cn/pupperclient/mixin/interfaces/IMixinLivingEntity.java b/src/main/java/cn/pupperclient/mixin/interfaces/IMixinLivingEntity.java index 5b12dcd..c88dd00 100644 --- a/src/main/java/cn/pupperclient/mixin/interfaces/IMixinLivingEntity.java +++ b/src/main/java/cn/pupperclient/mixin/interfaces/IMixinLivingEntity.java @@ -1,7 +1,7 @@ package cn.pupperclient.mixin.interfaces; -import net.minecraft.util.Hand; +import net.minecraft.world.InteractionHand; public interface IMixinLivingEntity { - void soarClient_CN$fakeSwingHand(Hand hand); + void soarClient_CN$fakeSwingHand(InteractionHand hand); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java index 419e688..6a362de 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java @@ -10,24 +10,23 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.settings.impl.KeybindSetting; +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyboardHandler; -import net.minecraft.client.Keyboard; -import net.minecraft.client.util.InputUtil; - -@Mixin(Keyboard.class) +@Mixin(KeyboardHandler.class) public abstract class MixinKeyboard { @Inject( - method = "onKey(JIIII)V", + method = "keyPress(JIIII)V", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/option/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V", + target = "Lnet/minecraft/client/KeyMapping;click(Lcom/mojang/blaze3d/platform/InputConstants$Key;)V", shift = At.Shift.AFTER ) ) private void onKeyPressed(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { - InputUtil.Key inputKey = InputUtil.fromKeyCode(key, scancode); + InputConstants.Key inputKey = InputConstants.getKey(key, scancode); for (KeybindSetting setting : PupperClient.getInstance().getModManager().getKeybindSettings()) { if (setting.getKey().equals(inputKey)) { setting.setPressed(); @@ -38,16 +37,16 @@ private void onKeyPressed(long window, int key, int scancode, int action, int mo } @Inject( - method = "onKey(JIIII)V", + method = "keyPress(JIIII)V", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/option/KeyBinding;setKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;Z)V", + target = "Lnet/minecraft/client/KeyMapping;set(Lcom/mojang/blaze3d/platform/InputConstants$Key;Z)V", shift = At.Shift.AFTER ) ) private void onKeyReleased(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { if (action == GLFW.GLFW_RELEASE) { - InputUtil.Key inputKey = InputUtil.fromKeyCode(key, scancode); + InputConstants.Key inputKey = InputConstants.getKey(key, scancode); for (KeybindSetting setting : PupperClient.getInstance().getModManager().getKeybindSettings()) { if (setting.getKey().equals(inputKey)) { setting.setKeyDown(false); @@ -58,7 +57,7 @@ private void onKeyReleased(long window, int key, int scancode, int action, int m @Inject( at = {@At("HEAD")}, - method = {"onKey"} + method = {"keyPress"} ) private void onKeyPress(long pWindowPointer, int pKey, int pScanCode, int pAction, int pModifiers, CallbackInfo ci) { if (pKey != -1 && PupperClient.getInstance() != null && EventBus.getInstance() != null) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index b60ca3c..cd40002 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -2,10 +2,23 @@ import java.io.File; import java.io.IOException; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.main.GameConfig; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.HitResult.Type; import cn.pupperclient.shader.impl.Kawaseblur; +import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.gui.screen.Screen; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -28,22 +41,7 @@ import cn.pupperclient.mixin.interfaces.IMixinMinecraftClient; import cn.pupperclient.skia.context.SkiaContext; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.RunArgs; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerInteractionManager; -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.particle.ParticleManager; -import net.minecraft.client.util.Window; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.hit.HitResult.Type; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; - -@Mixin(value = MinecraftClient.class, priority = 300) +@Mixin(value = Minecraft.class, priority = 300) public abstract class MixinMinecraftClient implements IMixinMinecraftClient { @Shadow @@ -51,29 +49,29 @@ public abstract class MixinMinecraftClient implements IMixinMinecraftClient { private Window window; @Shadow - public int attackCooldown; + public int missTime; @Shadow - public ClientPlayerInteractionManager interactionManager; + public MultiPlayerGameMode gameMode; @Final @Shadow - public ParticleManager particleManager; + public ParticleEngine particleEngine; @Shadow - public GameOptions options; + public Options options; @Shadow - public HitResult crosshairTarget; + public HitResult hitResult; @Shadow - public ClientWorld world; + public ClientLevel level; @Shadow - public ClientPlayerEntity player; + public LocalPlayer player; @Shadow - protected abstract String getWindowTitle(); + protected abstract String createTitle(); @Shadow public abstract void setScreen(@Nullable Screen screen); @@ -81,41 +79,41 @@ public abstract class MixinMinecraftClient implements IMixinMinecraftClient { @Unique private File assetDir; - @Inject(method = "(Lnet/minecraft/client/RunArgs;)V", at = @At("TAIL")) - public void onInit(RunArgs args, CallbackInfo ci) { - assetDir = args.directories.assetDir; + @Inject(method = "(Lnet/minecraft/client/main/GameConfig;)V", at = @At("TAIL")) + public void onInit(GameConfig args, CallbackInfo ci) { + assetDir = args.location.assetDirectory; } - @Inject(method = "stop", at = @At("HEAD")) + @Inject(method = "destroy", at = @At("HEAD")) public void onStop(CallbackInfo ci) { PupperClient.getInstance().getConfigManager().save(ConfigType.MOD); } - @Inject(method = "handleBlockBreaking", at = @At("HEAD")) + @Inject(method = "continueAttack", at = @At("HEAD")) private void handleBlockBreaking(boolean breaking, CallbackInfo ci) { if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isOldBreaking()) { - if (this.options.attackKey.isPressed() && this.options.useKey.isPressed()) { + if (this.options.keyAttack.isDown() && this.options.keyUse.isDown()) { - if (breaking && this.crosshairTarget != null && this.crosshairTarget.getType() == Type.BLOCK) { + if (breaking && this.hitResult != null && this.hitResult.getType() == Type.BLOCK) { - BlockHitResult blockHitResult = (BlockHitResult) this.crosshairTarget; + BlockHitResult blockHitResult = (BlockHitResult) this.hitResult; BlockPos blockPos = blockHitResult.getBlockPos(); - if (!this.world.getBlockState(blockPos).isAir()) { - Direction direction = blockHitResult.getSide(); - this.particleManager.addBlockBreakingParticles(blockPos, direction); - ((IMixinLivingEntity) player).soarClient_CN$fakeSwingHand(Hand.MAIN_HAND); + if (!this.level.getBlockState(blockPos).isAir()) { + Direction direction = blockHitResult.getDirection(); + this.particleEngine.crack(blockPos, direction); + ((IMixinLivingEntity) player).soarClient_CN$fakeSwingHand(InteractionHand.MAIN_HAND); } } } } } - @Inject(method = "doAttack", at = @At("HEAD")) + @Inject(method = "startAttack", at = @At("HEAD")) private void onHitDelayFix(CallbackInfoReturnable cir) { if (HitDelayFixMod.getInstance().isEnabled()) { - attackCooldown = 0; + missTime = 0; RenderSystem.defaultBlendFunc(); } } @@ -125,18 +123,18 @@ private void onHitDelayFix(CallbackInfoReturnable cir) { * @reason updateWindowTitle */ @Overwrite - public void updateWindowTitle() { + public void updateTitle() { this.window.setTitle(PupperClient.getInstance().getName() + " | " + PupperClient.getInstance().getVersion() + " for " - + getWindowTitle()); + + createTitle()); } @Inject(method = "", at = @At("TAIL")) public void init(CallbackInfo ci) throws IOException { - SkiaContext.createSurface(window.getWidth(), window.getHeight()); + SkiaContext.createSurface(window.getScreenWidth(), window.getScreenHeight()); PupperClient.getInstance().start(); } - @Inject(method = "stop", at = @At("HEAD")) + @Inject(method = "destroy", at = @At("HEAD")) public void onShutdown(CallbackInfo ci) { PupperClient.getInstance().onShutdown(); } @@ -146,12 +144,12 @@ public void onClientTick(CallbackInfo ci) { EventBus.getInstance().post(new ClientTickEvent()); } - @Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;printCrashReport()V")) + @Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;handleDelayedCrash()V")) public void onGameLoop(CallbackInfo ci) { EventBus.getInstance().post(new GameLoopEvent()); } - @Inject(method = "onResolutionChanged", at = @At("TAIL")) + @Inject(method = "resizeDisplay", at = @At("TAIL")) public void onResolutionChanged(CallbackInfo info) { Kawaseblur.GUI_BLUR.resize(); Kawaseblur.INGAME_BLUR.resize(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java index 8253540..7dd0adf 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java @@ -3,8 +3,6 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.client.MouseClickEvent; import cn.pupperclient.management.mod.impl.hud.CPSDisplayMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.Window; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -14,19 +12,20 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.MouseScrollEvent; import cn.pupperclient.management.mod.settings.impl.KeybindSetting; +import com.mojang.blaze3d.platform.InputConstants.Type; +import com.mojang.blaze3d.platform.Window; +import net.minecraft.client.Minecraft; +import net.minecraft.client.MouseHandler; -import net.minecraft.client.Mouse; -import net.minecraft.client.util.InputUtil.Type; - -@Mixin(Mouse.class) +@Mixin(MouseHandler.class) public abstract class MixinMouse { - @Inject(method = "onMouseButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V", shift = At.Shift.AFTER)) + @Inject(method = "onPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;click(Lcom/mojang/blaze3d/platform/InputConstants$Key;)V", shift = At.Shift.AFTER)) public void onPressed(long window, int button, int action, int mods, CallbackInfo ci) { for (KeybindSetting s : PupperClient.getInstance().getModManager().getKeybindSettings()) { - if (s.getKey().equals(Type.MOUSE.createFromCode(button))) { + if (s.getKey().equals(Type.MOUSE.getOrCreate(button))) { if (action == GLFW.GLFW_PRESS) { s.setPressed(); @@ -37,34 +36,34 @@ public void onPressed(long window, int button, int action, int mods, CallbackInf } } - @Inject(method = "onMouseButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;setKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;Z)V", shift = At.Shift.AFTER, ordinal = 0)) + @Inject(method = "onPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;set(Lcom/mojang/blaze3d/platform/InputConstants$Key;Z)V", shift = At.Shift.AFTER, ordinal = 0)) public void onReleased(long window, int button, int action, int mods, CallbackInfo ci) { for (KeybindSetting s : PupperClient.getInstance().getModManager().getKeybindSettings()) { - if (s.getKey().equals(Type.MOUSE.createFromCode(button))) { + if (s.getKey().equals(Type.MOUSE.getOrCreate(button))) { s.setKeyDown(false); } } } - @Inject(method = "onMouseButton", at = @At("HEAD")) + @Inject(method = "onPress", at = @At("HEAD")) private void onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) { if (action == GLFW.GLFW_PRESS) { - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); if (client == null) return; - double rawX = client.mouse.getX(); - double rawY = client.mouse.getY(); + double rawX = client.mouseHandler.xpos(); + double rawY = client.mouseHandler.ypos(); Window win = client.getWindow(); - double scaleFactor = win.getScaleFactor(); + double scaleFactor = win.getGuiScale(); double scaledX = rawX / scaleFactor; - double scaledY = win.getScaledHeight() - (rawY / scaleFactor); + double scaledY = win.getGuiScaledHeight() - (rawY / scaleFactor); EventBus.getInstance().post(new MouseClickEvent(button, scaledX, scaledY)); } } - @Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerInventory;setSelectedSlot(I)V", shift = At.Shift.BEFORE), cancellable = true) + @Inject(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;setSelectedHotbarSlot(I)V", shift = At.Shift.BEFORE), cancellable = true) private void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) { MouseScrollEvent event = new MouseScrollEvent(vertical); @@ -76,7 +75,7 @@ private void onMouseScroll(long window, double horizontal, double vertical, Call } } - @Inject(method = "onMouseButton", at = @At("HEAD")) + @Inject(method = "onPress", at = @At("HEAD")) public void onMouseButtonForCPS(long window, int button, int action, int mods, CallbackInfo ci) { CPSDisplayMod cpsDisplayMod = PupperClient.getInstance().getModManager().getMods() .stream() diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java index 28ce71e..49ecd3a 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java @@ -2,7 +2,14 @@ import java.util.Map; import java.util.UUID; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.BossHealthOverlay; +import net.minecraft.client.gui.components.LerpingBossEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.util.profiling.Profiler; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.BossEvent; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -14,31 +21,22 @@ import cn.pupperclient.management.mod.api.Position; import cn.pupperclient.management.mod.impl.hud.BossBarMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.BossBarHud; -import net.minecraft.client.gui.hud.ClientBossBar; -import net.minecraft.entity.boss.BossBar; -import net.minecraft.text.Text; -import net.minecraft.util.profiler.Profiler; -import net.minecraft.util.profiler.Profilers; - -@Mixin(BossBarHud.class) +@Mixin(BossHealthOverlay.class) public abstract class MixinBossBarHud { @Shadow @Final - private MinecraftClient client; + private Minecraft minecraft; @Shadow @Final - final Map bossBars = Maps.newLinkedHashMap(); + final Map events = Maps.newLinkedHashMap(); @Shadow - public abstract void renderBossBar(DrawContext context, int x, int y, BossBar bossBar); + public abstract void drawBar(GuiGraphics context, int x, int y, BossEvent bossBar); @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void render(DrawContext context, CallbackInfo ci) { + private void render(GuiGraphics context, CallbackInfo ci) { BossBarMod mod = BossBarMod.getInstance(); @@ -53,26 +51,26 @@ private void render(DrawContext context, CallbackInfo ci) { } } - public void onCustomRender(DrawContext context, int x, int y) { + public void onCustomRender(GuiGraphics context, int x, int y) { - if (!this.bossBars.isEmpty()) { + if (!this.events.isEmpty()) { - Profiler profiler = Profilers.get(); + ProfilerFiller profiler = Profiler.get(); profiler.push("bossHealth"); int j = y; - for (ClientBossBar clientBossBar : this.bossBars.values()) { + for (LerpingBossEvent clientBossBar : this.events.values()) { - Text text = clientBossBar.getName(); - int m = this.client.textRenderer.getWidth(text); + Component text = clientBossBar.getName(); + int m = this.minecraft.font.width(text); int n = x - m / 2; - context.drawTextWithShadow(this.client.textRenderer, text, n, j, 16777215); + context.drawString(this.minecraft.font, text, n, j, 16777215); int k = x - 91; - this.renderBossBar(context, k, j + 9, clientBossBar); + this.drawBar(context, k, j + 9, clientBossBar); j += 10 + 9; - if (j >= context.getScaledWindowHeight() / 3) { + if (j >= context.guiHeight() / 3) { break; } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java index 988c507..58cfc07 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java @@ -2,18 +2,18 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.server.ChatEvent; -import net.minecraft.client.gui.hud.ChatHud; -import net.minecraft.text.Text; +import net.minecraft.client.gui.components.ChatComponent; +import net.minecraft.network.chat.Component; 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(ChatHud.class) +@Mixin(ChatComponent.class) public abstract class MixinChatHud { - @Inject(method = "addMessage(Lnet/minecraft/text/Text;)V", at = @At("HEAD")) - private void onChatMessage(Text message, CallbackInfo ci) { + @Inject(method = "addMessage(Lnet/minecraft/network/chat/Component;)V", at = @At("HEAD")) + private void onChatMessage(Component message, CallbackInfo ci) { String rawMessage = message.getString(); if (rawMessage.startsWith("§7[§bPupper§7]")) return; ChatEvent event = new ChatEvent(rawMessage); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java index f1132de..462c3a5 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java @@ -1,23 +1,24 @@ package cn.pupperclient.mixin.mixins.minecraft.client.gui; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.LanguageOptionsScreen; -import net.minecraft.text.Text; 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 static cn.pupperclient.utils.minecraft.interfaces.IMinecraft.mc; +import static cn.pupperclient.utils.minecraft.interfaces.IMinecraft.client; -@Mixin(value = LanguageOptionsScreen.class, priority = 1001) +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.options.LanguageSelectScreen; +import net.minecraft.network.chat.Component; + +@Mixin(value = LanguageSelectScreen.class, priority = 1001) public class MixinLanguageScreen extends Screen { - protected MixinLanguageScreen(Text title) { + protected MixinLanguageScreen(Component title) { super(title); } @Inject(method = "onDone", at = @At("TAIL")) public void onDone(CallbackInfo ci) { - mc.inGameHud.getChatHud().reset(); + minecraft.gui.getChat().rescaleChat(); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinMultiplayerScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinMultiplayerScreen.java index 32fdd8f..9d95e6b 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinMultiplayerScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinMultiplayerScreen.java @@ -7,21 +7,20 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ServerJoinEvent; +import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; +import net.minecraft.client.multiplayer.ServerData; -import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; -import net.minecraft.client.network.ServerInfo; - -@Mixin(MultiplayerScreen.class) +@Mixin(JoinMultiplayerScreen.class) public class MixinMultiplayerScreen { - @Inject(method = "connect(Lnet/minecraft/client/network/ServerInfo;)V", at = @At("HEAD")) - private void onConnect(ServerInfo server, CallbackInfo ci) { - EventBus.getInstance().post(new ServerJoinEvent(server.address)); + @Inject(method = "join(Lnet/minecraft/client/multiplayer/ServerData;)V", at = @At("HEAD")) + private void onConnect(ServerData server, CallbackInfo ci) { + EventBus.getInstance().post(new ServerJoinEvent(server.ip)); } @Inject(method = "removed", at = @At("HEAD"), cancellable = true) public void onRemoved(CallbackInfo ci) { - if (((MultiplayerScreen) (Object) this).serverListWidget == null) { + if (((JoinMultiplayerScreen) (Object) this).serverSelectionList == null) { ci.cancel(); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java index 269bddc..1fa8ac6 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java @@ -6,30 +6,29 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import cn.pupperclient.gui.GuiResourcePackConvert; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.packs.PackSelectionScreen; +import net.minecraft.network.chat.Component; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.pack.PackScreen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.Text; - -@Mixin(PackScreen.class) +@Mixin(PackSelectionScreen.class) public class MixinPackScreen extends Screen { - protected MixinPackScreen(Text title) { + protected MixinPackScreen(Component title) { super(title); } @Inject(method = "init", at = @At("HEAD")) private void onInit(CallbackInfo ci) { - ButtonWidget.Builder builder = ButtonWidget - .builder(Text.of("Convert"), button -> { - if (client != null) { - client.setScreen(new GuiResourcePackConvert(this)); + Button.Builder builder = Button + .builder(Component.nullToEmpty("Convert"), button -> { + if (minecraft != null) { + minecraft.setScreen(new GuiResourcePackConvert(this)); } }).size(98, 20); - builder.position(width - 98 - 5, 5); - this.addDrawableChild(builder.build()); + builder.pos(width - 98 - 5, 5); + this.addRenderableWidget(builder.build()); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java index 534c732..83be38e 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java @@ -7,12 +7,6 @@ import io.github.humbleui.skija.Font; import io.github.humbleui.types.Rect; import java.awt.Color; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.SplashOverlay; -import net.minecraft.client.texture.ResourceTexture; -import net.minecraft.util.Identifier; -import net.minecraft.util.Util; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -24,19 +18,25 @@ import java.util.Optional; import java.util.function.Consumer; - -@Mixin(SplashOverlay.class) +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.LoadingOverlay; +import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.resources.ResourceLocation; + +@Mixin(LoadingOverlay.class) public abstract class MixinSplashScreen { - @Shadow @Final private MinecraftClient client; - @Shadow @Final private boolean reloading; - @Shadow @Final private Consumer> exceptionHandler; + @Shadow @Final private Minecraft minecraft; + @Shadow @Final private boolean fadeIn; + @Shadow @Final private Consumer> onFinish; // Animation timing variables @Unique private long soar_animationStartTime = -1L; @Unique private long soar_reloadStartTime = -1L; @Unique private static final long MAX_RELOAD_TIME = 15_000L; - @Unique private static final Identifier CUSTOM_LOGO = Identifier.of("pupper", "logo.png"); + @Unique private static final ResourceLocation CUSTOM_LOGO = ResourceLocation.fromNamespaceAndPath("pupper", "logo.png"); @Unique private static final int LOGO_ACTUAL_SIZE = 1080; @Unique private static final float LOGO_SCALE = 0.15f; @Unique private static final long ANIMATION_TOTAL_TIME = 4500L; @@ -60,16 +60,16 @@ public abstract class MixinSplashScreen { @Unique private void ensureLogoTexture() { - var tm = this.client.getTextureManager(); + var tm = this.minecraft.getTextureManager(); if (tm.getTexture(CUSTOM_LOGO) == null) { - tm.registerTexture(CUSTOM_LOGO, new ResourceTexture(CUSTOM_LOGO)); + tm.registerAndLoad(CUSTOM_LOGO, new SimpleTexture(CUSTOM_LOGO)); } } @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void pupper_takeOverAndRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - int width = MinecraftClient.getInstance().getWindow().getWidth(); - int height = MinecraftClient.getInstance().getWindow().getHeight(); + private void pupper_takeOverAndRender(GuiGraphics context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + int width = Minecraft.getInstance().getWindow().getScreenWidth(); + int height = Minecraft.getInstance().getWindow().getScreenHeight(); // Recreate surface if window size changed if (lastWindowWidth != width || lastWindowHeight != height) { @@ -94,8 +94,8 @@ private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, in ensureLogoTexture(); // Handle reloading state - if (this.reloading) { - if (this.soar_reloadStartTime == -1L) this.soar_reloadStartTime = Util.getMeasuringTimeMs(); + if (this.fadeIn) { + if (this.soar_reloadStartTime == -1L) this.soar_reloadStartTime = Util.getMillis(); this.soar_animationStartTime = -1L; this.welcomeDisplayed = false; this.tapPromptDisplayed = false; @@ -104,11 +104,11 @@ private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, in this.tapPromptStartTime = -1L; this.tapClickTime = -1L; - long reloadElapsed = Util.getMeasuringTimeMs() - this.soar_reloadStartTime; + long reloadElapsed = Util.getMillis() - this.soar_reloadStartTime; if (reloadElapsed > MAX_RELOAD_TIME) { try { - this.client.setOverlay(null); - this.exceptionHandler.accept(Optional.empty()); + this.minecraft.setOverlay(null); + this.onFinish.accept(Optional.empty()); } catch (Exception ignored) {} this.soar_reloadStartTime = -1L; return; @@ -120,43 +120,43 @@ private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, in this.soar_reloadStartTime = -1L; if (this.soar_animationStartTime == -1L) { - this.soar_animationStartTime = Util.getMeasuringTimeMs(); + this.soar_animationStartTime = Util.getMillis(); } - long timePassed = Util.getMeasuringTimeMs() - this.soar_animationStartTime; + long timePassed = Util.getMillis() - this.soar_animationStartTime; // Check if welcome screen should be displayed if (timePassed >= ANIMATION_TOTAL_TIME && !welcomeDisplayed) { welcomeDisplayed = true; - welcomeStartTime = Util.getMeasuringTimeMs(); + welcomeStartTime = Util.getMillis(); tapPromptDisplayed = false; tapClicked = false; } // Welcome screen logic if (welcomeDisplayed) { - long welcomeTimePassed = Util.getMeasuringTimeMs() - welcomeStartTime; + long welcomeTimePassed = Util.getMillis() - welcomeStartTime; // Check if tap prompt should be displayed (1-second delay) if (!tapPromptDisplayed) { tapPromptDisplayed = true; - tapPromptStartTime = Util.getMeasuringTimeMs(); + tapPromptStartTime = Util.getMillis(); } // Check if tap prompt was clicked - if (!tapClicked && GLFW.glfwGetMouseButton(this.client.getWindow().getHandle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS) { + if (!tapClicked && GLFW.glfwGetMouseButton(this.minecraft.getWindow().getWindow(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS) { tapClicked = true; - tapClickTime = Util.getMeasuringTimeMs(); + tapClickTime = Util.getMillis(); } if (tapClicked) { - long clickTimePassed = Util.getMeasuringTimeMs() - tapClickTime; + long clickTimePassed = Util.getMillis() - tapClickTime; if (clickTimePassed >= CLICK_FADE_DURATION) { // After fade out, close splash screen try { - this.client.setOverlay(null); - this.exceptionHandler.accept(Optional.empty()); + this.minecraft.setOverlay(null); + this.onFinish.accept(Optional.empty()); } catch (Exception ignored) {} this.soar_animationStartTime = -1L; this.welcomeDisplayed = false; @@ -175,8 +175,8 @@ private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, in // Check if timeout (auto exit after display time) if (welcomeTimePassed >= WELCOME_DISPLAY_TIME) { try { - this.client.setOverlay(null); - this.exceptionHandler.accept(Optional.empty()); + this.minecraft.setOverlay(null); + this.onFinish.accept(Optional.empty()); } catch (Exception ignored) {} this.soar_animationStartTime = -1L; this.welcomeDisplayed = false; @@ -248,7 +248,7 @@ private void renderLoadingScreen(int width, int height, long timePassed, float a @Unique private void drawLogo(int x, int y, int size, float alpha) { // Draw logo using Skia - int textureId = MinecraftClient.getInstance().getTextureManager().getTexture(CUSTOM_LOGO).getGlId(); + int textureId = Minecraft.getInstance().getTextureManager().getTexture(CUSTOM_LOGO).getId(); Skia.drawImage(textureId, x, y, size, size, alpha); } @@ -309,7 +309,7 @@ private void renderWelcomeScreen(int width, int height, long welcomeTimePassed, } else { // Before click: TTS text has continuous fade in/out animation if (tapPromptDisplayed) { - long ttsTimePassed = Util.getMeasuringTimeMs() - tapPromptStartTime; + long ttsTimePassed = Util.getMillis() - tapPromptStartTime; ttsAlpha = getTTSAnimationAlpha(ttsTimePassed); } else { ttsAlpha = 0f; // Not displayed yet diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java index f66c398..fad9a8d 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java @@ -1,26 +1,25 @@ package cn.pupperclient.mixin.mixins.minecraft.client.gui; import cn.pupperclient.gui.MainMenuGui; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.network.chat.Component; 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 net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.text.Text; - @Mixin(value = TitleScreen.class, priority = 1001) public abstract class MixinTitleScreen extends Screen { - protected MixinTitleScreen(Text title) { + protected MixinTitleScreen(Component title) { super(title); } @Inject(method = "init()V", at = @At("HEAD"), cancellable = true) public void onInit(CallbackInfo ci) { - MinecraftClient.getInstance().setScreen(new MainMenuGui()); + Minecraft.getInstance().setScreen(new MainMenuGui()); ci.cancel(); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/option/MixinKeyBinding.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/option/MixinKeyBinding.java index e2b5c3d..045e033 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/option/MixinKeyBinding.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/option/MixinKeyBinding.java @@ -10,21 +10,20 @@ import cn.pupperclient.management.mod.impl.player.SnapTapMod; import cn.pupperclient.mixin.interfaces.IMixinKeyBinding; +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; - -@Mixin(KeyBinding.class) +@Mixin(KeyMapping.class) public class MixinKeyBinding implements IMixinKeyBinding { @Shadow @Final - private InputUtil.Key defaultKey; + private InputConstants.Key defaultKey; @Shadow - private boolean pressed; + private boolean isDown; - @Inject(method = "isPressed", at = @At("HEAD"), cancellable = true) + @Inject(method = "isDown", at = @At("HEAD"), cancellable = true) public void onGetPressed(CallbackInfoReturnable cir) { SnapTapMod mod = SnapTapMod.getInstance(); @@ -33,8 +32,8 @@ public void onGetPressed(CallbackInfoReturnable cir) { return; } - if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_A) { - if (this.pressed) { + if (this.defaultKey.getValue() == InputConstants.KEY_A) { + if (this.isDown) { if (mod.getRightPressTime() == 0) { cir.setReturnValue(true); cir.cancel(); @@ -44,8 +43,8 @@ public void onGetPressed(CallbackInfoReturnable cir) { cir.setReturnValue(mod.getRightPressTime() <= mod.getLeftPressTime()); cir.cancel(); } - } else if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_D) { - if (this.pressed) { + } else if (this.defaultKey.getValue() == InputConstants.KEY_D) { + if (this.isDown) { if (mod.getLeftPressTime() == 0) { cir.setReturnValue(true); cir.cancel(); @@ -55,8 +54,8 @@ public void onGetPressed(CallbackInfoReturnable cir) { cir.setReturnValue(mod.getLeftPressTime() <= mod.getRightPressTime()); cir.cancel(); } - } else if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_W) { - if (this.pressed) { + } else if (this.defaultKey.getValue() == InputConstants.KEY_W) { + if (this.isDown) { if (mod.getForwardPressTime() == 0) { cir.setReturnValue(true); cir.cancel(); @@ -66,8 +65,8 @@ public void onGetPressed(CallbackInfoReturnable cir) { cir.setReturnValue(mod.getBackPressTime() <= mod.getForwardPressTime()); cir.cancel(); } - } else if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_S) { - if (this.pressed) { + } else if (this.defaultKey.getValue() == InputConstants.KEY_S) { + if (this.isDown) { if (mod.getBackPressTime() == 0) { cir.setReturnValue(true); cir.cancel(); @@ -80,7 +79,7 @@ public void onGetPressed(CallbackInfoReturnable cir) { } } - @Inject(method = "setPressed", at = @At("HEAD")) + @Inject(method = "setDown", at = @At("HEAD")) public void setPressed(boolean pressed, CallbackInfo ci) { SnapTapMod mod = SnapTapMod.getInstance(); @@ -89,25 +88,25 @@ public void setPressed(boolean pressed, CallbackInfo ci) { return; } - if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_A) { + if (this.defaultKey.getValue() == InputConstants.KEY_A) { if (pressed) { mod.setLeftPressTime(System.currentTimeMillis()); } else { mod.setLeftPressTime(0); } - } else if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_D) { + } else if (this.defaultKey.getValue() == InputConstants.KEY_D) { if (pressed) { mod.setRightPressTime(System.currentTimeMillis()); } else { mod.setRightPressTime(0); } - } else if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_W) { + } else if (this.defaultKey.getValue() == InputConstants.KEY_W) { if (pressed) { mod.setForwardPressTime(System.currentTimeMillis()); } else { mod.setForwardPressTime(0); } - } else if (this.defaultKey.getCode() == InputUtil.GLFW_KEY_S) { + } else if (this.defaultKey.getValue() == InputConstants.KEY_S) { if (pressed) { mod.setBackPressTime(System.currentTimeMillis()); } else { @@ -118,6 +117,6 @@ public void setPressed(boolean pressed, CallbackInfo ci) { @Override public boolean getRealIsPressed() { - return this.pressed; + return this.isDown; } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java index 1b90209..c2e88fd 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java @@ -1,14 +1,13 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.VertexBuffer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import net.minecraft.client.gl.VertexBuffer; -import net.minecraft.client.render.BufferRenderer; - -@Mixin(BufferRenderer.class) +@Mixin(BufferUploader.class) public interface BufferRendererAccessor { - @Accessor("currentVertexBuffer") + @Accessor("lastImmediateBuffer") static void setCurrentVertexBuffer(VertexBuffer vertexBuffer) { } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java index 29aef97..6235d53 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java @@ -9,12 +9,11 @@ import cn.pupperclient.management.mod.impl.player.FreelookMod; import cn.pupperclient.mixin.interfaces.IMixinCameraEntity; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.render.Camera; -import net.minecraft.entity.Entity; -import net.minecraft.world.BlockView; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; @Mixin(Camera.class) public abstract class MixinCamera { @@ -25,23 +24,23 @@ public abstract class MixinCamera { @Shadow protected abstract void setRotation(float yaw, float pitch); - @Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER)) - public void lockRotation(BlockView focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing, float tickDelta, CallbackInfo ci) { + @Inject(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER)) + public void lockRotation(BlockGetter focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing, float tickDelta, CallbackInfo ci) { - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); - if (FreelookMod.getInstance().isEnabled() && FreelookMod.getInstance().isActive() && cameraEntity instanceof ClientPlayerEntity) { + if (FreelookMod.getInstance().isEnabled() && FreelookMod.getInstance().isActive() && cameraEntity instanceof LocalPlayer) { IMixinCameraEntity cameraOverriddenEntity = (IMixinCameraEntity) cameraEntity; - if (firstTime && MinecraftClient.getInstance().player != null) { - cameraOverriddenEntity.soarClient_CN$setCameraPitch(client.player.getPitch()); - cameraOverriddenEntity.soarClient_CN$setCameraYaw(client.player.getYaw()); + if (firstTime && Minecraft.getInstance().player != null) { + cameraOverriddenEntity.soarClient_CN$setCameraPitch(client.player.getXRot()); + cameraOverriddenEntity.soarClient_CN$setCameraYaw(client.player.getYRot()); firstTime = false; } this.setRotation(cameraOverriddenEntity.soarClient_CN$getCameraYaw(), cameraOverriddenEntity.soarClient_CN$getCameraPitch()); } - if (FreelookMod.getInstance().isEnabled() && !FreelookMod.getInstance().isActive() && cameraEntity instanceof ClientPlayerEntity) { + if (FreelookMod.getInstance().isEnabled() && !FreelookMod.getInstance().isActive() && cameraEntity instanceof LocalPlayer) { firstTime = true; } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java index 580609a..9ffb377 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java @@ -12,54 +12,53 @@ import cn.pupperclient.management.mod.impl.misc.HypixelMod; import cn.pupperclient.utils.server.Server; import cn.pupperclient.utils.server.ServerUtils; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.EntityRenderer; -import net.minecraft.client.render.entity.state.EntityRenderState; -import net.minecraft.client.render.entity.state.PlayerEntityRenderState; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; -import net.minecraft.text.Text; -import net.minecraft.util.Colors; -import net.minecraft.util.Formatting; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.renderer.MultiBufferSource; +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.util.CommonColors; +import net.minecraft.world.entity.Entity; @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer { @Shadow @Final - private TextRenderer textRenderer; + private Font font; - @Inject(method = "renderLabelIfPresent", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/font/TextRenderer;draw(Lnet/minecraft/text/Text;FFIZLorg/joml/Matrix4f;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/font/TextRenderer$TextLayerType;II)I", ordinal = 1)) - private void onRenderLevelHead(S inState, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, + @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)I", ordinal = 1)) + private void onRenderLevelHead(S inState, Component text, PoseStack matrices, MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); - if (inState instanceof PlayerEntityRenderState state) { + if (inState instanceof PlayerRenderState state) { if (ServerUtils.isJoin(Server.HYPIXEL)) { - AbstractClientPlayerEntity player = (AbstractClientPlayerEntity) client.world.getEntityById(state.id); + AbstractClientPlayer player = (AbstractClientPlayer) client.level.getEntity(state.id); if (player != null && text.getString().contains(player.getName().getString())) { if (HypixelMod.getInstance().isEnabled() && HypixelMod.getInstance().getLevelHeadSetting().isEnabled()) { - String levelText = Formatting.AQUA.toString() + "Level: " + Formatting.YELLOW.toString() + String levelText = ChatFormatting.AQUA.toString() + "Level: " + ChatFormatting.YELLOW.toString() + PupperClient.getInstance().getHypixelManager() - .getByUuid(player.getUuid().toString().replace("-", "")).getNetworkLevel(); + .getByUuid(player.getUUID().toString().replace("-", "")).getNetworkLevel(); - float x = -textRenderer.getWidth(levelText) / 2F; + float x = -font.width(levelText) / 2F; float y = text.getString().contains("deadmau5") ? -20 : -10; - int color = (int) (client.options.getTextBackgroundOpacity(0.25F) * 255.0F) << 24; + int color = (int) (client.options.getBackgroundOpacity(0.25F) * 255.0F) << 24; - Matrix4f matrix4f = matrices.peek().getPositionMatrix(); + Matrix4f matrix4f = matrices.last().pose(); - textRenderer.draw(levelText, x, y, Colors.WHITE, false, matrix4f, vertexConsumers, - TextRenderer.TextLayerType.NORMAL, color, light); + font.drawInBatch(levelText, x, y, CommonColors.WHITE, false, matrix4f, vertexConsumers, + Font.DisplayMode.NORMAL, color, light); } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java index 6e86548..6a41769 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java @@ -15,17 +15,16 @@ import cn.pupperclient.management.mod.impl.settings.ModMenuSettings; import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.context.SkiaContext; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; @Mixin(GameRenderer.class) public class MixinGameRenderer { - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;render(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/client/render/RenderTickCounter;)V", shift = At.Shift.BEFORE)) - public void render(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.BEFORE)) + public void render(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { Kawaseblur.INGAME_BLUR.draw((int) HUDModSettings.getInstance().getBlurIntensitySetting().getValue()); @@ -33,14 +32,14 @@ public void render(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) SkiaContext.draw((context) -> { Skia.save(); - Skia.scale((float) MinecraftClient.getInstance().getWindow().getScaleFactor()); + Skia.scale((float) Minecraft.getInstance().getWindow().getGuiScale()); EventBus.getInstance().post(new RenderSkiaEvent(context)); Skia.restore(); }); } - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;render(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/client/render/RenderTickCounter;)V", shift = At.Shift.AFTER)) - public void renderGuiBlur(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.AFTER)) + public void renderGuiBlur(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { Kawaseblur.GUI_BLUR.draw((int) ModMenuSettings.getInstance().getBlurIntensitySetting().getValue()); @@ -56,7 +55,7 @@ private void getFov(Camera camera, float tickDelta, boolean changingFov, Callbac } } - @Inject(method = "tiltViewWhenHurt", at = @At("HEAD"), cancellable = true) + @Inject(method = "bobHurt", at = @At("HEAD"), cancellable = true) private void tiltViewWhenHurt(CallbackInfo ci) { if (NoHurtFov.getInstance().isEnabled() && NoHurtFov.getInstance().nohurtFov.isEnabled()) { ci.cancel(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java index d7ebc44..546694a 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java @@ -9,27 +9,26 @@ import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; import cn.pupperclient.management.mod.impl.render.CustomHandMod; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.item.BowItem; +import net.minecraft.world.item.FishingRodItem; +import net.minecraft.world.item.ItemStack; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.item.HeldItemRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.BowItem; -import net.minecraft.item.FishingRodItem; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Arm; -import net.minecraft.util.Hand; - -@Mixin(HeldItemRenderer.class) +@Mixin(ItemInHandRenderer.class) public abstract class MixinHeldItemRenderer { @Shadow - protected abstract void applySwingOffset(MatrixStack matrices, Arm arm, float swingProgress); + protected abstract void applyItemArmAttackTransform(PoseStack matrices, HumanoidArm arm, float swingProgress); - @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = ("Lnet/minecraft/client/render/item/HeldItemRenderer;renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V"), ordinal = 1)) - private void renderFirstPersonItem(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, - float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, - VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderItem(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;ZLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", ordinal = 1)) + private void renderFirstPersonItem(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, + float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, + MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { OldAnimationsMod mod = OldAnimationsMod.getInstance(); @@ -42,10 +41,10 @@ private void renderFirstPersonItem(AbstractClientPlayerEntity player, float tick } } - @Inject(method = "renderFirstPersonItem", at = @At("HEAD")) - private void applyCustomHand(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, - float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, - VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + @Inject(method = "renderArmWithItem", at = @At("HEAD")) + private void applyCustomHand(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, + float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, + MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { CustomHandMod mod = CustomHandMod.getInstance(); @@ -55,33 +54,33 @@ private void applyCustomHand(AbstractClientPlayerEntity player, float tickDelta, } } - @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;applyEquipOffset(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/Arm;F)V", ordinal = 2, shift = At.Shift.AFTER)) - private void applyFoodSwingOffset(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, - float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, - VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 2, shift = At.Shift.AFTER)) + private void applyFoodSwingOffset(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, + float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, + MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { applyOldSwingOffset(player, hand, swingProgress, matrices); } - @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;applyEquipOffset(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/Arm;F)V", ordinal = 3, shift = At.Shift.AFTER)) - private void applyBlockingSwingOffset(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, - float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, - VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 3, shift = At.Shift.AFTER)) + private void applyBlockingSwingOffset(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, + float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, + MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { applyOldSwingOffset(player, hand, swingProgress, matrices); } - @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;applyEquipOffset(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/Arm;F)V", ordinal = 4, shift = At.Shift.AFTER)) - private void applyBowSwingOffset(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, - float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, - VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 4, shift = At.Shift.AFTER)) + private void applyBowSwingOffset(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, + float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, + MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { applyOldSwingOffset(player, hand, swingProgress, matrices); } @Unique - private void applyOldSwingOffset(AbstractClientPlayerEntity player, Hand hand, float swingProgress, - MatrixStack matrices) { + private void applyOldSwingOffset(AbstractClientPlayer player, InteractionHand hand, float swingProgress, + PoseStack matrices) { if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isOldBreaking()) { - final Arm arm = hand == Hand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(); - applySwingOffset(matrices, arm, swingProgress); + final HumanoidArm arm = hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(); + applyItemArmAttackTransform(matrices, arm, swingProgress); } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java index eda3ab8..0e94aed 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java @@ -8,28 +8,27 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.RenderGameOverlayEvent; import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderTickCounter; - -@Mixin(InGameHud.class) +@Mixin(Gui.class) public class MixinInGameHud { /** * @author EldoDebug * @reason drawHeart */ @Overwrite - private void drawHeart(DrawContext context, InGameHud.HeartType type, int x, int y, boolean hardcore, boolean blinking, boolean half) { + private void renderHeart(GuiGraphics context, Gui.HeartType type, int x, int y, boolean hardcore, boolean blinking, boolean half) { OldAnimationsMod mod = OldAnimationsMod.getInstance(); - context.drawGuiTexture(RenderLayer::getGuiTextured, type.getTexture(hardcore, half, (!mod.isEnabled() || !mod.isDisableHeartFlash()) && blinking), x, y, 9, 9); + context.blitSprite(RenderType::guiTextured, type.getSprite(hardcore, half, (!mod.isEnabled() || !mod.isDisableHeartFlash()) && blinking), x, y, 9, 9); } - @Inject(method = "renderMainHud", at = @At("TAIL")) - private void renderMainHud(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { + @Inject(method = "renderHotbarAndDecorations", at = @At("TAIL")) + private void renderMainHud(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) { EventBus.getInstance().post(new RenderGameOverlayEvent(context)); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java index ad56a27..896162e 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java @@ -6,26 +6,25 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import cn.pupperclient.management.mod.impl.render.OverlayEditorMod; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.ScreenEffectRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.hud.InGameOverlayRenderer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; - -@Mixin(InGameOverlayRenderer.class) +@Mixin(ScreenEffectRenderer.class) public class MixinInGameOverlayRenderer { - @Inject(method = "renderUnderwaterOverlay", at = @At("HEAD"), cancellable = true) - private static void renderUnderwaterOverlay(MinecraftClient client, MatrixStack matrices, - VertexConsumerProvider vertexConsumers, CallbackInfo ci) { + @Inject(method = "renderWater", at = @At("HEAD"), cancellable = true) + private static void renderUnderwaterOverlay(Minecraft client, PoseStack matrices, + MultiBufferSource vertexConsumers, CallbackInfo ci) { if (OverlayEditorMod.getInstance().isEnabled() && OverlayEditorMod.getInstance().isClearWater()) { ci.cancel(); } } - @Inject(method = "renderFireOverlay", at = @At("HEAD"), cancellable = true) - private static void renderFireOverlay(MatrixStack matrices, VertexConsumerProvider vertexConsumers, + @Inject(method = "renderFire", at = @At("HEAD"), cancellable = true) + private static void renderFireOverlay(PoseStack matrices, MultiBufferSource vertexConsumers, CallbackInfo ci) { if (OverlayEditorMod.getInstance().isEnabled() && OverlayEditorMod.getInstance().isClearFire()) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java index 254342e..0781646 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java @@ -4,14 +4,13 @@ import org.spongepowered.asm.mixin.injection.At; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.client.renderer.LightTexture; import cn.pupperclient.management.mod.impl.render.FullbrightMod; -import net.minecraft.client.render.LightmapTextureManager; - -@Mixin(LightmapTextureManager.class) +@Mixin(LightTexture.class) public class MixinLightmapTextureManager { - @ModifyExpressionValue(method = "update(F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/SimpleOption;getValue()Ljava/lang/Object;", ordinal = 1)) + @ModifyExpressionValue(method = "updateLightTexture(F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/OptionInstance;get()Ljava/lang/Object;", ordinal = 1)) private Object injectFullBright(Object original) { if (FullbrightMod.getInstance().isEnabled()) { return (double) FullbrightMod.getInstance().getGamma(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java index 2613860..b3907c1 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java @@ -1,15 +1,15 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.option.AttackIndicator; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Arm; +import net.minecraft.client.AttackIndicatorStatus; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -18,15 +18,15 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(InGameHud.class) +@Mixin(Gui.class) public class PupperInGameHud { - @Shadow @Final private MinecraftClient client; + @Shadow @Final private Minecraft minecraft; @Shadow - private PlayerEntity getCameraPlayer() { - Entity var2 = this.client.getCameraEntity(); - PlayerEntity var10000; - if (var2 instanceof PlayerEntity playerEntity) { + private Player getCameraPlayer() { + Entity var2 = this.minecraft.getCameraEntity(); + Player var10000; + if (var2 instanceof Player playerEntity) { var10000 = playerEntity; } else { var10000 = null; @@ -39,34 +39,34 @@ private PlayerEntity getCameraPlayer() { @Unique private float slotAnimationProgress = 0f; @Unique private float offhandAlpha = 0f; - @Inject(method = "renderHotbar", at = @At("HEAD"), cancellable = true) - private void replaceHotbarRender(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { + @Inject(method = "renderItemHotbar", at = @At("HEAD"), cancellable = true) + private void replaceHotbarRender(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) { ci.cancel(); // 取消原版物品栏绘制 drawCustomHotbar(context, tickCounter); } @Unique - private void drawCustomHotbar(DrawContext context, RenderTickCounter tickCounter) { - PlayerEntity playerEntity = this.getCameraPlayer(); + private void drawCustomHotbar(GuiGraphics context, DeltaTracker tickCounter) { + Player playerEntity = this.getCameraPlayer(); if (playerEntity == null) return; - ItemStack itemStack = playerEntity.getOffHandStack(); - Arm arm = playerEntity.getMainArm().getOpposite(); - int centerX = context.getScaledWindowWidth() / 2; - int hotbarY = context.getScaledWindowHeight() - 22; + ItemStack itemStack = playerEntity.getOffhandItem(); + HumanoidArm arm = playerEntity.getMainArm().getOpposite(); + int centerX = context.guiWidth() / 2; + int hotbarY = context.guiHeight() - 22; - int selectedSlot = playerEntity.getInventory().selectedSlot; + int selectedSlot = playerEntity.getInventory().selected; updateSlotAnimation(selectedSlot); updateOffhandAlpha(playerEntity); - context.getMatrices().push(); - context.getMatrices().translate(0.0F, 0.0F, -90.0F); + context.pose().pushPose(); + context.pose().translate(0.0F, 0.0F, -90.0F); // 绘制自定义白色背景 drawCustomHotbarBackground(context, centerX, hotbarY, selectedSlot); // 绘制原版选择框 - context.drawGuiTexture(RenderLayer::getGuiTextured, InGameHud.HOTBAR_SELECTION_TEXTURE, + context.blitSprite(RenderType::guiTextured, Gui.HOTBAR_SELECTION_SPRITE, centerX - 91 - 1 + selectedSlot * 20, hotbarY - 1, 24, 23); // 绘制副手背景(带透明度) @@ -74,12 +74,12 @@ private void drawCustomHotbar(DrawContext context, RenderTickCounter tickCounter drawOffhandBackground(context, centerX, hotbarY, arm, offhandAlpha); } - context.getMatrices().pop(); + context.pose().popPose(); // 绘制物品(带动画) for(int i = 0; i < 9; ++i) { int slotX = centerX - 90 + i * 20 + 2; - int slotY = context.getScaledWindowHeight() - 16 - 3; + int slotY = context.guiHeight() - 16 - 3; // 计算动画偏移 float slotOffset = 0; @@ -89,41 +89,41 @@ private void drawCustomHotbar(DrawContext context, RenderTickCounter tickCounter slotOffset = slotAnimationProgress * 3; } - this.renderHotbarItem(context, slotX, (int)(slotY + slotOffset), tickCounter, playerEntity, - playerEntity.getInventory().main.get(i), i + 1); + this.renderSlot(context, slotX, (int)(slotY + slotOffset), tickCounter, playerEntity, + playerEntity.getInventory().items.get(i), i + 1); } // 绘制副手物品(带透明度) if (!itemStack.isEmpty() && offhandAlpha > 0) { - int offhandY = context.getScaledWindowHeight() - 16 - 3; - if (arm == Arm.LEFT) { - this.renderHotbarItem(context, centerX - 91 - 26, offhandY, tickCounter, playerEntity, itemStack, 100); + int offhandY = context.guiHeight() - 16 - 3; + if (arm == HumanoidArm.LEFT) { + this.renderSlot(context, centerX - 91 - 26, offhandY, tickCounter, playerEntity, itemStack, 100); } else { - this.renderHotbarItem(context, centerX + 91 + 10, offhandY, tickCounter, playerEntity, itemStack, 100); + this.renderSlot(context, centerX + 91 + 10, offhandY, tickCounter, playerEntity, itemStack, 100); } } // 保留原版攻击冷却指示器 - if (this.client.options.getAttackIndicator().getValue() == AttackIndicator.HOTBAR) { - float f = this.client.player.getAttackCooldownProgress(0.0F); + if (this.minecraft.options.attackIndicator().get() == AttackIndicatorStatus.HOTBAR) { + float f = this.minecraft.player.getAttackStrengthScale(0.0F); if (f < 1.0F) { - int indicatorY = context.getScaledWindowHeight() - 20; + int indicatorY = context.guiHeight() - 20; int indicatorX = centerX + 91 + 6; - if (arm == Arm.RIGHT) { + if (arm == HumanoidArm.RIGHT) { indicatorX = centerX - 91 - 22; } int progress = (int)(f * 19.0F); - context.drawGuiTexture(RenderLayer::getGuiTextured, InGameHud.HOTBAR_ATTACK_INDICATOR_BACKGROUND_TEXTURE, + context.blitSprite(RenderType::guiTextured, Gui.HOTBAR_ATTACK_INDICATOR_BACKGROUND_SPRITE, indicatorX, indicatorY, 18, 18); - context.drawGuiTexture(RenderLayer::getGuiTextured, InGameHud.HOTBAR_ATTACK_INDICATOR_PROGRESS_TEXTURE, + context.blitSprite(RenderType::guiTextured, Gui.HOTBAR_ATTACK_INDICATOR_PROGRESS_SPRITE, 18, 18, 0, 18 - progress, indicatorX, indicatorY + 18 - progress, 18, progress); } } } @Unique - private void drawCustomHotbarBackground(DrawContext context, int centerX, int hotbarY, int selectedSlot) { + private void drawCustomHotbarBackground(GuiGraphics context, int centerX, int hotbarY, int selectedSlot) { int hotbarWidth = 182; int hotbarX = centerX - 91; @@ -157,10 +157,10 @@ private void drawCustomHotbarBackground(DrawContext context, int centerX, int ho } @Unique - private void drawOffhandBackground(DrawContext context, int centerX, int hotbarY, Arm arm, float alpha) { + private void drawOffhandBackground(GuiGraphics context, int centerX, int hotbarY, HumanoidArm arm, float alpha) { int color = (int)(alpha * 64) << 24 | 0xFFFFFF; // 白色带透明度 - if (arm == Arm.LEFT) { + if (arm == HumanoidArm.LEFT) { // 左侧副手背景 context.fill(centerX - 91 - 29, hotbarY - 1, centerX - 91, hotbarY + 23, color); @@ -189,8 +189,8 @@ private void updateSlotAnimation(int currentSlot) { } @Unique - private void updateOffhandAlpha(PlayerEntity player) { - ItemStack offhandStack = player.getOffHandStack(); + private void updateOffhandAlpha(Player player) { + ItemStack offhandStack = player.getOffhandItem(); if (!offhandStack.isEmpty()) { offhandAlpha = Math.min(offhandAlpha + 0.1f, 1f); @@ -205,6 +205,6 @@ private float easeOutCubic(float x) { } @Shadow - private void renderHotbarItem(DrawContext context, int x, int y, RenderTickCounter tickCounter, PlayerEntity player, ItemStack stack, int seed) { + private void renderSlot(GuiGraphics context, int x, int y, DeltaTracker tickCounter, Player player, ItemStack stack, int seed) { } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java index 6d21c64..71edbc4 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java @@ -1,13 +1,13 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; import cn.pupperclient.management.mod.impl.hud.Scoreboard; -import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.gui.Gui; 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(InGameHud.class) +@Mixin(Gui.class) public class PupperScoreboard { @Inject(method = "renderScoreboardSidebar*", at = @At("HEAD"), cancellable = true) private void renderCustomScoreboard(CallbackInfo ci) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java index 32b2e0e..b6bb65f 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java @@ -2,7 +2,10 @@ import java.util.Arrays; import java.util.List; - +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.SoundEngine; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -11,25 +14,20 @@ import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; -import net.minecraft.client.sound.SoundInstance; -import net.minecraft.client.sound.SoundSystem; -import net.minecraft.sound.SoundEvents; -import net.minecraft.util.Identifier; - -@Mixin(SoundSystem.class) +@Mixin(SoundEngine.class) public class MixinSoundSystem { @Unique - private final List newPvPSounds = Arrays.asList(SoundEvents.ENTITY_PLAYER_ATTACK_KNOCKBACK.id(), - SoundEvents.ENTITY_PLAYER_ATTACK_SWEEP.id(), SoundEvents.ENTITY_PLAYER_ATTACK_CRIT.id(), - SoundEvents.ENTITY_PLAYER_ATTACK_STRONG.id(), SoundEvents.ENTITY_PLAYER_ATTACK_WEAK.id(), - SoundEvents.ENTITY_PLAYER_ATTACK_NODAMAGE.id()); + private final List newPvPSounds = Arrays.asList(SoundEvents.PLAYER_ATTACK_KNOCKBACK.location(), + SoundEvents.PLAYER_ATTACK_SWEEP.location(), SoundEvents.PLAYER_ATTACK_CRIT.location(), + SoundEvents.PLAYER_ATTACK_STRONG.location(), SoundEvents.PLAYER_ATTACK_WEAK.location(), + SoundEvents.PLAYER_ATTACK_NODAMAGE.location()); - @Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true) + @Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("HEAD"), cancellable = true) public void oldAnimations$disableNewPvPSounds(SoundInstance sound, CallbackInfo ci) { if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isOldPvPSounds() - && newPvPSounds.contains(sound.getId())) { + && newPvPSounds.contains(sound.getLocation())) { ci.cancel(); return; } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java index c5637d3..40b4125 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java @@ -7,8 +7,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import cn.pupperclient.skia.context.SkiaContext; - -import net.minecraft.client.util.Window; +import com.mojang.blaze3d.platform.Window; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWImage; import org.lwjgl.stb.STBImage; @@ -22,7 +21,7 @@ @Mixin(Window.class) public class MixinWindow { - @Inject(method = "onFramebufferSizeChanged", at = @At("RETURN")) + @Inject(method = "onFramebufferResize", at = @At("RETURN")) private void onFramebufferSizeChanged(long window, int width, int height, CallbackInfo ci) { SkiaContext.createSurface(width, height); } @@ -31,7 +30,7 @@ private void onFramebufferSizeChanged(long window, int width, int height, Callba private void onWindowInit(CallbackInfo ci) { try { // 获取窗口句柄 - long handle = ((Window)(Object)this).getHandle(); + long handle = ((Window)(Object)this).getWindow(); // 从资源加载图标 try (InputStream is = getClass().getResourceAsStream("/assets/pupper/logo.png")) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java index a324762..553761e 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java @@ -2,15 +2,15 @@ import cn.pupperclient.PupperClient; import com.mojang.authlib.GameProfile; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.util.SkinTextures; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerModelPart; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.resources.PlayerSkin; +import net.minecraft.core.BlockPos; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.PlayerModelPart; +import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -19,24 +19,24 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(value = AbstractClientPlayerEntity.class, priority = 2000) -public abstract class MixinAbstractClientPlayerEntity extends PlayerEntity { +@Mixin(value = AbstractClientPlayer.class, priority = 2000) +public abstract class MixinAbstractClientPlayerEntity extends Player { - @Shadow @Final public ClientWorld clientWorld; + @Shadow @Final public ClientLevel clientLevel; @Unique private boolean shownCape = false; - public MixinAbstractClientPlayerEntity(World world, BlockPos pos, float yaw, GameProfile gameProfile) { + public MixinAbstractClientPlayerEntity(Level world, BlockPos pos, float yaw, GameProfile gameProfile) { super(world, pos, yaw, gameProfile); } - @Inject(method = "getSkinTextures", at = @At("RETURN"), cancellable = true) - public void getSkinTextures(CallbackInfoReturnable cir) { - Identifier customCape = PupperClient.getInstance().getCapeManager().getSelectedCapeTexture(); + @Inject(method = "getSkin", at = @At("RETURN"), cancellable = true) + public void getSkinTextures(CallbackInfoReturnable cir) { + ResourceLocation customCape = PupperClient.getInstance().getCapeManager().getSelectedCapeTexture(); if (customCape != null) { - SkinTextures current = cir.getReturnValue(); - cir.setReturnValue(new SkinTextures( + PlayerSkin current = cir.getReturnValue(); + cir.setReturnValue(new PlayerSkin( current.texture(), current.textureUrl(), customCape, @@ -48,10 +48,10 @@ public void getSkinTextures(CallbackInfoReturnable cir) { } @Override - public void onTrackedDataSet(TrackedData data) { - super.onTrackedDataSet(data); - if (PLAYER_MODEL_PARTS.equals(data)) { - boolean showCape = isPartVisible(PlayerModelPart.CAPE); + public void onSyncedDataUpdated(EntityDataAccessor data) { + super.onSyncedDataUpdated(data); + if (DATA_PLAYER_MODE_CUSTOMISATION.equals(data)) { + boolean showCape = isModelPartShown(PlayerModelPart.CAPE); if (showCape != shownCape) { shownCape = showCape; } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java index f4d8578..1878ad2 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java @@ -1,9 +1,12 @@ package cn.pupperclient.mixin.mixins.minecraft.entity; import cn.pupperclient.utils.misc.SoundEventHelper; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.sound.SoundEvent; -import net.minecraft.util.math.Vec3d; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -16,14 +19,10 @@ import cn.pupperclient.management.mod.impl.player.FreelookMod; import cn.pupperclient.mixin.interfaces.IMixinCameraEntity; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.MathHelper; - @Mixin(Entity.class) public abstract class MixinEntity implements IMixinCameraEntity { @Unique - protected Vec3d stuckSpeedMultiplier; + protected Vec3 stuckSpeedMultiplier; @Unique private float cameraPitch; @@ -32,49 +31,49 @@ public abstract class MixinEntity implements IMixinCameraEntity { private float cameraYaw; @Shadow - public abstract float getPitch(); + public abstract float getXRot(); @Shadow - public abstract float getYaw(); + public abstract float getYRot(); @Shadow public abstract boolean equals(Object o); @Shadow - public abstract float getPitch(float tickDelta); + public abstract float getViewXRot(float tickDelta); @Shadow - public abstract float getYaw(float tickDelta); + public abstract float getViewYRot(float tickDelta); @Shadow - public abstract Vec3d getRotationVector(float pitch, float yaw); + public abstract Vec3 calculateViewVector(float pitch, float yaw); @Shadow - public abstract boolean saveNbt(NbtCompound nbt); + public abstract boolean save(CompoundTag nbt); @Shadow public abstract int getId(); - @Inject(method = "changeLookDirection", at = @At("HEAD")) + @Inject(method = "turn", at = @At("HEAD")) private void onPlayerDirectionChange(double cursorDeltaX, double cursorDeltaY, CallbackInfo ci) { - float prevPitch = getPitch(); - float prevYaw = getYaw(); + float prevPitch = getXRot(); + float prevYaw = getYRot(); float pitch = prevPitch + (float) (cursorDeltaY * .15); float yaw = prevYaw + (float) (cursorDeltaX * .15); - pitch = MathHelper.clamp(pitch, -90.0F, 90.0F); + pitch = Mth.clamp(pitch, -90.0F, 90.0F); EventBus.getInstance().post(new PlayerDirectionChangeEvent(prevPitch, prevYaw, pitch, yaw)); } - @Inject(method = "changeLookDirection", at = @At("HEAD"), cancellable = true) + @Inject(method = "turn", at = @At("HEAD"), cancellable = true) public void changeCameraLookDirection(double xDelta, double yDelta, CallbackInfo ci) { if (FreelookMod.getInstance().isEnabled() && FreelookMod.getInstance().isActive() - && (Entity) (Object) this instanceof ClientPlayerEntity) { + && (Entity) (Object) this instanceof LocalPlayer) { double pitchDelta = (yDelta * 0.15); double yawDelta = (xDelta * 0.15); - this.cameraPitch = MathHelper.clamp(this.cameraPitch + (float) pitchDelta, -90.0f, 90.0f); + this.cameraPitch = Mth.clamp(this.cameraPitch + (float) pitchDelta, -90.0f, 90.0f); this.cameraYaw += (float) yawDelta; ci.cancel(); @@ -106,7 +105,7 @@ public void changeCameraLookDirection(double xDelta, double yDelta, CallbackInfo this.cameraYaw = yaw; } - @Inject(method = "playSound", at = @At("HEAD")) + @Inject(method = "playSound(Lnet/minecraft/sounds/SoundEvent;FF)V", at = @At("HEAD")) private void onPlaySound(SoundEvent sound, float volume, float pitch, CallbackInfo ci) { SoundEventHelper.lastSoundSource = (Entity) (Object) this; SoundEventHelper.lastSoundEvent = sound; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinLivingEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinLivingEntity.java index c41445b..b54332c 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinLivingEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinLivingEntity.java @@ -1,9 +1,5 @@ package cn.pupperclient.mixin.mixins.minecraft.entity; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.data.DataTracker; -import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -13,78 +9,81 @@ import cn.pupperclient.management.mod.impl.hud.JumpResetIndicatorMod; import cn.pupperclient.management.mod.impl.player.NoJumpDelayMod; import cn.pupperclient.mixin.interfaces.IMixinLivingEntity; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.LivingEntity; -import net.minecraft.util.Hand; +import net.minecraft.client.Minecraft; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.Level; @Mixin(LivingEntity.class) public abstract class MixinLivingEntity extends Entity implements IMixinLivingEntity{ @Shadow - private int jumpingCooldown; + private int noJumpDelay; @Shadow - public int handSwingTicks; + public int swingTime; @Shadow - public boolean handSwinging; + public boolean swinging; @Shadow - public Hand preferredHand; + public InteractionHand swingingArm; - public MixinLivingEntity(EntityType type, World world) { + public MixinLivingEntity(EntityType type, Level world) { super(type, world); } @Shadow - protected abstract int getHandSwingDuration(); + protected abstract int getCurrentSwingDuration(); @Shadow - public abstract void jump(); + public abstract void jumpFromGround(); @Shadow - public abstract float getYaw(float tickDelta); + public abstract float getViewYRot(float tickDelta); @Shadow - protected abstract void initDataTracker(DataTracker.Builder builder); + protected abstract void defineSynchedData(SynchedEntityData.Builder builder); - @Inject(method = "tickMovement", at = @At("HEAD")) + @Inject(method = "aiStep", at = @At("HEAD")) public void onNoJumpDelay(CallbackInfo ci) { if (NoJumpDelayMod.getInstance().isEnabled()) { - jumpingCooldown = 0; + noJumpDelay = 0; } } - @Inject(method = "jump", at = @At("HEAD")) + @Inject(method = "jumpFromGround", at = @At("HEAD")) private void onJump(CallbackInfo info) { JumpResetIndicatorMod mod = JumpResetIndicatorMod.getInstance(); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); if ((Object) this == client.player) { - mod.setJumpAge(client.player.age); + mod.setJumpAge(client.player.tickCount); mod.setLastTime(System.currentTimeMillis()); } } - @Inject(method = "onDamaged", at = @At("HEAD")) + @Inject(method = "handleDamageEvent", at = @At("HEAD")) private void onDamage(CallbackInfo info) { JumpResetIndicatorMod mod = JumpResetIndicatorMod.getInstance(); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); if ((Object) this == client.player) { - mod.setHurtAge(client.player.age); + mod.setHurtAge(client.player.tickCount); } } @Override - public void soarClient_CN$fakeSwingHand(Hand hand) { - if (!this.handSwinging || this.handSwingTicks >= this.getHandSwingDuration() / 2 || this.handSwingTicks < 0) { - this.handSwingTicks = -1; - this.handSwinging = true; - this.preferredHand = hand; + public void soarClient_CN$fakeSwingHand(InteractionHand hand) { + if (!this.swinging || this.swingTime >= this.getCurrentSwingDuration() / 2 || this.swingTime < 0) { + this.swingTime = -1; + this.swinging = true; + this.swingingArm = hand; } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java index 7b0949f..dc181db 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java @@ -7,15 +7,14 @@ import cn.pupperclient.management.mod.impl.player.ForceMainHandMod; import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.Player; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.Arm; - -@Mixin(PlayerEntity.class) +@Mixin(Player.class) public class MixinPlayerEntity { - @Inject(method = "getAttackCooldownProgress", at = @At("HEAD"), cancellable = true) + @Inject(method = "getAttackStrengthScale", at = @At("HEAD"), cancellable = true) public void disableCooldown(CallbackInfoReturnable cir) { if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isDisableAttackCooldown()) { cir.setReturnValue(1F); @@ -23,14 +22,14 @@ public void disableCooldown(CallbackInfoReturnable cir) { } @Inject(method = "getMainArm", at = @At("HEAD"), cancellable = true) - private void injectGetMainArm(CallbackInfoReturnable cir) { + private void injectGetMainArm(CallbackInfoReturnable cir) { - MinecraftClient client = MinecraftClient.getInstance(); - PlayerEntity player = client.player; - PlayerEntity e = ((PlayerEntity) (Object) this); + Minecraft client = Minecraft.getInstance(); + Player player = client.player; + Player e = ((Player) (Object) this); if (ForceMainHandMod.getInstance().isEnabled() && e.getId() != player.getId()) { - cir.setReturnValue(ForceMainHandMod.getInstance().isRightHand() ? Arm.RIGHT : Arm.LEFT); + cir.setReturnValue(ForceMainHandMod.getInstance().isRightHand() ? HumanoidArm.RIGHT : HumanoidArm.LEFT); } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java index ff83513..c99e5f5 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java @@ -1,6 +1,5 @@ package cn.pupperclient.mixin.mixins.minecraft.network; -import net.minecraft.network.PacketCallbacks; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -11,46 +10,46 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ReceivePacketEvent; import cn.pupperclient.event.client.SendPacketEvent; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; +import net.minecraft.server.RunningOnDifferentThreadException; -import net.minecraft.network.ClientConnection; -import net.minecraft.network.OffThreadException; -import net.minecraft.network.listener.PacketListener; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.s2c.play.BundleS2CPacket; - -@Mixin(ClientConnection.class) +@Mixin(Connection.class) public abstract class MixinClientConnection { @Shadow - private static void handlePacket(Packet packet, PacketListener listener) { + private static void genericsFtw(Packet packet, PacketListener listener) { } @Shadow - protected abstract void sendImmediately(Packet packet, @Nullable PacketCallbacks callbacks, boolean flush); + protected abstract void sendPacket(Packet packet, @Nullable PacketSendListener callbacks, boolean flush); - @Inject(method = "send(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;)V", at = @At("HEAD"), cancellable = true) - private void onSendPacket(Packet packet, PacketCallbacks callbacks, CallbackInfo ci) { + @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketSendListener;)V", at = @At("HEAD"), cancellable = true) + private void onSendPacket(Packet packet, PacketSendListener callbacks, CallbackInfo ci) { SendPacketEvent event = new SendPacketEvent(packet); EventBus.getInstance().post(event); if (event.isCancelled()) { ci.cancel(); - ClientConnection self = (ClientConnection) (Object) this; + Connection self = (Connection) (Object) this; self.send(event.getPacket(), callbacks); } } - @Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true, require = 1) + @Inject(method = "genericsFtw", at = @At("HEAD"), cancellable = true, require = 1) private static void onRecievePacket(Packet packet, PacketListener listener, CallbackInfo ci) { - if (packet instanceof BundleS2CPacket bundleS2CPacket) { + if (packet instanceof ClientboundBundlePacket bundleS2CPacket) { ci.cancel(); - for (Packet packetInBundle : bundleS2CPacket.getPackets()) { + for (Packet packetInBundle : bundleS2CPacket.subPackets()) { try { - handlePacket(packetInBundle, listener); - } catch (OffThreadException ignored) { + genericsFtw(packetInBundle, listener); + } catch (RunningOnDifferentThreadException ignored) { } } return; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java index cc77357..4b7de69 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java @@ -1,15 +1,14 @@ package cn.pupperclient.mixin.mixins.minecraft.network.packet; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; - -@Mixin(PlayerInteractEntityC2SPacket.class) +@Mixin(ServerboundInteractPacket.class) public interface PlayerInteractEntityC2SPacketAccessor { - @Accessor("type") - PlayerInteractEntityC2SPacket.InteractTypeHandler getInteractTypeHandler(); + @Accessor("action") + ServerboundInteractPacket.Action getInteractTypeHandler(); @Accessor("entityId") int entityId(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinBiome.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinBiome.java index 1eaaa1a..554102e 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinBiome.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinBiome.java @@ -6,14 +6,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import cn.pupperclient.management.mod.impl.misc.WeatherChangerMod; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.biome.Biome; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.biome.Biome; @Mixin(Biome.class) public class MixinBiome { - @Inject(method = "getPrecipitation", at = @At("HEAD"), cancellable = true) + @Inject(method = "getPrecipitationAt", at = @At("HEAD"), cancellable = true) public void getPrecipitation(BlockPos pos, int seaLevel, CallbackInfoReturnable cir) { if(WeatherChangerMod.getInstance().isEnabled() && WeatherChangerMod.getInstance().isSnowing()) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java index a475077..d61a504 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java @@ -6,13 +6,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import cn.pupperclient.management.mod.impl.misc.TimeChangerMod; +import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.world.ClientWorld; - -@Mixin(ClientWorld.Properties.class) +@Mixin(ClientLevel.ClientLevelData.class) public class MixinClientWorldProperties { - @Inject(method = "getTimeOfDay", at = @At("HEAD"), cancellable = true) + @Inject(method = "getDayTime", at = @At("HEAD"), cancellable = true) public void getTimeOfDay(CallbackInfoReturnable cir) { if (TimeChangerMod.getInstance().isEnabled()) { cir.setReturnValue(TimeChangerMod.getInstance().getTime()); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinWorld.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinWorld.java index 9d68272..f3a6329 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinWorld.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinWorld.java @@ -6,13 +6,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import cn.pupperclient.management.mod.impl.misc.WeatherChangerMod; +import net.minecraft.world.level.Level; -import net.minecraft.world.World; - -@Mixin(World.class) +@Mixin(Level.class) public class MixinWorld { - @Inject(method = "getRainGradient", at = @At("HEAD"), cancellable = true) + @Inject(method = "getRainLevel", at = @At("HEAD"), cancellable = true) public void getRainGradient(float delta, CallbackInfoReturnable cir) { WeatherChangerMod mod = WeatherChangerMod.getInstance(); @@ -33,7 +32,7 @@ public void isRaining(CallbackInfoReturnable cir) { } } - @Inject(method = "getThunderGradient", at = @At("HEAD"), cancellable = true) + @Inject(method = "getThunderLevel", at = @At("HEAD"), cancellable = true) public void getThunderGradient(float delta, CallbackInfoReturnable cir) { WeatherChangerMod mod = WeatherChangerMod.getInstance(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/viafabricplus/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/viafabricplus/MixinMinecraftClient.java index d8e486c..1ef0daa 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/viafabricplus/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/viafabricplus/MixinMinecraftClient.java @@ -5,22 +5,21 @@ import org.spongepowered.asm.mixin.injection.At; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerInteractionManager; - -@Mixin(value = MinecraftClient.class, priority = 2000) +@Mixin(value = Minecraft.class, priority = 2000) public class MixinMinecraftClient { @Shadow - public ClientPlayerEntity player; + public LocalPlayer player; @Shadow - public ClientPlayerInteractionManager interactionManager; + public MultiPlayerGameMode gameMode; - @ModifyExpressionValue(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;isBreakingBlock()Z")) + @ModifyExpressionValue(method = "startUseItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;isDestroying()Z")) private boolean injectOldAnimation(boolean original) { if(OldAnimationsMod.getInstance().isEnabled()) { diff --git a/src/main/java/cn/pupperclient/shader/Framebuffer.java b/src/main/java/cn/pupperclient/shader/Framebuffer.java index 9a32327..fc0d613 100644 --- a/src/main/java/cn/pupperclient/shader/Framebuffer.java +++ b/src/main/java/cn/pupperclient/shader/Framebuffer.java @@ -7,15 +7,13 @@ import static org.lwjgl.opengl.GL30C.glGenerateMipmap; import java.nio.ByteBuffer; - +import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL30C; import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.Window; - public class Framebuffer { private int id; @@ -34,7 +32,7 @@ public Framebuffer() { } private void init() { - Window window = MinecraftClient.getInstance().getWindow(); + Window window = Minecraft.getInstance().getWindow(); id = GlStateManager.glGenFramebuffers(); bind(); @@ -49,8 +47,8 @@ private void init() { RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - width = Math.max(1, (int) (window.getFramebufferWidth() * sizeMulti)); - height = Math.max(1, (int) (window.getFramebufferHeight() * sizeMulti)); + width = Math.max(1, (int) (window.getWidth() * sizeMulti)); + height = Math.max(1, (int) (window.getHeight() * sizeMulti)); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null); GlStateManager._glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); @@ -92,7 +90,7 @@ public void setViewport() { } public void unbind() { - MinecraftClient.getInstance().getFramebuffer().beginWrite(false); + Minecraft.getInstance().getMainRenderTarget().bindWrite(false); } public void delete() { diff --git a/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java b/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java index e40bbc5..0dfc110 100644 --- a/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java +++ b/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java @@ -17,13 +17,12 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; - -import net.minecraft.client.util.math.MatrixStack; +import com.mojang.blaze3d.vertex.PoseStack; public class PostProcessRenderer { private static final Mesh mesh = new Mesh(); - private static final MatrixStack matrices = new MatrixStack(); + private static final PoseStack matrices = new PoseStack(); static { mesh.begin(); @@ -148,12 +147,12 @@ public void end() { building = false; } - public void beginRender(MatrixStack matrices) { + public void beginRender(PoseStack matrices) { RenderSystem.disableCull(); beganRendering = true; } - public void render(MatrixStack matrices) { + public void render(PoseStack matrices) { if (building) end(); diff --git a/src/main/java/cn/pupperclient/shader/Shader.java b/src/main/java/cn/pupperclient/shader/Shader.java index a2fc2e9..ab16728 100644 --- a/src/main/java/cn/pupperclient/shader/Shader.java +++ b/src/main/java/cn/pupperclient/shader/Shader.java @@ -13,7 +13,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; import org.apache.commons.io.IOUtils; import org.joml.Matrix4f; import org.lwjgl.BufferUtils; @@ -21,9 +22,6 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.Identifier; - public class Shader { public static Shader BOUND; @@ -69,8 +67,8 @@ public void set(String name, double v1, double v2) { private String read(String path) { try { return IOUtils.toString( - MinecraftClient.getInstance().getResourceManager() - .getResource(Identifier.of("pupper", "shaders/" + path)).get().getInputStream(), + Minecraft.getInstance().getResourceManager() + .getResource(ResourceLocation.fromNamespaceAndPath("pupper", "shaders/" + path)).get().open(), StandardCharsets.UTF_8); } catch (IOException e) { throw new IllegalStateException("Could not read shader '" + path + "'", e); diff --git a/src/main/java/cn/pupperclient/shader/ShaderHelper.java b/src/main/java/cn/pupperclient/shader/ShaderHelper.java index e7504ba..d7241b6 100644 --- a/src/main/java/cn/pupperclient/shader/ShaderHelper.java +++ b/src/main/java/cn/pupperclient/shader/ShaderHelper.java @@ -23,14 +23,13 @@ import java.nio.ByteBuffer; import java.nio.FloatBuffer; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.resources.ResourceLocation; import com.mojang.blaze3d.platform.GlStateManager; import cn.pupperclient.mixin.mixins.minecraft.client.render.BufferRendererAccessor; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.texture.AbstractTexture; -import net.minecraft.util.Identifier; public class ShaderHelper { public static int CURRENT_IBO; @@ -179,9 +178,9 @@ public static void disableLineSmooth() { glDisable(GL_LINE_SMOOTH); } - public static void bindTexture(Identifier id) { - AbstractTexture texture = MinecraftClient.getInstance().getTextureManager().getTexture(id); - bindTexture(texture.getGlId(), 0); + public static void bindTexture(ResourceLocation id) { + AbstractTexture texture = Minecraft.getInstance().getTextureManager().getTexture(id); + bindTexture(texture.getId(), 0); } public static void bindTexture(int i, int slot) { diff --git a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java index 13a1bf3..0d5450d 100644 --- a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java +++ b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java @@ -5,7 +5,7 @@ import cn.pupperclient.utils.time.TimerUtils; import it.unimi.dsi.fastutil.ints.IntDoubleImmutablePair; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public class Kawaseblur { @@ -69,7 +69,7 @@ public void draw(int radius) { PostProcessRenderer.beginRender(); - renderToFbo(fbos[0], MinecraftClient.getInstance().getFramebuffer().getColorAttachment(), shaderDown, + renderToFbo(fbos[0], Minecraft.getInstance().getMainRenderTarget().getColorTextureId(), shaderDown, offset); for (int i = 0; i < iterations; i++) { @@ -80,7 +80,7 @@ public void draw(int radius) { renderToFbo(fbos[i - 1], fbos[i].texture, shaderUp, offset); } - MinecraftClient.getInstance().getFramebuffer().beginWrite(true); + Minecraft.getInstance().getMainRenderTarget().bindWrite(true); shaderPassthrough.bind(); ShaderHelper.bindTexture(fbos[0].texture); shaderPassthrough.set("uTexture", 0); diff --git a/src/main/java/cn/pupperclient/skia/Skia.java b/src/main/java/cn/pupperclient/skia/Skia.java index f42765e..8d38d0e 100644 --- a/src/main/java/cn/pupperclient/skia/Skia.java +++ b/src/main/java/cn/pupperclient/skia/Skia.java @@ -2,11 +2,13 @@ import java.awt.Color; import java.io.File; - +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; import cn.pupperclient.management.mod.impl.settings.HUDModSettings; import cn.pupperclient.shader.impl.Kawaseblur; import cn.pupperclient.skia.context.SkiaContext; import cn.pupperclient.skia.image.ImageHelper; +import com.mojang.blaze3d.platform.Window; import io.github.humbleui.skija.Canvas; import io.github.humbleui.skija.ClipMode; import io.github.humbleui.skija.FilterTileMode; @@ -21,9 +23,6 @@ import io.github.humbleui.types.Point; import io.github.humbleui.types.RRect; import io.github.humbleui.types.Rect; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.Window; -import net.minecraft.util.Identifier; public class Skia { @@ -63,11 +62,11 @@ public static void drawBlur(float x, float y, float width, float height) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Window window = MinecraftClient.getInstance().getWindow(); + Window window = Minecraft.getInstance().getWindow(); try (Path path = Path.makeRect(Rect.makeXYWH(x, y, width, height))) { save(); getCanvas().clipPath(path, ClipMode.INTERSECT, true); - drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getScaledWidth(), window.getScaledHeight(), 1F, + drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), 1F, SurfaceOrigin.BOTTOM_LEFT); restore(); } @@ -78,11 +77,11 @@ public static void drawRoundedBlur(float x, float y, float width, float height, if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Window window = MinecraftClient.getInstance().getWindow(); + Window window = Minecraft.getInstance().getWindow(); try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { save(); getCanvas().clipPath(path, ClipMode.INTERSECT, true); - drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getScaledWidth(), window.getScaledHeight(), 1F, + drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), 1F, SurfaceOrigin.BOTTOM_LEFT); restore(); } @@ -287,7 +286,7 @@ public static void drawSkin(File file, float x, float y, float scale) { } } public static void drawMinecraftImage(String path, float x, float y, float width, float height) { - Identifier identifier = Identifier.of("minecraft", path); + ResourceLocation identifier = ResourceLocation.fromNamespaceAndPath("minecraft", path); if (imageHelper.load(identifier)) { getCanvas().drawImageRect(imageHelper.get(identifier.getPath()), Rect.makeXYWH(x, y, width, height)); diff --git a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java index 27acae6..f118938 100644 --- a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java +++ b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java @@ -1,14 +1,14 @@ package cn.pupperclient.skia.context; import java.util.function.Consumer; - +import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL33; import com.mojang.blaze3d.platform.GlConst; import com.mojang.blaze3d.systems.RenderSystem; - +import com.mojang.blaze3d.vertex.BufferUploader; import io.github.humbleui.skija.BackendRenderTarget; import io.github.humbleui.skija.Canvas; import io.github.humbleui.skija.ColorSpace; @@ -16,8 +16,6 @@ import io.github.humbleui.skija.Surface; import io.github.humbleui.skija.SurfaceColorFormat; import io.github.humbleui.skija.SurfaceOrigin; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.BufferRenderer; public class SkiaContext { @@ -46,7 +44,7 @@ public static void createSurface(int width, int height) { } renderTarget = BackendRenderTarget.makeGL(width, height, 0, 8, - MinecraftClient.getInstance().getFramebuffer().fbo, GL11.GL_RGBA8); + Minecraft.getInstance().getMainRenderTarget().frameBufferId, GL11.GL_RGBA8); surface = Surface.wrapBackendRenderTarget(context, renderTarget, SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.getSRGB()); } @@ -65,7 +63,7 @@ public static void draw(Consumer drawingLogic) { context.flush(); - BufferRenderer.reset(); + BufferUploader.reset(); GL33.glBindSampler(0, 0); RenderSystem.disableBlend(); GL11.glDisable(GL11.GL_BLEND); diff --git a/src/main/java/cn/pupperclient/skia/image/ImageHelper.java b/src/main/java/cn/pupperclient/skia/image/ImageHelper.java index 579fb35..f4248b2 100644 --- a/src/main/java/cn/pupperclient/skia/image/ImageHelper.java +++ b/src/main/java/cn/pupperclient/skia/image/ImageHelper.java @@ -8,7 +8,10 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; - +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; import org.lwjgl.opengl.GL11; import cn.pupperclient.skia.context.SkiaContext; @@ -17,10 +20,6 @@ import io.github.humbleui.skija.ColorType; import io.github.humbleui.skija.Image; import io.github.humbleui.skija.SurfaceOrigin; -import net.minecraft.client.MinecraftClient; -import net.minecraft.resource.Resource; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; public class ImageHelper { @@ -38,14 +37,14 @@ public boolean load(int texture, float width, float height, SurfaceOrigin origin return true; } - public boolean load(Identifier identifier) { + public boolean load(ResourceLocation identifier) { if (!images.containsKey(identifier.getPath())) { - ResourceManager resourceManager = MinecraftClient.getInstance().getResourceManager(); + ResourceManager resourceManager = Minecraft.getInstance().getResourceManager(); Resource resource; try { resource = resourceManager.getResourceOrThrow(identifier); - try (InputStream inputStream = resource.getInputStream()) { + try (InputStream inputStream = resource.open()) { byte[] imageData = inputStream.readAllBytes(); Image image = Image.makeDeferredFromEncodedBytes(imageData); diff --git a/src/main/java/cn/pupperclient/ui/component/Component.java b/src/main/java/cn/pupperclient/ui/component/Component.java index aad3c5b..65fbddb 100644 --- a/src/main/java/cn/pupperclient/ui/component/Component.java +++ b/src/main/java/cn/pupperclient/ui/component/Component.java @@ -1,12 +1,11 @@ package cn.pupperclient.ui.component; import cn.pupperclient.ui.component.handler.ComponentHandler; - -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public class Component { - protected MinecraftClient client = MinecraftClient.getInstance(); + protected Minecraft client = Minecraft.getInstance(); protected ComponentHandler handler; protected float x, y, width, height; diff --git a/src/main/java/cn/pupperclient/ui/component/handler/impl/KeybindHandler.java b/src/main/java/cn/pupperclient/ui/component/handler/impl/KeybindHandler.java index ff3643c..0997730 100644 --- a/src/main/java/cn/pupperclient/ui/component/handler/impl/KeybindHandler.java +++ b/src/main/java/cn/pupperclient/ui/component/handler/impl/KeybindHandler.java @@ -1,8 +1,7 @@ package cn.pupperclient.ui.component.handler.impl; import cn.pupperclient.ui.component.handler.ComponentHandler; - -import net.minecraft.client.util.InputUtil.Key; +import com.mojang.blaze3d.platform.InputConstants.Key; public abstract class KeybindHandler extends ComponentHandler { public abstract void onBinded(Key key); diff --git a/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java b/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java index 3b27ff9..3e83d4c 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java @@ -10,17 +10,16 @@ import cn.pupperclient.ui.component.api.PressAnimation; import cn.pupperclient.ui.component.handler.impl.KeybindHandler; import cn.pupperclient.utils.mouse.MouseUtils; - -import net.minecraft.client.util.InputUtil; +import com.mojang.blaze3d.platform.InputConstants; public class Keybind extends Component { private PressAnimation pressAnimation = new PressAnimation(); private boolean binding; - private InputUtil.Key key; + private InputConstants.Key key; - public Keybind(float x, float y, InputUtil.Key key) { + public Keybind(float x, float y, InputConstants.Key key) { super(x, y); this.key = key; width = 126; @@ -38,7 +37,7 @@ public void draw(double mouseX, double mouseY) { pressAnimation.draw(x, y, width, height, palette.getPrimaryContainer(), 0.12F); Skia.restore(); - Skia.drawFullCenteredText(binding ? "..." : key.getLocalizedText().getString(), x + (width / 2), + Skia.drawFullCenteredText(binding ? "..." : key.getDisplayName().getString(), x + (width / 2), y + (height / 2), palette.getSurface(), Fonts.getMedium(14)); } @@ -62,10 +61,10 @@ public void mouseReleased(double mouseX, double mouseY, int button) { if (binding) { if (button == GLFW.GLFW_MOUSE_BUTTON_MIDDLE) { - setKeyCode(InputUtil.UNKNOWN_KEY); + setKeyCode(InputConstants.UNKNOWN); } else if (button != GLFW.GLFW_MOUSE_BUTTON_LEFT && button != GLFW.GLFW_MOUSE_BUTTON_RIGHT && button != GLFW.GLFW_MOUSE_BUTTON_MIDDLE) { - setKeyCode(InputUtil.Type.MOUSE.createFromCode(button)); + setKeyCode(InputConstants.Type.MOUSE.getOrCreate(button)); } binding = false; @@ -77,16 +76,16 @@ public void mouseReleased(double mouseX, double mouseY, int button) { @Override public void keyPressed(int keyCode, int scanCode, int modifiers) { if (binding) { - setKeyCode(InputUtil.fromKeyCode(keyCode, scanCode)); + setKeyCode(InputConstants.getKey(keyCode, scanCode)); this.binding = false; } } - public InputUtil.Key getKeyCode() { + public InputConstants.Key getKeyCode() { return key; } - public void setKeyCode(InputUtil.Key key) { + public void setKeyCode(InputConstants.Key key) { this.key = key; diff --git a/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java b/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java index 411ecde..0171c5b 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java @@ -3,13 +3,12 @@ import org.lwjgl.glfw.GLFW; import cn.pupperclient.utils.math.MathUtils; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.StringHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.util.StringUtil; public class TextInputHelper { - private MinecraftClient client = MinecraftClient.getInstance(); + private Minecraft client = Minecraft.getInstance(); private String text; private boolean focused; @@ -28,13 +27,13 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { if (!focused) { return; } else if (modifiers == GLFW.GLFW_MOD_CONTROL && keyCode == GLFW.GLFW_KEY_C) { - client.keyboard.setClipboard(this.getSelectedText()); + client.keyboardHandler.setClipboard(this.getSelectedText()); return; } else if (modifiers == GLFW.GLFW_MOD_CONTROL && keyCode == GLFW.GLFW_KEY_V) { - writeText(client.keyboard.getClipboard()); + writeText(client.keyboardHandler.getClipboard()); return; } else if (modifiers == GLFW.GLFW_MOD_CONTROL && keyCode == GLFW.GLFW_KEY_X) { - client.keyboard.setClipboard(this.getSelectedText()); + client.keyboardHandler.setClipboard(this.getSelectedText()); this.writeText(""); return; } else if (modifiers == GLFW.GLFW_MOD_CONTROL && keyCode == GLFW.GLFW_KEY_A) { @@ -104,7 +103,7 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } public void charTyped(char chr, int modifiers) { - if (StringHelper.isValidChar(chr) && this.isFocused()) { + if (StringUtil.isAllowedChatCharacter(chr) && this.isFocused()) { this.writeText(Character.toString(chr)); } } @@ -112,7 +111,7 @@ public void charTyped(char chr, int modifiers) { private void writeText(String text) { String s = ""; - String s1 = StringHelper.stripInvalidChars(text); + String s1 = StringUtil.filterText(text); int min = Math.min(this.cursorPosition, this.selectionEnd); int max = Math.max(this.cursorPosition, this.selectionEnd); int len = this.maxStringLength - this.text.length() - (min - max); diff --git a/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java b/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java index c55ac1a..f8de20f 100644 --- a/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java +++ b/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java @@ -1,26 +1,26 @@ package cn.pupperclient.utils.chat; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.hud.ChatHud; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.ChatComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; public class ChatUtils { private static final String PREFIX = "§7[§bPupper§7] "; - private static final String PREFIX_FORMATTED = Formatting.GRAY + "[" + Formatting.AQUA + "Pupper" + Formatting.GRAY + "] "; - private static final Text PREFIX_TEXT = Text.literal("[") - .formatted(Formatting.GRAY) - .append(Text.literal("PupperClient").formatted(Formatting.AQUA)) - .append(Text.literal("] ").formatted(Formatting.GRAY)); + private static final String PREFIX_FORMATTED = ChatFormatting.GRAY + "[" + ChatFormatting.AQUA + "Pupper" + ChatFormatting.GRAY + "] "; + private static final Component PREFIX_TEXT = Component.literal("[") + .withStyle(ChatFormatting.GRAY) + .append(Component.literal("PupperClient").withStyle(ChatFormatting.AQUA)) + .append(Component.literal("] ").withStyle(ChatFormatting.GRAY)); - public static void component(Text component) { - MinecraftClient client = MinecraftClient.getInstance(); - if (client == null || client.world == null) return; + public static void component(Component component) { + Minecraft client = Minecraft.getInstance(); + if (client == null || client.level == null) return; client.execute(() -> { - ChatHud chat = client.inGameHud.getChatHud(); + ChatComponent chat = client.gui.getChat(); if (chat != null) { chat.addMessage(component); } @@ -31,10 +31,10 @@ public static void addChatMessage(String message) { addChatMessage(true, message); } - public static void addChatMessage(Text message) { + public static void addChatMessage(Component message) { if (message == null || message.getString().isEmpty()) return; - MutableText fullMessage = Text.empty() + MutableComponent fullMessage = Component.empty() .append(PREFIX_TEXT) .append(message); @@ -45,29 +45,29 @@ public static void addChatMessage(boolean prefix, String message) { if (message == null || message.isEmpty()) return; String formattedMessage = (prefix ? PREFIX : "") + message; - component(Text.literal(formattedMessage)); + component(Component.literal(formattedMessage)); } - public static void addFormattedMessage(String message, Formatting... formattings) { - MutableText text = Text.literal(PREFIX_FORMATTED).formatted(Formatting.GRAY); - text.append(Text.literal(message).formatted(formattings)); + public static void addFormattedMessage(String message, ChatFormatting... formattings) { + MutableComponent text = Component.literal(PREFIX_FORMATTED).withStyle(ChatFormatting.GRAY); + text.append(Component.literal(message).withStyle(formattings)); component(text); } public static void error(String message) { - addFormattedMessage(message, Formatting.RED); + addFormattedMessage(message, ChatFormatting.RED); } public static void success(String message) { - addFormattedMessage(message, Formatting.GREEN); + addFormattedMessage(message, ChatFormatting.GREEN); } public static void warning(String message) { - addFormattedMessage(message, Formatting.YELLOW); + addFormattedMessage(message, ChatFormatting.YELLOW); } public static void info(String message) { - addFormattedMessage(message, Formatting.BLUE); + addFormattedMessage(message, ChatFormatting.BLUE); } } diff --git a/src/main/java/cn/pupperclient/utils/file/FileLocation.java b/src/main/java/cn/pupperclient/utils/file/FileLocation.java index d88b65e..8241303 100644 --- a/src/main/java/cn/pupperclient/utils/file/FileLocation.java +++ b/src/main/java/cn/pupperclient/utils/file/FileLocation.java @@ -1,12 +1,11 @@ package cn.pupperclient.utils.file; import java.io.File; - -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public class FileLocation { - public static final File MAIN_DIR = new File(MinecraftClient.getInstance().runDirectory, "pupper"); + public static final File MAIN_DIR = new File(Minecraft.getInstance().gameDirectory, "pupper"); public static final File MUSIC_DIR = new File(MAIN_DIR, "music"); public static final File CACHE_DIR = new File(MAIN_DIR, "cache"); public static final File CONFIG_DIR = new File(MAIN_DIR, "config"); diff --git a/src/main/java/cn/pupperclient/utils/minecraft/interfaces/IMinecraft.java b/src/main/java/cn/pupperclient/utils/minecraft/interfaces/IMinecraft.java index c61e00c..b3b65e1 100644 --- a/src/main/java/cn/pupperclient/utils/minecraft/interfaces/IMinecraft.java +++ b/src/main/java/cn/pupperclient/utils/minecraft/interfaces/IMinecraft.java @@ -1,7 +1,7 @@ package cn.pupperclient.utils.minecraft.interfaces; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public interface IMinecraft { - MinecraftClient mc = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); } diff --git a/src/main/java/cn/pupperclient/utils/minecraft/player/HealthUtils.java b/src/main/java/cn/pupperclient/utils/minecraft/player/HealthUtils.java index 9bff7ce..a9be379 100644 --- a/src/main/java/cn/pupperclient/utils/minecraft/player/HealthUtils.java +++ b/src/main/java/cn/pupperclient/utils/minecraft/player/HealthUtils.java @@ -1,10 +1,10 @@ package cn.pupperclient.utils.minecraft.player; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.LivingEntity; -import net.minecraft.scoreboard.Scoreboard; -import net.minecraft.scoreboard.ScoreboardDisplaySlot; -import net.minecraft.scoreboard.ScoreboardObjective; +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.Scoreboard; public class HealthUtils { private static final String[] HP_KEYWORDS = {"hp", "health", "♥", "lives"}; @@ -24,25 +24,25 @@ public static float getActualHealth(LivingEntity entity) { } private static Float getHealthFromScoreboard(LivingEntity entity) { - MinecraftClient client = MinecraftClient.getInstance(); - if (client.world == null) return null; + Minecraft client = Minecraft.getInstance(); + if (client.level == null) return null; - Scoreboard scoreboard = client.world.getScoreboard(); - ScoreboardObjective objective = scoreboard.getObjectiveForSlot(ScoreboardDisplaySlot.BELOW_NAME); + Scoreboard scoreboard = client.level.getScoreboard(); + Objective objective = scoreboard.getDisplayObjective(DisplaySlot.BELOW_NAME); if (objective == null) return null; try { - var score = objective.getScoreboard().getScore(entity, objective); + var score = objective.getScoreboard().getPlayerScoreInfo(entity, objective); if (score == null) return null; var displayName = objective.getDisplayName(); - if (score.getScore() <= 0 || displayName == null || !containsHealthKeyword(displayName.getString())) { + if (score.value() <= 0 || displayName == null || !containsHealthKeyword(displayName.getString())) { return null; } - return (float) score.getScore(); + return (float) score.value(); } catch (Exception e) { return null; } diff --git a/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java b/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java index 15e43d9..7c4c652 100644 --- a/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java +++ b/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java @@ -1,18 +1,16 @@ package cn.pupperclient.utils.minecraft.player; import java.io.File; - +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; import cn.pupperclient.mixin.interfaces.IMixinMinecraftClient; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.Identifier; - public class SkinUtils { - public static File getSkin(Identifier identifier) { + public static File getSkin(ResourceLocation identifier) { String fileName = identifier.getPath().replace("skins/", ""); String folder = fileName.substring(0, 2); - File file = new File(((IMixinMinecraftClient) MinecraftClient.getInstance()).getAssetDir(), + File file = new File(((IMixinMinecraftClient) Minecraft.getInstance()).getAssetDir(), "skins/" + folder + "/" + fileName); return file; } diff --git a/src/main/java/cn/pupperclient/utils/misc/SoundEventHelper.java b/src/main/java/cn/pupperclient/utils/misc/SoundEventHelper.java index c59eb3d..0ab1538 100644 --- a/src/main/java/cn/pupperclient/utils/misc/SoundEventHelper.java +++ b/src/main/java/cn/pupperclient/utils/misc/SoundEventHelper.java @@ -1,7 +1,7 @@ package cn.pupperclient.utils.misc; -import net.minecraft.entity.Entity; -import net.minecraft.sound.SoundEvent; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.entity.Entity; public class SoundEventHelper { public static Entity lastSoundSource; diff --git a/src/main/java/cn/pupperclient/utils/server/ServerUtils.java b/src/main/java/cn/pupperclient/utils/server/ServerUtils.java index 0c2c8fe..b885ef2 100644 --- a/src/main/java/cn/pupperclient/utils/server/ServerUtils.java +++ b/src/main/java/cn/pupperclient/utils/server/ServerUtils.java @@ -1,26 +1,25 @@ package cn.pupperclient.utils.server; -import net.minecraft.client.MinecraftClient; - import java.util.Objects; +import net.minecraft.client.Minecraft; public class ServerUtils { - private static final MinecraftClient client = MinecraftClient.getInstance(); + private static final Minecraft client = Minecraft.getInstance(); public static boolean isJoin(Server server) { return isMultiplayer() && getAddress().contains(server.getAddress()); } public static boolean isSingleplayer() { - return client.isConnectedToLocalServer(); + return client.isSingleplayer(); } public static boolean isMultiplayer() { - return client.getCurrentServerEntry() != null; + return client.getCurrentServer() != null; } public static String getAddress() { - return isMultiplayer() ? Objects.requireNonNull(client.getCurrentServerEntry()).address : "null"; + return isMultiplayer() ? Objects.requireNonNull(client.getCurrentServer()).ip : "null"; } } diff --git a/src/main/java/cn/pupperclient/utils/thread/Multithreading.java b/src/main/java/cn/pupperclient/utils/thread/Multithreading.java index 3661ba3..b2de3c7 100644 --- a/src/main/java/cn/pupperclient/utils/thread/Multithreading.java +++ b/src/main/java/cn/pupperclient/utils/thread/Multithreading.java @@ -1,9 +1,8 @@ package cn.pupperclient.utils.thread; import java.util.concurrent.*; - +import net.minecraft.client.Minecraft; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import net.minecraft.client.MinecraftClient; public class Multithreading { private static final ExecutorService virtualThreadExecutor = Executors.newVirtualThreadPerTaskExecutor(); @@ -25,7 +24,7 @@ public static void runAsync(Runnable runnable) { } public static void runMainThread(Runnable runnable) { - MinecraftClient.getInstance().execute(runnable); + Minecraft.getInstance().execute(runnable); } public static void submit(Runnable runnable) { diff --git a/src/main/resources/pupper.accesswidener b/src/main/resources/pupper.accesswidener index 8d73f3a..397be5e 100644 --- a/src/main/resources/pupper.accesswidener +++ b/src/main/resources/pupper.accesswidener @@ -1,38 +1,30 @@ -accessWidener v2 named - -accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractType -accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler -accessible class net/minecraft/client/gui/hud/InGameHud$HeartType -accessible field net/minecraft/client/gui/screen/multiplayer/MultiplayerScreen serverListWidget Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerServerListWidget; -accessible field net/minecraft/network/packet/c2s/play/ClientCommandC2SPacket mode Lnet/minecraft/network/packet/c2s/play/ClientCommandC2SPacket$Mode; -accessible method net/minecraft/client/network/ClientPlayerEntity sendSprintingPacket ()V -accessible field net/minecraft/client/network/ClientPlayerEntity lastSneaking Z -accessible method net/minecraft/client/network/ClientCommonNetworkHandler send (Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V - -accessible field net/minecraft/util/PlayerInput jump Z -accessible field net/minecraft/util/PlayerInput sneak Z - -mutable field net/minecraft/util/PlayerInput jump Z -mutable field net/minecraft/util/PlayerInput sneak Z - -accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityX I -accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityY I -accessible field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityZ I - -mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityX I -mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityY I -mutable field net/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket velocityZ I - -accessible field net/minecraft/client/MinecraftClient itemUseCooldown I -accessible method net/minecraft/client/MinecraftClient doItemUse ()V -accessible method net/minecraft/client/MinecraftClient doAttack ()Z - -accessible method net/minecraft/entity/LivingEntity calcGlidingVelocity (Lnet/minecraft/util/math/Vec3d;)Lnet/minecraft/util/math/Vec3d; -accessible field net/minecraft/client/gui/hud/InGameHud HOTBAR_SELECTION_TEXTURE Lnet/minecraft/util/Identifier; -accessible field net/minecraft/client/gui/hud/InGameHud HOTBAR_ATTACK_INDICATOR_BACKGROUND_TEXTURE Lnet/minecraft/util/Identifier; -accessible field net/minecraft/client/gui/hud/InGameHud HOTBAR_ATTACK_INDICATOR_PROGRESS_TEXTURE Lnet/minecraft/util/Identifier; - -accessible method net/minecraft/client/render/entity/LivingEntityRenderer addFeature (Lnet/minecraft/client/render/entity/feature/FeatureRenderer;)Z -accessible field net/minecraft/client/render/entity/EntityRenderDispatcher renderers Ljava/util/Map; -accessible field net/minecraft/client/render/entity/LivingEntityRenderer features Ljava/util/List; -accessible field net/minecraft/client/render/entity/EntityRenderDispatcher modelRenderers Ljava/util/Map; +accessWidener v2 named +accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$ActionType +accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$Action +accessible class net/minecraft/client/gui/Gui$HeartType +accessible field net/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen serverSelectionList Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList; +accessible field net/minecraft/network/protocol/game/ServerboundPlayerCommandPacket action Lnet/minecraft/network/protocol/game/ServerboundPlayerCommandPacket$Action; +accessible method net/minecraft/client/player/LocalPlayer sendIsSprintingIfNeeded ()V +accessible field net/minecraft/client/player/LocalPlayer wasShiftKeyDown Z +accessible method net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl sendWhen (Lnet/minecraft/network/protocol/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V +accessible field net/minecraft/world/entity/player/Input jump Z +accessible field net/minecraft/world/entity/player/Input shift Z +mutable field net/minecraft/world/entity/player/Input jump Z +mutable field net/minecraft/world/entity/player/Input shift Z +accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I +accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I +accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I +mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I +mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I +mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I +accessible field net/minecraft/client/Minecraft rightClickDelay I +accessible method net/minecraft/client/Minecraft startUseItem ()V +accessible method net/minecraft/client/Minecraft startAttack ()Z +accessible method net/minecraft/world/entity/LivingEntity updateFallFlyingMovement (Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3; +accessible field net/minecraft/client/gui/Gui HOTBAR_SELECTION_SPRITE Lnet/minecraft/resources/ResourceLocation; +accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_BACKGROUND_SPRITE Lnet/minecraft/resources/ResourceLocation; +accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_PROGRESS_SPRITE Lnet/minecraft/resources/ResourceLocation; +accessible method net/minecraft/client/renderer/entity/LivingEntityRenderer addLayer (Lnet/minecraft/client/renderer/entity/layers/RenderLayer;)Z +accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher renderers Ljava/util/Map; +accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; +accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher playerRenderers Ljava/util/Map; From 428f49cd89c732edf2134c6d58b08d3612fbd6ac Mon Sep 17 00:00:00 2001 From: oneachina Date: Mon, 6 Apr 2026 17:46:59 +0800 Subject: [PATCH 02/45] chore: prepare to update Minecraft 26.1.1 --- build.gradle | 26 +++++++++---------- gradle.properties | 8 +++--- .../java/cn/pupperclient/gui/MainMenuGui.java | 3 +-- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index 8788e0e..7219c84 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.14-SNAPSHOT' + id 'fabric-loom' version '1.15-SNAPSHOT' id "me.modmuss50.mod-publish-plugin" version "1.1.0" } @@ -37,18 +37,18 @@ dependencies { minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - - modImplementation "com.viaversion:viafabricplus-api:4.0.2" - modRuntimeOnly "maven.modrinth:sodium:mc1.21.4-0.6.6-fabric" - modRuntimeOnly "maven.modrinth:iris:1.8.5+1.21.4-fabric" - modRuntimeOnly "maven.modrinth:sodium-extra:mc1.21.4-0.6.1+fabric" - modRuntimeOnly "maven.modrinth:lithium:mc1.21.4-0.14.7-fabric" - modImplementation "maven.modrinth:in-game-account-switcher:WBbjirJP" - modImplementation "com.viaversion:viafabricplus:4.0.2" - modRuntimeOnly "maven.modrinth:immediatelyfast:1.3.3+1.21.4-fabric" - modRuntimeOnly "maven.modrinth:entityculling:NkBXk0Ye" - modImplementation "maven.modrinth:modmenu:13.0.3" + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + + modImplementation "com.viaversion:viafabricplus-api:4.5.1" + modRuntimeOnly "maven.modrinth:sodium:mc26.1.1-0.8.9-fabric" + modRuntimeOnly "maven.modrinth:iris:1.10.9+26.1-fabric" + modRuntimeOnly "maven.modrinth:sodium-extra:mc26.1.1-0.8.6-fabric" + modRuntimeOnly "maven.modrinth:lithium:mc26.1.1-0.23.0-fabric" + // modImplementation "maven.modrinth:in-game-account-switcher:WBbjirJP" + modImplementation "com.viaversion:viafabricplus:4.5.1" + modRuntimeOnly "maven.modrinth:immediatelyfast:1.15.1+26.1.1-fabric" + modRuntimeOnly "maven.modrinth:entityculling:YSbzFHRt" + modImplementation "maven.modrinth:modmenu:18.0.0-alpha.8" jij 'io.github.smartboot.socket:aio-core:1.7.1' jij 'com.github.ben-manes.caffeine:caffeine:3.1.8' diff --git a/gradle.properties b/gradle.properties index 487c93e..5c1cf0a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,13 +4,13 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.4 -loader_version=0.18.2 +minecraft_version=26.1.1 +loader_version=0.18.6 # Mod Properties -mod_version=26.1.1 +mod_version=26.4.1 maven_group=cn.pupperclient archives_base_name=pupper # Dependencies -fabric_version=0.119.4+1.21.4 +fabric_api_version=0.145.4+26.1.1 diff --git a/src/main/java/cn/pupperclient/gui/MainMenuGui.java b/src/main/java/cn/pupperclient/gui/MainMenuGui.java index 10fdd89..cf37e8b 100644 --- a/src/main/java/cn/pupperclient/gui/MainMenuGui.java +++ b/src/main/java/cn/pupperclient/gui/MainMenuGui.java @@ -38,7 +38,6 @@ import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; import com.mojang.realmsclient.RealmsMainScreen; import net.minecraft.client.Minecraft; -import ru.vidtu.ias.screen.AccountScreen; public class MainMenuGui extends SimpleSoarGui { @@ -112,7 +111,7 @@ private void rebuildLayout() { centerX - buttonWidth / 2, centerY, buttonWidth, scaleFactor, () -> client.setScreen(new RealmsMainScreen(this)))); buttons.add(new MainMenuButton("menu.ias", Icon.ACCOUNT_BALANCE, - centerX - buttonWidth / 2, centerY + (60 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new AccountScreen(this)))); + centerX - buttonWidth / 2, centerY + (60 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new JoinMultiplayerScreen(this)))); buttons.add(new MainMenuButton("menu.modmenu", Icon.LIST, centerX - buttonWidth / 2, centerY + (120 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new ModsScreen(this)))); From 7ec77795519c4aa1af88772b8ffef40fb44c045a Mon Sep 17 00:00:00 2001 From: oneachina Date: Mon, 6 Apr 2026 17:48:08 +0800 Subject: [PATCH 03/45] chore: update java --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7219c84..ad5f9fd 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 21 + it.options.release = 25 } java { From 293b1cb9dc74e5ff3294d9361a2e804e65659c67 Mon Sep 17 00:00:00 2001 From: oneachina Date: Mon, 6 Apr 2026 20:37:22 +0800 Subject: [PATCH 04/45] chore: update minecraft, fabric, modlib etc.. --- build.gradle | 111 +++++++---------------- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 14 +-- gradlew.bat | 3 +- src/main/resources/fabric.mod.json | 2 +- src/main/resources/pupper.accesswidener | 30 ------ src/main/resources/pupper.classtweaker | 30 ++++++ 8 files changed, 72 insertions(+), 120 deletions(-) delete mode 100644 src/main/resources/pupper.accesswidener create mode 100644 src/main/resources/pupper.classtweaker diff --git a/build.gradle b/build.gradle index ad5f9fd..e033f94 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,8 @@ plugins { - id 'fabric-loom' version '1.15-SNAPSHOT' - id "me.modmuss50.mod-publish-plugin" version "1.1.0" + id 'net.fabricmc.fabric-loom' version '1.15-SNAPSHOT' } -project.ext.lwjglVersion = "3.3.3" +project.ext.lwjglVersion = "3.4.1" version = project.mod_version group = project.maven_group @@ -12,7 +11,7 @@ base { } loom { - accessWidenerPath = file("src/main/resources/pupper.accesswidener") + accessWidenerPath = file("src/main/resources/pupper.classtweaker") } repositories { @@ -27,47 +26,42 @@ repositories { } configurations { - jij modJij include.extendsFrom modJij - modImplementation.extendsFrom modJij + implementation.extendsFrom modJij } dependencies { minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings loom.officialMojangMappings() - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" - - modImplementation "com.viaversion:viafabricplus-api:4.5.1" - modRuntimeOnly "maven.modrinth:sodium:mc26.1.1-0.8.9-fabric" - modRuntimeOnly "maven.modrinth:iris:1.10.9+26.1-fabric" - modRuntimeOnly "maven.modrinth:sodium-extra:mc26.1.1-0.8.6-fabric" - modRuntimeOnly "maven.modrinth:lithium:mc26.1.1-0.23.0-fabric" + implementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + + implementation "com.viaversion:viafabricplus-api:4.5.1" + runtimeOnly "maven.modrinth:sodium:mc26.1.1-0.8.9-fabric" + runtimeOnly "maven.modrinth:iris:1.10.9+26.1-fabric" + // runtimeOnly "maven.modrinth:sodium-extra:mc26.1.1-0.8.6-fabric" + runtimeOnly "maven.modrinth:lithium:mc26.1.1-0.23.0-fabric" // modImplementation "maven.modrinth:in-game-account-switcher:WBbjirJP" - modImplementation "com.viaversion:viafabricplus:4.5.1" - modRuntimeOnly "maven.modrinth:immediatelyfast:1.15.1+26.1.1-fabric" - modRuntimeOnly "maven.modrinth:entityculling:YSbzFHRt" - modImplementation "maven.modrinth:modmenu:18.0.0-alpha.8" - - jij 'io.github.smartboot.socket:aio-core:1.7.1' - jij 'com.github.ben-manes.caffeine:caffeine:3.1.8' - jij 'io.github.humbleui:types:0.2.0' - jij 'io.github.humbleui:skija-windows-x64:0.143.2' - jij 'io.github.humbleui:skija-linux-x64:0.143.2' - jij 'io.github.humbleui:skija-linux-arm64:0.143.2' - jij 'io.github.humbleui:skija-macos-x64:0.143.2' - jij 'com.kohlschutter.junixsocket:junixsocket-common:2.10.1' - jij 'org.java-websocket:Java-WebSocket:1.6.0' - jij 'com.mpatric:mp3agic:0.9.1' - jij 'javazoom:jlayer:1.0.1' - jij 'com.googlecode.soundlibs:mp3spi:1.9.5.4' - jij 'org:jaudiotagger:2.0.3' - jij 'com.googlecode.soundlibs:jlayer:1.0.1.4' - jij "net.lenni0451:MCPing:1.4.2" - jij "net.lenni0451:Reflect:1.4.0" - modImplementation 'net.java.dev.jna:jna:5.12.1' - modImplementation 'net.java.dev.jna:jna-platform:5.12.1' + implementation "com.viaversion:viafabricplus:4.5.1" + runtimeOnly "maven.modrinth:immediatelyfast:1.15.1+26.1.1-fabric" + runtimeOnly "maven.modrinth:entityculling:YSbzFHRt" + implementation "maven.modrinth:modmenu:18.0.0-alpha.8" + + modJij 'io.github.smartboot.socket:aio-core:1.7.1' + modJij 'com.github.ben-manes.caffeine:caffeine:3.1.8' + modJij 'io.github.humbleui:types:0.2.0' + modJij 'io.github.humbleui:skija-windows-x64:0.116.4' + modJij 'com.kohlschutter.junixsocket:junixsocket-common:2.10.1' + modJij 'org.java-websocket:Java-WebSocket:1.6.0' + modJij 'com.mpatric:mp3agic:0.9.1' + modJij 'javazoom:jlayer:1.0.1' + modJij 'com.googlecode.soundlibs:mp3spi:1.9.5.4' + modJij 'org:jaudiotagger:2.0.3' + modJij 'com.googlecode.soundlibs:jlayer:1.0.1.4' + modJij "net.lenni0451:MCPing:1.4.2" + modJij "net.lenni0451:Reflect:1.4.0" + implementation 'net.java.dev.jna:jna:5.12.1' + implementation 'net.java.dev.jna:jna-platform:5.12.1' def lwjglNfdDeps = [ "org.lwjgl:lwjgl-nfd:$lwjglVersion", @@ -78,17 +72,7 @@ dependencies { ] lwjglNfdDeps.each { dep -> - jij dep - implementation dep - include dep - } - - afterEvaluate { - configurations.jij.incoming.resolutionResult.allDependencies.each { - dependencies.include(dependencies.implementation(dependencies.compileOnlyApi(it.requested.toString()) { - transitive = false - })) - } + modJij dep } } @@ -113,33 +97,6 @@ tasks.withType(JavaCompile).configureEach { } java { + toolchain.languageVersion = JavaLanguageVersion.of(25) withSourcesJar() } - -publishMods { - file = remapJar.archiveFile - changelog = providers.environmentVariable("CHANGELOG").getOrElse("No changelog provided") - type = STABLE - modLoaders.add("fabric") - - modrinth { - accessToken = providers.environmentVariable("MODRINTH_TOKEN") - projectId = "zN1WBfNk" - - minecraftVersions.add(project.minecraft_version) - - requires("fabric-api") - requires("viafabricplus") - requires("in-game-account-switcher") - requires("modmenu") - - optional("sodium", "iris") - } - - github { - accessToken = providers.environmentVariable("GITHUB_TOKEN") - repository = "PupperClient/Pupper-Client" - commitish = "main" - tagName = project.mod_version - } -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch delta 40682 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Ðt5p(LLtXn?pxm3OZHd|13r);5)1uCW40m{;j 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 A;{X5v delta 35496 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bad7c24..0ca609f 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-9.2.0-bin.zip +distributionUrl=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6..739907d 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -206,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a21..c4bdd3a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index fce97ca..ad4a87c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "id": "pupper", "version": "${version}", - "accessWidener": "pupper.accesswidener", + "accessWidener": "pupper.classtweaker", "name": "PupperClient", "icon": "assets/pupper/logo.png", "description": "Better, Faster Minecraft Client", diff --git a/src/main/resources/pupper.accesswidener b/src/main/resources/pupper.accesswidener deleted file mode 100644 index 397be5e..0000000 --- a/src/main/resources/pupper.accesswidener +++ /dev/null @@ -1,30 +0,0 @@ -accessWidener v2 named -accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$ActionType -accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$Action -accessible class net/minecraft/client/gui/Gui$HeartType -accessible field net/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen serverSelectionList Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList; -accessible field net/minecraft/network/protocol/game/ServerboundPlayerCommandPacket action Lnet/minecraft/network/protocol/game/ServerboundPlayerCommandPacket$Action; -accessible method net/minecraft/client/player/LocalPlayer sendIsSprintingIfNeeded ()V -accessible field net/minecraft/client/player/LocalPlayer wasShiftKeyDown Z -accessible method net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl sendWhen (Lnet/minecraft/network/protocol/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V -accessible field net/minecraft/world/entity/player/Input jump Z -accessible field net/minecraft/world/entity/player/Input shift Z -mutable field net/minecraft/world/entity/player/Input jump Z -mutable field net/minecraft/world/entity/player/Input shift Z -accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I -accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I -accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I -mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I -mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I -mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I -accessible field net/minecraft/client/Minecraft rightClickDelay I -accessible method net/minecraft/client/Minecraft startUseItem ()V -accessible method net/minecraft/client/Minecraft startAttack ()Z -accessible method net/minecraft/world/entity/LivingEntity updateFallFlyingMovement (Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3; -accessible field net/minecraft/client/gui/Gui HOTBAR_SELECTION_SPRITE Lnet/minecraft/resources/ResourceLocation; -accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_BACKGROUND_SPRITE Lnet/minecraft/resources/ResourceLocation; -accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_PROGRESS_SPRITE Lnet/minecraft/resources/ResourceLocation; -accessible method net/minecraft/client/renderer/entity/LivingEntityRenderer addLayer (Lnet/minecraft/client/renderer/entity/layers/RenderLayer;)Z -accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher renderers Ljava/util/Map; -accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; -accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher playerRenderers Ljava/util/Map; diff --git a/src/main/resources/pupper.classtweaker b/src/main/resources/pupper.classtweaker new file mode 100644 index 0000000..8faee09 --- /dev/null +++ b/src/main/resources/pupper.classtweaker @@ -0,0 +1,30 @@ +classTweaker v1 official +transitive-accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$ActionType +transitive-accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$Action +transitive-accessible class net/minecraft/client/gui/Gui$HeartType +transitive-accessible field net/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen serverSelectionList Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList; +transitive-accessible field net/minecraft/network/protocol/game/ServerboundPlayerCommandPacket action Lnet/minecraft/network/protocol/game/ServerboundPlayerCommandPacket$Action; +transitive-accessible method net/minecraft/client/player/LocalPlayer sendIsSprintingIfNeeded ()V +transitive-accessible field net/minecraft/client/player/LocalPlayer wasShiftKeyDown Z +transitive-accessible method net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl sendWhen (Lnet/minecraft/network/protocol/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V +transitive-accessible field net/minecraft/world/entity/player/Input jump Z +transitive-accessible field net/minecraft/world/entity/player/Input shift Z +transitive-mutable field net/minecraft/world/entity/player/Input jump Z +transitive-mutable field net/minecraft/world/entity/player/Input shift Z +transitive-accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I +transitive-accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I +transitive-accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I +transitive-mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I +transitive-mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I +transitive-mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I +transitive-accessible field net/minecraft/client/Minecraft rightClickDelay I +transitive-accessible method net/minecraft/client/Minecraft startUseItem ()V +transitive-accessible method net/minecraft/client/Minecraft startAttack ()Z +transitive-accessible method net/minecraft/world/entity/LivingEntity updateFallFlyingMovement (Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3; +transitive-accessible field net/minecraft/client/gui/Gui HOTBAR_SELECTION_SPRITE Lnet/minecraft/resources/ResourceLocation; +transitive-accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_BACKGROUND_SPRITE Lnet/minecraft/resources/ResourceLocation; +transitive-accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_PROGRESS_SPRITE Lnet/minecraft/resources/ResourceLocation; +transitive-accessible method net/minecraft/client/renderer/entity/LivingEntityRenderer addLayer (Lnet/minecraft/client/renderer/entity/layers/RenderLayer;)Z +transitive-accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher renderers Ljava/util/Map; +transitive-accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; +transitive-accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher playerRenderers Ljava/util/Map; From ae4d71de5be02a918829beed2abe92b29e8b4fea Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 11:58:19 +0800 Subject: [PATCH 05/45] fix(skia): fix skia (i guess) --- build.gradle | 4 +- .../client/MixinMinecraftClient.java | 24 +++ src/main/java/cn/pupperclient/skia/Skia.java | 6 +- .../skia/api/WrappedBackendRenderTarget.java | 69 +++++++ .../skia/context/SkiaContext.java | 98 ++++----- .../cn/pupperclient/skia/gl/Properties.java | 79 +++++++ .../java/cn/pupperclient/skia/gl/State.java | 194 ++++++++++++++++++ .../java/cn/pupperclient/skia/gl/States.java | 71 +++++++ .../pupperclient/skia/image/ImageHelper.java | 42 ++-- 9 files changed, 508 insertions(+), 79 deletions(-) create mode 100644 src/main/java/cn/pupperclient/skia/api/WrappedBackendRenderTarget.java create mode 100644 src/main/java/cn/pupperclient/skia/gl/Properties.java create mode 100644 src/main/java/cn/pupperclient/skia/gl/State.java create mode 100644 src/main/java/cn/pupperclient/skia/gl/States.java diff --git a/build.gradle b/build.gradle index e033f94..174002d 100644 --- a/build.gradle +++ b/build.gradle @@ -49,8 +49,10 @@ dependencies { modJij 'io.github.smartboot.socket:aio-core:1.7.1' modJij 'com.github.ben-manes.caffeine:caffeine:3.1.8' + modJij 'io.github.humbleui:types:0.2.0' - modJij 'io.github.humbleui:skija-windows-x64:0.116.4' + modJij 'io.github.humbleui:skija-windows-x64:0.119.3' + modJij 'com.kohlschutter.junixsocket:junixsocket-common:2.10.1' modJij 'org.java-websocket:Java-WebSocket:1.6.0' modJij 'com.mpatric:mp3agic:0.9.1' diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index cd40002..b527994 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -16,6 +16,8 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult.Type; +import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.gui.api.SimpleSoarGui; import cn.pupperclient.shader.impl.Kawaseblur; import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; @@ -70,6 +72,10 @@ public abstract class MixinMinecraftClient implements IMixinMinecraftClient { @Shadow public LocalPlayer player; + @Shadow + @Nullable + public Screen screen; + @Shadow protected abstract String createTitle(); @@ -149,6 +155,24 @@ public void onGameLoop(CallbackInfo ci) { EventBus.getInstance().post(new GameLoopEvent()); } + @Inject( + method = { "renderFrame", "runTick" }, + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/systems/RenderSystem;flipFrame(Lcom/mojang/blaze3d/TracyFrameCapture;)V" + ), + require = 0 + ) + private void onBeforeFlipFrame(CallbackInfo ci) { + if (level == null) { + return; + } + if (screen instanceof SimpleSoarGui) { + return; + } + SkiaContext.draw(canvas -> EventBus.getInstance().post(new RenderSkiaEvent(canvas))); + } + @Inject(method = "resizeDisplay", at = @At("TAIL")) public void onResolutionChanged(CallbackInfo info) { Kawaseblur.GUI_BLUR.resize(); diff --git a/src/main/java/cn/pupperclient/skia/Skia.java b/src/main/java/cn/pupperclient/skia/Skia.java index 8d38d0e..2f29c4d 100644 --- a/src/main/java/cn/pupperclient/skia/Skia.java +++ b/src/main/java/cn/pupperclient/skia/Skia.java @@ -3,7 +3,7 @@ import java.awt.Color; import java.io.File; import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import cn.pupperclient.management.mod.impl.settings.HUDModSettings; import cn.pupperclient.shader.impl.Kawaseblur; import cn.pupperclient.skia.context.SkiaContext; @@ -286,10 +286,10 @@ public static void drawSkin(File file, float x, float y, float scale) { } } public static void drawMinecraftImage(String path, float x, float y, float width, float height) { - ResourceLocation identifier = ResourceLocation.fromNamespaceAndPath("minecraft", path); + Identifier identifier = Identifier.fromNamespaceAndPath("minecraft", path); if (imageHelper.load(identifier)) { - getCanvas().drawImageRect(imageHelper.get(identifier.getPath()), Rect.makeXYWH(x, y, width, height)); + getCanvas().drawImageRect(imageHelper.get(identifier.toString()), Rect.makeXYWH(x, y, width, height)); } } diff --git a/src/main/java/cn/pupperclient/skia/api/WrappedBackendRenderTarget.java b/src/main/java/cn/pupperclient/skia/api/WrappedBackendRenderTarget.java new file mode 100644 index 0000000..ddba3e9 --- /dev/null +++ b/src/main/java/cn/pupperclient/skia/api/WrappedBackendRenderTarget.java @@ -0,0 +1,69 @@ +package cn.pupperclient.skia.api; + +import io.github.humbleui.skija.BackendRenderTarget; +import io.github.humbleui.skija.impl.Stats; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * @Author: oneachina + * @Date: 2026/2/3 11:18 + */ +public class WrappedBackendRenderTarget extends BackendRenderTarget { + private final int width; + private final int height; + private final int sampleCnt; + private final int stencilBits; + private final int fbId; + private final int fbFormat; + + public WrappedBackendRenderTarget( + int width, + int height, + int sampleCnt, + int stencilBits, + int fbId, + int fbFormat, + long ptr + ) { + super(ptr); + this.width = width; + this.height = height; + this.sampleCnt = sampleCnt; + this.stencilBits = stencilBits; + this.fbId = fbId; + this.fbFormat = fbFormat; + } + + /** + * @see BackendRenderTarget#makeGL(int, int, int, int, int, int) + */ + @Contract("_, _, _, _, _, _ -> new") + public static @NotNull WrappedBackendRenderTarget makeGL( + int width, + int height, + int sampleCnt, + int stencilBits, + int fbId, + int fbFormat + ) { + Stats.onNativeCall(); + return new WrappedBackendRenderTarget( + width, + height, + sampleCnt, + stencilBits, + fbId, + fbFormat, + _nMakeGL(width, height, sampleCnt, stencilBits, fbId, fbFormat) + ); + } + + // Getters + public int getWidth() { return width; } + public int getHeight() { return height; } + public int getSampleCnt() { return sampleCnt; } + public int getStencilBits() { return stencilBits; } + public int getFbId() { return fbId; } + public int getFbFormat() { return fbFormat; } +} diff --git a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java index f118938..1774fbc 100644 --- a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java +++ b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java @@ -1,88 +1,72 @@ package cn.pupperclient.skia.context; +import java.util.Objects; import java.util.function.Consumer; -import net.minecraft.client.Minecraft; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL33; -import com.mojang.blaze3d.platform.GlConst; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.BufferUploader; -import io.github.humbleui.skija.BackendRenderTarget; -import io.github.humbleui.skija.Canvas; -import io.github.humbleui.skija.ColorSpace; -import io.github.humbleui.skija.DirectContext; -import io.github.humbleui.skija.Surface; -import io.github.humbleui.skija.SurfaceColorFormat; -import io.github.humbleui.skija.SurfaceOrigin; +import cn.pupperclient.skia.api.WrappedBackendRenderTarget; +import cn.pupperclient.skia.gl.States; +import io.github.humbleui.skija.*; + +import org.lwjgl.opengl.GL11; public class SkiaContext { private static DirectContext context = null; private static Surface surface; private static BackendRenderTarget renderTarget; + private static final GLBackendState[] states = { + GLBackendState.BLEND, + GLBackendState.VERTEX, + GLBackendState.PIXEL_STORE, + GLBackendState.TEXTURE_BINDING, + GLBackendState.MISC + }; public static Canvas getCanvas() { return surface.getCanvas(); } public static void createSurface(int width, int height) { - if (context == null) { context = DirectContext.makeGL(); } - if (surface != null) { - surface.close(); - surface = null; - } - - if (renderTarget != null) { - renderTarget.close(); - renderTarget = null; - } - - renderTarget = BackendRenderTarget.makeGL(width, height, 0, 8, - Minecraft.getInstance().getMainRenderTarget().frameBufferId, GL11.GL_RGBA8); - surface = Surface.wrapBackendRenderTarget(context, renderTarget, SurfaceOrigin.BOTTOM_LEFT, - SurfaceColorFormat.RGBA_8888, ColorSpace.getSRGB()); + if (surface != null) surface.close(); + if (renderTarget != null) renderTarget.close(); + + renderTarget = WrappedBackendRenderTarget.makeGL( + width, + height, + 0, + 8, + 0, + FramebufferFormat.GR_GL_RGBA8 + ); + + surface = Surface.wrapBackendRenderTarget( + Objects.requireNonNull(context, "Context must not be null"), + Objects.requireNonNull(renderTarget, "RenderTarget must not be null"), + SurfaceOrigin.BOTTOM_LEFT, + SurfaceColorFormat.RGBA_8888, + ColorSpace.getSRGB() + ); } public static void draw(Consumer drawingLogic) { + if (context == null || surface == null) { + return; + } - RenderSystem.pixelStore(GlConst.GL_UNPACK_ROW_LENGTH, 0); - RenderSystem.pixelStore(GlConst.GL_UNPACK_SKIP_PIXELS, 0); - RenderSystem.pixelStore(GlConst.GL_UNPACK_SKIP_ROWS, 0); - RenderSystem.pixelStore(GlConst.GL_UNPACK_ALIGNMENT, 4); - RenderSystem.clearColor(0f, 0f, 0f, 0f); - context.resetGLAll(); + States.push(); + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glClearColor(0f, 0f, 0f, 0f); + context.resetGL(states); Canvas canvas = getCanvas(); drawingLogic.accept(canvas); - context.flush(); - - BufferUploader.reset(); - GL33.glBindSampler(0, 0); - RenderSystem.disableBlend(); - GL11.glDisable(GL11.GL_BLEND); - RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); - RenderSystem.blendEquation(GL33.GL_FUNC_ADD); - GL33.glBlendEquation(GL33.GL_FUNC_ADD); - RenderSystem.colorMask(true, true, true, true); - GL11.glColorMask(true, true, true, true); - RenderSystem.depthMask(true); - GL11.glDepthMask(true); - RenderSystem.disableScissor(); - GL11.glDisable(GL11.GL_SCISSOR_TEST); - GL11.glDisable(GL11.GL_STENCIL_TEST); - RenderSystem.disableDepthTest(); - GL11.glDisable(GL11.GL_DEPTH_TEST); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - RenderSystem.activeTexture(GL13.GL_TEXTURE0); - RenderSystem.disableCull(); + context.flushAndSubmit(surface); + States.pop(); } public static DirectContext getContext() { diff --git a/src/main/java/cn/pupperclient/skia/gl/Properties.java b/src/main/java/cn/pupperclient/skia/gl/Properties.java new file mode 100644 index 0000000..96f20e4 --- /dev/null +++ b/src/main/java/cn/pupperclient/skia/gl/Properties.java @@ -0,0 +1,79 @@ +/* + * This file is part of https://github.com/Lyzev/Skija. + * + * Copyright (c) 2025. Lyzev + * + * Skija is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + */ + +package cn.pupperclient.skia.gl; + +import java.util.BitSet; + +/* + * Converted to Java by oneachina + */ +public class Properties { + + public final int[] lastActiveTexture = new int[1]; + public final int[] lastProgram = new int[1]; + public final int[] lastTexture = new int[1]; + public final int[] lastSampler = new int[1]; + public final int[] lastArrayBuffer = new int[1]; + public final int[] lastVertexArrayObject = new int[1]; + public final int[] lastPolygonMode = new int[2]; + public final int[] lastViewport = new int[4]; + public final int[] lastScissorBox = new int[4]; + public final int[] lastBlendSrcRgb = new int[1]; + public final int[] lastBlendDstRgb = new int[1]; + public final int[] lastBlendSrcAlpha = new int[1]; + public final int[] lastBlendDstAlpha = new int[1]; + public final int[] lastBlendEquationRgb = new int[1]; + public final int[] lastBlendEquationAlpha = new int[1]; + + public final int[] lastPixelUnpackBufferBinding = new int[1]; + public final int[] lastUnpackAlignment = new int[1]; + public final int[] lastUnpackRowLength = new int[1]; + public final int[] lastUnpackSkipPixels = new int[1]; + public final int[] lastUnpackSkipRows = new int[1]; + public final int[] lastPackSwapBytes = new int[1]; + public final int[] lastPackLsbFirst = new int[1]; + public final int[] lastPackRowLength = new int[1]; + public final int[] lastPackImageHeight = new int[1]; + public final int[] lastPackSkipPixels = new int[1]; + public final int[] lastPackSkipRows = new int[1]; + public final int[] lastPackSkipImages = new int[1]; + public final int[] lastPackAlignment = new int[1]; + public final int[] lastUnpackSwapBytes = new int[1]; + public final int[] lastUnpackLsbFirst = new int[1]; + public final int[] lastUnpackImageHeight = new int[1]; + public final int[] lastUnpackSkipImages = new int[1]; + + private final BitSet flags = new BitSet(7); + + // Boolean Properties via BitSet + + public boolean isLastEnableBlend() { return flags.get(0); } + public void setLastEnableBlend(boolean value) { flags.set(0, value); } + + public boolean isLastEnableCullFace() { return flags.get(1); } + public void setLastEnableCullFace(boolean value) { flags.set(1, value); } + + public boolean isLastEnableDepthTest() { return flags.get(2); } + public void setLastEnableDepthTest(boolean value) { flags.set(2, value); } + + public boolean isLastEnableStencilTest() { return flags.get(3); } + public void setLastEnableStencilTest(boolean value) { flags.set(3, value); } + + public boolean isLastEnableScissorTest() { return flags.get(4); } + public void setLastEnableScissorTest(boolean value) { flags.set(4, value); } + + public boolean isLastEnablePrimitiveRestart() { return flags.get(5); } + public void setLastEnablePrimitiveRestart(boolean value) { flags.set(5, value); } + + public boolean isLastDepthMask() { return flags.get(6); } + public void setLastDepthMask(boolean value) { flags.set(6, value); } +} diff --git a/src/main/java/cn/pupperclient/skia/gl/State.java b/src/main/java/cn/pupperclient/skia/gl/State.java new file mode 100644 index 0000000..e403938 --- /dev/null +++ b/src/main/java/cn/pupperclient/skia/gl/State.java @@ -0,0 +1,194 @@ +/* + * Hina Client + * Copyright (C) 2026 Hina Client + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file is part of https://github.com/Lyzev/Skija. + * + * Copyright (c) 2025. Lyzev + * + * Skija is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + */ + +/* + * Converted to Java by oneachina + */ + +package cn.pupperclient.skia.gl; + +import org.lwjgl.opengl.GL; +import static org.lwjgl.opengl.GL45.*; + +/** + * Represents the OpenGL state. + */ +public class State { + private final int glVersion; + private final Properties props = new Properties(); + + public State(int glVersion) { + this.glVersion = glVersion; + } + + /** + * Saves the current OpenGL state. + * + * @see #pop() + */ + public State push() { + glGetIntegerv(GL_ACTIVE_TEXTURE, props.lastActiveTexture); + glActiveTexture(GL_TEXTURE0); + glGetIntegerv(GL_CURRENT_PROGRAM, props.lastProgram); + glGetIntegerv(GL_TEXTURE_BINDING_2D, props.lastTexture); + + if (glVersion >= 330 || GL.getCapabilities().GL_ARB_sampler_objects) { + glGetIntegerv(GL_SAMPLER_BINDING, props.lastSampler); + } + + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, props.lastArrayBuffer); + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, props.lastVertexArrayObject); + + if (glVersion >= 200) { + glGetIntegerv(GL_POLYGON_MODE, props.lastPolygonMode); + } + + glGetIntegerv(GL_VIEWPORT, props.lastViewport); + glGetIntegerv(GL_SCISSOR_BOX, props.lastScissorBox); + glGetIntegerv(GL_BLEND_SRC_RGB, props.lastBlendSrcRgb); + glGetIntegerv(GL_BLEND_DST_RGB, props.lastBlendDstRgb); + glGetIntegerv(GL_BLEND_SRC_ALPHA, props.lastBlendSrcAlpha); + glGetIntegerv(GL_BLEND_DST_ALPHA, props.lastBlendDstAlpha); + glGetIntegerv(GL_BLEND_EQUATION_RGB, props.lastBlendEquationRgb); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, props.lastBlendEquationAlpha); + + props.setLastEnableBlend(glIsEnabled(GL_BLEND)); + props.setLastEnableCullFace(glIsEnabled(GL_CULL_FACE)); + props.setLastEnableDepthTest(glIsEnabled(GL_DEPTH_TEST)); + props.setLastEnableStencilTest(glIsEnabled(GL_STENCIL_TEST)); + props.setLastEnableScissorTest(glIsEnabled(GL_SCISSOR_TEST)); + + if (glVersion >= 310) { + props.setLastEnablePrimitiveRestart(glIsEnabled(GL_PRIMITIVE_RESTART)); + } + + props.setLastDepthMask(glGetBoolean(GL_DEPTH_WRITEMASK)); + + glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, props.lastPixelUnpackBufferBinding); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + glGetIntegerv(GL_PACK_SWAP_BYTES, props.lastPackSwapBytes); + glGetIntegerv(GL_PACK_LSB_FIRST, props.lastPackLsbFirst); + glGetIntegerv(GL_PACK_ROW_LENGTH, props.lastPackRowLength); + glGetIntegerv(GL_PACK_SKIP_PIXELS, props.lastPackSkipPixels); + glGetIntegerv(GL_PACK_SKIP_ROWS, props.lastPackSkipRows); + glGetIntegerv(GL_PACK_ALIGNMENT, props.lastPackAlignment); + + glGetIntegerv(GL_UNPACK_SWAP_BYTES, props.lastUnpackSwapBytes); + glGetIntegerv(GL_UNPACK_LSB_FIRST, props.lastUnpackLsbFirst); + glGetIntegerv(GL_UNPACK_ALIGNMENT, props.lastUnpackAlignment); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, props.lastUnpackRowLength); + glGetIntegerv(GL_UNPACK_SKIP_PIXELS, props.lastUnpackSkipPixels); + glGetIntegerv(GL_UNPACK_SKIP_ROWS, props.lastUnpackSkipRows); + + if (glVersion >= 120) { + glGetIntegerv(GL_PACK_IMAGE_HEIGHT, props.lastPackImageHeight); + glGetIntegerv(GL_PACK_SKIP_IMAGES, props.lastPackSkipImages); + glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, props.lastUnpackImageHeight); + glGetIntegerv(GL_UNPACK_SKIP_IMAGES, props.lastUnpackSkipImages); + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + + return this; + } + + /** + * Restores the state that was saved with {@link #push()}. + * + * @see #push() + */ + public State pop() { + glUseProgram(props.lastProgram[0]); + glBindTexture(GL_TEXTURE_2D, props.lastTexture[0]); + + if (glVersion >= 330 || GL.getCapabilities().GL_ARB_sampler_objects) { + glBindSampler(0, props.lastSampler[0]); + } + + glActiveTexture(props.lastActiveTexture[0]); + glBindVertexArray(props.lastVertexArrayObject[0]); + glBindBuffer(GL_ARRAY_BUFFER, props.lastArrayBuffer[0]); + + glBlendEquationSeparate(props.lastBlendEquationRgb[0], props.lastBlendEquationAlpha[0]); + glBlendFuncSeparate( + props.lastBlendSrcRgb[0], + props.lastBlendDstRgb[0], + props.lastBlendSrcAlpha[0], + props.lastBlendDstAlpha[0] + ); + + if (props.isLastEnableBlend()) glEnable(GL_BLEND); else glDisable(GL_BLEND); + if (props.isLastEnableCullFace()) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); + if (props.isLastEnableDepthTest()) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); + if (props.isLastEnableStencilTest()) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST); + if (props.isLastEnableScissorTest()) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); + + if (glVersion >= 310) { + if (props.isLastEnablePrimitiveRestart()) glEnable(GL_PRIMITIVE_RESTART); + else glDisable(GL_PRIMITIVE_RESTART); + } + + if (glVersion >= 200) { + glPolygonMode(GL_FRONT_AND_BACK, props.lastPolygonMode[0]); + } + + glViewport(props.lastViewport[0], props.lastViewport[1], props.lastViewport[2], props.lastViewport[3]); + glScissor(props.lastScissorBox[0], props.lastScissorBox[1], props.lastScissorBox[2], props.lastScissorBox[3]); + + glPixelStorei(GL_PACK_SWAP_BYTES, props.lastPackSwapBytes[0]); + glPixelStorei(GL_PACK_LSB_FIRST, props.lastPackLsbFirst[0]); + glPixelStorei(GL_PACK_ROW_LENGTH, props.lastPackRowLength[0]); + glPixelStorei(GL_PACK_SKIP_PIXELS, props.lastPackSkipPixels[0]); + glPixelStorei(GL_PACK_SKIP_ROWS, props.lastPackSkipRows[0]); + glPixelStorei(GL_PACK_ALIGNMENT, props.lastPackAlignment[0]); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, props.lastPixelUnpackBufferBinding[0]); + glPixelStorei(GL_UNPACK_SWAP_BYTES, props.lastUnpackSwapBytes[0]); + glPixelStorei(GL_UNPACK_LSB_FIRST, props.lastUnpackLsbFirst[0]); + glPixelStorei(GL_UNPACK_ALIGNMENT, props.lastUnpackAlignment[0]); + glPixelStorei(GL_UNPACK_ROW_LENGTH, props.lastUnpackRowLength[0]); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, props.lastUnpackSkipPixels[0]); + glPixelStorei(GL_UNPACK_SKIP_ROWS, props.lastUnpackSkipRows[0]); + + if (glVersion >= 120) { + glPixelStorei(GL_PACK_IMAGE_HEIGHT, props.lastPackImageHeight[0]); + glPixelStorei(GL_PACK_SKIP_IMAGES, props.lastPackSkipImages[0]); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, props.lastUnpackImageHeight[0]); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, props.lastUnpackSkipImages[0]); + } + + glDepthMask(props.isLastDepthMask()); + + return this; + } +} diff --git a/src/main/java/cn/pupperclient/skia/gl/States.java b/src/main/java/cn/pupperclient/skia/gl/States.java new file mode 100644 index 0000000..e3b6803 --- /dev/null +++ b/src/main/java/cn/pupperclient/skia/gl/States.java @@ -0,0 +1,71 @@ +/* + * This file is part of https://github.com/Lyzev/Skija. + * + * Copyright (c) 2024-2025. Lyzev + * + * Skija is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + * + * Skija 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Skija. If not, see . + */ + +package cn.pupperclient.skia.gl; + +import org.lwjgl.opengl.GL30.*; +import java.util.Stack; + +import static org.lwjgl.opengl.GL11.glGetIntegerv; +import static org.lwjgl.opengl.GL30C.GL_MAJOR_VERSION; +import static org.lwjgl.opengl.GL30C.GL_MINOR_VERSION; + +/** + * Stores and restores OpenGL states. + */ +public final class States { + + /** + * The current OpenGL version. + */ + private static final int GL_VERSION; + + /** + * The stack of OpenGL states. + */ + private static final Stack STATES = new Stack<>(); + + private States() { + // private constructor to prevent instantiation + } + + /** + * Pushes the current OpenGL state onto the stack. + */ + public static void push() { + STATES.push(new State(GL_VERSION).push()); + } + + /** + * Pops the last OpenGL state from the stack and restores it. + */ + public static void pop() { + if (STATES.isEmpty()) { + throw new IllegalStateException("No state to restore."); + } + STATES.pop().pop(); + } + + static { + int[] major = new int[1]; + int[] minor = new int[1]; + glGetIntegerv(GL_MAJOR_VERSION, major); + glGetIntegerv(GL_MINOR_VERSION, minor); + GL_VERSION = major[0] * 100 + minor[0] * 10; + } +} diff --git a/src/main/java/cn/pupperclient/skia/image/ImageHelper.java b/src/main/java/cn/pupperclient/skia/image/ImageHelper.java index f4248b2..016f6f2 100644 --- a/src/main/java/cn/pupperclient/skia/image/ImageHelper.java +++ b/src/main/java/cn/pupperclient/skia/image/ImageHelper.java @@ -9,7 +9,7 @@ import java.util.Map; import java.util.Optional; import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import org.lwjgl.opengl.GL11; @@ -24,22 +24,29 @@ public class ImageHelper { private Map images = new HashMap<>(); - private Map textures = new HashMap<>(); + private Map textures = new HashMap<>(); public boolean load(int texture, float width, float height, SurfaceOrigin origin) { - if (!textures.containsKey(texture)) { - Image image = Image.adoptGLTextureFrom(SkiaContext.getContext(), texture, GL11.GL_TEXTURE_2D, (int) width, - (int) height, GL11.GL_RGBA8, origin, ColorType.RGBA_8888); - textures.put(texture, image); - } + int w = Math.max(1, (int) width); + int h = Math.max(1, (int) height); + TextureEntry existing = textures.get(texture); + if (existing == null || existing.width != w || existing.height != h || existing.origin != origin) { + if (existing != null) { + existing.image.close(); + } + Image image = Image.adoptGLTextureFrom(SkiaContext.getContext(), texture, GL11.GL_TEXTURE_2D, w, h, + GL11.GL_RGBA8, origin, ColorType.RGBA_8888); + textures.put(texture, new TextureEntry(image, w, h, origin)); + } return true; } - public boolean load(ResourceLocation identifier) { + public boolean load(Identifier identifier) { - if (!images.containsKey(identifier.getPath())) { + String key = identifier.toString(); + if (!images.containsKey(key)) { ResourceManager resourceManager = Minecraft.getInstance().getResourceManager(); Resource resource; try { @@ -48,10 +55,7 @@ public boolean load(ResourceLocation identifier) { byte[] imageData = inputStream.readAllBytes(); Image image = Image.makeDeferredFromEncodedBytes(imageData); - if (image == null) { - return false; - } - images.put(identifier.getPath(), image); + images.put(key, image); return true; } catch (IOException e) { cn.pupperclient.PupperLogger.error("ImageHelper", "Failed to read identifier bytes", e); @@ -59,8 +63,6 @@ public boolean load(ResourceLocation identifier) { } catch (FileNotFoundException e) { cn.pupperclient.PupperLogger.error("ImageHelper", "Identifier resource not found", e); } - - } return true; } @@ -106,8 +108,9 @@ public Image get(String path) { public Image get(int texture) { - if (textures.containsKey(texture)) { - return textures.get(texture); + TextureEntry entry = textures.get(texture); + if (entry != null) { + return entry.image; } return null; @@ -116,7 +119,10 @@ public Image get(int texture) { public void clear() { images.values().forEach(Image::close); images.clear(); - textures.values().forEach(Image::close); + textures.values().forEach(entry -> entry.image.close()); textures.clear(); } + + private record TextureEntry(Image image, int width, int height, SurfaceOrigin origin) { + } } From d331a8a78ed6aabba919b818d7b98f1d84e7faa0 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 12:01:35 +0800 Subject: [PATCH 06/45] chore(skija): update skija version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 174002d..b608e78 100644 --- a/build.gradle +++ b/build.gradle @@ -51,7 +51,7 @@ dependencies { modJij 'com.github.ben-manes.caffeine:caffeine:3.1.8' modJij 'io.github.humbleui:types:0.2.0' - modJij 'io.github.humbleui:skija-windows-x64:0.119.3' + modJij 'io.github.humbleui:skija-windows-x64:0.143.12' modJij 'com.kohlschutter.junixsocket:junixsocket-common:2.10.1' modJij 'org.java-websocket:Java-WebSocket:1.6.0' From 6af3424fbfa719991f70840ce318f0aa9c4f35af Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 12:11:45 +0800 Subject: [PATCH 07/45] fix(utils): port Minecraft 26.1 * fix ChatUtils * add `@NonNull` in FileUtils * fix SkinUtils import --- .../cn/pupperclient/utils/chat/ChatUtils.java | 6 ++--- .../cn/pupperclient/utils/file/FileUtils.java | 26 ++++++++++--------- .../utils/minecraft/player/SkinUtils.java | 4 +-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java b/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java index f8de20f..c1dc04e 100644 --- a/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java +++ b/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java @@ -17,13 +17,11 @@ public class ChatUtils { public static void component(Component component) { Minecraft client = Minecraft.getInstance(); - if (client == null || client.level == null) return; + if (client.level == null) return; client.execute(() -> { ChatComponent chat = client.gui.getChat(); - if (chat != null) { - chat.addMessage(component); - } + chat.addClientSystemMessage(component); }); } diff --git a/src/main/java/cn/pupperclient/utils/file/FileUtils.java b/src/main/java/cn/pupperclient/utils/file/FileUtils.java index 85116f6..9dd0c4e 100644 --- a/src/main/java/cn/pupperclient/utils/file/FileUtils.java +++ b/src/main/java/cn/pupperclient/utils/file/FileUtils.java @@ -1,5 +1,7 @@ package cn.pupperclient.utils.file; +import org.jspecify.annotations.NonNull; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -20,19 +22,19 @@ public class FileUtils { public static void deleteDirectory(Path directory) throws IOException { if (!Files.exists(directory)) return; - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } + Files.walkFileTree(directory, new SimpleFileVisitor<>() { + @Override + public @NonNull FileVisitResult visitFile(@NonNull Path file, @NonNull BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - }); + @Override + public @NonNull FileVisitResult postVisitDirectory(@NonNull Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); } public static void zip(File source, File zipFile) throws IOException { diff --git a/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java b/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java index 7c4c652..a2f6ab1 100644 --- a/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java +++ b/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java @@ -2,12 +2,12 @@ import java.io.File; import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import cn.pupperclient.mixin.interfaces.IMixinMinecraftClient; public class SkinUtils { - public static File getSkin(ResourceLocation identifier) { + public static File getSkin(Identifier identifier) { String fileName = identifier.getPath().replace("skins/", ""); String folder = fileName.substring(0, 2); File file = new File(((IMixinMinecraftClient) Minecraft.getInstance()).getAssetDir(), From 3f342be520389938780ec93e9d7dce9ca33bc95c Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 12:12:25 +0800 Subject: [PATCH 08/45] fix(skia): update skija import and usage --- .../pupperclient/skia/context/SkiaContext.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java index 1774fbc..acc7eed 100644 --- a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java +++ b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java @@ -14,12 +14,12 @@ public class SkiaContext { private static DirectContext context = null; private static Surface surface; private static BackendRenderTarget renderTarget; - private static final GLBackendState[] states = { - GLBackendState.BLEND, - GLBackendState.VERTEX, - GLBackendState.PIXEL_STORE, - GLBackendState.TEXTURE_BINDING, - GLBackendState.MISC + private static final BackendState[] states = { + BackendState.GL_BLEND, + BackendState.GL_VERTEX, + BackendState.GL_PIXEL_STORE, + BackendState.GL_TEXTURE_BINDING, + BackendState.GL_MISC }; public static Canvas getCanvas() { @@ -47,7 +47,7 @@ public static void createSurface(int width, int height) { Objects.requireNonNull(context, "Context must not be null"), Objects.requireNonNull(renderTarget, "RenderTarget must not be null"), SurfaceOrigin.BOTTOM_LEFT, - SurfaceColorFormat.RGBA_8888, + ColorType.RGBA_8888, ColorSpace.getSRGB() ); } @@ -60,7 +60,7 @@ public static void draw(Consumer drawingLogic) { States.push(); GL11.glDisable(GL11.GL_CULL_FACE); GL11.glClearColor(0f, 0f, 0f, 0f); - context.resetGL(states); + context.reset(states); Canvas canvas = getCanvas(); drawingLogic.accept(canvas); From 56f7caf9e023123cb0cd277b6428e6b34a045d40 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 14:36:39 +0800 Subject: [PATCH 09/45] fix shader work progress... --- .../event/client/FramebufferSizeEvent.java | 25 ++ .../mixin/interfaces/IRenderPipeline.java | 11 + .../client/MixinMinecraftClient.java | 13 +- .../client/render/MixinGameRenderer.java | 28 +- .../client/render/RenderPipelineMixin.java | 26 ++ .../minecraft/client/util/MixinWindow.java | 14 +- .../shader/ExtendedRenderPipelineBuilder.java | 97 +++++ .../cn/pupperclient/shader/Framebuffer.java | 114 ------ .../cn/pupperclient/shader/MeshUniforms.java | 48 +++ .../shader/PostProcessRenderer.java | 184 --------- .../shader/PupperFullScreenRenderer.java | 37 ++ .../shader/PupperMeshBuilder.java | 175 +++++++++ .../shader/PupperMeshRenderer.java | 148 +++++++ .../shader/PupperRenderPipelines.java | 164 ++++++++ .../pupperclient/shader/PupperRenderer2D.java | 82 ++++ .../shader/PupperVertexFormatElements.java | 24 ++ .../shader/PupperVertexFormats.java | 29 ++ .../java/cn/pupperclient/shader/Shader.java | 136 ------- .../cn/pupperclient/shader/ShaderHelper.java | 202 ---------- .../cn/pupperclient/shader/ShapeMode.java | 20 + .../pupperclient/shader/impl/Kawaseblur.java | 200 ++++++---- .../shader/patch/FixedUniformStorage.java | 93 +++++ .../cn/pupperclient/utils/color/Color.java | 365 ++++++++++++++++++ .../cn/pupperclient/utils/misc/ICopyable.java | 12 + .../utils/misc/ISerializable.java | 13 + .../utils/render/RenderUtils.java | 28 ++ .../pupper/shaders/{blur.vert => blur.vsh} | 0 .../assets/pupper/shaders/blur_down.frag | 27 -- .../assets/pupper/shaders/blur_down.fsh | 24 ++ .../assets/pupper/shaders/blur_up.frag | 30 -- .../assets/pupper/shaders/blur_up.fsh | 27 ++ .../{passthrough.frag => passthrough.fsh} | 4 +- .../{passthrough.vert => passthrough.vsh} | 0 .../assets/pupper/shaders/pos_color.fsh | 9 + .../assets/pupper/shaders/pos_color.vsh | 17 + src/main/resources/pupper.mixins.json | 1 + 36 files changed, 1642 insertions(+), 785 deletions(-) create mode 100644 src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java create mode 100644 src/main/java/cn/pupperclient/mixin/interfaces/IRenderPipeline.java create mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/RenderPipelineMixin.java create mode 100644 src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java delete mode 100644 src/main/java/cn/pupperclient/shader/Framebuffer.java create mode 100644 src/main/java/cn/pupperclient/shader/MeshUniforms.java delete mode 100644 src/main/java/cn/pupperclient/shader/PostProcessRenderer.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperFullScreenRenderer.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperRenderer2D.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperVertexFormatElements.java create mode 100644 src/main/java/cn/pupperclient/shader/PupperVertexFormats.java delete mode 100644 src/main/java/cn/pupperclient/shader/Shader.java delete mode 100644 src/main/java/cn/pupperclient/shader/ShaderHelper.java create mode 100644 src/main/java/cn/pupperclient/shader/ShapeMode.java create mode 100644 src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java create mode 100644 src/main/java/cn/pupperclient/utils/color/Color.java create mode 100644 src/main/java/cn/pupperclient/utils/misc/ICopyable.java create mode 100644 src/main/java/cn/pupperclient/utils/misc/ISerializable.java create mode 100644 src/main/java/cn/pupperclient/utils/render/RenderUtils.java rename src/main/resources/assets/pupper/shaders/{blur.vert => blur.vsh} (100%) delete mode 100644 src/main/resources/assets/pupper/shaders/blur_down.frag create mode 100644 src/main/resources/assets/pupper/shaders/blur_down.fsh delete mode 100644 src/main/resources/assets/pupper/shaders/blur_up.frag create mode 100644 src/main/resources/assets/pupper/shaders/blur_up.fsh rename src/main/resources/assets/pupper/shaders/{passthrough.frag => passthrough.fsh} (57%) rename src/main/resources/assets/pupper/shaders/{passthrough.vert => passthrough.vsh} (100%) create mode 100644 src/main/resources/assets/pupper/shaders/pos_color.fsh create mode 100644 src/main/resources/assets/pupper/shaders/pos_color.vsh diff --git a/src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java b/src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java new file mode 100644 index 0000000..de91210 --- /dev/null +++ b/src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java @@ -0,0 +1,25 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.event.client; + +import cn.pupperclient.event.Event; + +public class FramebufferSizeEvent extends Event { + private final int width; + private final int height; + + public FramebufferSizeEvent(int width, int height) { + this.height = height; + this.width = width; + } + + public int getHeight() { + return height; + } + + public int getWidth() { + return width; + } +} diff --git a/src/main/java/cn/pupperclient/mixin/interfaces/IRenderPipeline.java b/src/main/java/cn/pupperclient/mixin/interfaces/IRenderPipeline.java new file mode 100644 index 0000000..2ee5120 --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/interfaces/IRenderPipeline.java @@ -0,0 +1,11 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.mixin.interfaces; + +public interface IRenderPipeline { + void pupper$setLineSmooth(boolean lineSmooth); + + boolean pupper$getLineSmooth(); +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index b527994..c70f222 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -2,6 +2,7 @@ import java.io.File; import java.io.IOException; + import net.minecraft.client.Minecraft; import net.minecraft.client.Options; import net.minecraft.client.gui.screens.Screen; @@ -18,9 +19,7 @@ import net.minecraft.world.phys.HitResult.Type; import cn.pupperclient.event.client.RenderSkiaEvent; import cn.pupperclient.gui.api.SimpleSoarGui; -import cn.pupperclient.shader.impl.Kawaseblur; import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -60,7 +59,8 @@ public abstract class MixinMinecraftClient implements IMixinMinecraftClient { @Shadow public ParticleEngine particleEngine; - @Shadow + @Final + @Shadow public Options options; @Shadow @@ -120,7 +120,6 @@ private void handleBlockBreaking(boolean breaking, CallbackInfo ci) { private void onHitDelayFix(CallbackInfoReturnable cir) { if (HitDelayFixMod.getInstance().isEnabled()) { missTime = 0; - RenderSystem.defaultBlendFunc(); } } @@ -173,12 +172,6 @@ private void onBeforeFlipFrame(CallbackInfo ci) { SkiaContext.draw(canvas -> EventBus.getInstance().post(new RenderSkiaEvent(canvas))); } - @Inject(method = "resizeDisplay", at = @At("TAIL")) - public void onResolutionChanged(CallbackInfo info) { - Kawaseblur.GUI_BLUR.resize(); - Kawaseblur.INGAME_BLUR.resize(); - } - @Override public File getAssetDir() { return this.assetDir; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java index 6a41769..7a4a316 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java @@ -2,7 +2,15 @@ import cn.pupperclient.management.mod.impl.render.NoHurtFov; import cn.pupperclient.shader.impl.Kawaseblur; +import cn.pupperclient.utils.render.RenderUtils; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.vertex.PoseStack; +import org.joml.Matrix4f; +import org.joml.Matrix4fStack; +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.callback.CallbackInfo; @@ -23,11 +31,18 @@ @Mixin(GameRenderer.class) public class MixinGameRenderer { - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.BEFORE)) + @Shadow + @Final + private Minecraft minecraft; + + @Unique + private final Matrix4fStack matrices = new Matrix4fStack(); + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.BEFORE)) public void render(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Kawaseblur.INGAME_BLUR.draw((int) HUDModSettings.getInstance().getBlurIntensitySetting().getValue()); + Kawaseblur.INGAME_BLUR.draw(minecraft., (int) HUDModSettings.getInstance().getBlurIntensitySetting().getValue()); } SkiaContext.draw((context) -> { @@ -42,7 +57,7 @@ public void render(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { public void renderGuiBlur(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Kawaseblur.GUI_BLUR.draw((int) ModMenuSettings.getInstance().getBlurIntensitySetting().getValue()); + Kawaseblur.GUI_BLUR.draw(, (int) ModMenuSettings.getInstance().getBlurIntensitySetting().getValue()); } } @@ -62,4 +77,11 @@ private void tiltViewWhenHurt(CallbackInfo ci) { } } + @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderItemInHand(Lnet/minecraft/client/renderer/state/level/CameraRenderState;FLorg/joml/Matrix4fc;)V")) + private void onRenderLevel(DeltaTracker deltaTracker, CallbackInfo ci, @Local(ordinal = 0) Matrix4f projection, @Local(ordinal = 0) Matrix4f position, @Local(ordinal = 0) float tickDelta, @Local PoseStack matrixStack) { + Matrix4f currentMatrix = new Matrix4f(matrixStack); + Matrix4f invertedMatrix = currentMatrix.invert(); + Matrix4f correctedPosition = MixinPlugin.isIrisPresent && RenderUtils.isShaderPackInUse() ? new Matrix4f(position).mul(invertedMatrix) : new Matrix4f(position); + RenderUtils.updateScreenCenter(projection, correctedPosition); + } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/RenderPipelineMixin.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/RenderPipelineMixin.java new file mode 100644 index 0000000..be24a7f --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/RenderPipelineMixin.java @@ -0,0 +1,26 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.mixin.mixins.minecraft.client.render; + +import cn.pupperclient.mixin.interfaces.IRenderPipeline; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(RenderPipeline.class) +public abstract class RenderPipelineMixin implements IRenderPipeline { + @Unique + private boolean lineSmooth; + + @Override + public void pupper$setLineSmooth(boolean lineSmooth) { + this.lineSmooth = lineSmooth; + } + + @Override + public boolean pupper$getLineSmooth() { + return lineSmooth; + } +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java index 40b4125..fc04ce1 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java @@ -1,7 +1,11 @@ package cn.pupperclient.mixin.mixins.minecraft.client.util; import cn.pupperclient.PupperClient; +import cn.pupperclient.event.EventBus; +import cn.pupperclient.event.client.FramebufferSizeEvent; +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.CallbackInfo; @@ -20,19 +24,19 @@ @Mixin(Window.class) public class MixinWindow { + @Shadow + @Final + private long handle; - @Inject(method = "onFramebufferResize", at = @At("RETURN")) + @Inject(method = "onFramebufferResize", at = @At("RETURN")) private void onFramebufferSizeChanged(long window, int width, int height, CallbackInfo ci) { SkiaContext.createSurface(width, height); + EventBus.getInstance().post(new FramebufferSizeEvent(width, height)); } @Inject(method = "", at = @At("RETURN")) private void onWindowInit(CallbackInfo ci) { try { - // 获取窗口句柄 - long handle = ((Window)(Object)this).getWindow(); - - // 从资源加载图标 try (InputStream is = getClass().getResourceAsStream("/assets/pupper/logo.png")) { if (is == null) { System.err.println("PupperClient icon not found!"); diff --git a/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java b/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java new file mode 100644 index 0000000..5635dc2 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java @@ -0,0 +1,97 @@ +package cn.pupperclient.shader; + +import cn.pupperclient.mixin.interfaces.IRenderPipeline; +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.ColorTargetState; +import com.mojang.blaze3d.pipeline.DepthStencilState; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.CompareOp; +import com.mojang.blaze3d.shaders.UniformType; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.resources.Identifier; + +public class ExtendedRenderPipelineBuilder { + private final RenderPipeline.Builder builder; + private boolean lineSmooth; + private CompareOp depthTest; + private Boolean writeDepth; + private BlendFunction blendFunction; + + public ExtendedRenderPipelineBuilder(RenderPipeline.Snippet... snippets) { + builder = RenderPipeline.builder(snippets); + } + + public ExtendedRenderPipelineBuilder withLocation(Identifier location) { + builder.withLocation(location); + return this; + } + + public ExtendedRenderPipelineBuilder withVertexFormat(VertexFormat format, VertexFormat.Mode mode) { + builder.withVertexFormat(format, mode); + return this; + } + + public ExtendedRenderPipelineBuilder withVertexShader(Identifier shader) { + builder.withVertexShader(shader); + return this; + } + + public ExtendedRenderPipelineBuilder withFragmentShader(Identifier shader) { + builder.withFragmentShader(shader); + return this; + } + + public ExtendedRenderPipelineBuilder withSampler(String sampler) { + builder.withSampler(sampler); + return this; + } + + public ExtendedRenderPipelineBuilder withUniform(String uniform, UniformType type) { + builder.withUniform(uniform, type); + return this; + } + + public ExtendedRenderPipelineBuilder withCull(boolean cull) { + builder.withCull(cull); + return this; + } + + public ExtendedRenderPipelineBuilder withDepthTestFunction(CompareOp depthTest) { + this.depthTest = depthTest; + return this; + } + + public ExtendedRenderPipelineBuilder withDepthWrite(boolean writeDepth) { + this.writeDepth = writeDepth; + return this; + } + + public ExtendedRenderPipelineBuilder withBlend(BlendFunction blendFunction) { + this.blendFunction = blendFunction; + return this; + } + + public ExtendedRenderPipelineBuilder withLineSmooth() { + lineSmooth = true; + return this; + } + + public RenderPipeline build() { + if (depthTest != null || writeDepth != null) { + builder.withDepthStencilState(new DepthStencilState( + depthTest != null ? depthTest : DepthStencilState.DEFAULT.depthTest(), + writeDepth != null ? writeDepth : DepthStencilState.DEFAULT.writeDepth() + )); + } + + if (blendFunction != null) { + builder.withColorTargetState(new ColorTargetState(blendFunction)); + } + + RenderPipeline pipeline = builder.build(); + ((IRenderPipeline) pipeline).pupper$setLineSmooth(lineSmooth); + + return pipeline; + } +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/Framebuffer.java b/src/main/java/cn/pupperclient/shader/Framebuffer.java deleted file mode 100644 index fc0d613..0000000 --- a/src/main/java/cn/pupperclient/shader/Framebuffer.java +++ /dev/null @@ -1,114 +0,0 @@ -package cn.pupperclient.shader; - -import static org.lwjgl.opengl.GL11C.*; -import static org.lwjgl.opengl.GL12C.GL_CLAMP_TO_EDGE; -import static org.lwjgl.opengl.GL30C.GL_COLOR_ATTACHMENT0; -import static org.lwjgl.opengl.GL30C.GL_FRAMEBUFFER; -import static org.lwjgl.opengl.GL30C.glGenerateMipmap; - -import java.nio.ByteBuffer; -import net.minecraft.client.Minecraft; -import org.lwjgl.opengl.GL30C; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; - -public class Framebuffer { - - private int id; - public int texture; - public double sizeMulti = 1; - public int width, height; - private boolean mipmapEnabled = false; - - public Framebuffer(double sizeMulti) { - this.sizeMulti = sizeMulti; - init(); - } - - public Framebuffer() { - init(); - } - - private void init() { - Window window = Minecraft.getInstance().getWindow(); - - id = GlStateManager.glGenFramebuffers(); - bind(); - - texture = GlStateManager._genTexture(); - ShaderHelper.bindTexture(texture); - ShaderHelper.defaultPixelStore(); - - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - width = Math.max(1, (int) (window.getWidth() * sizeMulti)); - height = Math.max(1, (int) (window.getHeight() * sizeMulti)); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null); - GlStateManager._glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); - - unbind(); - } - - public void enableMipmap() { - if (sizeMulti < 1.0) { - mipmapEnabled = true; - bind(); - ShaderHelper.bindTexture(texture); - - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - RenderSystem.texParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - unbind(); - } - } - - public void generateMipmap() { - if (mipmapEnabled && sizeMulti < 1.0) { - bind(); - ShaderHelper.bindTexture(texture); - ShaderHelper.generateMipmap(GL_TEXTURE_2D); - unbind(); - } - } - - public void bind() { - GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, id); - } - - public void setViewport() { - RenderSystem.viewport(0, 0, width, height); - } - - public void unbind() { - Minecraft.getInstance().getMainRenderTarget().bindWrite(false); - } - - public void delete() { - if (id != 0) { - GlStateManager._glDeleteFramebuffers(id); - id = 0; - } - if (texture != 0) { - GlStateManager._deleteTexture(texture); - texture = 0; - } - } - - public void resize() { - delete(); - init(); - if (mipmapEnabled) { - enableMipmap(); - } - } -} diff --git a/src/main/java/cn/pupperclient/shader/MeshUniforms.java b/src/main/java/cn/pupperclient/shader/MeshUniforms.java new file mode 100644 index 0000000..e161331 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/MeshUniforms.java @@ -0,0 +1,48 @@ +package cn.pupperclient.shader; + +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.buffers.Std140Builder; +import com.mojang.blaze3d.buffers.Std140SizeCalculator; +import net.minecraft.client.renderer.DynamicUniformStorage; +import org.joml.Matrix4f; + +import java.nio.ByteBuffer; + +public class MeshUniforms { + public static final int SIZE = new Std140SizeCalculator() + .putMat4f() + .putMat4f() + .get(); + + private static final Data DATA = new Data(); + + private static final DynamicUniformStorage STORAGE = new DynamicUniformStorage<>("Meteor - Mesh UBO", SIZE, 16); + + public static void flipFrame() { + STORAGE.endFrame(); + } + + public static GpuBufferSlice write(Matrix4f proj, Matrix4f modelView) { + DATA.proj = proj; + DATA.modelView = modelView; + + return STORAGE.writeUniform(DATA); + } + + private static final class Data implements DynamicUniformStorage.DynamicUniform { + private Matrix4f proj; + private Matrix4f modelView; + + @Override + public void write(ByteBuffer buffer) { + Std140Builder.intoBuffer(buffer) + .putMat4f(proj) + .putMat4f(modelView); + } + + @Override + public boolean equals(Object o) { + return false; + } + } +} diff --git a/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java b/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java deleted file mode 100644 index 0dfc110..0000000 --- a/src/main/java/cn/pupperclient/shader/PostProcessRenderer.java +++ /dev/null @@ -1,184 +0,0 @@ -package cn.pupperclient.shader; - -import static org.lwjgl.opengl.GL11C.GL_FLOAT; -import static org.lwjgl.opengl.GL11C.GL_UNSIGNED_INT; -import static org.lwjgl.opengl.GL15C.GL_ARRAY_BUFFER; -import static org.lwjgl.opengl.GL15C.GL_DYNAMIC_DRAW; -import static org.lwjgl.opengl.GL15C.GL_ELEMENT_ARRAY_BUFFER; -import static org.lwjgl.system.MemoryUtil.memAddress0; -import static org.lwjgl.system.MemoryUtil.memPutFloat; -import static org.lwjgl.system.MemoryUtil.memPutInt; - -import java.nio.ByteBuffer; - -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL15C; -import org.lwjgl.opengl.GL32C; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; - -public class PostProcessRenderer { - - private static final Mesh mesh = new Mesh(); - private static final PoseStack matrices = new PoseStack(); - - static { - mesh.begin(); - mesh.quad(mesh.vec2(-1, -1).next(), mesh.vec2(-1, 1).next(), mesh.vec2(1, 1).next(), mesh.vec2(1, -1).next()); - mesh.end(); - } - - public static void beginRender() { - mesh.beginRender(matrices); - } - - public static void render() { - mesh.render(matrices); - } - - public static void endRender() { - mesh.endRender(); - } - - private static class Mesh { - - private final int vao, vbo, ibo; - - private final ByteBuffer vertices; - private final long verticesPointerStart; - private long verticesPointer; - - private final ByteBuffer indices; - private final long indicesPointer; - - private int vertexI, indicesCount; - - private boolean building; - private boolean beganRendering; - - public Mesh() { - int drawMode = 3; - int stride = 8; - - int primitiveVerticesSize = stride * drawMode; - - vertices = BufferUtils.createByteBuffer(primitiveVerticesSize * 256 * 4); - verticesPointerStart = memAddress0(vertices); - - indices = BufferUtils.createByteBuffer(drawMode * 512 * 4); - indicesPointer = memAddress0(indices); - - vao = GlStateManager._glGenVertexArrays(); - GlStateManager._glBindVertexArray(vao); - - vbo = GlStateManager._glGenBuffers(); - GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, vbo); - - ibo = GlStateManager._glGenBuffers(); - GlStateManager._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - - GlStateManager._enableVertexAttribArray(0); - GlStateManager._vertexAttribPointer(0, 2, GL_FLOAT, false, stride, 0); - - GlStateManager._glBindVertexArray(0); - GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, 0); - GlStateManager._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - public void begin() { - - if (building) { - return; - } - - verticesPointer = verticesPointerStart; - vertexI = 0; - indicesCount = 0; - - building = true; - } - - public Mesh vec2(double x, double y) { - long p = verticesPointer; - - memPutFloat(p, (float) x); - memPutFloat(p + 4, (float) y); - - verticesPointer += 8; - return this; - } - - public int next() { - return vertexI++; - } - - public void quad(int i1, int i2, int i3, int i4) { - long p = indicesPointer + indicesCount * 4L; - - memPutInt(p, i1); - memPutInt(p + 4, i2); - memPutInt(p + 8, i3); - - memPutInt(p + 12, i3); - memPutInt(p + 16, i4); - memPutInt(p + 20, i1); - - indicesCount += 6; - } - - public void end() { - - if (!building) { - return; - } - - if (indicesCount > 0) { - GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, vbo); - GlStateManager._glBufferData(GL_ARRAY_BUFFER, vertices.limit(getVerticesOffset()), GL_DYNAMIC_DRAW); - GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, 0); - - GlStateManager._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - GlStateManager._glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.limit(indicesCount * 4), GL_DYNAMIC_DRAW); - GlStateManager._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - building = false; - } - - public void beginRender(PoseStack matrices) { - RenderSystem.disableCull(); - beganRendering = true; - } - - public void render(PoseStack matrices) { - if (building) - end(); - - if (indicesCount > 0) { - boolean wasBeganRendering = beganRendering; - if (!wasBeganRendering) - beginRender(matrices); - - Shader.BOUND.setDefaults(); - - GlStateManager._glBindVertexArray(vao); - RenderSystem.drawElements(GL32C.GL_TRIANGLES, indicesCount, GL_UNSIGNED_INT); - - GlStateManager._glBindVertexArray(0); - - if (!wasBeganRendering) - endRender(); - } - } - - public void endRender() { - beganRendering = false; - } - - private int getVerticesOffset() { - return (int) (verticesPointer - verticesPointerStart); - } - } -} diff --git a/src/main/java/cn/pupperclient/shader/PupperFullScreenRenderer.java b/src/main/java/cn/pupperclient/shader/PupperFullScreenRenderer.java new file mode 100644 index 0000000..b3a59a7 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperFullScreenRenderer.java @@ -0,0 +1,37 @@ +package cn.pupperclient.shader; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.vertex.VertexFormat; + +public class PupperFullScreenRenderer { + public static GpuBuffer vbo; + public static GpuBuffer ibo; + + /** + * Deprecated for performance reasons, use {@link PupperMeshRenderer#fullscreen()} or the {@link PupperFullScreenRenderer#vbo} + * and {@link PupperFullScreenRenderer#ibo} buffer objects instead. + */ + @Deprecated(forRemoval = true) + public static PupperMeshBuilder mesh; + + private PupperFullScreenRenderer() {} + + static { + mesh = new PupperMeshBuilder(PupperVertexFormats.POS2, VertexFormat.Mode.TRIANGLES); + + mesh.begin(); + + mesh.quad( + mesh.vec2(-1, -1).next(), + mesh.vec2(-1, 1).next(), + mesh.vec2(1, 1).next(), + mesh.vec2(1, -1).next() + ); + + mesh.end(); + + vbo = mesh.getVertexBuffer(); + ibo = mesh.getIndexBuffer(); + } +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java b/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java new file mode 100644 index 0000000..3bc122f --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java @@ -0,0 +1,175 @@ +package cn.pupperclient.shader; + +import cn.pupperclient.utils.color.Color; +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.fabricmc.loader.api.FabricLoader; +import org.lwjgl.BufferUtils; + +import java.nio.ByteBuffer; + +import static org.lwjgl.system.MemoryUtil.*; + +public class PupperMeshBuilder { + private static final boolean DEBUG = FabricLoader.getInstance().isDevelopmentEnvironment(); + + public double alpha = 1; + + private final VertexFormat format; + private final int primitiveVerticesSize; + private final int primitiveIndicesCount; + + private ByteBuffer vertices = null; + private long verticesPointerStart, verticesPointer; + + private ByteBuffer indices = null; + private long indicesPointer; + + private int vertexI, indicesCount; + + private boolean building; + private double cameraX, cameraZ; + + public PupperMeshBuilder(RenderPipeline pipeline) { + this(pipeline.getVertexFormat(), pipeline.getVertexFormatMode()); + } + + public PupperMeshBuilder(VertexFormat format, VertexFormat.Mode mode) { + this.format = format; + primitiveVerticesSize = format.getVertexSize(); + primitiveIndicesCount = mode.connectedPrimitives ? mode.primitiveStride : mode.primitiveLength; + } + + public void begin() { + if (building) throw new IllegalStateException("Mesh.begin() called while already building."); + + verticesPointer = verticesPointerStart; + vertexI = 0; + indicesCount = 0; + + building = true; + + cameraX = 0; + cameraZ = 0; + } + + public PupperMeshBuilder vec3(double x, double y, double z) { + debugVertexBufferCapacity(); + + long p = verticesPointer; + + memPutFloat(p, (float) (x - cameraX)); + memPutFloat(p + 4, (float) y); + memPutFloat(p + 8, (float) (z - cameraZ)); + + verticesPointer += 12; + return this; + } + + public PupperMeshBuilder vec2(double x, double y) { + debugVertexBufferCapacity(); + + long p = verticesPointer; + + memPutFloat(p, (float) x); + memPutFloat(p + 4, (float) y); + + verticesPointer += 8; + return this; + } + + public PupperMeshBuilder color(Color c) { + debugVertexBufferCapacity(); + + long p = verticesPointer; + + memPutByte(p, (byte) c.r); + memPutByte(p + 1, (byte) c.g); + memPutByte(p + 2, (byte) c.b); + memPutByte(p + 3, (byte) (c.a * (float) alpha)); + + verticesPointer += 4; + return this; + } + + public int next() { + return vertexI++; + } + + public void line(int i1, int i2) { + growIfNeeded(); + memPutInt(indicesPointer, i1); + memPutInt(indicesPointer + 4, i2); + indicesPointer += 8; + indicesCount += 2; + } + + public void quad(int i1, int i2, int i3, int i4) { + growIfNeeded(); + memPutInt(indicesPointer, i1); + memPutInt(indicesPointer + 4, i2); + memPutInt(indicesPointer + 8, i3); + memPutInt(indicesPointer + 12, i1); + memPutInt(indicesPointer + 16, i3); + memPutInt(indicesPointer + 20, i4); + indicesPointer += 24; + indicesCount += 6; + } + + public void growIfNeeded() { + if (getVerticesOffset() + primitiveVerticesSize >= vertices.capacity()) { + int newSize = vertices.capacity() * 2; + int offset = getVerticesOffset(); + ByteBuffer newVertices = BufferUtils.createByteBuffer(newSize); + memCopy(verticesPointerStart, memAddress0(newVertices), offset); + vertices = newVertices; + verticesPointerStart = memAddress0(vertices); + verticesPointer = verticesPointerStart + offset; + } + + if ((indicesCount + primitiveIndicesCount) * 4 >= indices.capacity()) { + int newSize = indices.capacity() * 2; + ByteBuffer newIndices = BufferUtils.createByteBuffer(newSize); + memCopy(memAddress0(indices), memAddress0(newIndices), indicesCount * 4L); + indices = newIndices; + indicesPointer = memAddress0(indices); + } + } + + public void end() { + building = false; + } + + public GpuBuffer getVertexBuffer() { + vertices.limit(getVerticesOffset()); + return format.uploadImmediateVertexBuffer(vertices); + } + + public GpuBuffer getIndexBuffer() { + indices.limit(indicesCount * 4); + return format.uploadImmediateIndexBuffer(indices); + } + + public PupperMeshBuilder tex2(float u, float v) { + memPutFloat(verticesPointer, u); + memPutFloat(verticesPointer + 4, v); + verticesPointer += 8; + return this; + } + + public int getIndicesCount() { return indicesCount; } + private int getVerticesOffset() { return (int) (verticesPointer - verticesPointerStart); } + + private void debugVertexBufferCapacity() { + if (DEBUG && (vertices == null || vertexI * primitiveVerticesSize >= vertices.capacity())) { + throw new IndexOutOfBoundsException("Vertices written to MeshBuilder without calling 'ensureCapacity()' first!"); + } + } + + private void debugIndexBufferCapacity() { + if (DEBUG && (indices == null || indicesCount * Integer.BYTES >= indices.capacity())) { + throw new IndexOutOfBoundsException("Indices written to MeshBuilder without calling 'ensureCapacity()' first!"); + } + } +} diff --git a/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java b/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java new file mode 100644 index 0000000..58fee8b --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java @@ -0,0 +1,148 @@ +package cn.pupperclient.shader; + +import cn.pupperclient.utils.color.Color; +import com.ibm.icu.impl.Pair; +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.systems.RenderPass; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.util.ARGB; +import net.minecraft.util.Tuple; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; + +import java.util.HashMap; +import java.util.OptionalDouble; +import java.util.OptionalInt; + +public class PupperMeshRenderer { + private static final PupperMeshRenderer INSTANCE = new PupperMeshRenderer(); + + private static boolean taken; + + private GpuTextureView colorAttachment; + private GpuTextureView depthAttachment; + private Color clearColor; + private RenderPipeline pipeline; + private @Nullable PupperMeshBuilder mesh; + private @Nullable GpuBuffer vertexBuffer; + private @Nullable GpuBuffer indexBuffer; + private Matrix4f matrix; + private final HashMap uniforms = new HashMap<>(); + private final HashMap> samplers = new HashMap<>(); + + PupperMeshRenderer() {} + + public static PupperMeshRenderer begin() { + if (taken) throw new IllegalStateException("MeshRenderer already taken."); + taken = true; + + return INSTANCE; + } + + public PupperMeshRenderer attachments(GpuTextureView color, GpuTextureView depth) { + colorAttachment = color; + depthAttachment = depth; + return this; + } + + public PupperMeshRenderer pipeline(RenderPipeline pipeline) { + this.pipeline = pipeline; + return this; + } + + public PupperMeshRenderer mesh(PupperMeshBuilder mesh) { + this.mesh = mesh; + return this; + } + + public PupperMeshRenderer mesh(PupperMeshBuilder mesh, Matrix4f matrix) { + this.mesh = mesh; + return this.transform(matrix); + } + + public PupperMeshRenderer mesh(PupperMeshBuilder mesh, PoseStack matrices) { + this.mesh = mesh; + return this.transform(matrices); + } + + public PupperMeshRenderer mesh(GpuBuffer vertices, GpuBuffer indices) { + this.vertexBuffer = vertices; + this.indexBuffer = indices; + return this; + } + + public PupperMeshRenderer transform(Matrix4f matrix) { + this.matrix = matrix; + return this; + } + + public PupperMeshRenderer transform(PoseStack matrices) { + this.matrix = matrices.last().pose(); + return this; + } + + public PupperMeshRenderer fullscreen() { + return this.mesh(PupperFullScreenRenderer.vbo, PupperFullScreenRenderer.ibo); + } + + public PupperMeshRenderer uniform(String name, GpuBufferSlice slice) { + uniforms.put(name, slice); + return this; + } + + public PupperMeshRenderer sampler(String name, GpuTextureView view, GpuSampler sampler) { + if (name != null && view != null && sampler != null) { + samplers.put(name, new Tuple<>(view, sampler)); + } + + return this; + } + + public void end() { + int indexCount = mesh != null ? mesh.getIndicesCount() + : (int) (indexBuffer != null ? indexBuffer.size() / Integer.BYTES : -1); + + if (pipeline != null && mesh != null && indexCount > 0) { + GpuBuffer vertexBuffer = mesh.getVertexBuffer(); + GpuBuffer indexBuffer = mesh != null ? mesh.getIndexBuffer() : this.indexBuffer; + + if (vertexBuffer != null && indexBuffer != null) { + GpuBufferSlice meshData = MeshUniforms.write(RenderUtils.projection, RenderSystem.getModelViewStack()); + + OptionalInt clearColor = this.clearColor != null ? + OptionalInt.of(ARGB.color(this.clearColor.a, this.clearColor.r, this.clearColor.g, this.clearColor.b)) : + OptionalInt.empty(); + + RenderPass pass = (depthAttachment != null && pipeline.wantsDepthTexture()) ? + RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Meteor MeshRenderer", colorAttachment, clearColor, depthAttachment, OptionalDouble.empty()) : + RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Meteor MeshRenderer", colorAttachment, clearColor); + + pass.setPipeline(pipeline); + + pass.setUniform("MeshData", meshData); + + pass.setVertexBuffer(0, vertexBuffer); + pass.setIndexBuffer(indexBuffer, VertexFormat.IndexType.INT); + pass.drawIndexed(0, 0, indexCount, 1); + + pass.close(); + } + } + + colorAttachment = null; + depthAttachment = null; + clearColor = null; + pipeline = null; + mesh = null; + matrix = null; + + taken = false; + } +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java b/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java new file mode 100644 index 0000000..26884e6 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java @@ -0,0 +1,164 @@ +package cn.pupperclient.shader; + +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.shaders.UniformType; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.viaversion.viaversion.libs.mcstructs.core.Identifier; +import net.minecraft.client.Minecraft; +import net.minecraft.server.packs.resources.ResourceManager; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public abstract class PupperRenderPipelines { + private static final List PIPELINES = new ArrayList<>(); + + private static final RenderPipeline.Snippet MESH_UNIFORMS = RenderPipeline.builder() + .withUniform("MeshData", UniformType.UNIFORM_BUFFER) + .buildSnippet(); + + public static final RenderPipeline BLUR_DOWN = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(getLocation("pipeline/blur_down")) + .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.Mode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "blur").get()) + .withFragmentShader(Identifier.of("pupper", "blur_down").get()) + .withSampler("Sampler0") + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + public static final RenderPipeline BLUR_UP = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(Identifier.of("pupper", "pipeline/blur_up")) + .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.DrawMode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "blur")) + .withFragmentShader(Identifier.of("pupper", "blur_up")) + .withSampler("Sampler0") + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + public static final RenderPipeline PASSTHROUGH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(Identifier.of("pupper", "pipeline/passthrough")) + .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.DrawMode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "passthrough")) + .withFragmentShader(Identifier.of("pupper", "passthrough")) + .withSampler("Sampler0") + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + public static final RenderPipeline UI_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(Identifier.of("pupper", "pipeline/ui_colored")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.DrawMode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "ui_colored")) + .withFragmentShader(Identifier.of("pupper", "ui_colored")) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + public static final RenderPipeline UI_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLineSmooth() + .withLocation(Identifier.of("pupper", "pipeline/ui_colored_lines")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.DrawMode.LINES) + .withVertexShader(Identifier.of("pupper", "ui_colored")) + .withFragmentShader(Identifier.of("pupper", "ui_colored")) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + public static final RenderPipeline WORLD_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(Identifier.of("pupper", "pipeline/world_colored")) + .withVertexFormat(PupperVertexFormats.POS3_COLOR, VertexFormat.DrawMode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "pos_color.vsh")) // Uses pos_color.vsh.vsh + .withFragmentShader(Identifier.of("pupper", "pos_color.vsh")) // Uses pos_color.vsh.fsh + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) // 3D needs depth testing + .withDepthWrite(false) // Usually false for ESP/Overlays to avoid glitching + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + // 3D Wireframe (Lines) + public static final RenderPipeline WORLD_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLineSmooth() + .withLocation(Identifier.of("pupper", "pipeline/world_colored_lines")) + .withVertexFormat(PupperVertexFormats.POS3_COLOR, VertexFormat.DrawMode.LINES) + .withVertexShader(Identifier.of("pupper", "pos_color.vsh")) + .withFragmentShader(Identifier.of("pupper", "pos_color.vsh")) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .build() + ); + + public static final RenderPipeline UI_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(Identifier.of("pupper", "pipeline/ui_textured")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.DrawMode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "ui_textured")) + .withFragmentShader(Identifier.of("pupper", "ui_textured")) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .build() + ); + + public static final RenderPipeline UI_ROUNDED_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(Identifier.of("pupper", "pipeline/ui_rounded_textured")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.DrawMode.TRIANGLES) + .withVertexShader(Identifier.of("pupper", "ui_textured")) + .withFragmentShader(Identifier.of("pupper", "ui_rounded_textured")) // 指向新的 SDF Shader + .withBlend(BlendFunction.TRANSLUCENT) + .build() + ); + + private static RenderPipeline add(RenderPipeline pipeline) { + PIPELINES.add(pipeline); + return pipeline; + } + + private PupperRenderPipelines() {} + + public static void precompile() { + GpuDevice device = RenderSystem.getDevice(); + ResourceManager resources = Minecraft.getInstance().getResourceManager(); + + for (RenderPipeline pipeline : PIPELINES) { + device.precompilePipeline(pipeline, (identifier, shaderType) -> { + var resource = resources.getResource(identifier).get(); + + try (var in = resource.open()) { + return IOUtils.toString(in, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + } + + private static Identifier getLocation(String path) { + return Identifier.of("pupper", path); + } +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java b/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java new file mode 100644 index 0000000..db9eed5 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java @@ -0,0 +1,82 @@ +package cn.pupperclient.shader; + +import com.mojang.blaze3d.systems.RenderPass; +import net.minecraft.client.MinecraftClient; + +import java.util.function.Consumer; + +public class PupperRenderer2D { + public static PupperRenderer2D COLOR; + + public final PupperMeshBuilder triangles; + public final PupperMeshBuilder lines; + public final PupperMeshBuilder texturedMesh; + + public PupperRenderer2D() { + triangles = new PupperMeshBuilder(PupperRenderPipelines.UI_COLORED); + lines = new PupperMeshBuilder(PupperRenderPipelines.UI_COLORED_LINES); + texturedMesh = new PupperMeshBuilder(PupperRenderPipelines.UI_TEXTURED); + } + + public static void init() { + COLOR = new PupperRenderer2D(); + } + + public void setAlpha(double alpha) { + triangles.alpha = alpha; + lines.alpha = alpha; + } + + public void begin() { + triangles.begin(); + lines.begin(); + } + + public void end() { + triangles.end(); + lines.end(); + + render(null); + } + + public void render(Consumer setupCallback) { + if (triangles.getIndicesCount() > 0) { + PupperMeshRenderer.begin() + .attachments(MinecraftClient.getInstance().getFramebuffer()) + .pipeline(PupperRenderPipelines.UI_COLORED) + .mesh(triangles) + .setupCallback(setupCallback) + .end(); + } + + if (lines.getIndicesCount() > 0) { + PupperMeshRenderer.begin() + .attachments(MinecraftClient.getInstance().getFramebuffer()) + .pipeline(PupperRenderPipelines.UI_COLORED_LINES) + .mesh(lines) + .setupCallback(setupCallback) + .end(); + } + } + + public void quad(double x, double y, double width, double height, int color) { + int i1 = triangles.vec2(x, y).color(color).next(); + int i2 = triangles.vec2(x, y + height).color(color).next(); + int i3 = triangles.vec2(x + width, y + height).color(color).next(); + int i4 = triangles.vec2(x + width, y).color(color).next(); + + triangles.quad(i1, i2, i3, i4); + } + + public void line(double x1, double y1, double x2, double y2, int color) { + lines.line( + lines.vec2(x1, y1).color(color).next(), + lines.vec2(x2, y2).color(color).next() + ); + } + + public PupperMeshBuilder getTexturedMesh() { + return texturedMesh; + } +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/PupperVertexFormatElements.java b/src/main/java/cn/pupperclient/shader/PupperVertexFormatElements.java new file mode 100644 index 0000000..223d77a --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperVertexFormatElements.java @@ -0,0 +1,24 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package cn.pupperclient.shader; + +import com.mojang.blaze3d.vertex.VertexFormatElement; + +public abstract class PupperVertexFormatElements { + public static final VertexFormatElement POS2 = VertexFormatElement.register(getNextVertexFormatElementId(), 0, VertexFormatElement.Type.FLOAT, false, 2); + + private PupperVertexFormatElements() {} + + private static int getNextVertexFormatElementId() { + int id = 0; + while (VertexFormatElement.byId(id) != null) { + id++; + if (id >= 32) throw new RuntimeException("Too many mods registering VertexFormatElements"); + } + return id; + } +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java b/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java new file mode 100644 index 0000000..923477b --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java @@ -0,0 +1,29 @@ +package cn.pupperclient.shader; + +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; + +public abstract class PupperVertexFormats { + public static final VertexFormat POS2 = VertexFormat.builder() + .add("Position", PupperVertexFormatElements.POS2) + .build(); + + public static final VertexFormat POS2_COLOR = VertexFormat.builder() + .add("Position", PupperVertexFormatElements.POS2) + .add("Color", VertexFormatElement.COLOR) + .build(); + + public static final VertexFormat POS3_COLOR = VertexFormat.builder() + .add("Position", VertexFormatElement.POSITION) + .add("Color", VertexFormatElement.COLOR) + .build(); + + public static final VertexFormat POS2_COLOR_TEX = VertexFormat.builder() + .add("Position", VertexFormatElement.POSITION) + .add("Color", VertexFormatElement.COLOR) + .add("UV0", VertexFormatElement.UV0) + .build(); + + private PupperVertexFormats() {} +} +// based on meteor diff --git a/src/main/java/cn/pupperclient/shader/Shader.java b/src/main/java/cn/pupperclient/shader/Shader.java deleted file mode 100644 index ab16728..0000000 --- a/src/main/java/cn/pupperclient/shader/Shader.java +++ /dev/null @@ -1,136 +0,0 @@ -package cn.pupperclient.shader; - -import static org.lwjgl.opengl.GL11C.GL_FALSE; -import static org.lwjgl.opengl.GL11C.GL_TRUE; -import static org.lwjgl.opengl.GL20C.GL_FRAGMENT_SHADER; -import static org.lwjgl.opengl.GL20C.GL_VERTEX_SHADER; -import static org.lwjgl.opengl.GL20C.glDeleteProgram; - -import java.io.IOException; -import java.nio.FloatBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; -import org.apache.commons.io.IOUtils; -import org.joml.Matrix4f; -import org.lwjgl.BufferUtils; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; - -public class Shader { - - public static Shader BOUND; - private final int id; - private final Map locations = new HashMap<>(); - - private static final FloatBuffer MAT = BufferUtils.createFloatBuffer(16); - - public Shader(String vertPath, String fragPath) { - int vertex = GlStateManager.glCreateShader(GL_VERTEX_SHADER); - int fragment = GlStateManager.glCreateShader(GL_FRAGMENT_SHADER); - - GlStateManager.glShaderSource(vertex, read(vertPath)); - GlStateManager.glShaderSource(fragment, read(fragPath)); - - String vertexLog = ShaderHelper.compileShader(vertex); - String fragmentLog = ShaderHelper.compileShader(fragment); - - if (vertexLog != null || fragmentLog != null) { - System.err.println("Vertex Log (" + vertPath + "): " + vertexLog); - System.err.println("Fragment Log (" + fragPath + "): " + fragmentLog); - } - - this.id = GlStateManager.glCreateProgram(); - String programLog = ShaderHelper.linkProgram(id, vertex, fragment); - - if (programLog != null) { - System.err.println("Program Log (" + vertPath + ", " + fragPath + "): " + programLog); - } - - GlStateManager.glDeleteShader(vertex); - GlStateManager.glDeleteShader(fragment); - } - - public void set(String name, double v) { - set(name, (float) v); - } - - public void set(String name, double v1, double v2) { - set(name, (float) v1, (float) v2); - } - - private String read(String path) { - try { - return IOUtils.toString( - Minecraft.getInstance().getResourceManager() - .getResource(ResourceLocation.fromNamespaceAndPath("pupper", "shaders/" + path)).get().open(), - StandardCharsets.UTF_8); - } catch (IOException e) { - throw new IllegalStateException("Could not read shader '" + path + "'", e); - } - } - - public void bind() { - ShaderHelper.useProgram(id); - BOUND = this; - } - - public int getLocation(String name) { - if (locations.containsKey(name)) { - return locations.get(name); - } - - int location = ShaderHelper.getUniformLocation(id, name); - locations.put(name, location); - - return location; - } - - public void set(String name, int v) { - ShaderHelper.uniformInt(getLocation(name), v); - } - - public void set(String name, float v) { - ShaderHelper.uniformFloat(getLocation(name), v); - } - - public void set(String name, float v1, float v2) { - ShaderHelper.uniformFloat2(getLocation(name), v1, v2); - } - - public void set(String name, float v1, float v2, float v3) { - ShaderHelper.uniformFloat3(getLocation(name), v1, v2, v3); - } - - public void set(String name, float v1, float v2, float v3, float v4) { - ShaderHelper.uniformFloat4(getLocation(name), v1, v2, v3, v4); - } - - public void set(String name, float[] v) { - ShaderHelper.uniformFloat3Array(getLocation(name), v); - } - - public void set(String name, Matrix4f mat) { - mat.get(MAT); - ShaderHelper.uniformMatrix4(getLocation(name), false, MAT); - } - - public void setDefaults() { - set("u_Proj", RenderSystem.getProjectionMatrix()); - // Modern approach: use RenderSystem matrices directly or pass from context - } - - public void unbind() { - ShaderHelper.useProgram(0); - BOUND = null; - } - - public void delete() { - org.lwjgl.opengl.GL20C.glDeleteProgram(id); - } -} diff --git a/src/main/java/cn/pupperclient/shader/ShaderHelper.java b/src/main/java/cn/pupperclient/shader/ShaderHelper.java deleted file mode 100644 index d7241b6..0000000 --- a/src/main/java/cn/pupperclient/shader/ShaderHelper.java +++ /dev/null @@ -1,202 +0,0 @@ -package cn.pupperclient.shader; - -import static org.lwjgl.opengl.GL11C.GL_FALSE; -import static org.lwjgl.opengl.GL11C.GL_LINE_SMOOTH; -import static org.lwjgl.opengl.GL11C.GL_ONE_MINUS_SRC_ALPHA; -import static org.lwjgl.opengl.GL11C.GL_SRC_ALPHA; -import static org.lwjgl.opengl.GL11C.GL_UNPACK_ALIGNMENT; -import static org.lwjgl.opengl.GL11C.GL_UNPACK_LSB_FIRST; -import static org.lwjgl.opengl.GL11C.GL_UNPACK_ROW_LENGTH; -import static org.lwjgl.opengl.GL11C.GL_UNPACK_SKIP_PIXELS; -import static org.lwjgl.opengl.GL11C.GL_UNPACK_SKIP_ROWS; -import static org.lwjgl.opengl.GL11C.GL_UNPACK_SWAP_BYTES; -import static org.lwjgl.opengl.GL11C.glDisable; -import static org.lwjgl.opengl.GL11C.glEnable; -import static org.lwjgl.opengl.GL11C.glLineWidth; -import static org.lwjgl.opengl.GL11C.glTexImage2D; -import static org.lwjgl.opengl.GL12C.GL_UNPACK_IMAGE_HEIGHT; -import static org.lwjgl.opengl.GL12C.GL_UNPACK_SKIP_IMAGES; -import static org.lwjgl.opengl.GL13C.GL_TEXTURE0; -import static org.lwjgl.opengl.GL15C.GL_ELEMENT_ARRAY_BUFFER; -import static org.lwjgl.opengl.GL20C.*; -import static org.lwjgl.opengl.GL30C.*; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.resources.ResourceLocation; -import com.mojang.blaze3d.platform.GlStateManager; -import cn.pupperclient.mixin.mixins.minecraft.client.render.BufferRendererAccessor; - -import com.mojang.blaze3d.systems.RenderSystem; - -public class ShaderHelper { - public static int CURRENT_IBO; - private static int prevIbo; - - private ShaderHelper() {} - - public static void bindVertexArray(int vao) { - GlStateManager._glBindVertexArray(vao); - BufferRendererAccessor.setCurrentVertexBuffer(null); - } - - public static void bindIndexBuffer(int ibo) { - if (ibo != 0) - prevIbo = CURRENT_IBO; - GlStateManager._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo != 0 ? ibo : prevIbo); - } - - public static String compileShader(int shader) { - GlStateManager.glCompileShader(shader); - - if (GlStateManager.glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE) { - return GlStateManager.glGetShaderInfoLog(shader, 512); - } - - return null; - } - - public static String linkProgram(int program, int vertShader, int fragShader) { - GlStateManager.glAttachShader(program, vertShader); - GlStateManager.glAttachShader(program, fragShader); - GlStateManager.glLinkProgram(program); - - if (GlStateManager.glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) { - return GlStateManager.glGetProgramInfoLog(program, 512); - } - - return null; - } - - public static void useProgram(int program) { - RenderSystem.setShaderGameTime(System.currentTimeMillis(), 0); - GlStateManager._glUseProgram(program); - } - - public static void viewport(int x, int y, int width, int height) { - RenderSystem.viewport(x, y, width, height); - } - - public static int getUniformLocation(int program, String name) { - return GlStateManager._glGetUniformLocation(program, name); - } - - public static void uniformInt(int location, int v) { - // No direct RenderSystem wrapper for uniform1i by location, use GlStateManager if available or native - // GlStateManager doesn't have uniform1i usually, RenderSystem has it for ShaderInstance but not raw programs - // For raw programs, we might need native or a helper. - // Actually, GlStateManager often has _glUniform1i but let's check. - // If not, we stay with native for uniforms if no wrapper exists. - org.lwjgl.opengl.GL20C.glUniform1i(location, v); - } - - public static void uniformFloat(int location, float v) { - org.lwjgl.opengl.GL20C.glUniform1f(location, v); - } - - public static void uniformFloat2(int location, float v1, float v2) { - org.lwjgl.opengl.GL20C.glUniform2f(location, v1, v2); - } - - public static void uniformFloat3(int location, float v1, float v2, float v3) { - org.lwjgl.opengl.GL20C.glUniform3f(location, v1, v2, v3); - } - - public static void uniformFloat4(int location, float v1, float v2, float v3, float v4) { - org.lwjgl.opengl.GL20C.glUniform4f(location, v1, v2, v3, v4); - } - - public static void uniformFloat3Array(int location, float[] v) { - org.lwjgl.opengl.GL20C.glUniform3fv(location, v); - } - - public static void uniformMatrix4(int location, boolean transpose, FloatBuffer matrices) { - org.lwjgl.opengl.GL20C.glUniformMatrix4fv(location, transpose, matrices); - } - - public static void pixelStore(int name, int param) { - RenderSystem.pixelStore(name, param); - } - - public static void textureParam(int target, int name, int param) { - RenderSystem.texParameter(target, name, param); - } - - public static void textureImage2D(int target, int level, int internalFormat, int width, int height, int border, - int format, int type, ByteBuffer pixels) { - glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels); - } - - public static void defaultPixelStore() { - pixelStore(GL_UNPACK_SWAP_BYTES, GL_FALSE); - pixelStore(GL_UNPACK_LSB_FIRST, GL_FALSE); - pixelStore(GL_UNPACK_ROW_LENGTH, 0); - pixelStore(GL_UNPACK_IMAGE_HEIGHT, 0); - pixelStore(GL_UNPACK_SKIP_ROWS, 0); - pixelStore(GL_UNPACK_SKIP_PIXELS, 0); - pixelStore(GL_UNPACK_SKIP_IMAGES, 0); - pixelStore(GL_UNPACK_ALIGNMENT, 4); - } - - public static void framebufferTexture2D(int target, int attachment, int textureTarget, int texture, int level) { - GlStateManager._glFramebufferTexture2D(target, attachment, textureTarget, texture, level); - } - - public static void enableDepth() { - RenderSystem.enableDepthTest(); - } - - public static void disableDepth() { - RenderSystem.disableDepthTest(); - } - - public static void enableBlend() { - RenderSystem.enableBlend(); - RenderSystem.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - public static void disableBlend() { - RenderSystem.disableBlend(); - } - - public static void enableCull() { - RenderSystem.enableCull(); - } - - public static void disableCull() { - RenderSystem.disableCull(); - } - - public static void enableLineSmooth() { - glEnable(GL_LINE_SMOOTH); - glLineWidth(1); - } - - public static void disableLineSmooth() { - glDisable(GL_LINE_SMOOTH); - } - - public static void bindTexture(ResourceLocation id) { - AbstractTexture texture = Minecraft.getInstance().getTextureManager().getTexture(id); - bindTexture(texture.getId(), 0); - } - - public static void bindTexture(int i, int slot) { - RenderSystem.activeTexture(GL_TEXTURE0 + slot); - RenderSystem.bindTexture(i); - } - - public static void bindTexture(int i) { - bindTexture(i, 0); - } - - public static void resetTextureSlot() { - RenderSystem.activeTexture(GL_TEXTURE0); - } - - public static void generateMipmap(int target) { - glGenerateMipmap(target); - } -} diff --git a/src/main/java/cn/pupperclient/shader/ShapeMode.java b/src/main/java/cn/pupperclient/shader/ShapeMode.java new file mode 100644 index 0000000..f188c01 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/ShapeMode.java @@ -0,0 +1,20 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package cn.pupperclient.shader; + +public enum ShapeMode { + Lines, + Sides, + Both; + + public boolean lines() { + return this == Lines || this == Both; + } + + public boolean sides() { + return this == Sides ||this == Both; + } +} diff --git a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java index 0d5450d..c3217d4 100644 --- a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java +++ b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java @@ -1,104 +1,160 @@ package cn.pupperclient.shader.impl; -import cn.pupperclient.management.mod.impl.settings.SystemSettings; +import cn.pupperclient.event.EventBus; +import cn.pupperclient.event.EventListener; +import cn.pupperclient.event.client.FramebufferSizeEvent; import cn.pupperclient.shader.*; - -import cn.pupperclient.utils.time.TimerUtils; -import it.unimi.dsi.fastutil.ints.IntDoubleImmutablePair; +import cn.pupperclient.shader.patch.FixedUniformStorage; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.buffers.Std140Builder; +import com.mojang.blaze3d.buffers.Std140SizeCalculator; +import com.mojang.blaze3d.opengl.GlStateManager; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.FilterMode; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.textures.TextureFormat; +import it.unimi.dsi.fastutil.ints.IntFloatImmutablePair; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.DynamicUniformStorage; +import org.jspecify.annotations.NonNull; -public class Kawaseblur { +import java.nio.ByteBuffer; +public class Kawaseblur { public static final Kawaseblur GUI_BLUR = new Kawaseblur(); public static final Kawaseblur INGAME_BLUR = new Kawaseblur(); + private final Minecraft mc = Minecraft.getInstance(); + + private final IntFloatImmutablePair[] strengths = new IntFloatImmutablePair[]{ + IntFloatImmutablePair.of(1, 1.25f), // LVL 1 + IntFloatImmutablePair.of(1, 2.25f), // LVL 2 + IntFloatImmutablePair.of(2, 2.0f), // LVL 3 + IntFloatImmutablePair.of(2, 3.0f), // LVL 4 + IntFloatImmutablePair.of(2, 4.25f), // LVL 5 + IntFloatImmutablePair.of(3, 2.5f), // LVL 6 + IntFloatImmutablePair.of(3, 3.25f), // LVL 7 + IntFloatImmutablePair.of(3, 4.25f), // LVL 8 + IntFloatImmutablePair.of(3, 5.5f), // LVL 9 + IntFloatImmutablePair.of(4, 3.25f), // LVL 10 + IntFloatImmutablePair.of(4, 4.0f), // LVL 11 + IntFloatImmutablePair.of(4, 5.0f), // LVL 12 + IntFloatImmutablePair.of(4, 6.0f), // LVL 13 + IntFloatImmutablePair.of(4, 7.25f), // LVL 14 + IntFloatImmutablePair.of(4, 8.25f), // LVL 15 + IntFloatImmutablePair.of(5, 4.5f), // LVL 16 + IntFloatImmutablePair.of(5, 5.25f), // LVL 17 + IntFloatImmutablePair.of(5, 6.25f), // LVL 18 + IntFloatImmutablePair.of(5, 7.25f), // LVL 19 + IntFloatImmutablePair.of(5, 8.5f) // LVL 20 + }; + + private final GpuTextureView[] fbos = new GpuTextureView[6]; + private GpuBufferSlice[] ubos; + + private boolean enabled; + private long fadeEndAt; + private float previousOffset = -1; + + private Kawaseblur() { + EventBus.getInstance().register(this); - private static final IntDoubleImmutablePair[] STRENGTHS = new IntDoubleImmutablePair[] { - IntDoubleImmutablePair.of(1, 1.25), IntDoubleImmutablePair.of(1, 2.25), IntDoubleImmutablePair.of(2, 2.0), - IntDoubleImmutablePair.of(2, 3.0), IntDoubleImmutablePair.of(2, 4.25), IntDoubleImmutablePair.of(3, 2.5), - IntDoubleImmutablePair.of(3, 3.25), IntDoubleImmutablePair.of(3, 4.25), IntDoubleImmutablePair.of(3, 5.5), - IntDoubleImmutablePair.of(4, 3.25), IntDoubleImmutablePair.of(4, 4.0), IntDoubleImmutablePair.of(4, 5.0), - IntDoubleImmutablePair.of(4, 6.0), IntDoubleImmutablePair.of(4, 7.25), IntDoubleImmutablePair.of(4, 8.25), - IntDoubleImmutablePair.of(5, 4.5), IntDoubleImmutablePair.of(5, 5.25), IntDoubleImmutablePair.of(5, 6.25), - IntDoubleImmutablePair.of(5, 7.25), IntDoubleImmutablePair.of(5, 8.5) }; - - private static Shader shaderDown, shaderUp, shaderPassthrough; - private final Framebuffer[] fbos = new Framebuffer[6]; - private final TimerUtils timer = new TimerUtils(); - private boolean firstTick = true; - - public void resize() { for (int i = 0; i < fbos.length; i++) { - if (fbos[i] != null) { - fbos[i].resize(); - } else { - fbos[i] = new Framebuffer(1 / Math.pow(2, i)); - } + fbos[i] = createFbo(i); } } - public void draw(int radius) { + public void draw(CommandEncoder encoder, int iterations) { + if (iterations <= 0) return; + GpuTextureView mainFbo = mc.getFramebuffer(); + + renderPass(encoder, fbos[0], mainFbo.getColorAttachment(), PupperRenderPipelines.PASSTHROUGH, 0); - if (shaderDown == null) { - shaderDown = new Shader("blur.vert", "blur_down.frag"); - shaderUp = new Shader("blur.vert", "blur_up.frag"); - shaderPassthrough = new Shader("passthrough.vert", "passthrough.frag"); + for (int i = 0; i < iterations; i++) { + renderPass(encoder, fbos[Math.min(i + 1, 4)], fbos[i].getColorAttachment(), PupperRenderPipelines.BLUR_DOWN, i); } - if (firstTick) { - for (int i = 0; i < fbos.length; i++) { - if (fbos[i] == null) { - fbos[i] = new Framebuffer(1 / Math.pow(2, i)); - } - } - firstTick = false; + for (int i = iterations; i > 0; i--) { + renderPass(encoder, fbos[i - 1], fbos[i].getColorAttachment(), PupperRenderPipelines.BLUR_UP, i); } - SystemSettings setting = SystemSettings.getInstance(); + renderPass(encoder, mainFbo, fbos[0].getColorAttachment(), PupperRenderPipelines.PASSTHROUGH, 0); + } - if(setting.isFastBlur()) { - if (timer.delay(16)) { - timer.reset(); - } else { - return; - } - } + private void renderToFbo(GpuTextureView targetFbo, GpuTextureView sourceTexture, RenderPipeline pipeline, GpuBufferSlice ubo) { + PupperMeshRenderer.begin() + .attachments(targetFbo, null) + .pipeline(pipeline) + .fullscreen() + .uniform("BlurData", ubo) + .sampler("u_Texture", sourceTexture, RenderSystem.getSamplerCache().getClampToEdge(FilterMode.LINEAR)) + .end(); + } + + public GpuTextureView[] getFbos() { + return fbos; + } - IntDoubleImmutablePair strength = STRENGTHS[(int) ((radius - 1))]; - int iterations = strength.leftInt(); - double offset = strength.rightDouble(); + private GpuTextureView createFbo(int i, int baseWidth, int baseHeight) { + double scale = 1 / Math.pow(2, i); + int width = (int) (baseWidth * scale); + int height = (int) (baseHeight * scale); - PostProcessRenderer.beginRender(); + width = Math.max(width, 1); + height = Math.max(height, 1); - renderToFbo(fbos[0], Minecraft.getInstance().getMainRenderTarget().getColorTextureId(), shaderDown, - offset); + return RenderSystem.getDevice().createTextureView(RenderSystem.getDevice().createTexture("Blur - " + i, 15, TextureFormat.RGBA8, width, height, 1, 1)); + } - for (int i = 0; i < iterations; i++) { - renderToFbo(fbos[i + 1], fbos[i].texture, shaderDown, offset); + private void rebuildFbos(int w, int h) { + for (int i = 0; i < fbos.length; i++) { + if (fbos[i] != null) { + fbos[i].close(); + } + fbos[i] = createFbo(i, w, h); } + previousOffset = -1; + } - for (int i = iterations; i >= 1; i--) { - renderToFbo(fbos[i - 1], fbos[i].texture, shaderUp, offset); - } + @EventListener + private void onFramebufferSize(FramebufferSizeEvent event) { + int newWidth = event.getWidth(); + int newHeight = event.getHeight(); - Minecraft.getInstance().getMainRenderTarget().bindWrite(true); - shaderPassthrough.bind(); - ShaderHelper.bindTexture(fbos[0].texture); - shaderPassthrough.set("uTexture", 0); - PostProcessRenderer.endRender(); + rebuildFbos(newWidth, newHeight); } - public int getTexture() { - return fbos[0].texture; + // Uniforms + private void updateUniforms(float offset) { + UNIFORM_STORAGE.clear(); + + BlurUniformData[] uboData = new BlurUniformData[6]; + for (int i = 0; i < uboData.length; i++) { + GpuTextureView fbo = fbos[i]; + uboData[i] = new BlurUniformData( + 0.5f / fbo.getWidth(0), 0.5f / fbo.getHeight(0), + offset + ); + } + + ubos = UNIFORM_STORAGE.writeAll(uboData); } - private void renderToFbo(Framebuffer targetFbo, int sourceText, Shader shader, double offset) { - targetFbo.bind(); - targetFbo.setViewport(); - shader.bind(); - ShaderHelper.bindTexture(sourceText); - shader.set("uTexture", 0); - shader.set("uHalfTexelSize", .5 / targetFbo.width, .5 / targetFbo.height); - shader.set("uOffset", offset); - PostProcessRenderer.render(); + private static final int UNIFORM_SIZE = new Std140SizeCalculator() + .putVec2() + .putFloat() + .get(); + + private static final FixedUniformStorage UNIFORM_STORAGE = new FixedUniformStorage<>("Meteor - Blur UBO", UNIFORM_SIZE, 6); + + private record BlurUniformData(float halfTexelSizeX, float halfTexelSizeY, float offset) implements DynamicUniformStorage.DynamicUniform { + @Override + public void write(@NonNull ByteBuffer buffer) { + Std140Builder.intoBuffer(buffer) + .putVec2(halfTexelSizeX, halfTexelSizeY) + .putFloat(offset); + } } } diff --git a/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java b/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java new file mode 100644 index 0000000..3d229c2 --- /dev/null +++ b/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java @@ -0,0 +1,93 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package cn.pupperclient.shader.patch; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.renderer.DynamicUniformStorage; +import net.minecraft.client.renderer.MappableRingBuffer; +import net.minecraft.util.Mth; + +import java.nio.ByteBuffer; + +/** + * UBO storage with a constant size. Exceeding this size causes an {@link IndexOutOfBoundsException} to be thrown. + * + * @author Crosby + * @see DynamicUniformStorage + */ +public class FixedUniformStorage { + private final MappableRingBuffer buffer; + private final int blockSize; + private final int capacity; + private int size; + + public FixedUniformStorage(String name, int blockSize, int capacity) { + GpuDevice gpuDevice = RenderSystem.getDevice(); + this.blockSize = Mth.roundToward(blockSize, gpuDevice.getUniformOffsetAlignment()); + this.capacity = capacity; + int alignedCapacity = Mth.smallestEncompassingPowerOfTwo(capacity); + this.size = 0; + this.buffer = new MappableRingBuffer(() -> name + " x" + this.blockSize, 130, this.blockSize * alignedCapacity); + } + + public GpuBufferSlice write(T value) { + if (this.size >= this.capacity) { + throw new IndexOutOfBoundsException(String.format("Index %s out of bounds for length %s", this.size, this.capacity)); + } else { + int i = this.size * this.blockSize; + GpuBufferSlice slice = this.buffer.currentBuffer().slice(i, this.blockSize); + + try (GpuBuffer.MappedView mappedView = RenderSystem.getDevice() + .createCommandEncoder() + .mapBuffer(slice, false, true)) { + value.write(mappedView.data()); + } + + this.size++; + return slice; + } + } + + public GpuBufferSlice[] writeAll(T[] values) { + if (values.length == 0) { + return new GpuBufferSlice[0]; + } else if (this.size + values.length > this.capacity) { + throw new IndexOutOfBoundsException(String.format("Index %s out of bounds for length %s", this.size + values.length - 1, this.capacity)); + } else { + int i = this.size * this.blockSize; + GpuBufferSlice[] gpuBufferSlices = new GpuBufferSlice[values.length]; + GpuBuffer ubo = this.buffer.currentBuffer(); + + try (GpuBuffer.MappedView mappedView = RenderSystem.getDevice() + .createCommandEncoder() + .mapBuffer(ubo.slice(i, values.length * this.blockSize), false, true)) { + ByteBuffer byteBuffer = mappedView.data(); + + for (int j = 0; j < values.length; j++) { + T uploadable = values[j]; + gpuBufferSlices[j] = ubo.slice(i + j * this.blockSize, this.blockSize); + byteBuffer.position(j * this.blockSize); + uploadable.write(byteBuffer); + } + } + + this.size += values.length; + return gpuBufferSlices; + } + } + + public void clear() { + this.size = 0; + this.buffer.rotate(); + } + + public void close() { + this.buffer.close(); + } +} diff --git a/src/main/java/cn/pupperclient/utils/color/Color.java b/src/main/java/cn/pupperclient/utils/color/Color.java new file mode 100644 index 0000000..4748339 --- /dev/null +++ b/src/main/java/cn/pupperclient/utils/color/Color.java @@ -0,0 +1,365 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package cn.pupperclient.utils.color; + +import cn.pupperclient.utils.misc.ICopyable; +import cn.pupperclient.utils.misc.ISerializable; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; +import org.joml.Vector4f; + +@SuppressWarnings("unused") +public class Color implements ICopyable, ISerializable { + public static final Color CLEAR = new Color(0, 0, 0, 0); + public static final Color WHITE = new Color(java.awt.Color.WHITE); + public static final Color LIGHT_GRAY = new Color(java.awt.Color.LIGHT_GRAY); + public static final Color GRAY = new Color(java.awt.Color.GRAY); + public static final Color DARK_GRAY = new Color(java.awt.Color.DARK_GRAY); + public static final Color BLACK = new Color(java.awt.Color.BLACK); + public static final Color RED = new Color(java.awt.Color.RED); + public static final Color PINK = new Color(java.awt.Color.PINK); + public static final Color ORANGE = new Color(java.awt.Color.ORANGE); + public static final Color YELLOW = new Color(java.awt.Color.YELLOW); + public static final Color GREEN = new Color(java.awt.Color.GREEN); + public static final Color MAGENTA = new Color(java.awt.Color.MAGENTA); + public static final Color CYAN = new Color(java.awt.Color.CYAN); + public static final Color BLUE = new Color(java.awt.Color.BLUE); + + public int r, g, b, a; + + public Color() { + this(255, 255, 255, 255); + } + + public Color(int r, int g, int b) { + this.r = r; + this.g = g; + this.b = b; + this.a = 255; + + validate(); + } + + public Color(int r, int g, int b, int a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + + validate(); + } + + public Color(float r, float g, float b, float a) { + this.r = (int)(r*255); + this.g = (int)(g*255); + this.b = (int)(b*255); + this.a = (int)(a*255); + + validate(); + } + + public Color(int packed) { + this.r = toRGBAR(packed); + this.g = toRGBAG(packed); + this.b = toRGBAB(packed); + this.a = toRGBAA(packed); + } + + public Color(Color color) { + this.r = color.r; + this.g = color.g; + this.b = color.b; + this.a = color.a; + } + + public Color(java.awt.Color color) { + this.r = color.getRed(); + this.g = color.getGreen(); + this.b = color.getBlue(); + this.a = color.getAlpha(); + } + + public Color(@NotNull ChatFormatting formatting) { + if (formatting.isColor()) { + this.r = toRGBAR(formatting.getColor()); + this.g = toRGBAG(formatting.getColor()); + this.b = toRGBAB(formatting.getColor()); + this.a = toRGBAA(formatting.getColor()); + } else { + this.r = 255; + this.g = 255; + this.b = 255; + this.a = 255; + } + } + + public Color(TextColor textColor) { + this.r = toRGBAR(textColor.getValue()); + this.g = toRGBAG(textColor.getValue()); + this.b = toRGBAB(textColor.getValue()); + this.a = toRGBAA(textColor.getValue()); + } + + public Color(Style style) { + TextColor textColor = style.getColor(); + if (textColor == null) { + this.r = 255; + this.g = 255; + this.b = 255; + this.a = 255; + } else { + this.r = toRGBAR(textColor.getValue()); + this.g = toRGBAG(textColor.getValue()); + this.b = toRGBAB(textColor.getValue()); + this.a = toRGBAA(textColor.getValue()); + } + } + + public static int fromRGBA(int r, int g, int b, int a) { + return (r << 16) + (g << 8) + (b) + (a << 24); + } + + public static int toRGBAR(int color) { + return (color >> 16) & 0x000000FF; + } + + public static int toRGBAG(int color) { + return (color >> 8) & 0x000000FF; + } + + public static int toRGBAB(int color) { + return (color) & 0x000000FF; + } + + public static int toRGBAA(int color) { + return (color >> 24) & 0x000000FF; + } + + public static Color fromHsv(double h, double s, double v) { + double hh, p, q, t, ff; + int i; + double r, g, b; + + if (s <= 0.0) { // < is bogus, just shuts up warnings + r = v; + g = v; + b = v; + return new Color((int) (r * 255), (int) (g * 255), (int) (b * 255), 255); + } + hh = h; + if (hh >= 360.0) hh = 0.0; + hh /= 60.0; + i = (int) hh; + ff = hh - i; + p = v * (1.0 - s); + q = v * (1.0 - (s * ff)); + t = v * (1.0 - (s * (1.0 - ff))); + + switch (i) { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + case 5: + default: + r = v; + g = p; + b = q; + break; + } + return new Color((int) (r * 255), (int) (g * 255), (int) (b * 255), 255); + } + + public Color set(int r, int g, int b, int a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + + validate(); + + return this; + } + + public Color r(int r) { + this.r = r; + validate(); + return this; + } + + public Color g(int g) { + this.g = g; + validate(); + return this; + } + + public Color b(int b) { + this.b = b; + validate(); + return this; + } + + public Color a(int a) { + this.a = a; + validate(); + return this; + } + + @Override + public Color set(Color value) { + r = value.r; + g = value.g; + b = value.b; + a = value.a; + + validate(); + + return this; + } + + public boolean parse(String text) { + String[] split = text.split(","); + if (split.length != 3 && split.length != 4) return false; + + try { + // Not assigned directly because of exception handling + int r = Integer.parseInt(split[0]); + int g = Integer.parseInt(split[1]); + int b = Integer.parseInt(split[2]); + int a = split.length == 4 ? Integer.parseInt(split[3]) : this.a; + + this.r = r; + this.g = g; + this.b = b; + this.a = a; + + return true; + } catch (NumberFormatException ignored) { + return false; + } + } + + @Override + public Color copy() { + return new Color(r, g, b, a); + } + + public TextColor toTextColor() { + return TextColor.fromRgb(getPacked()); + } + + public Style toStyle() { + return Style.EMPTY.withColor(toTextColor()); + } + + public Style styleWith(Style style) { + return style.withColor(toTextColor()); + } + + public void validate() { + if (r < 0) r = 0; + else if (r > 255) r = 255; + + if (g < 0) g = 0; + else if (g > 255) g = 255; + + if (b < 0) b = 0; + else if (b > 255) b = 255; + + if (a < 0) a = 0; + else if (a > 255) a = 255; + } + + public Vec3 getVec3() { + return new Vec3(r / 255.0, g / 255.0, b / 255.0); + } + + public Vector3f getVec3f() { + return new Vector3f(r / 255.0f, g / 255.0f, b / 255.0f); + } + + public Vector4f getVec4f() { + return new Vector4f(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); + } + + public int getPacked() { + return fromRGBA(r, g, b, a); + } + + @Override + public CompoundTag toTag() { + CompoundTag tag = new CompoundTag(); + + tag.putInt("r", r); + tag.putInt("g", g); + tag.putInt("b", b); + tag.putInt("a", a); + + return tag; + } + + @Override + public Color fromTag(CompoundTag tag) { + r = tag.getInt("r").orElse(0); + g = tag.getInt("g").orElse(0); + b = tag.getInt("b").orElse(0); + a = tag.getInt("a").orElse(0); + + validate(); + return this; + } + + @Override + public String toString() { + return r + " " + g + " " + b + " " + a; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Color color = (Color) o; + + return r == color.r && g == color.g && b == color.b && a == color.a; + } + + @Override + public int hashCode() { + int result = r; + result = 31 * result + g; + result = 31 * result + b; + result = 31 * result + a; + return result; + } +} diff --git a/src/main/java/cn/pupperclient/utils/misc/ICopyable.java b/src/main/java/cn/pupperclient/utils/misc/ICopyable.java new file mode 100644 index 0000000..1cc5d03 --- /dev/null +++ b/src/main/java/cn/pupperclient/utils/misc/ICopyable.java @@ -0,0 +1,12 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package cn.pupperclient.utils.misc; + +public interface ICopyable> { + T set(T value); + + T copy(); +} diff --git a/src/main/java/cn/pupperclient/utils/misc/ISerializable.java b/src/main/java/cn/pupperclient/utils/misc/ISerializable.java new file mode 100644 index 0000000..f3fc79c --- /dev/null +++ b/src/main/java/cn/pupperclient/utils/misc/ISerializable.java @@ -0,0 +1,13 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.utils.misc; + +import net.minecraft.nbt.CompoundTag; + +public interface ISerializable { + CompoundTag toTag(); + + T fromTag(CompoundTag tag); +} diff --git a/src/main/java/cn/pupperclient/utils/render/RenderUtils.java b/src/main/java/cn/pupperclient/utils/render/RenderUtils.java new file mode 100644 index 0000000..a032138 --- /dev/null +++ b/src/main/java/cn/pupperclient/utils/render/RenderUtils.java @@ -0,0 +1,28 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.utils.render; + +import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; +import org.joml.Vector4f; + +public class RenderUtils implements IMinecraft { + public static Vec3 center; + public static final Matrix4f projection = new Matrix4f(); + + public static void updateScreenCenter(Matrix4f projection, Matrix4f view) { + RenderUtils.projection.set(projection); + + Matrix4f invProjection = new Matrix4f(projection).invert(); + Matrix4f invView = new Matrix4f(view).invert(); + + Vector4f center4 = new Vector4f(0, 0, 0, 1).mul(invProjection).mul(invView); + center4.div(center4.w); + + Vec3 camera = client.gameRenderer.getMainCamera().position(); + center = new Vec3(camera.x + center4.x, camera.y + center4.y, camera.z + center4.z); + } +} diff --git a/src/main/resources/assets/pupper/shaders/blur.vert b/src/main/resources/assets/pupper/shaders/blur.vsh similarity index 100% rename from src/main/resources/assets/pupper/shaders/blur.vert rename to src/main/resources/assets/pupper/shaders/blur.vsh diff --git a/src/main/resources/assets/pupper/shaders/blur_down.frag b/src/main/resources/assets/pupper/shaders/blur_down.frag deleted file mode 100644 index 7f49298..0000000 --- a/src/main/resources/assets/pupper/shaders/blur_down.frag +++ /dev/null @@ -1,27 +0,0 @@ -#version 330 core - -precision lowp float; - -in vec2 uv; -out vec4 color; - -uniform sampler2D uTexture; -uniform vec2 uHalfTexelSize; -uniform float uOffset; - -vec4 safeTexture2D(sampler2D tex, vec2 uv) { - uv = clamp(uv, 0.001, 0.999); // 防止在边缘采样 - return texture(tex, uv); -} - -void main() { - color = ( - texture(uTexture, uv) * 4 + - texture(uTexture, uv - uHalfTexelSize.xy * uOffset) + - texture(uTexture, uv + uHalfTexelSize.xy * uOffset) + - texture(uTexture, uv + vec2(uHalfTexelSize.x, -uHalfTexelSize.y) * uOffset) + - texture(uTexture, uv - vec2(uHalfTexelSize.x, -uHalfTexelSize.y) * uOffset) - ) / 8; - color.a = 1; -} - diff --git a/src/main/resources/assets/pupper/shaders/blur_down.fsh b/src/main/resources/assets/pupper/shaders/blur_down.fsh new file mode 100644 index 0000000..1b1fcbe --- /dev/null +++ b/src/main/resources/assets/pupper/shaders/blur_down.fsh @@ -0,0 +1,24 @@ +#version 330 core + +precision lowp float; + +in vec2 uv; +out vec4 color; + +uniform sampler2D u_Texture; + +layout (std140) uniform BlurData { + vec2 u_HalfTexelSize; + float u_Offset; +}; + +void main() { + color = ( + texture(u_Texture, uv) * 4 + + texture(u_Texture, uv - u_HalfTexelSize * u_Offset) + + texture(u_Texture, uv + u_HalfTexelSize * u_Offset) + + texture(u_Texture, uv + vec2(u_HalfTexelSize.x, -u_HalfTexelSize.y) * u_Offset) + + texture(u_Texture, uv - vec2(u_HalfTexelSize.x, -u_HalfTexelSize.y) * u_Offset) + ) / 8; + color.a = 1; +} diff --git a/src/main/resources/assets/pupper/shaders/blur_up.frag b/src/main/resources/assets/pupper/shaders/blur_up.frag deleted file mode 100644 index dfd8931..0000000 --- a/src/main/resources/assets/pupper/shaders/blur_up.frag +++ /dev/null @@ -1,30 +0,0 @@ -#version 330 core - -precision lowp float; - -in vec2 uv; -out vec4 color; - -uniform sampler2D uTexture; -uniform vec2 uHalfTexelSize; -uniform float uOffset; - -vec4 safeTexture2D(sampler2D tex, vec2 uv) { - uv = clamp(uv, 0.001, 0.999); // 防止在边缘采样 - return texture(tex, uv); -} - -void main() { - color = ( - texture(uTexture, uv + vec2(- uHalfTexelSize.x * 2, 0) * uOffset) + - texture(uTexture, uv + vec2(- uHalfTexelSize.x, uHalfTexelSize.y) * uOffset) * 2 + - texture(uTexture, uv + vec2(0, uHalfTexelSize.y * 2) * uOffset) + - texture(uTexture, uv + uHalfTexelSize * uOffset) * 2 + - texture(uTexture, uv + vec2(uHalfTexelSize.x * 2, 0) * uOffset) + - texture(uTexture, uv + vec2(uHalfTexelSize.x, -uHalfTexelSize.y) * uOffset) * 2 + - texture(uTexture, uv + vec2(0, -uHalfTexelSize.y * 2) * uOffset) + - texture(uTexture, uv - uHalfTexelSize * uOffset) * 2 - ) / 12; - color.a = 1; -} - diff --git a/src/main/resources/assets/pupper/shaders/blur_up.fsh b/src/main/resources/assets/pupper/shaders/blur_up.fsh new file mode 100644 index 0000000..45a133c --- /dev/null +++ b/src/main/resources/assets/pupper/shaders/blur_up.fsh @@ -0,0 +1,27 @@ +#version 330 core + +precision lowp float; + +in vec2 uv; +out vec4 color; + +uniform sampler2D u_Texture; + +layout (std140) uniform BlurData { + vec2 u_HalfTexelSize; + float u_Offset; +}; + +void main() { + color = ( + texture(u_Texture, uv + vec2(- u_HalfTexelSize.x * 2, 0) * u_Offset) + + texture(u_Texture, uv + vec2(- u_HalfTexelSize.x, u_HalfTexelSize.y) * u_Offset) * 2 + + texture(u_Texture, uv + vec2(0, u_HalfTexelSize.y * 2) * u_Offset) + + texture(u_Texture, uv + u_HalfTexelSize * u_Offset) * 2 + + texture(u_Texture, uv + vec2(u_HalfTexelSize.x * 2, 0) * u_Offset) + + texture(u_Texture, uv + vec2(u_HalfTexelSize.x, -u_HalfTexelSize.y) * u_Offset) * 2 + + texture(u_Texture, uv + vec2(0, -u_HalfTexelSize.y * 2) * u_Offset) + + texture(u_Texture, uv - u_HalfTexelSize * u_Offset) * 2 + ) / 12; + color.a = 1; +} diff --git a/src/main/resources/assets/pupper/shaders/passthrough.frag b/src/main/resources/assets/pupper/shaders/passthrough.fsh similarity index 57% rename from src/main/resources/assets/pupper/shaders/passthrough.frag rename to src/main/resources/assets/pupper/shaders/passthrough.fsh index 6d9dedf..f3483ed 100644 --- a/src/main/resources/assets/pupper/shaders/passthrough.frag +++ b/src/main/resources/assets/pupper/shaders/passthrough.fsh @@ -5,8 +5,8 @@ precision lowp float; in vec2 uv; out vec4 color; -uniform sampler2D uTexture; +uniform sampler2D u_Texture; void main() { - color = texture(uTexture, uv); + color = texture(u_Texture, uv); } diff --git a/src/main/resources/assets/pupper/shaders/passthrough.vert b/src/main/resources/assets/pupper/shaders/passthrough.vsh similarity index 100% rename from src/main/resources/assets/pupper/shaders/passthrough.vert rename to src/main/resources/assets/pupper/shaders/passthrough.vsh diff --git a/src/main/resources/assets/pupper/shaders/pos_color.fsh b/src/main/resources/assets/pupper/shaders/pos_color.fsh new file mode 100644 index 0000000..567156e --- /dev/null +++ b/src/main/resources/assets/pupper/shaders/pos_color.fsh @@ -0,0 +1,9 @@ +#version 330 core + +out vec4 color; + +in vec4 v_Color; + +void main() { + color = v_Color; +} diff --git a/src/main/resources/assets/pupper/shaders/pos_color.vsh b/src/main/resources/assets/pupper/shaders/pos_color.vsh new file mode 100644 index 0000000..352f6ee --- /dev/null +++ b/src/main/resources/assets/pupper/shaders/pos_color.vsh @@ -0,0 +1,17 @@ +#version 330 core + +layout (location = 0) in vec4 pos; +layout (location = 1) in vec4 color; + +layout (std140) uniform MeshData { + mat4 u_Proj; + mat4 u_ModelView; +}; + +out vec4 v_Color; + +void main() { + gl_Position = u_Proj * u_ModelView * pos; + + v_Color = color; +} diff --git a/src/main/resources/pupper.mixins.json b/src/main/resources/pupper.mixins.json index 8223db7..ff2b34f 100644 --- a/src/main/resources/pupper.mixins.json +++ b/src/main/resources/pupper.mixins.json @@ -25,6 +25,7 @@ "minecraft.client.render.MixinLightmapTextureManager", "minecraft.client.render.PupperInGameHud", "minecraft.client.render.PupperScoreboard", + "minecraft.client.render.RenderPipelineMixin", "minecraft.client.sound.MixinSoundSystem", "minecraft.client.util.MixinWindow", "minecraft.entity.MixinAbstractClientPlayerEntity", From a74227b1a24b2b259fdd16c19d92c5b4d6a36b43 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 18:02:16 +0800 Subject: [PATCH 10/45] chore: update Minecraft 26.1.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b608e78..5c346d0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'net.fabricmc.fabric-loom' version '1.15-SNAPSHOT' + id 'net.fabricmc.fabric-loom' version '1.16-SNAPSHOT' } project.ext.lwjglVersion = "3.4.1" From aa400624095fe8e8d7bcb47be00dc98fe802c279 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 18:05:58 +0800 Subject: [PATCH 11/45] feat: fix shader some errors --- gradle.properties | 3 +- .../java/cn/pupperclient/PupperClient.java | 5 + .../event/client/FramebufferSizeEvent.java | 25 ----- .../event/client/ResolutionChangedEvent.java | 9 ++ .../java/cn/pupperclient/gui/api/SoarGui.java | 5 - .../interfaces/IMixinMinecraftClient.java | 2 +- .../accessors/GameRendererAccessor.java | 16 +++ .../client/MixinMinecraftClient.java | 28 ++++- .../client/render/BufferRendererAccessor.java | 13 --- .../client/render/GuiRendererMixin.java | 60 ++++++++++ .../client/render/MixinGameRenderer.java | 26 +---- .../minecraft/client/util/MixinWindow.java | 3 - .../shader/ExtendedRenderPipelineBuilder.java | 81 +------------ .../shader/PupperMeshBuilder.java | 76 ++++++++----- .../shader/PupperMeshRenderer.java | 22 +++- .../pupperclient/shader/PupperRenderer2D.java | 68 ++++++----- .../pupperclient/shader/impl/Kawaseblur.java | 106 +++++++++++++----- .../shader/patch/FixedUniformStorage.java | 4 +- src/main/java/cn/pupperclient/skia/Skia.java | 33 +++--- .../utils/minecraft/player/SkinUtils.java | 2 +- .../utils/render/RenderUtils.java | 37 ++++-- src/main/resources/fabric.mod.json | 2 +- src/main/resources/pupper.classtweaker | 4 + src/main/resources/pupper.mixins.json | 3 +- 24 files changed, 367 insertions(+), 266 deletions(-) delete mode 100644 src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java create mode 100644 src/main/java/cn/pupperclient/event/client/ResolutionChangedEvent.java create mode 100644 src/main/java/cn/pupperclient/mixin/mixins/accessors/GameRendererAccessor.java delete mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java create mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java diff --git a/gradle.properties b/gradle.properties index 5c1cf0a..df2a37d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,9 @@ -# Done to increase the memory available to gradle. org.gradle.jvmargs=-Xmx4G org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=26.1.1 +minecraft_version=26.1.2 loader_version=0.18.6 # Mod Properties diff --git a/src/main/java/cn/pupperclient/PupperClient.java b/src/main/java/cn/pupperclient/PupperClient.java index 7555c16..f383b29 100644 --- a/src/main/java/cn/pupperclient/PupperClient.java +++ b/src/main/java/cn/pupperclient/PupperClient.java @@ -35,6 +35,7 @@ public class PupperClient implements IMinecraft { private static final String ICON_PATH = "assets/pupper/logo.png"; private static final String CLIENT_NAME = "Pupper Client"; private static final String CLIENT_VERSION = "26.1.1"; + private static final String MOD_ID = "pupper"; private static final PupperClient INSTANCE = new PupperClient(); @@ -204,4 +205,8 @@ public void setProtocolVersion(ProtocolVersion version) { public CapeManager getCapeManager() { return capeManager; } + + public static String getModId() { + return MOD_ID; + } } diff --git a/src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java b/src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java deleted file mode 100644 index de91210..0000000 --- a/src/main/java/cn/pupperclient/event/client/FramebufferSizeEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @Author: oneachina - * @link: github.com/oneachina - */ -package cn.pupperclient.event.client; - -import cn.pupperclient.event.Event; - -public class FramebufferSizeEvent extends Event { - private final int width; - private final int height; - - public FramebufferSizeEvent(int width, int height) { - this.height = height; - this.width = width; - } - - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } -} diff --git a/src/main/java/cn/pupperclient/event/client/ResolutionChangedEvent.java b/src/main/java/cn/pupperclient/event/client/ResolutionChangedEvent.java new file mode 100644 index 0000000..1817a1e --- /dev/null +++ b/src/main/java/cn/pupperclient/event/client/ResolutionChangedEvent.java @@ -0,0 +1,9 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.event.client; + +import cn.pupperclient.event.Event; + +public class ResolutionChangedEvent extends Event {} diff --git a/src/main/java/cn/pupperclient/gui/api/SoarGui.java b/src/main/java/cn/pupperclient/gui/api/SoarGui.java index ee0f31c..9305501 100644 --- a/src/main/java/cn/pupperclient/gui/api/SoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SoarGui.java @@ -63,11 +63,6 @@ public void draw(double mouseX, double mouseY) { ColorPalette palette = PupperClient.getInstance().getColorManager().getPalette(); - if (ModMenuSettings.getInstance().getBlurSetting().isEnabled()) { - Skia.drawImage(Kawaseblur.GUI_BLUR.getTexture(), 0, 0, client.getWindow().getWidth(), - client.getWindow().getHeight(), inOutAnimation.getValue(), SurfaceOrigin.BOTTOM_LEFT); - } - Skia.save(); Skia.setAlpha((int) (inOutAnimation.getValue() * 255)); Skia.scale(getX(), getY(), getWidth(), getHeight(), 2 - inOutAnimation.getValue()); diff --git a/src/main/java/cn/pupperclient/mixin/interfaces/IMixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/interfaces/IMixinMinecraftClient.java index 26d9a2c..28efab4 100644 --- a/src/main/java/cn/pupperclient/mixin/interfaces/IMixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/interfaces/IMixinMinecraftClient.java @@ -3,5 +3,5 @@ import java.io.File; public interface IMixinMinecraftClient { - File getAssetDir(); + File pupper$getAssetDir(); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/accessors/GameRendererAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/accessors/GameRendererAccessor.java new file mode 100644 index 0000000..3fc54fe --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/mixins/accessors/GameRendererAccessor.java @@ -0,0 +1,16 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.mixin.mixins.accessors; + +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.fog.FogRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GameRenderer.class) +public interface GameRendererAccessor { + @Accessor("fogRenderer") + FogRenderer pupper$fogRenderer(); +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index c70f222..76aa974 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.IOException; +import cn.pupperclient.event.client.ResolutionChangedEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; import net.minecraft.client.gui.screens.Screen; @@ -13,7 +14,10 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.InteractionHand; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult.Type; @@ -105,10 +109,21 @@ private void handleBlockBreaking(boolean breaking, CallbackInfo ci) { BlockHitResult blockHitResult = (BlockHitResult) this.hitResult; BlockPos blockPos = blockHitResult.getBlockPos(); + BlockState blockState = level.getBlockState(blockPos); - if (!this.level.getBlockState(blockPos).isAir()) { + if (!blockState.isAir()) { Direction direction = blockHitResult.getDirection(); - this.particleEngine.crack(blockPos, direction); + BlockParticleOption particleOption = new BlockParticleOption(ParticleTypes.BLOCK, blockState); + + double x = blockPos.getX() + 0.5 + direction.getStepX() * 0.5; + double y = blockPos.getY() + 0.5 + direction.getStepY() * 0.5; + double z = blockPos.getZ() + 0.5 + direction.getStepZ() * 0.5; + + double xSpeed = direction.getStepX() * 0.2; + double ySpeed = 0.1; + double zSpeed = direction.getStepZ() * 0.2; + + level.addParticle(particleOption, x, y, z, xSpeed, ySpeed, zSpeed); ((IMixinLivingEntity) player).soarClient_CN$fakeSwingHand(InteractionHand.MAIN_HAND); } } @@ -149,7 +164,7 @@ public void onClientTick(CallbackInfo ci) { EventBus.getInstance().post(new ClientTickEvent()); } - @Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;handleDelayedCrash()V")) + @Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/SingleTickProfiler;createTickProfiler(Ljava/lang/String;)Lnet/minecraft/util/profiling/SingleTickProfiler;")) public void onGameLoop(CallbackInfo ci) { EventBus.getInstance().post(new GameLoopEvent()); } @@ -173,7 +188,12 @@ private void onBeforeFlipFrame(CallbackInfo ci) { } @Override - public File getAssetDir() { + public File pupper$getAssetDir() { return this.assetDir; } + + @Inject(method = "resizeGui", at = @At("TAIL")) + private void onResizeGui(CallbackInfo ci) { + EventBus.getInstance().post(new ResolutionChangedEvent()); + } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java deleted file mode 100644 index c2e88fd..0000000 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/BufferRendererAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.pupperclient.mixin.mixins.minecraft.client.render; - -import com.mojang.blaze3d.vertex.BufferUploader; -import com.mojang.blaze3d.vertex.VertexBuffer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(BufferUploader.class) -public interface BufferRendererAccessor { - @Accessor("lastImmediateBuffer") - static void setCurrentVertexBuffer(VertexBuffer vertexBuffer) { - } -} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java new file mode 100644 index 0000000..9af618b --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java @@ -0,0 +1,60 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.mixin.mixins.minecraft.client.render; + +import cn.pupperclient.PupperClient; +import cn.pupperclient.event.EventBus; +import cn.pupperclient.mixin.mixins.accessors.GameRendererAccessor; +import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; +import cn.pupperclient.utils.render.RenderUtils; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.render.GuiRenderer; +import net.minecraft.client.renderer.fog.FogRenderer; +import net.minecraft.client.renderer.state.gui.GuiRenderState; +import net.minecraft.util.profiling.Profiler; +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; + +@Mixin(GuiRenderer.class) +public abstract class GuiRendererMixin implements IMinecraft { + @Shadow + public abstract void render(GpuBufferSlice fogBuffer); + + @Shadow + public abstract void endFrame(); + + @Unique + private GuiRenderState renderState; + + @Inject(method = "draw", at = @At("HEAD")) + private void draw(CallbackInfo ci) { + var mouseX = (int) client.mouseHandler.getScaledXPos(client.getWindow()); + var mouseY = (int) client.mouseHandler.getScaledYPos(client.getWindow()); + + var fogRenderer = ((GameRendererAccessor) client.gameRenderer).pupper$fogRenderer(); + + if (RenderUtils.canUpdate()) { + Profiler.get().push(PupperClient.getModId() + "_render_2d"); + + RenderUtils.unscaledProjection(); + + this.render(fogRenderer.getBuffer(FogRenderer.FogMode.NONE)); + + RenderUtils.scaledProjection(); + + Profiler.get().pop(); + } + + assert client.getMainRenderTarget().getDepthTexture() != null; + RenderSystem.getDevice().createCommandEncoder().clearDepthTexture(client.getMainRenderTarget().getDepthTexture(), 1.0); + endFrame(); + } +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java index 7a4a316..934372e 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java @@ -1,12 +1,15 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.impl.render.NoHurtFov; import cn.pupperclient.shader.impl.Kawaseblur; import cn.pupperclient.utils.render.RenderUtils; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.util.profiling.Profiler; import org.joml.Matrix4f; import org.joml.Matrix4fStack; +import org.joml.Matrix4fc; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -36,15 +39,10 @@ public class MixinGameRenderer { private Minecraft minecraft; @Unique - private final Matrix4fStack matrices = new Matrix4fStack(); + private final PoseStack matrices = new PoseStack(); @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.BEFORE)) public void render(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { - - if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Kawaseblur.INGAME_BLUR.draw(minecraft., (int) HUDModSettings.getInstance().getBlurIntensitySetting().getValue()); - } - SkiaContext.draw((context) -> { Skia.save(); Skia.scale((float) Minecraft.getInstance().getWindow().getGuiScale()); @@ -52,14 +50,6 @@ public void render(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { Skia.restore(); }); } - - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.AFTER)) - public void renderGuiBlur(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { - - if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Kawaseblur.GUI_BLUR.draw(, (int) ModMenuSettings.getInstance().getBlurIntensitySetting().getValue()); - } - } @Inject(method = "getFov", at = @At(value = "RETURN", ordinal = 1), cancellable = true) private void getFov(Camera camera, float tickDelta, boolean changingFov, CallbackInfoReturnable cir) { @@ -76,12 +66,4 @@ private void tiltViewWhenHurt(CallbackInfo ci) { ci.cancel(); } } - - @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderItemInHand(Lnet/minecraft/client/renderer/state/level/CameraRenderState;FLorg/joml/Matrix4fc;)V")) - private void onRenderLevel(DeltaTracker deltaTracker, CallbackInfo ci, @Local(ordinal = 0) Matrix4f projection, @Local(ordinal = 0) Matrix4f position, @Local(ordinal = 0) float tickDelta, @Local PoseStack matrixStack) { - Matrix4f currentMatrix = new Matrix4f(matrixStack); - Matrix4f invertedMatrix = currentMatrix.invert(); - Matrix4f correctedPosition = MixinPlugin.isIrisPresent && RenderUtils.isShaderPackInUse() ? new Matrix4f(position).mul(invertedMatrix) : new Matrix4f(position); - RenderUtils.updateScreenCenter(projection, correctedPosition); - } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java index fc04ce1..bb36d88 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java @@ -1,8 +1,6 @@ package cn.pupperclient.mixin.mixins.minecraft.client.util; import cn.pupperclient.PupperClient; -import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.FramebufferSizeEvent; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -31,7 +29,6 @@ public class MixinWindow { @Inject(method = "onFramebufferResize", at = @At("RETURN")) private void onFramebufferSizeChanged(long window, int width, int height, CallbackInfo ci) { SkiaContext.createSurface(width, height); - EventBus.getInstance().post(new FramebufferSizeEvent(width, height)); } @Inject(method = "", at = @At("RETURN")) diff --git a/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java b/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java index 5635dc2..7c95c30 100644 --- a/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java +++ b/src/main/java/cn/pupperclient/shader/ExtendedRenderPipelineBuilder.java @@ -1,74 +1,15 @@ package cn.pupperclient.shader; import cn.pupperclient.mixin.interfaces.IRenderPipeline; -import com.mojang.blaze3d.pipeline.BlendFunction; -import com.mojang.blaze3d.pipeline.ColorTargetState; -import com.mojang.blaze3d.pipeline.DepthStencilState; import com.mojang.blaze3d.pipeline.RenderPipeline; -import com.mojang.blaze3d.platform.CompareOp; -import com.mojang.blaze3d.shaders.UniformType; -import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.resources.Identifier; -public class ExtendedRenderPipelineBuilder { - private final RenderPipeline.Builder builder; +public class ExtendedRenderPipelineBuilder extends RenderPipeline.Builder { private boolean lineSmooth; - private CompareOp depthTest; - private Boolean writeDepth; - private BlendFunction blendFunction; public ExtendedRenderPipelineBuilder(RenderPipeline.Snippet... snippets) { - builder = RenderPipeline.builder(snippets); - } - - public ExtendedRenderPipelineBuilder withLocation(Identifier location) { - builder.withLocation(location); - return this; - } - - public ExtendedRenderPipelineBuilder withVertexFormat(VertexFormat format, VertexFormat.Mode mode) { - builder.withVertexFormat(format, mode); - return this; - } - - public ExtendedRenderPipelineBuilder withVertexShader(Identifier shader) { - builder.withVertexShader(shader); - return this; - } - - public ExtendedRenderPipelineBuilder withFragmentShader(Identifier shader) { - builder.withFragmentShader(shader); - return this; - } - - public ExtendedRenderPipelineBuilder withSampler(String sampler) { - builder.withSampler(sampler); - return this; - } - - public ExtendedRenderPipelineBuilder withUniform(String uniform, UniformType type) { - builder.withUniform(uniform, type); - return this; - } - - public ExtendedRenderPipelineBuilder withCull(boolean cull) { - builder.withCull(cull); - return this; - } - - public ExtendedRenderPipelineBuilder withDepthTestFunction(CompareOp depthTest) { - this.depthTest = depthTest; - return this; - } - - public ExtendedRenderPipelineBuilder withDepthWrite(boolean writeDepth) { - this.writeDepth = writeDepth; - return this; - } - - public ExtendedRenderPipelineBuilder withBlend(BlendFunction blendFunction) { - this.blendFunction = blendFunction; - return this; + for (RenderPipeline.Snippet snippet : snippets) { + withSnippet(snippet); + } } public ExtendedRenderPipelineBuilder withLineSmooth() { @@ -76,19 +17,9 @@ public ExtendedRenderPipelineBuilder withLineSmooth() { return this; } + @Override public RenderPipeline build() { - if (depthTest != null || writeDepth != null) { - builder.withDepthStencilState(new DepthStencilState( - depthTest != null ? depthTest : DepthStencilState.DEFAULT.depthTest(), - writeDepth != null ? writeDepth : DepthStencilState.DEFAULT.writeDepth() - )); - } - - if (blendFunction != null) { - builder.withColorTargetState(new ColorTargetState(blendFunction)); - } - - RenderPipeline pipeline = builder.build(); + RenderPipeline pipeline = super.build(); ((IRenderPipeline) pipeline).pupper$setLineSmooth(lineSmooth); return pipeline; diff --git a/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java b/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java index 3bc122f..fa099e9 100644 --- a/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java +++ b/src/main/java/cn/pupperclient/shader/PupperMeshBuilder.java @@ -29,7 +29,6 @@ public class PupperMeshBuilder { private int vertexI, indicesCount; private boolean building; - private double cameraX, cameraZ; public PupperMeshBuilder(RenderPipeline pipeline) { this(pipeline.getVertexFormat(), pipeline.getVertexFormatMode()); @@ -41,6 +40,11 @@ public PupperMeshBuilder(VertexFormat format, VertexFormat.Mode mode) { primitiveIndicesCount = mode.connectedPrimitives ? mode.primitiveStride : mode.primitiveLength; } + public PupperMeshBuilder(VertexFormat format, VertexFormat.Mode drawMode, int vertexCount, int indexCount) { + this(format, drawMode); + allocateBuffers(vertexCount, indexCount); + } + public void begin() { if (building) throw new IllegalStateException("Mesh.begin() called while already building."); @@ -49,22 +53,6 @@ public void begin() { indicesCount = 0; building = true; - - cameraX = 0; - cameraZ = 0; - } - - public PupperMeshBuilder vec3(double x, double y, double z) { - debugVertexBufferCapacity(); - - long p = verticesPointer; - - memPutFloat(p, (float) (x - cameraX)); - memPutFloat(p + 4, (float) y); - memPutFloat(p + 8, (float) (z - cameraZ)); - - verticesPointer += 12; - return this; } public PupperMeshBuilder vec2(double x, double y) { @@ -98,7 +86,7 @@ public int next() { } public void line(int i1, int i2) { - growIfNeeded(); + debugIndexBufferCapacity(); memPutInt(indicesPointer, i1); memPutInt(indicesPointer + 4, i2); indicesPointer += 8; @@ -106,7 +94,7 @@ public void line(int i1, int i2) { } public void quad(int i1, int i2, int i3, int i4) { - growIfNeeded(); + debugIndexBufferCapacity(); memPutInt(indicesPointer, i1); memPutInt(indicesPointer + 4, i2); memPutInt(indicesPointer + 8, i3); @@ -117,27 +105,53 @@ public void quad(int i1, int i2, int i3, int i4) { indicesCount += 6; } - public void growIfNeeded() { - if (getVerticesOffset() + primitiveVerticesSize >= vertices.capacity()) { - int newSize = vertices.capacity() * 2; + public void ensureQuadCapacity() { + ensureCapacity(4, 6); + } + + public void ensureTriCapacity() { + ensureCapacity(3, 3); + } + + public void ensureLineCapacity() { + ensureCapacity(2, 2); + } + + public void ensureCapacity(int vertexCount, int indexCount) { + if (DEBUG && (indexCount % primitiveIndicesCount != 0)) { + throw new IllegalArgumentException("Unexpected amount of indices written to MeshBuilder."); + } + + if (vertices == null || indices == null) { + allocateBuffers(256 * 4, 512 * 4); + return; + } + + if ((vertexI + vertexCount) * primitiveVerticesSize >= vertices.capacity()) { int offset = getVerticesOffset(); + int newSize = Math.max(vertices.capacity() * 2, vertices.capacity() + vertexCount * primitiveVerticesSize); ByteBuffer newVertices = BufferUtils.createByteBuffer(newSize); - memCopy(verticesPointerStart, memAddress0(newVertices), offset); + memCopy(memAddress0(vertices), memAddress0(newVertices), offset); + vertices = newVertices; verticesPointerStart = memAddress0(vertices); verticesPointer = verticesPointerStart + offset; } - if ((indicesCount + primitiveIndicesCount) * 4 >= indices.capacity()) { - int newSize = indices.capacity() * 2; + if ((indicesCount + indexCount) * Integer.BYTES >= indices.capacity()) { + int newSize = Math.max(indices.capacity() * 2, indices.capacity() + indexCount * Integer.BYTES); + ByteBuffer newIndices = BufferUtils.createByteBuffer(newSize); memCopy(memAddress0(indices), memAddress0(newIndices), indicesCount * 4L); + indices = newIndices; indicesPointer = memAddress0(indices); } } public void end() { + if (!building) throw new IllegalStateException("Mesh.end() called while not building."); + building = false; } @@ -161,6 +175,14 @@ public PupperMeshBuilder tex2(float u, float v) { public int getIndicesCount() { return indicesCount; } private int getVerticesOffset() { return (int) (verticesPointer - verticesPointerStart); } + private void allocateBuffers(int vertexCount, int indexCount) { + vertices = BufferUtils.createByteBuffer(primitiveVerticesSize * vertexCount); + verticesPointer = verticesPointerStart = memAddress0(vertices); + + indices = BufferUtils.createByteBuffer(indexCount * Integer.BYTES); + indicesPointer = memAddress0(indices); + } + private void debugVertexBufferCapacity() { if (DEBUG && (vertices == null || vertexI * primitiveVerticesSize >= vertices.capacity())) { throw new IndexOutOfBoundsException("Vertices written to MeshBuilder without calling 'ensureCapacity()' first!"); @@ -172,4 +194,8 @@ private void debugIndexBufferCapacity() { throw new IndexOutOfBoundsException("Indices written to MeshBuilder without calling 'ensureCapacity()' first!"); } } + + public boolean isBuilding() { + return building; + } } diff --git a/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java b/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java index 58fee8b..2977b28 100644 --- a/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java +++ b/src/main/java/cn/pupperclient/shader/PupperMeshRenderer.java @@ -1,10 +1,11 @@ package cn.pupperclient.shader; import cn.pupperclient.utils.color.Color; -import com.ibm.icu.impl.Pair; +import cn.pupperclient.utils.render.RenderUtils; import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.GpuSampler; @@ -45,6 +46,12 @@ public static PupperMeshRenderer begin() { return INSTANCE; } + public PupperMeshRenderer attachments(RenderTarget framebuffer) { + colorAttachment = framebuffer.getColorTextureView(); + depthAttachment = framebuffer.getDepthTextureView(); + return this; + } + public PupperMeshRenderer attachments(GpuTextureView color, GpuTextureView depth) { colorAttachment = color; depthAttachment = depth; @@ -120,13 +127,20 @@ public void end() { OptionalInt.empty(); RenderPass pass = (depthAttachment != null && pipeline.wantsDepthTexture()) ? - RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Meteor MeshRenderer", colorAttachment, clearColor, depthAttachment, OptionalDouble.empty()) : - RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Meteor MeshRenderer", colorAttachment, clearColor); + RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Pupper MeshRenderer", colorAttachment, clearColor, depthAttachment, OptionalDouble.empty()) : + RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Pupper MeshRenderer", colorAttachment, clearColor); pass.setPipeline(pipeline); - pass.setUniform("MeshData", meshData); + for (var entry : uniforms.entrySet()) { + pass.setUniform(entry.getKey(), entry.getValue()); + } + + for (var entry : samplers.entrySet()) { + pass.bindTexture(entry.getKey(), entry.getValue().getA(), entry.getValue().getB()); + } + pass.setVertexBuffer(0, vertexBuffer); pass.setIndexBuffer(indexBuffer, VertexFormat.IndexType.INT); pass.drawIndexed(0, 0, indexCount, 1); diff --git a/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java b/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java index db9eed5..ce37aff 100644 --- a/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java +++ b/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java @@ -1,30 +1,31 @@ package cn.pupperclient.shader; -import com.mojang.blaze3d.systems.RenderPass; -import net.minecraft.client.MinecraftClient; - -import java.util.function.Consumer; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import net.minecraft.client.Minecraft; public class PupperRenderer2D { public static PupperRenderer2D COLOR; + public static PupperRenderer2D TEXTURE; + + private final boolean textured; public final PupperMeshBuilder triangles; public final PupperMeshBuilder lines; - public final PupperMeshBuilder texturedMesh; - public PupperRenderer2D() { - triangles = new PupperMeshBuilder(PupperRenderPipelines.UI_COLORED); + public PupperRenderer2D(boolean textured) { + triangles = new PupperMeshBuilder(textured ? PupperRenderPipelines.UI_TEXTURED : PupperRenderPipelines.UI_COLORED); lines = new PupperMeshBuilder(PupperRenderPipelines.UI_COLORED_LINES); - texturedMesh = new PupperMeshBuilder(PupperRenderPipelines.UI_TEXTURED); + this.textured = textured; } - public static void init() { - COLOR = new PupperRenderer2D(); + static { + COLOR = new PupperRenderer2D(false); + TEXTURE = new PupperRenderer2D(true); } public void setAlpha(double alpha) { triangles.alpha = alpha; - lines.alpha = alpha; } public void begin() { @@ -35,28 +36,35 @@ public void begin() { public void end() { triangles.end(); lines.end(); + } + + public void render() { + render(null, null, null); + } + + public void render(GpuTextureView textureView, GpuSampler sampler) { + if (!textured) + throw new IllegalStateException("Tried to render with a texture with a non-textured Renderer2D"); - render(null); + render("u_Texture", textureView, sampler); } - public void render(Consumer setupCallback) { - if (triangles.getIndicesCount() > 0) { - PupperMeshRenderer.begin() - .attachments(MinecraftClient.getInstance().getFramebuffer()) - .pipeline(PupperRenderPipelines.UI_COLORED) - .mesh(triangles) - .setupCallback(setupCallback) - .end(); - } - - if (lines.getIndicesCount() > 0) { - PupperMeshRenderer.begin() - .attachments(MinecraftClient.getInstance().getFramebuffer()) - .pipeline(PupperRenderPipelines.UI_COLORED_LINES) - .mesh(lines) - .setupCallback(setupCallback) - .end(); - } + public void render(String samplerName, GpuTextureView samplerView, GpuSampler sampler) { + if (lines.isBuilding()) lines.end(); + if (triangles.isBuilding()) triangles.end(); + + MeshRenderer.begin() + .attachments(Minecraft.getInstance().getMainRenderTarget()) + .pipeline(MeteorRenderPipelines.UI_COLORED_LINES) + .mesh(lines) + .end(); + + MeshRenderer.begin() + .attachments(Minecraft.getInstance().getMainRenderTarget()) + .pipeline(textured ? MeteorRenderPipelines.UI_TEXTURED : MeteorRenderPipelines.UI_COLORED) + .mesh(triangles) + .sampler(samplerName, samplerView, sampler) + .end(); } public void quad(double x, double y, double width, double height, int color) { diff --git a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java index c3217d4..c63186d 100644 --- a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java +++ b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java @@ -2,18 +2,18 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.FramebufferSizeEvent; +import cn.pupperclient.event.client.ResolutionChangedEvent; +import cn.pupperclient.gui.modmenu.GuiModMenu; +import cn.pupperclient.management.mod.impl.settings.HUDModSettings; +import cn.pupperclient.management.mod.impl.settings.ModMenuSettings; import cn.pupperclient.shader.*; import cn.pupperclient.shader.patch.FixedUniformStorage; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import com.mojang.blaze3d.opengl.GlStateManager; import com.mojang.blaze3d.pipeline.RenderPipeline; -import com.mojang.blaze3d.systems.CommandEncoder; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.FilterMode; -import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.textures.TextureFormat; import it.unimi.dsi.fastutil.ints.IntFloatImmutablePair; @@ -24,8 +24,7 @@ import java.nio.ByteBuffer; public class Kawaseblur { - public static final Kawaseblur GUI_BLUR = new Kawaseblur(); - public static final Kawaseblur INGAME_BLUR = new Kawaseblur(); + // public static final Kawaseblur INGAME_BLUR = new Kawaseblur(); private final Minecraft mc = Minecraft.getInstance(); private final IntFloatImmutablePair[] strengths = new IntFloatImmutablePair[]{ @@ -66,21 +65,67 @@ private Kawaseblur() { } } - public void draw(CommandEncoder encoder, int iterations) { - if (iterations <= 0) return; - GpuTextureView mainFbo = mc.getFramebuffer(); + public void draw() { + boolean shouldRender = shouldRender(); + long time = System.currentTimeMillis(); - renderPass(encoder, fbos[0], mainFbo.getColorAttachment(), PupperRenderPipelines.PASSTHROUGH, 0); + if (enabled) { + if (!shouldRender) { + if (fadeEndAt == -1) fadeEndAt = System.currentTimeMillis() + 100; + + if (time >= fadeEndAt) { + enabled = false; + fadeEndAt = -1; + } + } + } else { + if (shouldRender) { + enabled = true; + fadeEndAt = System.currentTimeMillis() + 100; + } + } + + if (!enabled) return; + + // Update progress + double progress = 1; + + if (time < fadeEndAt) { + if (shouldRender) progress = 1 - (fadeEndAt - time) / 100f; + else progress = (fadeEndAt - time) / 100f; + } else { + fadeEndAt = -1; + } + + // Update strength + int blur_intensity = getBlurIntensity(); + + IntFloatImmutablePair blur_strength = strengths[(int) ((blur_intensity - 1) * progress)]; + int iterations = blur_strength.leftInt(); + float offset = blur_strength.rightFloat(); + + // Update uniforms + if (previousOffset != offset) { + updateUniforms(offset); + previousOffset = offset; + } + + renderToFbo(fbos[0], mc.getMainRenderTarget().getColorTextureView(), PupperRenderPipelines.BLUR_DOWN, ubos[0]); for (int i = 0; i < iterations; i++) { - renderPass(encoder, fbos[Math.min(i + 1, 4)], fbos[i].getColorAttachment(), PupperRenderPipelines.BLUR_DOWN, i); + renderToFbo(fbos[i + 1], fbos[i], PupperRenderPipelines.BLUR_DOWN, ubos[i + 1]); } - for (int i = iterations; i > 0; i--) { - renderPass(encoder, fbos[i - 1], fbos[i].getColorAttachment(), PupperRenderPipelines.BLUR_UP, i); + for (int i = iterations; i >= 1; i--) { + renderToFbo(fbos[i - 1], fbos[i], PupperRenderPipelines.BLUR_UP, ubos[i - 1]); } - renderPass(encoder, mainFbo, fbos[0].getColorAttachment(), PupperRenderPipelines.PASSTHROUGH, 0); + PupperMeshRenderer.begin() + .attachments(mc.getMainRenderTarget()) + .pipeline(PupperRenderPipelines.PASSTHROUGH) + .fullscreen() + .sampler("u_Texture", fbos[0], RenderSystem.getSamplerCache().getClampToEdge(FilterMode.LINEAR)) // todo ??? + .end(); } private void renderToFbo(GpuTextureView targetFbo, GpuTextureView sourceTexture, RenderPipeline pipeline, GpuBufferSlice ubo) { @@ -93,37 +138,33 @@ private void renderToFbo(GpuTextureView targetFbo, GpuTextureView sourceTexture, .end(); } + @SuppressWarnings("unused") public GpuTextureView[] getFbos() { return fbos; } - private GpuTextureView createFbo(int i, int baseWidth, int baseHeight) { + private GpuTextureView createFbo(int i) { double scale = 1 / Math.pow(2, i); - int width = (int) (baseWidth * scale); - int height = (int) (baseHeight * scale); - width = Math.max(width, 1); - height = Math.max(height, 1); + int width = (int) (mc.getWindow().getWidth() * scale); + int height = (int) (mc.getWindow().getHeight() * scale); - return RenderSystem.getDevice().createTextureView(RenderSystem.getDevice().createTexture("Blur - " + i, 15, TextureFormat.RGBA8, width, height, 1, 1)); + return RenderSystem.getDevice().createTextureView(RenderSystem.getDevice().createTexture("Blur - " + i, 15, TextureFormat.RGBA8, width, height, 1, 1)); } - private void rebuildFbos(int w, int h) { + private void rebuildFbos() { for (int i = 0; i < fbos.length; i++) { if (fbos[i] != null) { fbos[i].close(); } - fbos[i] = createFbo(i, w, h); + fbos[i] = createFbo(i); } previousOffset = -1; } @EventListener - private void onFramebufferSize(FramebufferSizeEvent event) { - int newWidth = event.getWidth(); - int newHeight = event.getHeight(); - - rebuildFbos(newWidth, newHeight); + private void onResolutionChanged(ResolutionChangedEvent event) { + rebuildFbos(); } // Uniforms @@ -157,4 +198,15 @@ public void write(@NonNull ByteBuffer buffer) { .putFloat(offset); } } + + private int getBlurIntensity() { + if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { + return (int) ModMenuSettings.getInstance().getBlurIntensitySetting().getValue(); + } + return 5; + } + + private boolean shouldRender() { + return mc.screen instanceof GuiModMenu; + } } diff --git a/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java b/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java index 3d229c2..72f52c2 100644 --- a/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java +++ b/src/main/java/cn/pupperclient/shader/patch/FixedUniformStorage.java @@ -66,12 +66,12 @@ public GpuBufferSlice[] writeAll(T[] values) { try (GpuBuffer.MappedView mappedView = RenderSystem.getDevice() .createCommandEncoder() - .mapBuffer(ubo.slice(i, values.length * this.blockSize), false, true)) { + .mapBuffer(ubo.slice(i, (long) values.length * this.blockSize), false, true)) { ByteBuffer byteBuffer = mappedView.data(); for (int j = 0; j < values.length; j++) { T uploadable = values[j]; - gpuBufferSlices[j] = ubo.slice(i + j * this.blockSize, this.blockSize); + gpuBufferSlices[j] = ubo.slice(i + (long) j * this.blockSize, this.blockSize); byteBuffer.position(j * this.blockSize); uploadable.write(byteBuffer); } diff --git a/src/main/java/cn/pupperclient/skia/Skia.java b/src/main/java/cn/pupperclient/skia/Skia.java index 2f29c4d..8dd0e50 100644 --- a/src/main/java/cn/pupperclient/skia/Skia.java +++ b/src/main/java/cn/pupperclient/skia/Skia.java @@ -58,18 +58,19 @@ public static void drawRoundedRectVarying(float x, float y, float width, float h getCanvas().drawRRect(RRect.makeComplexXYWH(x, y, width, height, corners), setupPaint(color)); } + // TODO: fix Draw Blur Texture in anywhere public static void drawBlur(float x, float y, float width, float height) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Window window = Minecraft.getInstance().getWindow(); - try (Path path = Path.makeRect(Rect.makeXYWH(x, y, width, height))) { - save(); - getCanvas().clipPath(path, ClipMode.INTERSECT, true); - drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), 1F, - SurfaceOrigin.BOTTOM_LEFT); - restore(); - } +// Window window = Minecraft.getInstance().getWindow(); +// try (Path path = Path.makeRect(Rect.makeXYWH(x, y, width, height))) { +// save(); +// getCanvas().clipPath(path, ClipMode.INTERSECT, true); +// drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), 1F, +// SurfaceOrigin.BOTTOM_LEFT); +// restore(); +// } } } @@ -77,14 +78,14 @@ public static void drawRoundedBlur(float x, float y, float width, float height, if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { - Window window = Minecraft.getInstance().getWindow(); - try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { - save(); - getCanvas().clipPath(path, ClipMode.INTERSECT, true); - drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), 1F, - SurfaceOrigin.BOTTOM_LEFT); - restore(); - } +// Window window = Minecraft.getInstance().getWindow(); +// try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { +// save(); +// getCanvas().clipPath(path, ClipMode.INTERSECT, true); +// drawImage(Kawaseblur.INGAME_BLUR.getTexture(), 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), 1F, +// SurfaceOrigin.BOTTOM_LEFT); +// restore(); +// } } } diff --git a/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java b/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java index a2f6ab1..ae2b4f5 100644 --- a/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java +++ b/src/main/java/cn/pupperclient/utils/minecraft/player/SkinUtils.java @@ -10,7 +10,7 @@ public class SkinUtils { public static File getSkin(Identifier identifier) { String fileName = identifier.getPath().replace("skins/", ""); String folder = fileName.substring(0, 2); - File file = new File(((IMixinMinecraftClient) Minecraft.getInstance()).getAssetDir(), + File file = new File(((IMixinMinecraftClient) Minecraft.getInstance()).pupper$getAssetDir(), "skins/" + folder + "/" + fileName); return file; } diff --git a/src/main/java/cn/pupperclient/utils/render/RenderUtils.java b/src/main/java/cn/pupperclient/utils/render/RenderUtils.java index a032138..8a401e5 100644 --- a/src/main/java/cn/pupperclient/utils/render/RenderUtils.java +++ b/src/main/java/cn/pupperclient/utils/render/RenderUtils.java @@ -5,24 +5,43 @@ package cn.pupperclient.utils.render; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; +import com.mojang.blaze3d.ProjectionType; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.renderer.Projection; +import net.minecraft.client.renderer.ProjectionMatrixBuffer; import net.minecraft.world.phys.Vec3; import org.joml.Matrix4f; -import org.joml.Vector4f; public class RenderUtils implements IMinecraft { public static Vec3 center; public static final Matrix4f projection = new Matrix4f(); + private static final ProjectionMatrixBuffer matrixBuffer = new ProjectionMatrixBuffer("pupper-projection-matrix"); - public static void updateScreenCenter(Matrix4f projection, Matrix4f view) { - RenderUtils.projection.set(projection); + public static void unscaledProjection() { + float width = client.getWindow().getWidth(); + float height = client.getWindow().getHeight(); - Matrix4f invProjection = new Matrix4f(projection).invert(); - Matrix4f invView = new Matrix4f(view).invert(); + var proj = new Projection(); + proj.setupOrtho(-10, 100, width, height, true); + var matrix = proj.getMatrix(new Matrix4f()); - Vector4f center4 = new Vector4f(0, 0, 0, 1).mul(invProjection).mul(invView); - center4.div(center4.w); + RenderSystem.setProjectionMatrix(matrixBuffer.getBuffer(matrix), ProjectionType.ORTHOGRAPHIC); + RenderUtils.projection.set(matrix); + } + + public static void scaledProjection() { + float width = (float) (client.getWindow().getWidth() / client.getWindow().getGuiScale()); + float height = (float) (client.getWindow().getHeight() / client.getWindow().getGuiScale()); + + var proj = new Projection(); + proj.setupOrtho(-10, 100, width, height, true); + var matrix = proj.getMatrix(new Matrix4f()); + + RenderSystem.setProjectionMatrix(matrixBuffer.getBuffer(matrix), ProjectionType.PERSPECTIVE); + RenderUtils.projection.set(matrix); + } - Vec3 camera = client.gameRenderer.getMainCamera().position(); - center = new Vec3(camera.x + center4.x, camera.y + center4.y, camera.z + center4.z); + public static boolean canUpdate() { + return client.level != null && client.player != null; } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index ad4a87c..0f39d9b 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,7 +21,7 @@ "depends": { "fabricloader": ">=0.16.10", "fabric": "*", - "minecraft": "1.21.4", + "minecraft": "26.1.2", "viafabricplus": "*", "ias": "*" }, diff --git a/src/main/resources/pupper.classtweaker b/src/main/resources/pupper.classtweaker index 8faee09..b8b4dd4 100644 --- a/src/main/resources/pupper.classtweaker +++ b/src/main/resources/pupper.classtweaker @@ -28,3 +28,7 @@ transitive-accessible method net/minecraft/client/renderer/entity/LivingEntityRe transitive-accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher renderers Ljava/util/Map; transitive-accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; transitive-accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher playerRenderers Ljava/util/Map; + +# ExtendedRenderPipelineBuilder +accessible method com/mojang/blaze3d/pipeline/RenderPipeline$Builder ()V +accessible method com/mojang/blaze3d/pipeline/RenderPipeline$Builder withSnippet (Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;)V diff --git a/src/main/resources/pupper.mixins.json b/src/main/resources/pupper.mixins.json index ff2b34f..042e878 100644 --- a/src/main/resources/pupper.mixins.json +++ b/src/main/resources/pupper.mixins.json @@ -3,6 +3,7 @@ "package": "cn.pupperclient.mixin.mixins", "compatibilityLevel": "JAVA_21", "client": [ + "accessors.GameRendererAccessor", "minecraft.client.MixinClientBrandRetriever", "minecraft.client.MixinKeyboard", "minecraft.client.MixinMinecraftClient", @@ -15,7 +16,7 @@ "minecraft.client.gui.MixinSplashScreen", "minecraft.client.gui.MixinTitleScreen", "minecraft.client.option.MixinKeyBinding", - "minecraft.client.render.BufferRendererAccessor", + "minecraft.client.render.GuiRendererMixin", "minecraft.client.render.MixinCamera", "minecraft.client.render.MixinEntityRenderer", "minecraft.client.render.MixinGameRenderer", From 701c9fe47b1f1c85502ba509896e735f6dd5b0a0 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 18:09:50 +0800 Subject: [PATCH 12/45] chore: clean useless renderer2d --- .../pupperclient/shader/PupperRenderer2D.java | 90 ------------------- 1 file changed, 90 deletions(-) delete mode 100644 src/main/java/cn/pupperclient/shader/PupperRenderer2D.java diff --git a/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java b/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java deleted file mode 100644 index ce37aff..0000000 --- a/src/main/java/cn/pupperclient/shader/PupperRenderer2D.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.pupperclient.shader; - -import com.mojang.blaze3d.textures.GpuSampler; -import com.mojang.blaze3d.textures.GpuTextureView; -import net.minecraft.client.Minecraft; - -public class PupperRenderer2D { - public static PupperRenderer2D COLOR; - public static PupperRenderer2D TEXTURE; - - private final boolean textured; - - public final PupperMeshBuilder triangles; - public final PupperMeshBuilder lines; - - public PupperRenderer2D(boolean textured) { - triangles = new PupperMeshBuilder(textured ? PupperRenderPipelines.UI_TEXTURED : PupperRenderPipelines.UI_COLORED); - lines = new PupperMeshBuilder(PupperRenderPipelines.UI_COLORED_LINES); - this.textured = textured; - } - - static { - COLOR = new PupperRenderer2D(false); - TEXTURE = new PupperRenderer2D(true); - } - - public void setAlpha(double alpha) { - triangles.alpha = alpha; - } - - public void begin() { - triangles.begin(); - lines.begin(); - } - - public void end() { - triangles.end(); - lines.end(); - } - - public void render() { - render(null, null, null); - } - - public void render(GpuTextureView textureView, GpuSampler sampler) { - if (!textured) - throw new IllegalStateException("Tried to render with a texture with a non-textured Renderer2D"); - - render("u_Texture", textureView, sampler); - } - - public void render(String samplerName, GpuTextureView samplerView, GpuSampler sampler) { - if (lines.isBuilding()) lines.end(); - if (triangles.isBuilding()) triangles.end(); - - MeshRenderer.begin() - .attachments(Minecraft.getInstance().getMainRenderTarget()) - .pipeline(MeteorRenderPipelines.UI_COLORED_LINES) - .mesh(lines) - .end(); - - MeshRenderer.begin() - .attachments(Minecraft.getInstance().getMainRenderTarget()) - .pipeline(textured ? MeteorRenderPipelines.UI_TEXTURED : MeteorRenderPipelines.UI_COLORED) - .mesh(triangles) - .sampler(samplerName, samplerView, sampler) - .end(); - } - - public void quad(double x, double y, double width, double height, int color) { - int i1 = triangles.vec2(x, y).color(color).next(); - int i2 = triangles.vec2(x, y + height).color(color).next(); - int i3 = triangles.vec2(x + width, y + height).color(color).next(); - int i4 = triangles.vec2(x + width, y).color(color).next(); - - triangles.quad(i1, i2, i3, i4); - } - - public void line(double x1, double y1, double x2, double y2, int color) { - lines.line( - lines.vec2(x1, y1).color(color).next(), - lines.vec2(x2, y2).color(color).next() - ); - } - - public PupperMeshBuilder getTexturedMesh() { - return texturedMesh; - } -} -// based on meteor From 08288b2261ecde0dbb1db4589a0e90d381df3677 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 18:16:32 +0800 Subject: [PATCH 13/45] fix(shader): Port Minecraft 26.1 --- .../shader/PupperRenderPipelines.java | 137 ++++++++---------- .../shader/PupperVertexFormats.java | 5 - .../cn/pupperclient/shader/ShapeMode.java | 20 --- .../pupperclient/shader/impl/Kawaseblur.java | 2 +- 4 files changed, 59 insertions(+), 105 deletions(-) delete mode 100644 src/main/java/cn/pupperclient/shader/ShapeMode.java diff --git a/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java b/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java index 26884e6..f17765a 100644 --- a/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java +++ b/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java @@ -1,13 +1,16 @@ package cn.pupperclient.shader; import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.ColorTargetState; +import com.mojang.blaze3d.pipeline.DepthStencilState; import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.CompareOp; import com.mojang.blaze3d.shaders.UniformType; import com.mojang.blaze3d.systems.GpuDevice; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.VertexFormat; -import com.viaversion.viaversion.libs.mcstructs.core.Identifier; import net.minecraft.client.Minecraft; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import org.apache.commons.io.IOUtils; @@ -23,113 +26,89 @@ public abstract class PupperRenderPipelines { .withUniform("MeshData", UniformType.UNIFORM_BUFFER) .buildSnippet(); + + // Blur public static final RenderPipeline BLUR_DOWN = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(getLocation("pipeline/blur_down")) .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.Mode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "blur").get()) - .withFragmentShader(Identifier.of("pupper", "blur_down").get()) - .withSampler("Sampler0") - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .withDepthWrite(false) - .withBlend(BlendFunction.TRANSLUCENT) + .withVertexShader(getLocation("blur")) + .withFragmentShader(getLocation("blur_down")) + .withSampler("u_Texture") + .withUniform("BlurData", UniformType.UNIFORM_BUFFER) + .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) .withCull(false) .build() ); public static final RenderPipeline BLUR_UP = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(Identifier.of("pupper", "pipeline/blur_up")) - .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.DrawMode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "blur")) - .withFragmentShader(Identifier.of("pupper", "blur_up")) - .withSampler("Sampler0") - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .withDepthWrite(false) - .withBlend(BlendFunction.TRANSLUCENT) + .withLocation(getLocation("pipeline/blur_up")) + .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.Mode.TRIANGLES) + .withVertexShader(getLocation("blur")) + .withFragmentShader(getLocation("blur_up")) + .withSampler("u_Texture") + .withUniform("BlurData", UniformType.UNIFORM_BUFFER) + .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) .withCull(false) .build() ); - public static final RenderPipeline PASSTHROUGH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(Identifier.of("pupper", "pipeline/passthrough")) - .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.DrawMode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "passthrough")) - .withFragmentShader(Identifier.of("pupper", "passthrough")) + public static final RenderPipeline BLUR_PASSTHROUGH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) + .withLocation(getLocation("pipeline/passthrough")) + .withVertexFormat(PupperVertexFormats.POS2, VertexFormat.Mode.TRIANGLES) + .withVertexShader(getLocation("passthrough")) + .withFragmentShader(getLocation("passthrough")) .withSampler("Sampler0") - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .withDepthWrite(false) - .withBlend(BlendFunction.TRANSLUCENT) + .withSampler("u_Texture") + .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) .withCull(false) .build() ); + // UI public static final RenderPipeline UI_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(Identifier.of("pupper", "pipeline/ui_colored")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.DrawMode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "ui_colored")) - .withFragmentShader(Identifier.of("pupper", "ui_colored")) - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .withDepthWrite(false) - .withBlend(BlendFunction.TRANSLUCENT) - .withCull(false) + .withLocation(getLocation("pipeline/ui_colored")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.Mode.TRIANGLES) + .withVertexShader(getLocation("ui_colored")) + .withFragmentShader(getLocation("ui_colored")) + .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) + .withCull(true) .build() ); public static final RenderPipeline UI_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLineSmooth() - .withLocation(Identifier.of("pupper", "pipeline/ui_colored_lines")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.DrawMode.LINES) - .withVertexShader(Identifier.of("pupper", "ui_colored")) - .withFragmentShader(Identifier.of("pupper", "ui_colored")) - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .withDepthWrite(false) - .withBlend(BlendFunction.TRANSLUCENT) - .withCull(false) + .withLocation(getLocation("pipeline/ui_colored_lines")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.Mode.LINES) + .withVertexShader(getLocation("ui_colored")) + .withFragmentShader(getLocation("ui_colored")) + .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) + .withCull(true) .build() ); - - public static final RenderPipeline WORLD_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(Identifier.of("pupper", "pipeline/world_colored")) - .withVertexFormat(PupperVertexFormats.POS3_COLOR, VertexFormat.DrawMode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "pos_color.vsh")) // Uses pos_color.vsh.vsh - .withFragmentShader(Identifier.of("pupper", "pos_color.vsh")) // Uses pos_color.vsh.fsh - .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) // 3D needs depth testing - .withDepthWrite(false) // Usually false for ESP/Overlays to avoid glitching - .withBlend(BlendFunction.TRANSLUCENT) - .withCull(false) - .build() - ); - - // 3D Wireframe (Lines) - public static final RenderPipeline WORLD_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLineSmooth() - .withLocation(Identifier.of("pupper", "pipeline/world_colored_lines")) - .withVertexFormat(PupperVertexFormats.POS3_COLOR, VertexFormat.DrawMode.LINES) - .withVertexShader(Identifier.of("pupper", "pos_color.vsh")) - .withFragmentShader(Identifier.of("pupper", "pos_color.vsh")) - .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) - .withDepthWrite(false) - .withBlend(BlendFunction.TRANSLUCENT) - .withCull(false) - .build() - ); - + public static final RenderPipeline UI_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(Identifier.of("pupper", "pipeline/ui_textured")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.DrawMode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "ui_textured")) - .withFragmentShader(Identifier.of("pupper", "ui_textured")) - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .withBlend(BlendFunction.TRANSLUCENT) - .withDepthWrite(false) + .withLocation(getLocation("pipeline/ui_textured")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.Mode.TRIANGLES) + .withVertexShader(getLocation("ui_textured")) + .withFragmentShader(getLocation("ui_textured")) + .withSampler("u_Texture") + .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) + .withCull(true) .build() ); public static final RenderPipeline UI_ROUNDED_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(Identifier.of("pupper", "pipeline/ui_rounded_textured")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.DrawMode.TRIANGLES) - .withVertexShader(Identifier.of("pupper", "ui_textured")) - .withFragmentShader(Identifier.of("pupper", "ui_rounded_textured")) // 指向新的 SDF Shader - .withBlend(BlendFunction.TRANSLUCENT) + .withLocation(getLocation("pipeline/ui_rounded_textured")) + .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.Mode.TRIANGLES) + .withVertexShader(getLocation("ui_textured")) + .withFragmentShader(getLocation("ui_rounded_textured")) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) .build() ); @@ -158,7 +137,7 @@ public static void precompile() { } private static Identifier getLocation(String path) { - return Identifier.of("pupper", path); + return Identifier.fromNamespaceAndPath("pupper", path); } } // based on meteor diff --git a/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java b/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java index 923477b..fd481e9 100644 --- a/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java +++ b/src/main/java/cn/pupperclient/shader/PupperVertexFormats.java @@ -13,11 +13,6 @@ public abstract class PupperVertexFormats { .add("Color", VertexFormatElement.COLOR) .build(); - public static final VertexFormat POS3_COLOR = VertexFormat.builder() - .add("Position", VertexFormatElement.POSITION) - .add("Color", VertexFormatElement.COLOR) - .build(); - public static final VertexFormat POS2_COLOR_TEX = VertexFormat.builder() .add("Position", VertexFormatElement.POSITION) .add("Color", VertexFormatElement.COLOR) diff --git a/src/main/java/cn/pupperclient/shader/ShapeMode.java b/src/main/java/cn/pupperclient/shader/ShapeMode.java deleted file mode 100644 index f188c01..0000000 --- a/src/main/java/cn/pupperclient/shader/ShapeMode.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). - * Copyright (c) Meteor Development. - */ - -package cn.pupperclient.shader; - -public enum ShapeMode { - Lines, - Sides, - Both; - - public boolean lines() { - return this == Lines || this == Both; - } - - public boolean sides() { - return this == Sides ||this == Both; - } -} diff --git a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java index c63186d..ace89ef 100644 --- a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java +++ b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java @@ -122,7 +122,7 @@ public void draw() { PupperMeshRenderer.begin() .attachments(mc.getMainRenderTarget()) - .pipeline(PupperRenderPipelines.PASSTHROUGH) + .pipeline(PupperRenderPipelines.BLUR_PASSTHROUGH) .fullscreen() .sampler("u_Texture", fbos[0], RenderSystem.getSamplerCache().getClampToEdge(FilterMode.LINEAR)) // todo ??? .end(); From 463ec5737965db6673bab79e225ca2b176bfe6bf Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 18:53:44 +0800 Subject: [PATCH 14/45] chore: update version --- src/main/java/cn/pupperclient/PupperClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/pupperclient/PupperClient.java b/src/main/java/cn/pupperclient/PupperClient.java index f383b29..8f9432b 100644 --- a/src/main/java/cn/pupperclient/PupperClient.java +++ b/src/main/java/cn/pupperclient/PupperClient.java @@ -34,7 +34,7 @@ public class PupperClient implements IMinecraft { private static final String CONFIG_FILE_NAME = "pupper.ok"; private static final String ICON_PATH = "assets/pupper/logo.png"; private static final String CLIENT_NAME = "Pupper Client"; - private static final String CLIENT_VERSION = "26.1.1"; + private static final String CLIENT_VERSION = "mc26.1.2-pupper26.4.1"; private static final String MOD_ID = "pupper"; private static final PupperClient INSTANCE = new PupperClient(); From 3f6caf95d2a0b3bd6c61b9a4671ac8475e15bfd1 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 19:52:00 +0800 Subject: [PATCH 15/45] fix(mixin): Port Minecraft 26.1 --- .../event/client/DrawItemHotbarEvent.java | 10 + .../event/client/RenderGameOverlayEvent.java | 8 +- .../event/server/PacketHandler.java | 46 ++--- .../management/cape/CapeManager.java | 23 ++- .../accessors/EntityRenderStateAccessor.java | 15 ++ .../client/MixinClientBrandRetriever.java | 2 - .../minecraft/client/MixinKeyboard.java | 25 ++- .../client/MixinMinecraftClient.java | 8 +- .../mixins/minecraft/client/MixinMouse.java | 85 ++++----- .../minecraft/client/gui/MixinBossBarHud.java | 177 ++++++++++++------ .../minecraft/client/gui/MixinChatHud.java | 2 +- .../client/gui/MixinLanguageScreen.java | 2 - .../minecraft/client/gui/MixinPackScreen.java | 6 +- .../client/gui/MixinSplashScreen.java | 38 ++-- .../client/gui/MixinTitleScreen.java | 2 +- .../client/render/GuiRendererMixin.java | 5 - .../client/render/LightmapMixin.java | 36 ++++ .../minecraft/client/render/MixinCamera.java | 45 +++-- .../client/render/MixinEntityRenderer.java | 101 ++++++---- .../client/render/MixinGameRenderer.java | 50 ----- .../client/render/MixinHeldItemRenderer.java | 44 ++--- .../client/render/MixinInGameHud.java | 17 +- .../render/MixinInGameOverlayRenderer.java | 4 +- .../render/MixinLightmapTextureManager.java | 20 -- .../client/render/PupperInGameHud.java | 176 +---------------- .../client/render/PupperScoreboard.java | 2 +- .../client/sound/MixinSoundSystem.java | 44 +++-- .../MixinAbstractClientPlayerEntity.java | 21 +-- .../network/MixinClientConnection.java | 20 +- ...PlayerInteractEntityC2SPacketAccessor.java | 15 -- .../world/MixinClientWorldProperties.java | 2 +- .../utils/render/RenderUtils.java | 2 - src/main/resources/fabric.mod.json | 8 + src/main/resources/pupper.mixins.json | 3 +- 34 files changed, 471 insertions(+), 593 deletions(-) create mode 100644 src/main/java/cn/pupperclient/event/client/DrawItemHotbarEvent.java create mode 100644 src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java create mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/LightmapMixin.java delete mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java delete mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java diff --git a/src/main/java/cn/pupperclient/event/client/DrawItemHotbarEvent.java b/src/main/java/cn/pupperclient/event/client/DrawItemHotbarEvent.java new file mode 100644 index 0000000..f9fe0a7 --- /dev/null +++ b/src/main/java/cn/pupperclient/event/client/DrawItemHotbarEvent.java @@ -0,0 +1,10 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.event.client; + +import cn.pupperclient.event.Event; + +public class DrawItemHotbarEvent extends Event { +} diff --git a/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java b/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java index 27e6c9f..e9f556c 100644 --- a/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java +++ b/src/main/java/cn/pupperclient/event/client/RenderGameOverlayEvent.java @@ -1,17 +1,17 @@ package cn.pupperclient.event.client; import cn.pupperclient.event.Event; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; public class RenderGameOverlayEvent extends Event { - private final GuiGraphics context; + private final GuiGraphicsExtractor context; - public RenderGameOverlayEvent(GuiGraphics context) { + public RenderGameOverlayEvent(GuiGraphicsExtractor context) { this.context = context; } - public GuiGraphics getContext() { + public GuiGraphicsExtractor getContext() { return context; } } diff --git a/src/main/java/cn/pupperclient/event/server/PacketHandler.java b/src/main/java/cn/pupperclient/event/server/PacketHandler.java index 5773dd1..278ca6f 100644 --- a/src/main/java/cn/pupperclient/event/server/PacketHandler.java +++ b/src/main/java/cn/pupperclient/event/server/PacketHandler.java @@ -1,6 +1,7 @@ package cn.pupperclient.event.server; import cn.pupperclient.event.EventBus; +import cn.pupperclient.event.EventListener; import cn.pupperclient.event.client.ReceivePacketEvent; import cn.pupperclient.event.client.SendPacketEvent; import cn.pupperclient.event.server.impl.AttackEntityEvent; @@ -8,37 +9,27 @@ import cn.pupperclient.event.server.impl.GameJoinEvent; import cn.pupperclient.event.server.impl.ReceiveChatEvent; import cn.pupperclient.event.server.impl.SendChatEvent; -import cn.pupperclient.mixin.mixins.minecraft.network.packet.PlayerInteractEntityC2SPacketAccessor; import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundDamageEventPacket; -import net.minecraft.network.protocol.game.ClientboundLoginPacket; -import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; -import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; -import net.minecraft.network.protocol.game.ServerboundChatPacket; -import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.network.protocol.game.*; public class PacketHandler { - public final EventBus.EventListener onSendPacket = packetEvent -> { + @EventListener + public void onSendPacket(SendPacketEvent packetEvent) { Packet basePacket = packetEvent.getPacket(); - if (basePacket instanceof ServerboundInteractPacket) { + if (basePacket instanceof ServerboundInteractPacket packet) { - ServerboundInteractPacket packet = (ServerboundInteractPacket) basePacket; - ServerboundInteractPacket.ActionType type = ((PlayerInteractEntityC2SPacketAccessor) packet) - .getInteractTypeHandler().getType(); - - if (type.equals(ServerboundInteractPacket.ActionType.ATTACK)) { + if (!packet.usingSecondaryAction()) { EventBus.getInstance() - .post(new AttackEntityEvent(((PlayerInteractEntityC2SPacketAccessor) packet).entityId())); + .post(new AttackEntityEvent((packet.entityId()))); } } - if (basePacket instanceof ServerboundChatPacket) { + if (basePacket instanceof ServerboundChatPacket packet) { - ServerboundChatPacket packet = (ServerboundChatPacket) basePacket; - SendChatEvent event = new SendChatEvent(packet.message()); + SendChatEvent event = new SendChatEvent(packet.message()); EventBus.getInstance().post(event); @@ -48,21 +39,19 @@ public class PacketHandler { } }; - public final EventBus.EventListener onReceivePacket = packetEvent -> { + @EventListener + public void onReceivePacket(ReceivePacketEvent packetEvent) { Packet basePacket = packetEvent.getPacket(); - if (basePacket instanceof ClientboundDamageEventPacket) { - - ClientboundDamageEventPacket packet = (ClientboundDamageEventPacket) basePacket; + if (basePacket instanceof ClientboundDamageEventPacket packet) { - EventBus.getInstance().post(new DamageEntityEvent(packet.entityId())); + EventBus.getInstance().post(new DamageEntityEvent(packet.entityId())); } - if (basePacket instanceof ClientboundPlayerChatPacket) { + if (basePacket instanceof ClientboundPlayerChatPacket packet) { - ClientboundPlayerChatPacket packet = (ClientboundPlayerChatPacket) basePacket; - ReceiveChatEvent event = new ReceiveChatEvent(packet.body().content()); + ReceiveChatEvent event = new ReceiveChatEvent(packet.body().content()); EventBus.getInstance().post(event); @@ -71,10 +60,9 @@ public class PacketHandler { } } - if (basePacket instanceof ClientboundSystemChatPacket) { + if (basePacket instanceof ClientboundSystemChatPacket packet) { - ClientboundSystemChatPacket packet = (ClientboundSystemChatPacket) basePacket; - ReceiveChatEvent event = new ReceiveChatEvent(packet.content().getString()); + ReceiveChatEvent event = new ReceiveChatEvent(packet.content().getString()); EventBus.getInstance().post(event); diff --git a/src/main/java/cn/pupperclient/management/cape/CapeManager.java b/src/main/java/cn/pupperclient/management/cape/CapeManager.java index 0240655..4d73ec3 100644 --- a/src/main/java/cn/pupperclient/management/cape/CapeManager.java +++ b/src/main/java/cn/pupperclient/management/cape/CapeManager.java @@ -1,5 +1,6 @@ package cn.pupperclient.management.cape; +import cn.pupperclient.PupperClient; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.systems.RenderSystem; import java.io.Closeable; @@ -9,13 +10,14 @@ import java.util.concurrent.Executors; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.DynamicTexture; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.ClientAsset; +import net.minecraft.resources.Identifier; public class CapeManager implements Closeable { private static CapeManager instance; - private final Map loadedCapes = Collections.synchronizedMap(new HashMap<>()); - private final Map loadedCapeTextures = Collections.synchronizedMap(new HashMap<>()); + private final Map loadedCapes = Collections.synchronizedMap(new HashMap<>()); + private final Map loadedCapeTextures = Collections.synchronizedMap(new HashMap<>()); private String selectedCapeId = null; @@ -38,9 +40,10 @@ public String getSelectedCapeId() { return selectedCapeId; } - public ResourceLocation getSelectedCapeTexture() { + public ClientAsset.Texture getSelectedCapeTexture() { if (selectedCapeId == null) return null; - return getLoadedCape(selectedCapeId); + var capeTexture = getLoadedCape(selectedCapeId); + return new ClientAsset.ResourceTexture(Identifier.fromNamespaceAndPath(PupperClient.getModId(), "capes/selectedcape"), capeTexture); } public void clearSelectedCape() { @@ -51,10 +54,10 @@ public void loadCape(String id, byte[] textureData) { if (id == null || textureData == null) return; executorService.submit(() -> { - RenderSystem.recordRenderCall(() -> { + RenderSystem.queueFencedTask(() -> { DynamicTexture nativeImage = createNativeTexture(textureData); if (nativeImage != null) { - ResourceLocation identifier = ResourceLocation.fromNamespaceAndPath("pupper", namespace + "/" + id); + Identifier identifier = Identifier.fromNamespaceAndPath("pupper", namespace + "/" + id); Minecraft.getInstance().getTextureManager().register(identifier, nativeImage); loadedCapes.put(id, identifier); loadedCapeTextures.put(identifier, nativeImage); @@ -70,7 +73,7 @@ public void unloadCape(String id) { selectedCapeId = null; } - ResourceLocation cape = loadedCapes.remove(id); + Identifier cape = loadedCapes.remove(id); if (cape != null) { DynamicTexture texture = loadedCapeTextures.remove(cape); if (texture != null) { @@ -80,7 +83,7 @@ public void unloadCape(String id) { } } - public ResourceLocation getLoadedCape(String id) { + public Identifier getLoadedCape(String id) { return id != null ? loadedCapes.get(id) : null; } @@ -91,7 +94,7 @@ public Set getLoadedCapeIds() { private static DynamicTexture createNativeTexture(byte[] bytes) { if (bytes == null) return null; try { - return new DynamicTexture(NativeImage.read(bytes)); + return new DynamicTexture(() -> "pupper_capetexture", NativeImage.read(bytes)); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java new file mode 100644 index 0000000..01fd132 --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java @@ -0,0 +1,15 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.mixin.mixins.accessors; + +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(EntityRenderState.class) +public interface EntityRenderStateAccessor { + @Accessor("id") + int getEntityId(); +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java index 7e940d4..a2d1d45 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java @@ -2,7 +2,6 @@ import cn.pupperclient.PupperClient; import net.minecraft.client.ClientBrandRetriever; -import net.minecraft.obfuscate.DontObfuscate; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -12,7 +11,6 @@ public class MixinClientBrandRetriever { * @author oneachina * @reason Set Pupper Brand */ - @DontObfuscate @Overwrite public static String getClientModName() { return PupperClient.getInstance().getName() + "(" + PupperClient.getInstance().getVersion() + ")"; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java index 6a362de..137ff64 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinKeyboard.java @@ -15,18 +15,17 @@ @Mixin(KeyboardHandler.class) public abstract class MixinKeyboard { - @Inject( - method = "keyPress(JIIII)V", + method = "keyPress(JILnet/minecraft/client/input/KeyEvent;)V", at = @At( value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;click(Lcom/mojang/blaze3d/platform/InputConstants$Key;)V", shift = At.Shift.AFTER ) ) - private void onKeyPressed(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + private void onKeyPressed(long handle, int action, net.minecraft.client.input.KeyEvent event, CallbackInfo ci) { if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { - InputConstants.Key inputKey = InputConstants.getKey(key, scancode); + InputConstants.Key inputKey = InputConstants.getKey(event); for (KeybindSetting setting : PupperClient.getInstance().getModManager().getKeybindSettings()) { if (setting.getKey().equals(inputKey)) { setting.setPressed(); @@ -37,16 +36,16 @@ private void onKeyPressed(long window, int key, int scancode, int action, int mo } @Inject( - method = "keyPress(JIIII)V", + method = "keyPress(JILnet/minecraft/client/input/KeyEvent;)V", at = @At( value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;set(Lcom/mojang/blaze3d/platform/InputConstants$Key;Z)V", shift = At.Shift.AFTER ) ) - private void onKeyReleased(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + private void onKeyReleased(long handle, int action, net.minecraft.client.input.KeyEvent event, CallbackInfo ci) { if (action == GLFW.GLFW_RELEASE) { - InputConstants.Key inputKey = InputConstants.getKey(key, scancode); + InputConstants.Key inputKey = InputConstants.getKey(event); for (KeybindSetting setting : PupperClient.getInstance().getModManager().getKeybindSettings()) { if (setting.getKey().equals(inputKey)) { setting.setKeyDown(false); @@ -55,13 +54,11 @@ private void onKeyReleased(long window, int key, int scancode, int action, int m } } - @Inject( - at = {@At("HEAD")}, - method = {"keyPress"} - ) - private void onKeyPress(long pWindowPointer, int pKey, int pScanCode, int pAction, int pModifiers, CallbackInfo ci) { - if (pKey != -1 && PupperClient.getInstance() != null && EventBus.getInstance() != null) { - EventBus.getInstance().post(new KeyEvent(pKey, pAction != 0)); + @Inject(method = "keyPress(JILnet/minecraft/client/input/KeyEvent;)V", at = @At("HEAD")) + private void onKeyPress(long handle, int action, net.minecraft.client.input.KeyEvent event, CallbackInfo ci) { + int key = event.key(); + if (key != -1 && EventBus.getInstance() != null) { + EventBus.getInstance().post(new KeyEvent(key, action != 0)); } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index 76aa974..14ed1a2 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -4,6 +4,7 @@ import java.io.IOException; import cn.pupperclient.event.client.ResolutionChangedEvent; +import cn.pupperclient.skia.Skia; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; import net.minecraft.client.gui.screens.Screen; @@ -184,7 +185,12 @@ private void onBeforeFlipFrame(CallbackInfo ci) { if (screen instanceof SimpleSoarGui) { return; } - SkiaContext.draw(canvas -> EventBus.getInstance().post(new RenderSkiaEvent(canvas))); + SkiaContext.draw((context) -> { + Skia.save(); + Skia.scale((float) Minecraft.getInstance().getWindow().getGuiScale()); + EventBus.getInstance().post(new RenderSkiaEvent(context)); + Skia.restore(); + }); } @Override diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java index 7dd0adf..c36543c 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMouse.java @@ -3,6 +3,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.client.MouseClickEvent; import cn.pupperclient.management.mod.impl.hud.CPSDisplayMod; +import net.minecraft.client.input.MouseButtonInfo; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -20,36 +21,35 @@ @Mixin(MouseHandler.class) public abstract class MixinMouse { - @Inject(method = "onPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;click(Lcom/mojang/blaze3d/platform/InputConstants$Key;)V", shift = At.Shift.AFTER)) - public void onPressed(long window, int button, int action, int mods, CallbackInfo ci) { - - for (KeybindSetting s : PupperClient.getInstance().getModManager().getKeybindSettings()) { - - if (s.getKey().equals(Type.MOUSE.getOrCreate(button))) { - - if (action == GLFW.GLFW_PRESS) { - s.setPressed(); - } - - s.setKeyDown(true); - } - } - } + @Inject(method = "onButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;click(Lcom/mojang/blaze3d/platform/InputConstants$Key;)V", shift = At.Shift.AFTER)) + private void onButtonPressed(long handle, MouseButtonInfo rawButtonInfo, int action, CallbackInfo ci) { + int button = rawButtonInfo.button(); + if (action == GLFW.GLFW_PRESS) { + for (KeybindSetting s : PupperClient.getInstance().getModManager().getKeybindSettings()) { + if (s.getKey().equals(Type.MOUSE.getOrCreate(button))) { + s.setPressed(); + s.setKeyDown(true); + } + } + } + } - @Inject(method = "onPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;set(Lcom/mojang/blaze3d/platform/InputConstants$Key;Z)V", shift = At.Shift.AFTER, ordinal = 0)) - public void onReleased(long window, int button, int action, int mods, CallbackInfo ci) { - for (KeybindSetting s : PupperClient.getInstance().getModManager().getKeybindSettings()) { - if (s.getKey().equals(Type.MOUSE.getOrCreate(button))) { - s.setKeyDown(false); - } - } - } + @Inject(method = "onButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;set(Lcom/mojang/blaze3d/platform/InputConstants$Key;Z)V", shift = At.Shift.AFTER)) + private void onButtonReleased(long window, MouseButtonInfo rawButtonInfo, int action, CallbackInfo ci) { + int button = rawButtonInfo.button(); + if (action == GLFW.GLFW_RELEASE) { + for (KeybindSetting s : PupperClient.getInstance().getModManager().getKeybindSettings()) { + if (s.getKey().equals(Type.MOUSE.getOrCreate(button))) { + s.setKeyDown(false); + } + } + } + } - @Inject(method = "onPress", at = @At("HEAD")) - private void onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) { + @Inject(method = "onButton", at = @At("HEAD")) + private void onMouseButtonEvent(long window, MouseButtonInfo rawButtonInfo, int action, CallbackInfo ci) { if (action == GLFW.GLFW_PRESS) { Minecraft client = Minecraft.getInstance(); - if (client == null) return; double rawX = client.mouseHandler.xpos(); double rawY = client.mouseHandler.ypos(); @@ -59,33 +59,28 @@ private void onMouseButton(long window, int button, int action, int mods, Callba double scaledX = rawX / scaleFactor; double scaledY = win.getGuiScaledHeight() - (rawY / scaleFactor); - EventBus.getInstance().post(new MouseClickEvent(button, scaledX, scaledY)); + EventBus.getInstance().post(new MouseClickEvent(rawButtonInfo.button(), scaledX, scaledY)); } } - @Inject(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;setSelectedHotbarSlot(I)V", shift = At.Shift.BEFORE), cancellable = true) - private void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) { - - MouseScrollEvent event = new MouseScrollEvent(vertical); - - EventBus.getInstance().post(event); + @Inject(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;setSelectedSlot(I)V"), cancellable = true) + private void onMouseScroll(long window, double x_offset, double y_offset, CallbackInfo ci) { + MouseScrollEvent event = new MouseScrollEvent(y_offset); + EventBus.getInstance().post(event); + if (event.isCancelled()) { + ci.cancel(); + } + } - if (event.isCancelled()) { - ci.cancel(); - } - } + @Inject(method = "onButton", at = @At("HEAD")) + private void onMouseButtonForCPS(long window, MouseButtonInfo rawButtonInfo, int action, CallbackInfo ci) { + if (action != GLFW.GLFW_PRESS) return; - @Inject(method = "onPress", at = @At("HEAD")) - public void onMouseButtonForCPS(long window, int button, int action, int mods, CallbackInfo ci) { - CPSDisplayMod cpsDisplayMod = PupperClient.getInstance().getModManager().getMods() + PupperClient.getInstance().getModManager().getMods() .stream() .filter(mod -> mod instanceof CPSDisplayMod) .map(mod -> (CPSDisplayMod) mod) - .findFirst() - .orElse(null); + .findFirst().ifPresent(cpsDisplayMod -> cpsDisplayMod.onMouseClick(rawButtonInfo.button(), true)); - if (cpsDisplayMod != null && action == GLFW.GLFW_PRESS) { - cpsDisplayMod.onMouseClick(button, true); - } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java index 49ecd3a..bdc314d 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinBossBarHud.java @@ -1,81 +1,138 @@ package cn.pupperclient.mixin.mixins.minecraft.client.gui; -import java.util.Map; -import java.util.UUID; +import cn.pupperclient.management.mod.api.Position; +import cn.pupperclient.management.mod.impl.hud.BossBarMod; +import com.google.common.collect.Maps; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.BossHealthOverlay; import net.minecraft.client.gui.components.LerpingBossEvent; +import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Mth; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.BossEvent; 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.callback.CallbackInfo; -import com.google.common.collect.Maps; -import cn.pupperclient.management.mod.api.Position; -import cn.pupperclient.management.mod.impl.hud.BossBarMod; +import java.util.Map; +import java.util.UUID; @Mixin(BossHealthOverlay.class) public abstract class MixinBossBarHud { - @Shadow - @Final - private Minecraft minecraft; - - @Shadow - @Final - final Map events = Maps.newLinkedHashMap(); - - @Shadow - public abstract void drawBar(GuiGraphics context, int x, int y, BossEvent bossBar); - - @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void render(GuiGraphics context, CallbackInfo ci) { - - BossBarMod mod = BossBarMod.getInstance(); - - if (mod.isEnabled() && !mod.isVanillaPosition()) { - Position position = mod.getPosition(); - onCustomRender(context, (int) position.getX(), (int) position.getY()); - position.setScale(1.0F); - position.setSize(182, 14); - ci.cancel(); - } else if (!mod.isEnabled()) { - ci.cancel(); - } - } - - public void onCustomRender(GuiGraphics context, int x, int y) { - - if (!this.events.isEmpty()) { - - ProfilerFiller profiler = Profiler.get(); - profiler.push("bossHealth"); - int j = y; - - for (LerpingBossEvent clientBossBar : this.events.values()) { - - Component text = clientBossBar.getName(); - int m = this.minecraft.font.width(text); - int n = x - m / 2; - context.drawString(this.minecraft.font, text, n, j, 16777215); - - int k = x - 91; - this.drawBar(context, k, j + 9, clientBossBar); - - j += 10 + 9; - if (j >= context.guiHeight() / 3) { - break; - } - } - - profiler.pop(); - } - } + @Shadow + @Final + private Minecraft minecraft; + + @Shadow + @Final + private Map events = Maps.newLinkedHashMap(); + + @Shadow + private void extractBar(GuiGraphicsExtractor graphics, int x, int y, BossEvent event, int width, Identifier[] sprites, Identifier[] overlaySprites) { + } + + @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) + private void onExtractRenderState(GuiGraphicsExtractor graphics, CallbackInfo ci) { + BossBarMod mod = BossBarMod.getInstance(); + + if (mod.isEnabled()) { + if (!mod.isVanillaPosition()) { + Position position = mod.getPosition(); + onCustomRender(graphics, (int) position.getX(), (int) position.getY()); + position.setScale(1.0F); + position.setSize(182, 14); + ci.cancel(); + } + } else { + ci.cancel(); + } + } + + @Unique + private void onCustomRender(GuiGraphicsExtractor graphics, int x, int y) { + if (!this.events.isEmpty()) { + ProfilerFiller profiler = Profiler.get(); + profiler.push("bossHealth"); + + int currentY = y; + for (LerpingBossEvent event : this.events.values()) { + Component name = event.getName(); + int textWidth = this.minecraft.font.width(name); + int textX = x - textWidth / 2; + graphics.text(this.minecraft.font, name, textX, currentY, -1); + + int barX = x - 91; + int barY = currentY + 9; + this.drawCustomBar(graphics, barX, barY, event); + + currentY += 19; // 10 + 9 + if (currentY >= graphics.guiHeight() / 3) { + break; + } + } + + profiler.pop(); + } + } + + @Unique + private void drawCustomBar(GuiGraphicsExtractor graphics, int x, int y, BossEvent event) { + // 绘制背景 + Identifier[] bgSprites = new Identifier[]{ + Identifier.withDefaultNamespace("boss_bar/pink_background"), + Identifier.withDefaultNamespace("boss_bar/blue_background"), + Identifier.withDefaultNamespace("boss_bar/red_background"), + Identifier.withDefaultNamespace("boss_bar/green_background"), + Identifier.withDefaultNamespace("boss_bar/yellow_background"), + Identifier.withDefaultNamespace("boss_bar/purple_background"), + Identifier.withDefaultNamespace("boss_bar/white_background") + }; + Identifier[] progressSprites = new Identifier[]{ + Identifier.withDefaultNamespace("boss_bar/pink_progress"), + Identifier.withDefaultNamespace("boss_bar/blue_progress"), + Identifier.withDefaultNamespace("boss_bar/red_progress"), + Identifier.withDefaultNamespace("boss_bar/green_progress"), + Identifier.withDefaultNamespace("boss_bar/yellow_progress"), + Identifier.withDefaultNamespace("boss_bar/purple_progress"), + Identifier.withDefaultNamespace("boss_bar/white_progress") + }; + Identifier[] overlayBgSprites = new Identifier[]{ + Identifier.withDefaultNamespace("boss_bar/notched_6_background"), + Identifier.withDefaultNamespace("boss_bar/notched_10_background"), + Identifier.withDefaultNamespace("boss_bar/notched_12_background"), + Identifier.withDefaultNamespace("boss_bar/notched_20_background") + }; + Identifier[] overlayProgressSprites = new Identifier[]{ + Identifier.withDefaultNamespace("boss_bar/notched_6_progress"), + Identifier.withDefaultNamespace("boss_bar/notched_10_progress"), + Identifier.withDefaultNamespace("boss_bar/notched_12_progress"), + Identifier.withDefaultNamespace("boss_bar/notched_20_progress") + }; + + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, + bgSprites[event.getColor().ordinal()], 182, 5, 0, 0, x, y, 182, 5); + if (event.getOverlay() != BossEvent.BossBarOverlay.PROGRESS) { + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, + overlayBgSprites[event.getOverlay().ordinal() - 1], 182, 5, 0, 0, x, y, 182, 5); + } + + int progressWidth = Mth.lerpDiscrete(event.getProgress(), 0, 182); + if (progressWidth > 0) { + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, + progressSprites[event.getColor().ordinal()], 182, 5, 0, 0, x, y, progressWidth, 5); + if (event.getOverlay() != BossEvent.BossBarOverlay.PROGRESS) { + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, + overlayProgressSprites[event.getOverlay().ordinal() - 1], 182, 5, 0, 0, x, y, progressWidth, 5); + } + } + } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java index 58cfc07..d079970 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinChatHud.java @@ -12,7 +12,7 @@ @Mixin(ChatComponent.class) public abstract class MixinChatHud { - @Inject(method = "addMessage(Lnet/minecraft/network/chat/Component;)V", at = @At("HEAD")) + @Inject(method = "addClientSystemMessage", at = @At("HEAD")) private void onChatMessage(Component message, CallbackInfo ci) { String rawMessage = message.getString(); if (rawMessage.startsWith("§7[§bPupper§7]")) return; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java index 462c3a5..6516fdf 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinLanguageScreen.java @@ -5,8 +5,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import static cn.pupperclient.utils.minecraft.interfaces.IMinecraft.client; - import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.options.LanguageSelectScreen; import net.minecraft.network.chat.Component; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java index 1fa8ac6..a1ec59d 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinPackScreen.java @@ -22,11 +22,7 @@ protected MixinPackScreen(Component title) { private void onInit(CallbackInfo ci) { Button.Builder builder = Button - .builder(Component.nullToEmpty("Convert"), button -> { - if (minecraft != null) { - minecraft.setScreen(new GuiResourcePackConvert(this)); - } - }).size(98, 20); + .builder(Component.nullToEmpty("Convert"), _ -> minecraft.setScreen(new GuiResourcePackConvert(this))).size(98, 20); builder.pos(width - 98 - 5, 5); this.addRenderableWidget(builder.build()); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java index 83be38e..a4177d9 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java @@ -1,12 +1,18 @@ package cn.pupperclient.mixin.mixins.minecraft.client.gui; +import cn.pupperclient.PupperLogger; import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.context.SkiaContext; import cn.pupperclient.skia.font.Fonts; +import com.mojang.blaze3d.opengl.GlTexture; import io.github.humbleui.skija.Canvas; import io.github.humbleui.skija.Font; import io.github.humbleui.types.Rect; import java.awt.Color; + +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Util; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -18,12 +24,8 @@ import java.util.Optional; import java.util.function.Consumer; -import net.minecraft.Util; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.LoadingOverlay; -import net.minecraft.client.renderer.texture.SimpleTexture; -import net.minecraft.resources.ResourceLocation; @Mixin(LoadingOverlay.class) public abstract class MixinSplashScreen { @@ -36,7 +38,7 @@ public abstract class MixinSplashScreen { @Unique private long soar_animationStartTime = -1L; @Unique private long soar_reloadStartTime = -1L; @Unique private static final long MAX_RELOAD_TIME = 15_000L; - @Unique private static final ResourceLocation CUSTOM_LOGO = ResourceLocation.fromNamespaceAndPath("pupper", "logo.png"); + @Unique private static final Identifier CUSTOM_LOGO = Identifier.fromNamespaceAndPath("pupper", "logo.png"); @Unique private static final int LOGO_ACTUAL_SIZE = 1080; @Unique private static final float LOGO_SCALE = 0.15f; @Unique private static final long ANIMATION_TOTAL_TIME = 4500L; @@ -61,13 +63,11 @@ public abstract class MixinSplashScreen { @Unique private void ensureLogoTexture() { var tm = this.minecraft.getTextureManager(); - if (tm.getTexture(CUSTOM_LOGO) == null) { - tm.registerAndLoad(CUSTOM_LOGO, new SimpleTexture(CUSTOM_LOGO)); - } + tm.getTexture(CUSTOM_LOGO); } - @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void pupper_takeOverAndRender(GuiGraphics context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) + private void pupper_takeOverAndRender(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { int width = Minecraft.getInstance().getWindow().getScreenWidth(); int height = Minecraft.getInstance().getWindow().getScreenHeight(); @@ -84,9 +84,7 @@ private void pupper_takeOverAndRender(GuiGraphics context, int mouseX, int mouse ci.cancel(); - SkiaContext.draw(canvas -> { - renderWithSkia(canvas, width, height, mouseX, mouseY); - }); + SkiaContext.draw(canvas -> renderWithSkia(canvas, width, height, mouseX, mouseY)); } @Unique @@ -144,7 +142,7 @@ private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, in } // Check if tap prompt was clicked - if (!tapClicked && GLFW.glfwGetMouseButton(this.minecraft.getWindow().getWindow(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS) { + if (!tapClicked && GLFW.glfwGetMouseButton(this.minecraft.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS) { tapClicked = true; tapClickTime = Util.getMillis(); } @@ -248,8 +246,13 @@ private void renderLoadingScreen(int width, int height, long timePassed, float a @Unique private void drawLogo(int x, int y, int size, float alpha) { // Draw logo using Skia - int textureId = Minecraft.getInstance().getTextureManager().getTexture(CUSTOM_LOGO).getId(); - Skia.drawImage(textureId, x, y, size, size, alpha); + var textureId = Minecraft.getInstance().getTextureManager().getTexture(CUSTOM_LOGO).getTexture(); + + if (textureId instanceof GlTexture glTexture) { + Skia.drawImage(glTexture.glId(), x, y, size, size, alpha); + } else { + PupperLogger.warn("Splash", "don't have logo GlTexture"); + } } @Unique @@ -299,7 +302,7 @@ private void renderWelcomeScreen(int width, int height, long welcomeTimePassed, // Text transparency calculations float welcomeAlpha = 1.0f; // Welcome text always full opacity (no animation) - float ttsAlpha = 1.0f; // TTS text alpha + float ttsAlpha; // TTS text alpha if (clicked) { // After click: 2-second fade out for all text @@ -315,7 +318,6 @@ private void renderWelcomeScreen(int width, int height, long welcomeTimePassed, ttsAlpha = 0f; // Not displayed yet } // Welcome text remains at full opacity - welcomeAlpha = 1.0f; } // Draw welcome text (no animation, just fade out after click) diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java index fad9a8d..77ea983 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java @@ -23,7 +23,7 @@ public void onInit(CallbackInfo ci) { ci.cancel(); } - @Inject(method = "render", at = @At("HEAD"), cancellable = true) + @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) public void onRender(CallbackInfo ci) { ci.cancel(); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java index 9af618b..8624ba3 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java @@ -5,13 +5,11 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; import cn.pupperclient.PupperClient; -import cn.pupperclient.event.EventBus; import cn.pupperclient.mixin.mixins.accessors.GameRendererAccessor; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import cn.pupperclient.utils.render.RenderUtils; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.render.GuiRenderer; import net.minecraft.client.renderer.fog.FogRenderer; import net.minecraft.client.renderer.state.gui.GuiRenderState; @@ -36,9 +34,6 @@ public abstract class GuiRendererMixin implements IMinecraft { @Inject(method = "draw", at = @At("HEAD")) private void draw(CallbackInfo ci) { - var mouseX = (int) client.mouseHandler.getScaledXPos(client.getWindow()); - var mouseY = (int) client.mouseHandler.getScaledYPos(client.getWindow()); - var fogRenderer = ((GameRendererAccessor) client.gameRenderer).pupper$fogRenderer(); if (RenderUtils.canUpdate()) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/LightmapMixin.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/LightmapMixin.java new file mode 100644 index 0000000..95a6aaa --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/LightmapMixin.java @@ -0,0 +1,36 @@ +package cn.pupperclient.mixin.mixins.minecraft.client.render; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.GpuTexture; +import net.minecraft.client.renderer.Lightmap; +import net.minecraft.client.renderer.state.LightmapRenderState; +import net.minecraft.util.ARGB; +import net.minecraft.util.profiling.Profiler; +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 cn.pupperclient.management.mod.impl.render.FullbrightMod; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Lightmap.class) +public abstract class LightmapMixin { + @Shadow + @Final + private GpuTexture texture; + + @Inject(method = "render", at = @At("HEAD"), cancellable = true) + private void render$fullbright(LightmapRenderState renderState, CallbackInfo ci) { + if (FullbrightMod.getInstance().isEnabled()) { + var profile = Profiler.get(); + profile.push("lightmap"); + + RenderSystem.getDevice().createCommandEncoder().clearColorTexture(texture, ARGB.color(255, 255, 255, 255)); + + profile.pop(); + ci.cancel(); + } + } +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java index 6235d53..21b2d08 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinCamera.java @@ -1,5 +1,7 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +import cn.pupperclient.management.mod.impl.player.ZoomMod; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,7 +15,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.BlockGetter; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Camera.class) public abstract class MixinCamera { @@ -23,25 +25,32 @@ public abstract class MixinCamera { @Shadow protected abstract void setRotation(float yaw, float pitch); - - @Inject(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER)) - public void lockRotation(BlockGetter focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing, float tickDelta, CallbackInfo ci) { - - Minecraft client = Minecraft.getInstance(); - - if (FreelookMod.getInstance().isEnabled() && FreelookMod.getInstance().isActive() && cameraEntity instanceof LocalPlayer) { - IMixinCameraEntity cameraOverriddenEntity = (IMixinCameraEntity) cameraEntity; - - if (firstTime && Minecraft.getInstance().player != null) { - cameraOverriddenEntity.soarClient_CN$setCameraPitch(client.player.getXRot()); - cameraOverriddenEntity.soarClient_CN$setCameraYaw(client.player.getYRot()); - firstTime = false; - } - this.setRotation(cameraOverriddenEntity.soarClient_CN$getCameraYaw(), cameraOverriddenEntity.soarClient_CN$getCameraPitch()); + @Shadow + private @Nullable Entity entity; + + @Inject(method = "alignWithEntity", at = @At("TAIL")) + private void onAlignWithEntity(float partialTicks, CallbackInfo ci) { + if (!FreelookMod.getInstance().isEnabled() || !FreelookMod.getInstance().isActive()) return; + Entity entity = this.entity; + if (!(entity instanceof LocalPlayer)) return; + + var cameraOverridden = (IMixinCameraEntity) entity; + if (firstTime && Minecraft.getInstance().player != null) { + cameraOverridden.soarClient_CN$setCameraYaw(Minecraft.getInstance().player.getYRot()); + cameraOverridden.soarClient_CN$setCameraPitch(Minecraft.getInstance().player.getXRot()); + firstTime = false; } - if (FreelookMod.getInstance().isEnabled() && !FreelookMod.getInstance().isActive() && cameraEntity instanceof LocalPlayer) { - firstTime = true; + + this.setRotation(cameraOverridden.soarClient_CN$getCameraYaw(), cameraOverridden.soarClient_CN$getCameraPitch()); + } + + @Inject(method = "calculateFov", at = @At("RETURN"), cancellable = true) + private void onCalculateFov(float partialTicks, CallbackInfoReturnable cir) { + if (ZoomMod.getInstance().isEnabled()) { + float original = cir.getReturnValue(); + float modified = ZoomMod.getInstance().getFov(original); + cir.setReturnValue(modified); } } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java index 9ffb377..40697a4 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinEntityRenderer.java @@ -1,14 +1,7 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; import cn.pupperclient.PupperClient; -import org.joml.Matrix4f; -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.CallbackInfo; - +import cn.pupperclient.PupperLogger; import cn.pupperclient.management.mod.impl.misc.HypixelMod; import cn.pupperclient.utils.server.Server; import cn.pupperclient.utils.server.ServerUtils; @@ -18,50 +11,82 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.player.AbstractClientPlayer; 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.state.EntityRenderState; -import net.minecraft.client.renderer.entity.state.PlayerRenderState; +import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.network.chat.Component; import net.minecraft.util.CommonColors; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import org.joml.Matrix4f; +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.callback.CallbackInfo; @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer { + @Unique + private Entity entity; - @Shadow - @Final - private Font font; - - @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)I", ordinal = 1)) - private void onRenderLevelHead(S inState, Component text, PoseStack matrices, MultiBufferSource vertexConsumers, - int light, CallbackInfo ci) { - - Minecraft client = Minecraft.getInstance(); + @Shadow + @Final + private Font font; - if (inState instanceof PlayerRenderState state) { - if (ServerUtils.isJoin(Server.HYPIXEL)) { + @Inject(method = "extractRenderState", at = @At(value = "TAIL")) + private void getEntity(T entity, S state, float partialTicks, CallbackInfo ci) { + this.entity = entity; + } - AbstractClientPlayer player = (AbstractClientPlayer) client.level.getEntity(state.id); + @Inject( + method = "submitNameDisplay(Lnet/minecraft/client/renderer/entity/state/EntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/level/CameraRenderState;I)V", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V", + shift = At.Shift.AFTER + ) + ) + private void onRenderLevelHead(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera, int offset, CallbackInfo ci) { + Minecraft client = Minecraft.getInstance(); + if (client.level == null) return; - if (player != null && text.getString().contains(player.getName().getString())) { + if (!ServerUtils.isJoin(Server.HYPIXEL)) return; + if (!HypixelMod.getInstance().isEnabled() || !HypixelMod.getInstance().getLevelHeadSetting().isEnabled()) return; + if (state.entityType != EntityType.PLAYER) return; + if (state.nameTag == null) return; - if (HypixelMod.getInstance().isEnabled() - && HypixelMod.getInstance().getLevelHeadSetting().isEnabled()) { - String levelText = ChatFormatting.AQUA.toString() + "Level: " + ChatFormatting.YELLOW.toString() - + PupperClient.getInstance().getHypixelManager() - .getByUuid(player.getUUID().toString().replace("-", "")).getNetworkLevel(); + AbstractClientPlayer player = (AbstractClientPlayer) entity; + if (player == null) return; - float x = -font.width(levelText) / 2F; - float y = text.getString().contains("deadmau5") ? -20 : -10; - int color = (int) (client.options.getBackgroundOpacity(0.25F) * 255.0F) << 24; + String levelText = ChatFormatting.AQUA + "Level: " + ChatFormatting.YELLOW + + PupperClient.getInstance().getHypixelManager() + .getByUuid(player.getUUID().toString().replace("-", "")) + .getNetworkLevel(); - Matrix4f matrix4f = matrices.last().pose(); + float x = -font.width(levelText) / 2.0F; + float y = -10.0F; + int backgroundColor = (int) (client.options.getBackgroundOpacity(0.25F) * 255.0F) << 24; + Matrix4f matrix = poseStack.last().pose(); + int light = state.lightCoords; - font.drawInBatch(levelText, x, y, CommonColors.WHITE, false, matrix4f, vertexConsumers, - Font.DisplayMode.NORMAL, color, light); - } - } - } - } - } + if (submitNodeCollector instanceof MultiBufferSource bufferSource) { + font.drawInBatch( + Component.literal(levelText), + x, y, + CommonColors.WHITE, + false, + matrix, + bufferSource, + Font.DisplayMode.NORMAL, + backgroundColor, + light + ); + } else { + PupperLogger.warn("MixinEntityRenderer", "submitNodeCollector cast MultiBufferSource error"); + } + } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java index 934372e..b98f81d 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinGameRenderer.java @@ -1,65 +1,15 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; -import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.impl.render.NoHurtFov; -import cn.pupperclient.shader.impl.Kawaseblur; -import cn.pupperclient.utils.render.RenderUtils; -import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.util.profiling.Profiler; -import org.joml.Matrix4f; -import org.joml.Matrix4fStack; -import org.joml.Matrix4fc; -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.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; -import cn.pupperclient.management.mod.impl.player.ZoomMod; -import cn.pupperclient.management.mod.impl.settings.HUDModSettings; -import cn.pupperclient.management.mod.impl.settings.ModMenuSettings; -import cn.pupperclient.skia.Skia; -import cn.pupperclient.skia.context.SkiaContext; -import net.minecraft.client.Camera; -import net.minecraft.client.DeltaTracker; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GameRenderer; @Mixin(GameRenderer.class) public class MixinGameRenderer { - - @Shadow - @Final - private Minecraft minecraft; - - @Unique - private final PoseStack matrices = new PoseStack(); - - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", shift = At.Shift.BEFORE)) - public void render(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { - SkiaContext.draw((context) -> { - Skia.save(); - Skia.scale((float) Minecraft.getInstance().getWindow().getGuiScale()); - EventBus.getInstance().post(new RenderSkiaEvent(context)); - Skia.restore(); - }); - } - - @Inject(method = "getFov", at = @At(value = "RETURN", ordinal = 1), cancellable = true) - private void getFov(Camera camera, float tickDelta, boolean changingFov, CallbackInfoReturnable cir) { - if (ZoomMod.getInstance().isEnabled()) { - float value = cir.getReturnValue(); - value = ZoomMod.getInstance().getFov(value); - cir.setReturnValue(value); - } - } - @Inject(method = "bobHurt", at = @At("HEAD"), cancellable = true) private void tiltViewWhenHurt(CallbackInfo ci) { if (NoHurtFov.getInstance().isEnabled() && NoHurtFov.getInstance().nohurtFov.isEnabled()) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java index 546694a..b520eaf 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinHeldItemRenderer.java @@ -1,5 +1,6 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +import net.minecraft.client.renderer.SubmitNodeCollector; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -12,7 +13,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.renderer.ItemInHandRenderer; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.item.BowItem; @@ -25,54 +25,42 @@ public abstract class MixinHeldItemRenderer { @Shadow protected abstract void applyItemArmAttackTransform(PoseStack matrices, HumanoidArm arm, float swingProgress); - @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderItem(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;ZLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", ordinal = 1)) - private void renderFirstPersonItem(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, - float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, - MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - + @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderItem(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V", ordinal = 1)) + private void renderFirstPersonItem(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack item, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { OldAnimationsMod mod = OldAnimationsMod.getInstance(); if (item.getItem() instanceof BowItem && mod.isEnabled() && mod.isOldBow()) { - matrices.translate(0f, 0.05f, 0.04f); - matrices.scale(0.93f, 1f, 1f); + poseStack.translate(0f, 0.05f, 0.04f); + poseStack.scale(0.93f, 1f, 1f); } else if (item.getItem() instanceof FishingRodItem && mod.isEnabled() && mod.isOldRod()) { - matrices.translate(0.08f, -0.027f, -0.33f); - matrices.scale(0.93f, 1f, 1f); + poseStack.translate(0.08f, -0.027f, -0.33f); + poseStack.scale(0.93f, 1f, 1f); } } @Inject(method = "renderArmWithItem", at = @At("HEAD")) - private void applyCustomHand(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, - float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, - MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - + private void applyCustomHand(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { CustomHandMod mod = CustomHandMod.getInstance(); if(mod.isEnabled()) { - matrices.translate(mod.getX(), mod.getY(), mod.getZ()); - matrices.scale(mod.getScale(), mod.getScale(), mod.getScale()); + poseStack.translate(mod.getX(), mod.getY(), mod.getZ()); + poseStack.scale(mod.getScale(), mod.getScale(), mod.getScale()); } } @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 2, shift = At.Shift.AFTER)) - private void applyFoodSwingOffset(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, - float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, - MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - applyOldSwingOffset(player, hand, swingProgress, matrices); + private void applyFoodSwingOffset(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { + applyOldSwingOffset(player, hand, attack, poseStack); } @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 3, shift = At.Shift.AFTER)) - private void applyBlockingSwingOffset(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, - float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, - MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - applyOldSwingOffset(player, hand, swingProgress, matrices); + private void applyBlockingSwingOffset(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { + applyOldSwingOffset(player, hand, attack, poseStack); } @Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 4, shift = At.Shift.AFTER)) - private void applyBowSwingOffset(AbstractClientPlayer player, float tickDelta, float pitch, InteractionHand hand, - float swingProgress, ItemStack item, float equipProgress, PoseStack matrices, - MultiBufferSource vertexConsumers, int light, CallbackInfo ci) { - applyOldSwingOffset(player, hand, swingProgress, matrices); + private void applyBowSwingOffset(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) { + applyOldSwingOffset(player, hand, attack, poseStack); } @Unique diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java index 0e94aed..37f5f59 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java @@ -1,5 +1,10 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.world.entity.player.Player; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -10,8 +15,6 @@ import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; import net.minecraft.client.DeltaTracker; import net.minecraft.client.gui.Gui; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.RenderType; @Mixin(Gui.class) public class MixinInGameHud { @@ -20,15 +23,13 @@ public class MixinInGameHud { * @reason drawHeart */ @Overwrite - private void renderHeart(GuiGraphics context, Gui.HeartType type, int x, int y, boolean hardcore, boolean blinking, boolean half) { - + private void extractHeart(final GuiGraphicsExtractor graphics, final Gui.HeartType type, final int xo, final int yo, final boolean isHardcore, final boolean blinks, final boolean half) { OldAnimationsMod mod = OldAnimationsMod.getInstance(); - - context.blitSprite(RenderType::guiTextured, type.getSprite(hardcore, half, (!mod.isEnabled() || !mod.isDisableHeartFlash()) && blinking), x, y, 9, 9); + graphics.blitSprite(RenderPipelines.GUI, type.getSprite(isHardcore, half, (!mod.isEnabled() || !mod.isDisableHeartFlash()) && blinks), xo, yo, 9, 9); } - @Inject(method = "renderHotbarAndDecorations", at = @At("TAIL")) - private void renderMainHud(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) { + @Inject(method = "extractHotbarAndDecorations", at = @At("TAIL")) + private void renderMainHud(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { EventBus.getInstance().post(new RenderGameOverlayEvent(context)); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java index 896162e..601fe85 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameOverlayRenderer.java @@ -1,5 +1,6 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +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; @@ -24,8 +25,7 @@ private static void renderUnderwaterOverlay(Minecraft client, PoseStack matrices } @Inject(method = "renderFire", at = @At("HEAD"), cancellable = true) - private static void renderFireOverlay(PoseStack matrices, MultiBufferSource vertexConsumers, - CallbackInfo ci) { + private static void renderFireOverlay(PoseStack poseStack, MultiBufferSource bufferSource, TextureAtlasSprite sprite, CallbackInfo ci) { if (OverlayEditorMod.getInstance().isEnabled() && OverlayEditorMod.getInstance().isClearFire()) { ci.cancel(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java deleted file mode 100644 index 0781646..0000000 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinLightmapTextureManager.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.pupperclient.mixin.mixins.minecraft.client.render; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.renderer.LightTexture; -import cn.pupperclient.management.mod.impl.render.FullbrightMod; - -@Mixin(LightTexture.class) -public class MixinLightmapTextureManager { - - @ModifyExpressionValue(method = "updateLightTexture(F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/OptionInstance;get()Ljava/lang/Object;", ordinal = 1)) - private Object injectFullBright(Object original) { - if (FullbrightMod.getInstance().isEnabled()) { - return (double) FullbrightMod.getInstance().getGamma(); - } - return original; - } -} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java index b3907c1..129dfa7 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java @@ -1,11 +1,12 @@ package cn.pupperclient.mixin.mixins.minecraft.client.render; +import cn.pupperclient.event.EventBus; +import cn.pupperclient.event.client.DrawItemHotbarEvent; import net.minecraft.client.AttackIndicatorStatus; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Gui; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.player.Player; @@ -39,172 +40,11 @@ private Player getCameraPlayer() { @Unique private float slotAnimationProgress = 0f; @Unique private float offhandAlpha = 0f; - @Inject(method = "renderItemHotbar", at = @At("HEAD"), cancellable = true) - private void replaceHotbarRender(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) { - ci.cancel(); // 取消原版物品栏绘制 - drawCustomHotbar(context, tickCounter); - } - - @Unique - private void drawCustomHotbar(GuiGraphics context, DeltaTracker tickCounter) { - Player playerEntity = this.getCameraPlayer(); - if (playerEntity == null) return; - - ItemStack itemStack = playerEntity.getOffhandItem(); - HumanoidArm arm = playerEntity.getMainArm().getOpposite(); - int centerX = context.guiWidth() / 2; - int hotbarY = context.guiHeight() - 22; - - int selectedSlot = playerEntity.getInventory().selected; - updateSlotAnimation(selectedSlot); - updateOffhandAlpha(playerEntity); - - context.pose().pushPose(); - context.pose().translate(0.0F, 0.0F, -90.0F); - - // 绘制自定义白色背景 - drawCustomHotbarBackground(context, centerX, hotbarY, selectedSlot); - - // 绘制原版选择框 - context.blitSprite(RenderType::guiTextured, Gui.HOTBAR_SELECTION_SPRITE, - centerX - 91 - 1 + selectedSlot * 20, hotbarY - 1, 24, 23); - - // 绘制副手背景(带透明度) - if (!itemStack.isEmpty() || offhandAlpha > 0) { - drawOffhandBackground(context, centerX, hotbarY, arm, offhandAlpha); - } - - context.pose().popPose(); - - // 绘制物品(带动画) - for(int i = 0; i < 9; ++i) { - int slotX = centerX - 90 + i * 20 + 2; - int slotY = context.guiHeight() - 16 - 3; - - // 计算动画偏移 - float slotOffset = 0; - if (i == lastSelectedSlot) { - slotOffset = (1 - slotAnimationProgress) * 3; - } else if (i == selectedSlot) { - slotOffset = slotAnimationProgress * 3; - } - - this.renderSlot(context, slotX, (int)(slotY + slotOffset), tickCounter, playerEntity, - playerEntity.getInventory().items.get(i), i + 1); - } - - // 绘制副手物品(带透明度) - if (!itemStack.isEmpty() && offhandAlpha > 0) { - int offhandY = context.guiHeight() - 16 - 3; - if (arm == HumanoidArm.LEFT) { - this.renderSlot(context, centerX - 91 - 26, offhandY, tickCounter, playerEntity, itemStack, 100); - } else { - this.renderSlot(context, centerX + 91 + 10, offhandY, tickCounter, playerEntity, itemStack, 100); - } - } - - // 保留原版攻击冷却指示器 - if (this.minecraft.options.attackIndicator().get() == AttackIndicatorStatus.HOTBAR) { - float f = this.minecraft.player.getAttackStrengthScale(0.0F); - if (f < 1.0F) { - int indicatorY = context.guiHeight() - 20; - int indicatorX = centerX + 91 + 6; - if (arm == HumanoidArm.RIGHT) { - indicatorX = centerX - 91 - 22; - } - - int progress = (int)(f * 19.0F); - context.blitSprite(RenderType::guiTextured, Gui.HOTBAR_ATTACK_INDICATOR_BACKGROUND_SPRITE, - indicatorX, indicatorY, 18, 18); - context.blitSprite(RenderType::guiTextured, Gui.HOTBAR_ATTACK_INDICATOR_PROGRESS_SPRITE, - 18, 18, 0, 18 - progress, indicatorX, indicatorY + 18 - progress, 18, progress); - } - } - } - - @Unique - private void drawCustomHotbarBackground(GuiGraphics context, int centerX, int hotbarY, int selectedSlot) { - int hotbarWidth = 182; - int hotbarX = centerX - 91; - - // 绘制主背景(白色半透明) - for(int i = 0; i < 9; ++i) { - int slotX = hotbarX + i * 20; - - // 计算动画偏移 - float slotOffset = 0; - if (i == lastSelectedSlot) { - slotOffset = (1 - slotAnimationProgress) * 3; - } else if (i == selectedSlot) { - slotOffset = slotAnimationProgress * 3; - } - - // 槽位背景颜色 - int color = (i == selectedSlot) ? - 0x80FFFFFF : // 选中槽位更亮 - 0x40FFFFFF; // 普通槽位 + @Inject(method = "extractItemHotbar", at = @At("HEAD"), cancellable = true) + private void replaceHotbarRender(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { + DrawItemHotbarEvent event = new DrawItemHotbarEvent(); + EventBus.getInstance().post(event); - // 绘制槽位背景 - context.fill(slotX + 1, (int)(hotbarY + 1 + slotOffset), - slotX + 19, (int)(hotbarY + 19 + slotOffset), color); - - // 绘制选中指示器 - if (i == selectedSlot) { - context.fill(slotX, (int)(hotbarY - 1 + slotOffset), - slotX + 20, (int)(hotbarY + 1 + slotOffset), 0xE0FFFFFF); - } - } - } - - @Unique - private void drawOffhandBackground(GuiGraphics context, int centerX, int hotbarY, HumanoidArm arm, float alpha) { - int color = (int)(alpha * 64) << 24 | 0xFFFFFF; // 白色带透明度 - - if (arm == HumanoidArm.LEFT) { - // 左侧副手背景 - context.fill(centerX - 91 - 29, hotbarY - 1, - centerX - 91, hotbarY + 23, color); - } else { - // 右侧副手背景 - context.fill(centerX + 91, hotbarY - 1, - centerX + 91 + 29, hotbarY + 23, color); - } - } - - @Unique - private void updateSlotAnimation(int currentSlot) { - long currentTime = System.currentTimeMillis(); - - if (currentSlot != lastSelectedSlot) { - lastSelectedSlot = currentSlot; - lastHotbarUpdate = currentTime; - slotAnimationProgress = 0f; - } - - if (slotAnimationProgress < 1f) { - long elapsed = currentTime - lastHotbarUpdate; - slotAnimationProgress = Math.min(elapsed / 200f, 1f); - slotAnimationProgress = easeOutCubic(slotAnimationProgress); - } - } - - @Unique - private void updateOffhandAlpha(Player player) { - ItemStack offhandStack = player.getOffhandItem(); - - if (!offhandStack.isEmpty()) { - offhandAlpha = Math.min(offhandAlpha + 0.1f, 1f); - } else { - offhandAlpha = Math.max(offhandAlpha - 0.05f, 0f); - } - } - - @Unique - private float easeOutCubic(float x) { - return (float) (1 - Math.pow(1 - x, 3)); - } - - @Shadow - private void renderSlot(GuiGraphics context, int x, int y, DeltaTracker tickCounter, Player player, ItemStack stack, int seed) { + if (event.isCancelled()) ci.cancel(); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java index 71edbc4..9601739 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperScoreboard.java @@ -9,7 +9,7 @@ @Mixin(Gui.class) public class PupperScoreboard { - @Inject(method = "renderScoreboardSidebar*", at = @At("HEAD"), cancellable = true) + @Inject(method = "extractScoreboardSidebar*", at = @At("HEAD"), cancellable = true) private void renderCustomScoreboard(CallbackInfo ci) { if (Scoreboard.getInstance().isEnabled()) { ci.cancel(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java index b6bb65f..28324d8 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/sound/MixinSoundSystem.java @@ -1,35 +1,41 @@ package cn.pupperclient.mixin.mixins.minecraft.client.sound; -import java.util.Arrays; -import java.util.List; +import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.client.sounds.SoundEngine; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.sounds.SoundEvents; 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; -import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; +import java.util.Arrays; +import java.util.List; @Mixin(SoundEngine.class) public class MixinSoundSystem { - @Unique - private final List newPvPSounds = Arrays.asList(SoundEvents.PLAYER_ATTACK_KNOCKBACK.location(), - SoundEvents.PLAYER_ATTACK_SWEEP.location(), SoundEvents.PLAYER_ATTACK_CRIT.location(), - SoundEvents.PLAYER_ATTACK_STRONG.location(), SoundEvents.PLAYER_ATTACK_WEAK.location(), - SoundEvents.PLAYER_ATTACK_NODAMAGE.location()); - - @Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("HEAD"), cancellable = true) - public void oldAnimations$disableNewPvPSounds(SoundInstance sound, CallbackInfo ci) { + @Unique + private final List newPvPSounds = Arrays.asList( + SoundEvents.PLAYER_ATTACK_KNOCKBACK.location(), + SoundEvents.PLAYER_ATTACK_SWEEP.location(), + SoundEvents.PLAYER_ATTACK_CRIT.location(), + SoundEvents.PLAYER_ATTACK_STRONG.location(), + SoundEvents.PLAYER_ATTACK_WEAK.location(), + SoundEvents.PLAYER_ATTACK_NODAMAGE.location() + ); - if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isOldPvPSounds() - && newPvPSounds.contains(sound.getLocation())) { - ci.cancel(); - return; - } - } + @Inject( + method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)Lnet/minecraft/client/sounds/SoundEngine$PlayResult;", + at = @At("HEAD"), + cancellable = true + ) + public void oldAnimations$disableNewPvPSounds(SoundInstance sound, CallbackInfoReturnable cir) { + if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isOldPvPSounds() + && newPvPSounds.contains(sound.getIdentifier())) { + cir.setReturnValue(SoundEngine.PlayResult.NOT_STARTED); + } + } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java index 553761e..7c5216b 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAbstractClientPlayerEntity.java @@ -2,18 +2,13 @@ import cn.pupperclient.PupperClient; import com.mojang.authlib.GameProfile; -import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.resources.PlayerSkin; -import net.minecraft.core.BlockPos; import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.PlayerModelPart; +import net.minecraft.world.entity.player.PlayerSkin; import net.minecraft.world.level.Level; -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; @@ -21,26 +16,22 @@ @Mixin(value = AbstractClientPlayer.class, priority = 2000) public abstract class MixinAbstractClientPlayerEntity extends Player { - - @Shadow @Final public ClientLevel clientLevel; - @Unique private boolean shownCape = false; - public MixinAbstractClientPlayerEntity(Level world, BlockPos pos, float yaw, GameProfile gameProfile) { - super(world, pos, yaw, gameProfile); + public MixinAbstractClientPlayerEntity(Level world, GameProfile gameProfile) { + super(world, gameProfile); } @Inject(method = "getSkin", at = @At("RETURN"), cancellable = true) public void getSkinTextures(CallbackInfoReturnable cir) { - ResourceLocation customCape = PupperClient.getInstance().getCapeManager().getSelectedCapeTexture(); + var customCape = PupperClient.getInstance().getCapeManager().getSelectedCapeTexture(); if (customCape != null) { PlayerSkin current = cir.getReturnValue(); cir.setReturnValue(new PlayerSkin( - current.texture(), - current.textureUrl(), + current.body(), customCape, - current.elytraTexture(), + current.elytra(), current.model(), current.secure() )); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java index c99e5f5..7827261 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/MixinClientConnection.java @@ -1,10 +1,12 @@ package cn.pupperclient.mixin.mixins.minecraft.network; +import io.netty.channel.ChannelFutureListener; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import cn.pupperclient.event.EventBus; @@ -12,7 +14,6 @@ import cn.pupperclient.event.client.SendPacketEvent; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import net.minecraft.network.PacketSendListener; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundBundlePacket; import net.minecraft.server.RunningOnDifferentThreadException; @@ -25,19 +26,20 @@ private static void genericsFtw(Packet packet, Pac } @Shadow - protected abstract void sendPacket(Packet packet, @Nullable PacketSendListener callbacks, boolean flush); + protected abstract void sendPacket(Packet packet, @Nullable ChannelFutureListener listener, boolean flush); - @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketSendListener;)V", at = @At("HEAD"), cancellable = true) - private void onSendPacket(Packet packet, PacketSendListener callbacks, CallbackInfo ci) { + @Redirect( + method = "send(Lnet/minecraft/network/protocol/Packet;Lio/netty/channel/ChannelFutureListener;Z)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/network/Connection;sendPacket(Lnet/minecraft/network/protocol/Packet;Lio/netty/channel/ChannelFutureListener;Z)V") + ) + private void redirectSendPacket(Connection instance, Packet packet, ChannelFutureListener listener, boolean flush) { SendPacketEvent event = new SendPacketEvent(packet); EventBus.getInstance().post(event); - if (event.isCancelled()) { - ci.cancel(); - Connection self = (Connection) (Object) this; - self.send(event.getPacket(), callbacks); - } + if (!event.isCancelled()) { + sendPacket(packet, listener, flush); + } } @Inject(method = "genericsFtw", at = @At("HEAD"), cancellable = true, require = 1) diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java deleted file mode 100644 index 4b7de69..0000000 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/network/packet/PlayerInteractEntityC2SPacketAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.pupperclient.mixin.mixins.minecraft.network.packet; - -import net.minecraft.network.protocol.game.ServerboundInteractPacket; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(ServerboundInteractPacket.class) -public interface PlayerInteractEntityC2SPacketAccessor { - - @Accessor("action") - ServerboundInteractPacket.Action getInteractTypeHandler(); - - @Accessor("entityId") - int entityId(); -} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java index d61a504..bafaae8 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/world/MixinClientWorldProperties.java @@ -11,7 +11,7 @@ @Mixin(ClientLevel.ClientLevelData.class) public class MixinClientWorldProperties { - @Inject(method = "getDayTime", at = @At("HEAD"), cancellable = true) + @Inject(method = "getGameTime", at = @At("HEAD"), cancellable = true) public void getTimeOfDay(CallbackInfoReturnable cir) { if (TimeChangerMod.getInstance().isEnabled()) { cir.setReturnValue(TimeChangerMod.getInstance().getTime()); diff --git a/src/main/java/cn/pupperclient/utils/render/RenderUtils.java b/src/main/java/cn/pupperclient/utils/render/RenderUtils.java index 8a401e5..fbfa0a7 100644 --- a/src/main/java/cn/pupperclient/utils/render/RenderUtils.java +++ b/src/main/java/cn/pupperclient/utils/render/RenderUtils.java @@ -9,11 +9,9 @@ import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.renderer.Projection; import net.minecraft.client.renderer.ProjectionMatrixBuffer; -import net.minecraft.world.phys.Vec3; import org.joml.Matrix4f; public class RenderUtils implements IMinecraft { - public static Vec3 center; public static final Matrix4f projection = new Matrix4f(); private static final ProjectionMatrixBuffer matrixBuffer = new ProjectionMatrixBuffer("pupper-projection-matrix"); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 0f39d9b..b87fef6 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -25,6 +25,14 @@ "viafabricplus": "*", "ias": "*" }, + "breaks": { + "optifabric": "*", + "feather": "*", + "origins": "*", + "sodium": "<0.8.7", + "morechathistory": "*", + "lithium": "<0.21.3" + }, "custom": { "pupper:icon": "assets/pupper/logo.png", "modmenu": { diff --git a/src/main/resources/pupper.mixins.json b/src/main/resources/pupper.mixins.json index 042e878..2ca530d 100644 --- a/src/main/resources/pupper.mixins.json +++ b/src/main/resources/pupper.mixins.json @@ -17,13 +17,13 @@ "minecraft.client.gui.MixinTitleScreen", "minecraft.client.option.MixinKeyBinding", "minecraft.client.render.GuiRendererMixin", + "minecraft.client.render.LightmapMixin", "minecraft.client.render.MixinCamera", "minecraft.client.render.MixinEntityRenderer", "minecraft.client.render.MixinGameRenderer", "minecraft.client.render.MixinHeldItemRenderer", "minecraft.client.render.MixinInGameHud", "minecraft.client.render.MixinInGameOverlayRenderer", - "minecraft.client.render.MixinLightmapTextureManager", "minecraft.client.render.PupperInGameHud", "minecraft.client.render.PupperScoreboard", "minecraft.client.render.RenderPipelineMixin", @@ -34,7 +34,6 @@ "minecraft.entity.MixinLivingEntity", "minecraft.entity.MixinPlayerEntity", "minecraft.network.MixinClientConnection", - "minecraft.network.packet.PlayerInteractEntityC2SPacketAccessor", "minecraft.world.MixinBiome", "minecraft.world.MixinClientWorldProperties", "minecraft.world.MixinWorld", From d4f5e615cc5559637d8cf63c0cd91bee5bad3aeb Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 20:16:39 +0800 Subject: [PATCH 16/45] fix(gui): Port Minecraft 26.1 --- .../java/cn/pupperclient/gui/MainMenuGui.java | 23 ++--- .../cn/pupperclient/gui/MusicPlayGui.java | 2 +- .../pupperclient/gui/api/SimpleSoarGui.java | 35 ++++--- .../java/cn/pupperclient/gui/api/SoarGui.java | 11 +-- .../cn/pupperclient/gui/api/page/Page.java | 4 +- .../pupperclient/gui/api/page/SimplePage.java | 2 +- .../pupperclient/gui/edithud/GuiEditHUD.java | 2 +- .../modmenu/component/MusicControlBar.java | 4 +- .../gui/modmenu/component/SettingBar.java | 4 +- .../gui/modmenu/pages/CosmeticsPage.java | 4 +- .../gui/modmenu/pages/MusicPage.java | 6 +- .../gui/modmenu/pages/SettingsImplPage.java | 6 +- .../modmenu/pages/profile/ProfileAddPage.java | 8 +- .../gui/welcomegui/TermsScreen.java | 6 +- .../management/cape/CapeRenderer.java | 91 ++++++++++--------- .../pupperclient/ui/component/Component.java | 2 +- .../ui/component/impl/text/SearchBar.java | 2 +- .../ui/component/impl/text/TextField.java | 2 +- .../component/impl/text/TextInputHelper.java | 2 +- 19 files changed, 114 insertions(+), 102 deletions(-) diff --git a/src/main/java/cn/pupperclient/gui/MainMenuGui.java b/src/main/java/cn/pupperclient/gui/MainMenuGui.java index cf37e8b..da9ce12 100644 --- a/src/main/java/cn/pupperclient/gui/MainMenuGui.java +++ b/src/main/java/cn/pupperclient/gui/MainMenuGui.java @@ -37,7 +37,6 @@ import net.minecraft.client.gui.screens.options.OptionsScreen; import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; import com.mojang.realmsclient.RealmsMainScreen; -import net.minecraft.client.Minecraft; public class MainMenuGui extends SimpleSoarGui { @@ -68,8 +67,8 @@ public void init() { } @Override - public void resize(Minecraft client, int width, int height) { - super.resize(client, width, height); + public void resize(int width, int height) { + super.resize(width, height); rebuildLayout(); } @@ -103,9 +102,7 @@ private void rebuildLayout() { centerX - buttonWidth / 2, centerY - (120 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new SelectWorldScreen(this)))); buttons.add(new MainMenuButton("menu.multiplayer", Icon.GROUPS, - centerX - buttonWidth / 2, centerY - (60 * scaleFactor), buttonWidth, scaleFactor, () -> { - client.setScreen(new JoinMultiplayerScreen(this)); - })); + centerX - buttonWidth / 2, centerY - (60 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new JoinMultiplayerScreen(this)))); buttons.add(new MainMenuButton("menu.realms", Icon.DNS, centerX - buttonWidth / 2, centerY, buttonWidth, scaleFactor, () -> client.setScreen(new RealmsMainScreen(this)))); @@ -117,7 +114,7 @@ private void rebuildLayout() { centerX - buttonWidth / 2, centerY + (120 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new ModsScreen(this)))); buttons.add(new MainMenuButton("menu.options", Icon.SETTINGS, - centerX - buttonWidth / 2, centerY + (180 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new OptionsScreen(this, client.options)))); + centerX - buttonWidth / 2, centerY + (180 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new OptionsScreen(this, client.options, false)))); buttons.add(new MainMenuButton("menu.quit", Icon.CLOSE, centerX - buttonWidth / 2, centerY + (240 * scaleFactor), buttonWidth, scaleFactor, client::stop)); @@ -451,7 +448,7 @@ public boolean onMouseScrolled(double mouseX, double mouseY, double horizontalAm } @Override - public boolean onMousePressed(double mouseX, double mouseY, int button) { + public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { if (isWindowMinimized()) { return false; } @@ -529,15 +526,15 @@ public boolean onMouseReleased(double mouseX, double mouseY, int button) { } @Override - public boolean onCharTyped(char chr, int modifiers) { + public boolean onCharTyped(int chr) { if (showBackgroundWindow) { - exitBackgroundButton.charTyped(chr, modifiers); - addBackgroundButton.charTyped(chr, modifiers); + exitBackgroundButton.charTyped(chr); + addBackgroundButton.charTyped(chr); } if (showCustomizationWindow) { - darkModeSwitch.charTyped(chr, modifiers); - exitCustomizationButton.charTyped(chr, modifiers); + darkModeSwitch.charTyped(chr); + exitCustomizationButton.charTyped(chr); } return true; } diff --git a/src/main/java/cn/pupperclient/gui/MusicPlayGui.java b/src/main/java/cn/pupperclient/gui/MusicPlayGui.java index aafc59b..7c8346e 100644 --- a/src/main/java/cn/pupperclient/gui/MusicPlayGui.java +++ b/src/main/java/cn/pupperclient/gui/MusicPlayGui.java @@ -43,7 +43,7 @@ public void draw(double mouseX, double mouseY) { } @Override - public boolean onMousePressed(double mouseX, double mouseY, int button) { + public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { int windowWidth = client.getWindow().getWidth(); int windowHeight = client.getWindow().getHeight(); diff --git a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java index 5686a4c..51f1837 100644 --- a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java @@ -3,8 +3,11 @@ import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.context.SkiaContext; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; /** @@ -32,7 +35,7 @@ protected void init() { public abstract void draw(double mouseX, double mouseY); @Override - public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { + public void extractRenderState(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta) { SkiaContext.draw((skiaContext) -> { Skia.save(); @@ -50,17 +53,23 @@ public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { + double mouseX = click.x(); + double mouseY = click.y(); + double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); - return onMousePressed(finalMouseX, finalMouseY, button); + return onMousePressed(finalMouseX, finalMouseY, click.button(), doubled); } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { + public boolean mouseReleased(MouseButtonEvent click) { + double mouseX = click.x(); + double mouseY = click.y(); + double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); - return onMouseReleased(finalMouseX, finalMouseY, button); + return onMouseReleased(finalMouseX, finalMouseY, click.button()); } @Override @@ -71,22 +80,22 @@ public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmou } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - return onKeyPressed(keyCode, scanCode, modifiers); + public boolean keyPressed(KeyEvent event) { + return onKeyPressed(event.key(), event.scancode(), event.modifiers()); } @Override - public boolean charTyped(char chr, int modifiers) { - return onCharTyped(chr, modifiers); + public boolean charTyped(CharacterEvent input) { + return onCharTyped(input.codepoint()); } // Abstract or hook methods for subclasses to implement without overriding Screen methods directly - public boolean onMousePressed(double mouseX, double mouseY, int button) { return false; } + public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { return false; } public boolean onMouseReleased(double mouseX, double mouseY, int button) { return false; } public boolean onMouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { return false; } - public boolean onKeyPressed(int keyCode, int scanCode, int modifiers) { return super.keyPressed(keyCode, scanCode, modifiers); } - public boolean onCharTyped(char chr, int modifiers) { return super.charTyped(chr, modifiers); } + public boolean onKeyPressed(int keyCode, int scanCode, int modifiers) { return super.keyPressed(new KeyEvent(keyCode, scanCode, modifiers)); } + public boolean onCharTyped(int chr) { return super.charTyped(new CharacterEvent(chr)); } @Override public boolean isPauseScreen() { diff --git a/src/main/java/cn/pupperclient/gui/api/SoarGui.java b/src/main/java/cn/pupperclient/gui/api/SoarGui.java index 9305501..9ac6b6d 100644 --- a/src/main/java/cn/pupperclient/gui/api/SoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SoarGui.java @@ -4,7 +4,6 @@ import java.util.List; import cn.pupperclient.PupperClient; -import cn.pupperclient.shader.impl.Kawaseblur; import org.lwjgl.glfw.GLFW; import cn.pupperclient.animation.Animation; @@ -14,11 +13,9 @@ import cn.pupperclient.gui.api.page.SimplePage; import cn.pupperclient.management.color.api.ColorPalette; import cn.pupperclient.management.config.ConfigType; -import cn.pupperclient.management.mod.impl.settings.ModMenuSettings; import cn.pupperclient.skia.Skia; import cn.pupperclient.ui.component.Component; -import io.github.humbleui.skija.SurfaceOrigin; import net.minecraft.client.gui.screens.Screen; public abstract class SoarGui extends SimpleSoarGui { @@ -120,7 +117,7 @@ public void draw(double mouseX, double mouseY) { } @Override - public boolean onMousePressed(double mouseX, double mouseY, int button) { + public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { if (currentPage != null) { currentPage.mousePressed(mouseX, mouseY, button); @@ -154,14 +151,14 @@ public boolean onMouseScrolled(double mouseX, double mouseY, double horizontalAm } @Override - public boolean onCharTyped(char chr, int modifiers) { + public boolean onCharTyped(int chr) { if (currentPage != null) { - currentPage.charTyped(chr, modifiers); + currentPage.charTyped(chr); } for (Component c : components) { - c.charTyped(chr, modifiers); + c.charTyped(chr); } return true; } diff --git a/src/main/java/cn/pupperclient/gui/api/page/Page.java b/src/main/java/cn/pupperclient/gui/api/page/Page.java index 19512cc..88effa3 100644 --- a/src/main/java/cn/pupperclient/gui/api/page/Page.java +++ b/src/main/java/cn/pupperclient/gui/api/page/Page.java @@ -55,8 +55,8 @@ public void mouseReleased(double mouseX, double mouseY, int button) { } @Override - public void charTyped(char chr, int modifiers) { - searchBar.charTyped(chr, modifiers); + public void charTyped(int chr) { + searchBar.charTyped(chr); } @Override diff --git a/src/main/java/cn/pupperclient/gui/api/page/SimplePage.java b/src/main/java/cn/pupperclient/gui/api/page/SimplePage.java index 5b082a3..30535dd 100644 --- a/src/main/java/cn/pupperclient/gui/api/page/SimplePage.java +++ b/src/main/java/cn/pupperclient/gui/api/page/SimplePage.java @@ -39,7 +39,7 @@ public void mouseReleased(double mouseX, double mouseY, int button) { public void mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { } - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { } public void keyPressed(int keyCode, int scanCode, int modifiers) { diff --git a/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java b/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java index be24eee..63aa610 100644 --- a/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java +++ b/src/main/java/cn/pupperclient/gui/edithud/GuiEditHUD.java @@ -80,7 +80,7 @@ private float calculateNewScale(float currentScale, double wheelDelta) { } @Override - public boolean onMousePressed(double mouseX, double mouseY, int button) { + public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { getHoveredMod(mouseX, mouseY).ifPresent(mod -> { if (button == GLFW.GLFW_MOUSE_BUTTON_MIDDLE) { mod.getPosition().setScale(1.0F); diff --git a/src/main/java/cn/pupperclient/gui/modmenu/component/MusicControlBar.java b/src/main/java/cn/pupperclient/gui/modmenu/component/MusicControlBar.java index b00a12d..802c84b 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/component/MusicControlBar.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/component/MusicControlBar.java @@ -233,10 +233,10 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } @Override - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { if (addMusic) { for (Component c : components) { - c.charTyped(chr, modifiers); + c.charTyped(chr); } } } diff --git a/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java b/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java index 67e10e5..db38172 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/component/SettingBar.java @@ -201,10 +201,10 @@ public void mouseReleased(double mouseX, double mouseY, int button) { } @Override - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { if (component != null) { - component.charTyped(chr, modifiers); + component.charTyped(chr); } } diff --git a/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java b/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java index f647649..a49c718 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/pages/CosmeticsPage.java @@ -20,12 +20,12 @@ import cn.pupperclient.utils.file.FileDialog; import cn.pupperclient.utils.language.I18n; import cn.pupperclient.utils.mouse.MouseUtils; +import net.minecraft.resources.Identifier; import org.lwjgl.glfw.GLFW; import io.github.humbleui.skija.Font; import javax.imageio.ImageIO; import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; @@ -213,7 +213,7 @@ private void drawMd3Style(double mouseX, double mouseY) { } if (item.capeFile.exists()) { - ResourceLocation capeTexture = PupperClient.getInstance().getCapeManager().getLoadedCape(item.capeId); + Identifier capeTexture = PupperClient.getInstance().getCapeManager().getLoadedCape(item.capeId); if (capeTexture != null) { CapeRenderer.renderRoundedCapePreview(capeTexture, itemX + 5, itemY + 5, itemWidth - 10, itemHeight - 10, 8); diff --git a/src/main/java/cn/pupperclient/gui/modmenu/pages/MusicPage.java b/src/main/java/cn/pupperclient/gui/modmenu/pages/MusicPage.java index 6eea4e3..1f71c22 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/pages/MusicPage.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/pages/MusicPage.java @@ -294,9 +294,9 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } @Override - public void charTyped(char chr, int modifiers) { - super.charTyped(chr, modifiers); - controlBar.charTyped(chr, modifiers); + public void charTyped(int chr) { + super.charTyped(chr); + controlBar.charTyped(chr); } private void drawRoundedImage(File file, float x, float y, float width, float height, float cornerRadius, diff --git a/src/main/java/cn/pupperclient/gui/modmenu/pages/SettingsImplPage.java b/src/main/java/cn/pupperclient/gui/modmenu/pages/SettingsImplPage.java index 4dfb9a9..e1249d9 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/pages/SettingsImplPage.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/pages/SettingsImplPage.java @@ -139,8 +139,8 @@ public void mouseReleased(double mouseX, double mouseY, int button) { } @Override - public void charTyped(char chr, int modifiers) { - super.charTyped(chr, modifiers); + public void charTyped(int chr) { + super.charTyped(chr); for (SettingBar b : bars) { @@ -148,7 +148,7 @@ public void charTyped(char chr, int modifiers) { continue; } - b.charTyped(chr, modifiers); + b.charTyped(chr); } } diff --git a/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java b/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java index f1c04eb..18bc93b 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/pages/profile/ProfileAddPage.java @@ -62,7 +62,7 @@ public void init() { @Override public void onAction() { if (!nameField.getText().isEmpty()) { - PupperClient.getInstance().getProfileManager().save(nameField.getText(), client.getGameProfile().getName(), + PupperClient.getInstance().getProfileManager().save(nameField.getText(), client.getGameProfile().name(), addressField.getText(), currentIcon, ConfigType.MOD); PupperClient.getInstance().getProfileManager().readProfiles(); parent.setClosable(true); @@ -176,11 +176,11 @@ public void mouseReleased(double mouseX, double mouseY, int button) { } @Override - public void charTyped(char chr, int modifiers) { - super.charTyped(chr, modifiers); + public void charTyped(int chr) { + super.charTyped(chr); for (Component component : components) { - component.charTyped(chr, modifiers); + component.charTyped(chr); } } diff --git a/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java b/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java index a8da9be..e44b615 100644 --- a/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java +++ b/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java @@ -51,8 +51,8 @@ public void onAction() { } @Override - public void resize(Minecraft client, int width, int height) { - super.resize(client, width, height); + public void resize(int width, int height) { + super.resize(width, height); rebuildLayout(); } @@ -100,7 +100,7 @@ private void renderSkijaWelcome(double mouseX, double mouseY) { } @Override - public boolean onMousePressed(double mouseX, double mouseY, int button) { + public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { acceptButton.mousePressed(mouseX, mouseY, button); declineButton.mousePressed(mouseX, mouseY, button); return true; diff --git a/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java b/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java index ef1783f..9febcd4 100644 --- a/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java +++ b/src/main/java/cn/pupperclient/management/cape/CapeRenderer.java @@ -1,77 +1,86 @@ package cn.pupperclient.management.cape; +import cn.pupperclient.PupperLogger; import cn.pupperclient.skia.Skia; +import com.mojang.blaze3d.opengl.GlTexture; import io.github.humbleui.skija.ClipMode; import io.github.humbleui.skija.Path; import io.github.humbleui.skija.SurfaceOrigin; import io.github.humbleui.types.RRect; import io.github.humbleui.types.Rect; import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class CapeRenderer { - public static void renderCapePreview(ResourceLocation capeTexture, float x, float y, float width, float height) { + @SuppressWarnings("unused") + public static void renderCapePreview(Identifier capeTexture, float x, float y) { if (capeTexture == null) return; try { - int textureId = Minecraft.getInstance().getTextureManager().getTexture(capeTexture).getId(); + var texture = Minecraft.getInstance().getTextureManager().getTexture(capeTexture).getTexture(); - // 尝试不同的纹理尺寸 - boolean loaded = Skia.getImageHelper().load(textureId, 64, 32, SurfaceOrigin.TOP_LEFT) || - Skia.getImageHelper().load(textureId, 128, 64, SurfaceOrigin.TOP_LEFT); + if (texture instanceof GlTexture glTexture) { + int textureId = glTexture.glId(); + boolean loaded = Skia.getImageHelper().load(textureId, 64, 32, SurfaceOrigin.TOP_LEFT) || + Skia.getImageHelper().load(textureId, 128, 64, SurfaceOrigin.TOP_LEFT); - if (loaded) { - Skia.save(); - Skia.translate(x + 2, y + 8); - Skia.scale(2f, 2f, 1f); + if (loaded) { + Skia.save(); + Skia.translate(x + 2, y + 8); + Skia.scale(2f, 2f, 1f); - Rect srcRect = Rect.makeXYWH(1, 1, 10, 16); - Rect dstRect = Rect.makeXYWH(0, 0, 10, 16); - Skia.getCanvas().drawImageRect(Skia.getImageHelper().get(textureId), srcRect, dstRect, null, false); + Rect srcRect = Rect.makeXYWH(1, 1, 10, 16); + Rect dstRect = Rect.makeXYWH(0, 0, 10, 16); + Skia.getCanvas().drawImageRect(Skia.getImageHelper().get(textureId), srcRect, dstRect, null, false); - Skia.restore(); + Skia.restore(); - Skia.save(); - Skia.translate(x + 26, y + 8); - Skia.scale(2f, 2f, 1f); + Skia.save(); + Skia.translate(x + 26, y + 8); + Skia.scale(2f, 2f, 1f); - Rect srcRect2 = Rect.makeXYWH(12, 1, 10, 16); - Rect dstRect2 = Rect.makeXYWH(0, 0, 10, 16); - Skia.getCanvas().drawImageRect(Skia.getImageHelper().get(textureId), srcRect2, dstRect2, null, false); + Rect srcRect2 = Rect.makeXYWH(12, 1, 10, 16); + Rect dstRect2 = Rect.makeXYWH(0, 0, 10, 16); + Skia.getCanvas().drawImageRect(Skia.getImageHelper().get(textureId), srcRect2, dstRect2, null, false); - Skia.restore(); + Skia.restore(); + } + } else { + PupperLogger.warn("CapeRenderer", "Failed to render cape preview: : unknown glTexture"); } } catch (Exception e) { - System.err.println("Failed to render cape preview: " + e.getMessage()); + PupperLogger.warn("CapeRenderer", "Failed to render cape preview: " + e.getMessage()); } } - public static void renderRoundedCapePreview(ResourceLocation capeTexture, float x, float y, + public static void renderRoundedCapePreview(Identifier capeTexture, float x, float y, float width, float height, float radius) { if (capeTexture == null) return; try { - int textureId = Minecraft.getInstance().getTextureManager().getTexture(capeTexture).getId(); - - // 尝试不同的纹理尺寸 - boolean loaded = Skia.getImageHelper().load(textureId, 64, 32, SurfaceOrigin.TOP_LEFT) || - Skia.getImageHelper().load(textureId, 128, 64, SurfaceOrigin.TOP_LEFT); - - if (loaded) { - Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius)); - - // 根据实际纹理尺寸调整源矩形 - Rect srcRect = Rect.makeXYWH(1, 1, 10, 16); - Rect dstRect = Rect.makeXYWH(x, y, width, height); - - Skia.save(); - Skia.getCanvas().clipPath(path, ClipMode.INTERSECT, true); - Skia.getCanvas().drawImageRect(Skia.getImageHelper().get(textureId), srcRect, dstRect, null, false); - Skia.restore(); + var texture = Minecraft.getInstance().getTextureManager().getTexture(capeTexture).getTexture(); + if (texture instanceof GlTexture glTexture) { + int textureId = glTexture.glId(); + boolean loaded = Skia.getImageHelper().load(textureId, 64, 32, SurfaceOrigin.TOP_LEFT) || + Skia.getImageHelper().load(textureId, 128, 64, SurfaceOrigin.TOP_LEFT); + + if (loaded) { + Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius)); + + Rect srcRect = Rect.makeXYWH(1, 1, 10, 16); + Rect dstRect = Rect.makeXYWH(x, y, width, height); + + Skia.save(); + Skia.getCanvas().clipPath(path, ClipMode.INTERSECT, true); + Skia.getCanvas().drawImageRect(Skia.getImageHelper().get(textureId), srcRect, dstRect, null, false); + Skia.restore(); + } + } else { + PupperLogger.warn("CapeRenderer", "Failed to render rounded cape preview: unknown glTexture"); } } catch (Exception e) { - System.err.println("Failed to render rounded cape preview: " + e.getMessage()); + PupperLogger.warn("CapeRenderer", "Failed to render rounded cape preview: " + e.getMessage()); } } } diff --git a/src/main/java/cn/pupperclient/ui/component/Component.java b/src/main/java/cn/pupperclient/ui/component/Component.java index 65fbddb..bd1e862 100644 --- a/src/main/java/cn/pupperclient/ui/component/Component.java +++ b/src/main/java/cn/pupperclient/ui/component/Component.java @@ -25,7 +25,7 @@ public void mousePressed(double mouseX, double mouseY, int button) { public void mouseReleased(double mouseX, double mouseY, int button) { } - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { } public void keyPressed(int keyCode, int scanCode, int modifiers) { diff --git a/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java b/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java index 1656c05..f24514d 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java @@ -172,7 +172,7 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } @Override - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { input.charTyped(chr, modifiers); } diff --git a/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java b/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java index 9cb09e0..94f5a43 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java @@ -135,7 +135,7 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } @Override - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { input.charTyped(chr, modifiers); diff --git a/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java b/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java index 0171c5b..b986edf 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/text/TextInputHelper.java @@ -102,7 +102,7 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { } } - public void charTyped(char chr, int modifiers) { + public void charTyped(int chr) { if (StringUtil.isAllowedChatCharacter(chr) && this.isFocused()) { this.writeText(Character.toString(chr)); } From 216a0f7f8960b60a40ad68f3db5828d303dfc926 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 20:18:18 +0800 Subject: [PATCH 17/45] fix(gui): fix GuiResourcePackConvert --- .../java/cn/pupperclient/gui/GuiResourcePackConvert.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java b/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java index cd58706..d0289fc 100644 --- a/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java +++ b/src/main/java/cn/pupperclient/gui/GuiResourcePackConvert.java @@ -22,7 +22,7 @@ import cn.pupperclient.utils.file.FileLocation; import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.util.CommonColors; @@ -52,9 +52,9 @@ public void init() { } @Override - public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); - context.drawCenteredString(this.font, Component.literal(progress), this.width / 2, this.height / 2 - 50, CommonColors.WHITE); + public void extractRenderState(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta) { + super.extractRenderState(context, mouseX, mouseY, delta); + context.text(this.font, Component.literal(progress), this.width / 2, this.height / 2 - 50, CommonColors.WHITE); } private ResourcePackConverter createConverter() { From 1f22b02541af9172efd01fa6bce4943f544807c1 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 20:19:57 +0800 Subject: [PATCH 18/45] fix(component): Port Minecraft 26.1.2 --- src/main/java/cn/pupperclient/ui/component/impl/Keybind.java | 3 ++- .../java/cn/pupperclient/ui/component/impl/text/SearchBar.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java b/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java index 3e83d4c..be19ac5 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/Keybind.java @@ -1,5 +1,6 @@ package cn.pupperclient.ui.component.impl; +import net.minecraft.client.input.KeyEvent; import org.lwjgl.glfw.GLFW; import cn.pupperclient.PupperClient; @@ -76,7 +77,7 @@ public void mouseReleased(double mouseX, double mouseY, int button) { @Override public void keyPressed(int keyCode, int scanCode, int modifiers) { if (binding) { - setKeyCode(InputConstants.getKey(keyCode, scanCode)); + setKeyCode(InputConstants.getKey(new KeyEvent(keyCode, scanCode, modifiers))); this.binding = false; } } diff --git a/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java b/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java index f24514d..bbad9cb 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/text/SearchBar.java @@ -173,7 +173,7 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { @Override public void charTyped(int chr) { - input.charTyped(chr, modifiers); + input.charTyped(chr); } public String getHintText() { From 3dd4de7245e0830494d1283f745313929bfcbeef Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 20:21:18 +0800 Subject: [PATCH 19/45] fix(component/TextField): Port Minecraft 26.1.2 --- .../java/cn/pupperclient/ui/component/impl/text/TextField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java b/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java index 94f5a43..21983cb 100644 --- a/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java +++ b/src/main/java/cn/pupperclient/ui/component/impl/text/TextField.java @@ -137,7 +137,7 @@ public void keyPressed(int keyCode, int scanCode, int modifiers) { @Override public void charTyped(int chr) { - input.charTyped(chr, modifiers); + input.charTyped(chr); if (handler instanceof TextHandler) { ((TextHandler) handler).onTyped(getText()); From 320e11e0c4a2c7e8ed381108448a20d08da51ee4 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 20:42:09 +0800 Subject: [PATCH 20/45] fix(command): Port Minecraft 26.1.2 --- .../management/command/PupperCommand.java | 11 +- .../management/command/impl/BindCommand.java | 8 +- .../management/command/impl/IRCCommand.java | 3 +- .../management/command/impl/LoginCommand.java | 149 +++++------------- .../management/command/impl/MusicCommand.java | 35 ++-- 5 files changed, 69 insertions(+), 137 deletions(-) diff --git a/src/main/java/cn/pupperclient/management/command/PupperCommand.java b/src/main/java/cn/pupperclient/management/command/PupperCommand.java index bb7236c..68e1e32 100644 --- a/src/main/java/cn/pupperclient/management/command/PupperCommand.java +++ b/src/main/java/cn/pupperclient/management/command/PupperCommand.java @@ -1,6 +1,7 @@ package cn.pupperclient.management.command; import cn.pupperclient.PupperClient; +import cn.pupperclient.PupperLogger; import cn.pupperclient.management.command.impl.*; import cn.pupperclient.management.mod.Mod; import cn.pupperclient.management.mod.ModManager; @@ -14,6 +15,7 @@ import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; import java.io.IOException; +import java.util.Objects; public class PupperCommand implements IMinecraft { private static final String PREFIX = "."; @@ -39,7 +41,6 @@ public static void runCommand(String command) throws IOException { if (args.length == 0) { showHelp(); - return; } String mainCommand = args[0].toLowerCase(); @@ -181,12 +182,14 @@ private static void listMods() { } private static MutableComponent createClickableText(String displayText, String command, String hoverText, ChatFormatting color) { + ClickEvent clickEvent = new ClickEvent.SuggestCommand("." + command); + HoverEvent hoverEvent = new HoverEvent.ShowText(Component.literal(hoverText)); + return Component.literal(displayText) .withStyle(color) .withStyle(style -> style - .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Component.literal(hoverText).withStyle(ChatFormatting.GRAY)))); + .withClickEvent(clickEvent) + .withHoverEvent(hoverEvent)); } private static String getShortModName(String fullName) { diff --git a/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java b/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java index 20fd423..049bba0 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/BindCommand.java @@ -140,9 +140,11 @@ private static void listKeybinds() { for (Mod mod : mods) { MutableComponent message = Component.literal("§b• " + mod.getName() + " §7→ §a" + keyName + " §7(keycode: " + keyCode + ")") .withStyle(style -> style - .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ".bind " + mod.getName() + " none")) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - Component.literal("Click to clear this keybind").withStyle(ChatFormatting.GRAY)))); + .withClickEvent(new ClickEvent.SuggestCommand(".bind " + mod.getName() + " none")) + .withHoverEvent(new HoverEvent.ShowText( + Component.literal("Click to clear this keybind").withStyle(ChatFormatting.GRAY) + )) + ); ChatUtils.addChatMessage(message); boundCount++; diff --git a/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java b/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java index 8abe16b..8a04d67 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/IRCCommand.java @@ -2,6 +2,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.management.mod.impl.misc.IRCChatMod; +import cn.pupperclient.utils.chat.ChatUtils; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import net.minecraft.network.chat.Component; @@ -65,7 +66,7 @@ private static void sendHelp() { private static void sendMessage(String message) { if (client.player != null) { - client.player.displayClientMessage(Component.nullToEmpty(message), false); + ChatUtils.addChatMessage(Component.nullToEmpty(message)); } } } diff --git a/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java b/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java index eb21222..065175b 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/LoginCommand.java @@ -14,6 +14,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; +import org.jspecify.annotations.NonNull; public class LoginCommand { @@ -96,9 +97,7 @@ private static void sendCaptcha(String phone) { if (result == null || result.has("code") && result.get("code").getAsInt() != 200) { String errorMsg = result != null && result.has("message") ? result.get("message").getAsString() : "发送验证码失败"; - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c发送验证码失败: " + errorMsg); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c发送验证码失败: " + errorMsg)); return; } @@ -108,9 +107,7 @@ private static void sendCaptcha(String phone) { }); } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c发送验证码失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c发送验证码失败: " + e.getMessage())); PupperClient.LOGGER.error("发送验证码失败: {}", e.getMessage(), e); } }); @@ -129,7 +126,7 @@ private static void phoneLoginWithCaptcha(String phone, String captcha) { PupperLogger.info("登录请求URL: {}", url); - JsonObject result = sendPostRequest(url, null); + JsonObject result = sendPostRequest(url); if (result == null || result.has("code") && result.get("code").getAsInt() != 200) { String errorMsg = result != null && result.has("message") ? @@ -140,8 +137,8 @@ private static void phoneLoginWithCaptcha(String phone, String captcha) { // 提供重新发送验证码的快捷方式 MutableComponent retryText = Component.literal("§7[重新发送验证码]") .withStyle(style -> style - .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ".login send " + phone)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + .withClickEvent(new ClickEvent.SuggestCommand(".login send " + phone)) + .withHoverEvent(new HoverEvent.ShowText( Component.literal("点击重新发送验证码")))); ChatUtils.addChatMessage(retryText); }); @@ -174,9 +171,7 @@ private static void phoneLoginWithCaptcha(String phone, String captcha) { } } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c登录过程出错: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c登录过程出错: " + e.getMessage())); PupperClient.LOGGER.error("验证码登录失败: {}", e.getMessage(), e); } }); @@ -195,9 +190,7 @@ private static void startQRLogin() { JsonObject keyResult = sendGetRequest(keyUrl); if (keyResult == null || !keyResult.has("data") || keyResult.getAsJsonObject("data").get("code").getAsInt() != 200) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c获取二维码key失败"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c获取二维码key失败")); return; } @@ -208,9 +201,7 @@ private static void startQRLogin() { JsonObject qrResult = sendGetRequest(qrUrl); if (qrResult == null || !qrResult.has("data")) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c生成二维码失败"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c生成二维码失败")); return; } @@ -226,9 +217,7 @@ private static void startQRLogin() { checkQRStatus(qrKey); } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c二维码登录失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c二维码登录失败: " + e.getMessage())); PupperClient.LOGGER.error("二维码登录失败: {}", e.getMessage(), e); } }); @@ -255,18 +244,14 @@ private static void checkQRStatus(String qrKey) { int code = checkResult.get("code").getAsInt(); if (code == 800) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c二维码已过期,请重新生成"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c二维码已过期,请重新生成")); return; } else if (code == 801) { // 等待扫码,继续轮询 attempts++; continue; } else if (code == 802) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§6已扫描,请在手机上确认登录"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§6已扫描,请在手机上确认登录")); attempts++; continue; } else if (code == 803) { @@ -291,14 +276,10 @@ private static void checkQRStatus(String qrKey) { attempts++; } - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c二维码登录超时,请重试"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c二维码登录超时,请重试")); } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c检查二维码状态失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c检查二维码状态失败: " + e.getMessage())); PupperClient.LOGGER.error("检查二维码状态失败: {}", e.getMessage(), e); } }); @@ -362,9 +343,7 @@ private static void checkLoginStatus() { } }); } else { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c登录状态: 已过期"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c登录状态: 已过期")); currentCookie = null; currentUserId = null; currentNickname = null; @@ -372,15 +351,11 @@ private static void checkLoginStatus() { saveLoginStatus(); } } else { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c登录状态检查失败"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c登录状态检查失败")); } } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c检查登录状态失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c检查登录状态失败: " + e.getMessage())); PupperClient.LOGGER.error("检查登录状态失败: {}", e.getMessage(), e); } }); @@ -403,19 +378,13 @@ private static void refreshLogin() { JsonObject result = sendGetRequestWithCookie(refreshUrl); if (result != null && result.get("code").getAsInt() == 200) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§a登录状态刷新成功"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§a登录状态刷新成功")); } else { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c登录状态刷新失败"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c登录状态刷新失败")); } } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c刷新登录状态失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c刷新登录状态失败: " + e.getMessage())); PupperClient.LOGGER.error("刷新登录状态失败: {}", e.getMessage(), e); } }); @@ -442,14 +411,10 @@ private static void logout() { currentPhone = null; saveLoginStatus(); - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§a已退出登录"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§a已退出登录")); } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c退出登录失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c退出登录失败: " + e.getMessage())); PupperClient.LOGGER.error("退出登录失败: {}", e.getMessage(), e); } }); @@ -540,51 +505,21 @@ private static String buildKeyword(String[] args, int startIndex) { return keyword.toString(); } - /** - * 发送GET请求 - */ private static JsonObject sendGetRequest(String urlString) throws IOException { - return sendRequest(urlString, "GET", null, false); + return sendRequest(urlString, "GET", false); } - /** - * 发送带Cookie的GET请求 - */ private static JsonObject sendGetRequestWithCookie(String urlString) throws IOException { - return sendRequest(urlString, "GET", null, true); + return sendRequest(urlString, "GET", true); } - /** - * 发送POST请求 - */ - private static JsonObject sendPostRequest(String urlString, String postData) throws IOException { - return sendRequest(urlString, "POST", postData, false); + private static JsonObject sendPostRequest(String urlString) throws IOException { + return sendRequest(urlString, "POST", false); } - /** - * 通用请求方法 - */ - private static JsonObject sendRequest(String urlString, String method, String postData, boolean useCookie) throws IOException { + private static JsonObject sendRequest(String urlString, String method, boolean useCookie) throws IOException { URL url = new URL(urlString); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod(method); - connection.setConnectTimeout(10000); - connection.setReadTimeout(10000); - connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); - - // 如果使用cookie且当前有登录状态,添加cookie - if (useCookie && currentCookie != null) { - connection.setRequestProperty("Cookie", currentCookie); - } - - if ("POST".equals(method) && postData != null) { - connection.setDoOutput(true); - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - try (OutputStream os = connection.getOutputStream()) { - byte[] input = postData.getBytes(StandardCharsets.UTF_8); - os.write(input, 0, input.length); - } - } + HttpURLConnection connection = getHttpURLConnection(method, useCookie, url); int responseCode = connection.getResponseCode(); if (responseCode != 200) { @@ -604,33 +539,35 @@ private static JsonObject sendRequest(String urlString, String method, String po } } - /** - * 获取当前cookie(供MusicCommand使用) - */ + private static @NonNull HttpURLConnection getHttpURLConnection(String method, boolean useCookie, URL url) throws IOException { + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(method); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + + if (useCookie && currentCookie != null) { + connection.setRequestProperty("Cookie", currentCookie); + } + + return connection; + } + public static String getCurrentCookie() { if (currentCookie == null) { - loadLoginStatus(); // 尝试加载保存的登录状态 + loadLoginStatus(); } return currentCookie; } - /** - * 获取当前用户ID - */ public static String getCurrentUserId() { return currentUserId; } - /** - * 获取当前昵称 - */ public static String getCurrentNickname() { return currentNickname; } - /** - * 获取当前手机号 - */ public static String getCurrentPhone() { return currentPhone; } diff --git a/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java b/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java index d5326f5..cedf324 100644 --- a/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java +++ b/src/main/java/cn/pupperclient/management/command/impl/MusicCommand.java @@ -158,8 +158,8 @@ private static void searchMusic(String keyword, int limit) { // 格式化显示 MutableComponent songText = Component.literal("§b" + (i + 1) + ". §f" + songName) .withStyle(style -> style - .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ".music download " + songId)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + .withClickEvent(new ClickEvent.SuggestCommand(".music download " + songId)) + .withHoverEvent(new HoverEvent.ShowText( Component.literal("§6点击快速下载\n§7歌手: " + artistsStr + "\n§7专辑: " + albumName)))); MutableComponent artistText = Component.literal(" §7- " + artistsStr); @@ -194,9 +194,7 @@ private static void downloadMusic(String songId, String quality) { if (checkResult == null || !checkResult.get("success").getAsBoolean()) { String message = checkResult != null ? checkResult.get("message").getAsString() : "检查失败"; - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c音乐不可用: " + message); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c音乐不可用: " + message)); return; } @@ -204,25 +202,19 @@ private static void downloadMusic(String songId, String quality) { JsonObject urlResult = sendGetRequest(urlApi); if (urlResult == null || !urlResult.has("data")) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c获取音乐URL失败"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c获取音乐URL失败")); return; } JsonArray data = urlResult.getAsJsonArray("data"); if (data.isEmpty() || data.get(0).getAsJsonObject().get("url") == null) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c该音质暂不可用,请尝试其他音质"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c该音质暂不可用,请尝试其他音质")); return; } String musicUrl = data.get(0).getAsJsonObject().get("url").getAsString(); if (musicUrl == null || musicUrl.isEmpty()) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c获取音乐链接失败"); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c获取音乐链接失败")); return; } @@ -286,9 +278,7 @@ private static void downloadMusic(String songId, String quality) { }); } catch (Exception e) { - Multithreading.runMainThread(() -> { - ChatUtils.addChatMessage("§c下载失败: " + e.getMessage()); - }); + Multithreading.runMainThread(() -> ChatUtils.addChatMessage("§c下载失败: " + e.getMessage())); PupperClient.LOGGER.error("音乐下载失败: {}", e.getMessage(), e); } }); @@ -332,7 +322,7 @@ private static void listDownloadedMusic() { return; } - File[] musicFiles = MUSIC_DIR.listFiles((dir, name) -> + File[] musicFiles = MUSIC_DIR.listFiles((_, name) -> name.toLowerCase().endsWith(".mp3") || name.toLowerCase().endsWith(".flac")); if (musicFiles == null || musicFiles.length == 0) { @@ -349,7 +339,7 @@ private static void listDownloadedMusic() { MutableComponent fileText = Component.literal("§b" + (i + 1) + ". §f" + displayName) .withStyle(style -> style - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + .withHoverEvent(new HoverEvent.ShowText( Component.literal("§6文件: " + fileName + "\n§7大小: " + formatFileSize(musicFile.length()))))); ChatUtils.addChatMessage(fileText); @@ -448,8 +438,7 @@ private static boolean downloadFile(String fileUrl, File outputFile) { outputStream.write(buffer, 0, bytesRead); totalRead += bytesRead; - // 可以在这里添加进度显示(可选) - if (fileSize > 0 && totalRead % (1024 * 1024) == 0) { // 每MB更新一次 + if (fileSize > 0 && totalRead % (1024 * 1024) == 0) { int progress = (int) ((totalRead * 100) / fileSize); ChatUtils.addChatMessage("§7下载进度: " + progress + "%"); } @@ -484,8 +473,8 @@ private static MutableComponent createClickableText(String command, String hover return Component.literal(" [下载]") .withStyle(ChatFormatting.GREEN) .withStyle(style -> style - .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + .withClickEvent(new ClickEvent.SuggestCommand(command)) + .withHoverEvent(new HoverEvent.ShowText( Component.literal(hoverText).withStyle(ChatFormatting.GRAY)))); } } From e9c9f672baae10e63938ef3d36b9437e885dce7b Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 21:06:47 +0800 Subject: [PATCH 21/45] Make it Compile! :D --- .../mod/impl/hud/BedwarsStatsOverlayMod.java | 6 +++--- .../management/mod/impl/hud/FallDamageHelp.java | 2 +- .../management/mod/impl/hud/NameDisplayMod.java | 2 +- .../management/mod/impl/hud/StopwatchMod.java | 3 ++- .../management/mod/impl/hud/TargetHUDMod.java | 4 ++-- .../management/mod/impl/misc/IRCChatMod.java | 13 +++++++------ .../management/mod/impl/player/FreelookMod.java | 3 ++- .../management/mod/impl/player/TaplookMod.java | 3 ++- .../management/mod/impl/player/ZoomMod.java | 3 ++- .../mod/impl/settings/ModMenuSettings.java | 5 +++-- .../management/quickplay/QuickPlay.java | 8 ++++---- .../management/quickplay/impl/ArcadeQuickPlay.java | 4 ++-- .../management/websocket/WebSocketManager.java | 6 +++--- .../java/cn/pupperclient/utils/chat/ChatUtils.java | 7 +++++++ 14 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java index d3d7ec7..8ff06eb 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java @@ -48,14 +48,14 @@ public BedwarsStatsOverlayMod() { for (PlayerInfo player : Objects.requireNonNull(client.getConnection()).getOnlinePlayers()) { - String name = player.getProfile().getName(); - String uuid = player.getProfile().getId().toString().replace("-", ""); + String name = player.getProfile().name(); + String uuid = player.getProfile().id().toString().replace("-", ""); HypixelUser hypixelUser = PupperClient.getInstance().getHypixelManager().getByUuid(uuid); if (hypixelUser != null) { player.getSkin(); - File file = SkinUtils.getSkin(player.getSkin().texture()); + File file = SkinUtils.getSkin(player.getSkin().body().texturePath()); if (file.exists()) { Skia.drawPlayerHead(file, getX() + 5.5F, getY() + offsetY, 12, 12, 2.5F); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java index abb00c9..4e1056c 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java @@ -29,7 +29,7 @@ public static boolean willFallToDeath() { return false; } - Level world = player.getCommandSenderWorld(); + Level world = player.level(); double currentY = player.getY(); BlockPos playerBlockPos = player.blockPosition(); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java index fd4b1c6..58f6189 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java @@ -17,7 +17,7 @@ public NameDisplayMod() { @Override public String getText() { - return "Name: " + client.player.getGameProfile().getName(); + return "Name: " + client.player.getGameProfile().name(); } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java index acb8fda..08da80a 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java @@ -2,6 +2,7 @@ import java.text.DecimalFormat; +import net.minecraft.client.input.KeyEvent; import org.lwjgl.glfw.GLFW; import cn.pupperclient.event.EventBus; @@ -21,7 +22,7 @@ public class StopwatchMod extends SimpleHUDMod { private DecimalFormat timeFormat = new DecimalFormat("0.00"); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_P, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_P, 0, 0))); public StopwatchMod() { super("mod.stopwatch.name", "mod.stopwatch.description", Icon.TIMER); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java index 2181543..cec7a24 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java @@ -72,7 +72,7 @@ public void onDisable() { private void registerFabricCallbacks() { AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { - if (world.isClientSide && player instanceof LocalPlayer && entity instanceof Player newTarget) { + if (world.isClientSide() && player instanceof LocalPlayer && entity instanceof Player newTarget) { updateTarget(newTarget); } return InteractionResult.PASS; @@ -286,7 +286,7 @@ private void drawPlayerAvatar(Player player, float x, float y, float size) { private File getSkinFile(Player player) { if (player instanceof AbstractClientPlayer clientPlayer) { if (clientPlayer.getSkin() != null) { - File skinFile = SkinUtils.getSkin(clientPlayer.getSkin().texture()); + File skinFile = SkinUtils.getSkin(clientPlayer.getSkin().body().texturePath()); if (skinFile.exists()) { return skinFile; } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java b/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java index 09b710e..5874e04 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/misc/IRCChatMod.java @@ -11,6 +11,7 @@ import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.management.mod.settings.impl.StringSetting; import cn.pupperclient.skia.font.Icon; +import cn.pupperclient.utils.chat.ChatUtils; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import java.io.IOException; import net.minecraft.network.chat.Component; @@ -70,7 +71,7 @@ public void onDisable() { public void onMessage(String sender, String message) throws IOException { if (showMessagesSetting.isEnabled() && client.player != null) { String formattedMessage = String.format("§9[IRC] §b%s§f: %s", sender, message); - client.player.displayClientMessage(Component.nullToEmpty(formattedMessage), false); + ChatUtils.addChatMessage(Component.nullToEmpty(formattedMessage)); } } @@ -81,7 +82,7 @@ public void onDisconnected(String message) { PupperClient.LOGGER.warn("IRC disconnected: {}", message); if (client.player != null) { - client.player.displayClientMessage(Component.nullToEmpty("§cIRC disconnected: " + message), false); + ChatUtils.addChatMessage(Component.nullToEmpty("§cIRC disconnected: " + message)); } // Schedule reconnect if auto-connect is enabled @@ -97,7 +98,7 @@ public void onConnected() { PupperClient.LOGGER.info("IRC connected successfully"); if (client.player != null) { - client.player.displayClientMessage(Component.nullToEmpty("§aConnected to IRC server!"), false); + ChatUtils.addChatMessage(Component.nullToEmpty("§aConnected to IRC server!")); } } @@ -105,7 +106,7 @@ public void onConnected() { public String getInGameUsername() { // Use Minecraft username if available, otherwise use setting if (client.player != null) { - return client.player.getGameProfile().getName(); + return client.player.getGameProfile().name(); } return usernameSetting.getValue(); } @@ -153,7 +154,7 @@ public void connectToIRC() { PupperClient.LOGGER.error("Failed to create IRC transport", e); if (client.player != null) { - client.player.displayClientMessage(Component.nullToEmpty("§cFailed to connect to IRC: " + e.getMessage()), false); + ChatUtils.addChatMessage(Component.nullToEmpty("§cFailed to connect to IRC: " + e.getMessage())); } transport = null; @@ -210,7 +211,7 @@ public String getServerInfo() { private void sendChatMessage(String message) { if (client.player != null) { - client.player.displayClientMessage(Component.nullToEmpty(message), false); + ChatUtils.addChatMessage(Component.nullToEmpty(message)); } } diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java index 5c01b91..49418b6 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/FreelookMod.java @@ -2,6 +2,7 @@ import java.util.Arrays; import net.minecraft.client.CameraType; +import net.minecraft.client.input.KeyEvent; import org.lwjgl.glfw.GLFW; import cn.pupperclient.event.EventBus; @@ -26,7 +27,7 @@ public class FreelookMod extends Mod { private BooleanSetting toggleSetting = new BooleanSetting("setting.toggle", "setting.toggle.description", Icon.SWITCH, this, false); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_B, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_B, 0, 0))); public FreelookMod() { super("mod.freelook.name", "mod.freelook.description", Icon._360, ModCategory.PLAYER); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java index 09b0381..209fe71 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/TaplookMod.java @@ -2,6 +2,7 @@ import java.util.Arrays; import net.minecraft.client.CameraType; +import net.minecraft.client.input.KeyEvent; import org.lwjgl.glfw.GLFW; import cn.pupperclient.event.EventBus; @@ -25,7 +26,7 @@ public class TaplookMod extends Mod { private BooleanSetting toggleSetting = new BooleanSetting("setting.toggle", "setting.toggle.description", Icon.SWITCH, this, false); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_V, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_V, 0, 0))); public TaplookMod() { super("mod.taplook.name", "mod.taplook.description", Icon.TOUCH_APP, ModCategory.PLAYER); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java b/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java index d30607a..328a271 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/player/ZoomMod.java @@ -1,6 +1,7 @@ package cn.pupperclient.management.mod.impl.player; +import net.minecraft.client.input.KeyEvent; import org.lwjgl.glfw.GLFW; import cn.pupperclient.animation.SimpleAnimation; @@ -37,7 +38,7 @@ public class ZoomMod extends Mod { private BooleanSetting smoothCameraSetting = new BooleanSetting("setting.smoothcamera", "setting.smoothcamera.description", Icon.MOTION_BLUR, this, true); private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_C, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_C, 0, 0))); public ZoomMod() { super("mod.zoom.name", "mod.zoom.description", Icon.ZOOM_IN, ModCategory.PLAYER); diff --git a/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java b/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java index 6ccbda7..3c9ab66 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java @@ -5,6 +5,7 @@ import net.minecraft.client.gui.screens.Screen; import cn.pupperclient.PupperClient; import cn.pupperclient.gui.MusicPlayGui; +import net.minecraft.client.input.KeyEvent; import org.lwjgl.glfw.GLFW; import cn.pupperclient.event.EventBus; @@ -31,9 +32,9 @@ public class ModMenuSettings extends Mod { private boolean languageInitialized = false; private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", - Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_RIGHT_SHIFT, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_RIGHT_SHIFT, 0, 0))); private KeybindSetting keybindSetting_music = new KeybindSetting("setting.keybind_music", "setting.keybind_music.description", - Icon.KEYBOARD, this, InputConstants.getKey(GLFW.GLFW_KEY_M, 0)); + Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_M, 0, 0))); private BooleanSetting darkModeSetting = new BooleanSetting("setting.darkmode", "setting.darkmode.description", Icon.DARK_MODE, this, false); private HctColorSetting hctColorSetting = new HctColorSetting("setting.color", "setting.color.description", diff --git a/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java b/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java index a7600e4..ecb10e9 100644 --- a/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java +++ b/src/main/java/cn/pupperclient/management/quickplay/QuickPlay.java @@ -1,16 +1,16 @@ package cn.pupperclient.management.quickplay; import java.util.ArrayList; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class QuickPlay { private ArrayList commands = new ArrayList(); private final String name; - private final ResourceLocation icon; + private final Identifier icon; - public QuickPlay(String name, ResourceLocation icon) { + public QuickPlay(String name, Identifier icon) { this.name = name; this.icon = icon; this.addCommands(); @@ -26,7 +26,7 @@ public ArrayList getCommands() { return commands; } - public ResourceLocation getIcon() { + public Identifier getIcon() { return icon; } diff --git a/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java b/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java index 07ad353..942d7a0 100644 --- a/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java +++ b/src/main/java/cn/pupperclient/management/quickplay/impl/ArcadeQuickPlay.java @@ -3,11 +3,11 @@ import cn.pupperclient.management.quickplay.QuickPlay; import cn.pupperclient.management.quickplay.QuickPlayCommand; import java.util.ArrayList; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class ArcadeQuickPlay extends QuickPlay { public ArcadeQuickPlay() { - super("Arcade", ResourceLocation.fromNamespaceAndPath("pupper/icons/hypixel/", "Arcade.png")); + super("Arcade", Identifier.fromNamespaceAndPath("pupper/icons/hypixel/", "Arcade.png")); } @Override diff --git a/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java b/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java index da11d1f..04f39db 100644 --- a/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java +++ b/src/main/java/cn/pupperclient/management/websocket/WebSocketManager.java @@ -80,7 +80,7 @@ private boolean shouldReconnect(GameProfile newProfile) { if (!currentGameProfile.equals(newProfile)) { LOGGER.info("User changed from {} to {}, reconnecting", - currentGameProfile.getName(), newProfile.getName()); + currentGameProfile.name(), newProfile.name()); retryCount = 0; return true; } @@ -157,8 +157,8 @@ private boolean authenticateWithMojang() { private SoarWebSocketClient createWebSocketClient() throws URISyntaxException { Map headers = new HashMap<>(); - headers.put("name", currentGameProfile.getName()); - headers.put("uuid", currentGameProfile.getId().toString().replace("-", "")); + headers.put("name", currentGameProfile.name()); + headers.put("uuid", currentGameProfile.id().toString().replace("-", "")); return new SoarWebSocketClient(headers, this::onConnectionFailure); } diff --git a/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java b/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java index c1dc04e..ffd311c 100644 --- a/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java +++ b/src/main/java/cn/pupperclient/utils/chat/ChatUtils.java @@ -46,6 +46,13 @@ public static void addChatMessage(boolean prefix, String message) { component(Component.literal(formattedMessage)); } + public static void addChatMessage(boolean prefix, Component message) { + if (message == null) return; + + String formattedMessage = (prefix ? PREFIX : "") + message.getString(); + component(Component.literal(formattedMessage)); + } + public static void addFormattedMessage(String message, ChatFormatting... formattings) { MutableComponent text = Component.literal(PREFIX_FORMATTED).withStyle(ChatFormatting.GRAY); text.append(Component.literal(message).withStyle(formattings)); From 6a74b23ded3adc902b7bd113e6d10a0b48293e51 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 21:15:01 +0800 Subject: [PATCH 22/45] fix(classTweaker): clean and remove removed mappings --- src/main/resources/pupper.classtweaker | 43 +++++++------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/src/main/resources/pupper.classtweaker b/src/main/resources/pupper.classtweaker index b8b4dd4..cb862d2 100644 --- a/src/main/resources/pupper.classtweaker +++ b/src/main/resources/pupper.classtweaker @@ -1,34 +1,15 @@ classTweaker v1 official -transitive-accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$ActionType -transitive-accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$Action -transitive-accessible class net/minecraft/client/gui/Gui$HeartType -transitive-accessible field net/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen serverSelectionList Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList; -transitive-accessible field net/minecraft/network/protocol/game/ServerboundPlayerCommandPacket action Lnet/minecraft/network/protocol/game/ServerboundPlayerCommandPacket$Action; -transitive-accessible method net/minecraft/client/player/LocalPlayer sendIsSprintingIfNeeded ()V -transitive-accessible field net/minecraft/client/player/LocalPlayer wasShiftKeyDown Z -transitive-accessible method net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl sendWhen (Lnet/minecraft/network/protocol/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V -transitive-accessible field net/minecraft/world/entity/player/Input jump Z -transitive-accessible field net/minecraft/world/entity/player/Input shift Z -transitive-mutable field net/minecraft/world/entity/player/Input jump Z -transitive-mutable field net/minecraft/world/entity/player/Input shift Z -transitive-accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I -transitive-accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I -transitive-accessible field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I -transitive-mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket xa I -transitive-mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket ya I -transitive-mutable field net/minecraft/network/protocol/game/ClientboundSetEntityMotionPacket za I -transitive-accessible field net/minecraft/client/Minecraft rightClickDelay I -transitive-accessible method net/minecraft/client/Minecraft startUseItem ()V -transitive-accessible method net/minecraft/client/Minecraft startAttack ()Z -transitive-accessible method net/minecraft/world/entity/LivingEntity updateFallFlyingMovement (Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3; -transitive-accessible field net/minecraft/client/gui/Gui HOTBAR_SELECTION_SPRITE Lnet/minecraft/resources/ResourceLocation; -transitive-accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_BACKGROUND_SPRITE Lnet/minecraft/resources/ResourceLocation; -transitive-accessible field net/minecraft/client/gui/Gui HOTBAR_ATTACK_INDICATOR_PROGRESS_SPRITE Lnet/minecraft/resources/ResourceLocation; -transitive-accessible method net/minecraft/client/renderer/entity/LivingEntityRenderer addLayer (Lnet/minecraft/client/renderer/entity/layers/RenderLayer;)Z -transitive-accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher renderers Ljava/util/Map; -transitive-accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; -transitive-accessible field net/minecraft/client/renderer/entity/EntityRenderDispatcher playerRenderers Ljava/util/Map; + +# OldAnimationsMod +accessible class net/minecraft/client/gui/Gui$HeartType +accessible method net/minecraft/client/Minecraft startUseItem ()V + +# onHitDelayFix +accessible method net/minecraft/client/Minecraft startAttack ()Z # ExtendedRenderPipelineBuilder -accessible method com/mojang/blaze3d/pipeline/RenderPipeline$Builder ()V -accessible method com/mojang/blaze3d/pipeline/RenderPipeline$Builder withSnippet (Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;)V +accessible method com/mojang/blaze3d/pipeline/RenderPipeline$Builder ()V +accessible method com/mojang/blaze3d/pipeline/RenderPipeline$Builder withSnippet (Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;)V + +# MixinMultiplayerScreen onRemoved +accessible field net/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen serverSelectionList Lnet/minecraft/client/gui/screens/multiplayer/ServerSelectionList; From 7915accf13a02c9d0a52acda77711a61b6fbe0c3 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 21:31:30 +0800 Subject: [PATCH 23/45] refactor(gradle): migrate build scripts to Kotlin DSL and use version catalogs --- build.gradle | 104 ------------------------- build.gradle.kts | 118 +++++++++++++++++++++++++++++ gradle/libs.versions.toml | 74 ++++++++++++++++++ settings.gradle | 10 --- settings.gradle.kts | 10 +++ src/main/resources/fabric.mod.json | 6 +- 6 files changed, 207 insertions(+), 115 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 5c346d0..0000000 --- a/build.gradle +++ /dev/null @@ -1,104 +0,0 @@ -plugins { - id 'net.fabricmc.fabric-loom' version '1.16-SNAPSHOT' -} - -project.ext.lwjglVersion = "3.4.1" -version = project.mod_version -group = project.maven_group - -base { - archivesName = project.archives_base_name -} - -loom { - accessWidenerPath = file("src/main/resources/pupper.classtweaker") -} - -repositories { - mavenCentral() - maven { url 'https://jitpack.io' } - maven { url "https://api.modrinth.com/maven" } - maven { url "https://maven.lenni0451.net/everything" } - maven { url "https://repo.viaversion.com/" } - maven { url "https://repo.opencollab.dev/maven-snapshots/" } - maven { url "https://maven.terraformersmc.com/" } - maven { url "https://maven.florianreuth.de/snapshots" } -} - -configurations { - modJij - include.extendsFrom modJij - implementation.extendsFrom modJij -} - -dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - implementation "net.fabricmc:fabric-loader:${project.loader_version}" - implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" - - implementation "com.viaversion:viafabricplus-api:4.5.1" - runtimeOnly "maven.modrinth:sodium:mc26.1.1-0.8.9-fabric" - runtimeOnly "maven.modrinth:iris:1.10.9+26.1-fabric" - // runtimeOnly "maven.modrinth:sodium-extra:mc26.1.1-0.8.6-fabric" - runtimeOnly "maven.modrinth:lithium:mc26.1.1-0.23.0-fabric" - // modImplementation "maven.modrinth:in-game-account-switcher:WBbjirJP" - implementation "com.viaversion:viafabricplus:4.5.1" - runtimeOnly "maven.modrinth:immediatelyfast:1.15.1+26.1.1-fabric" - runtimeOnly "maven.modrinth:entityculling:YSbzFHRt" - implementation "maven.modrinth:modmenu:18.0.0-alpha.8" - - modJij 'io.github.smartboot.socket:aio-core:1.7.1' - modJij 'com.github.ben-manes.caffeine:caffeine:3.1.8' - - modJij 'io.github.humbleui:types:0.2.0' - modJij 'io.github.humbleui:skija-windows-x64:0.143.12' - - modJij 'com.kohlschutter.junixsocket:junixsocket-common:2.10.1' - modJij 'org.java-websocket:Java-WebSocket:1.6.0' - modJij 'com.mpatric:mp3agic:0.9.1' - modJij 'javazoom:jlayer:1.0.1' - modJij 'com.googlecode.soundlibs:mp3spi:1.9.5.4' - modJij 'org:jaudiotagger:2.0.3' - modJij 'com.googlecode.soundlibs:jlayer:1.0.1.4' - modJij "net.lenni0451:MCPing:1.4.2" - modJij "net.lenni0451:Reflect:1.4.0" - implementation 'net.java.dev.jna:jna:5.12.1' - implementation 'net.java.dev.jna:jna-platform:5.12.1' - - def lwjglNfdDeps = [ - "org.lwjgl:lwjgl-nfd:$lwjglVersion", - "org.lwjgl:lwjgl-nfd::natives-linux", - "org.lwjgl:lwjgl-nfd::natives-macos", - "org.lwjgl:lwjgl-nfd::natives-macos-arm64", - "org.lwjgl:lwjgl-nfd::natives-windows" - ] - - lwjglNfdDeps.each { dep -> - modJij dep - } -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } - - doLast { - def resourcePath = sourceSets.main.resources.srcDirs[0] - def iconFile = new File(resourcePath, "assets/pupper/logo.png") - if (!iconFile.exists()) { - throw new GradleException("Pupper icon not found: ${iconFile.absolutePath}") - } - } -} - -tasks.withType(JavaCompile).configureEach { - it.options.release = 25 -} - -java { - toolchain.languageVersion = JavaLanguageVersion.of(25) - withSourcesJar() -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..1921f0a --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,118 @@ +import net.fabricmc.loom.task.RemapJarTask + +plugins { + alias(libs.plugins.fabric.loom) +} + +val lwjglVersion = "3.4.1" + +val suffix: String = providers.gradleProperty("build_number").getOrElse("local") +version = "${libs.versions.minecraft.get()}-$suffix" +group = property("maven_group") as String +val minecraftVersion = property("minecraft_version") as String + +base { + archivesName = property("archives_base_name") as String +} + +loom { + accessWidenerPath = file("src/main/resources/pupper.classtweaker") +} + +repositories { + mavenCentral() + maven("https://jitpack.io") + maven("https://api.modrinth.com/maven") + maven("https://maven.lenni0451.net/everything") + maven("https://repo.viaversion.com/") + maven("https://repo.opencollab.dev/maven-snapshots/") + maven("https://maven.terraformersmc.com/") + maven("https://maven.florianreuth.de/snapshots") +} + +configurations { + create("modJij") + "include" { + extendsFrom(getByName("modJij")) + } + "implementation" { + extendsFrom(getByName("modJij")) + } +} + +dependencies { + // Minecraft & Fabric base + minecraft(libs.minecraft) + implementation(libs.fabric.loader) + implementation(libs.fabric.api) + + // Mod runtime + implementation(libs.viafabricplus.api) + runtimeOnly(libs.sodium) + runtimeOnly(libs.iris) + runtimeOnly(libs.lithium) + runtimeOnly(libs.immediatelyfast) + // runtimeOnly(libs.entityculling) + implementation(libs.modmenu) + implementation(libs.viafabricplus) + + // lib + "modJij"(libs.smartboot.aio) + "modJij"(libs.caffeine) + "modJij"(libs.humbleui.types) + "modJij"(libs.skija.windows) + "modJij"(libs.junixsocket.common) + "modJij"(libs.java.websocket) + "modJij"(libs.mp3agic) + "modJij"(libs.jlayer) + "modJij"(libs.mp3spi) + "modJij"(libs.jaudiotagger) + "modJij"(libs.jlayer.google) + "modJij"(libs.mcping) + "modJij"(libs.reflect) + + // JNA + implementation(libs.jna) + implementation(libs.jna.platform) + + // LWJGL NFD + "modJij"(libs.lwjgl.nfd) + + // LWJGL NFD Natives + val nfdNatives = listOf( + "natives-linux", + "natives-macos", + "natives-macos-arm64", + "natives-windows" + ) + nfdNatives.forEach { classifier -> + "modJij"("org.lwjgl:lwjgl-nfd:$lwjglVersion:$classifier") + } +} + +tasks.processResources { + inputs.property("version", project.version) + + filesMatching("fabric.mod.json") { + expand(mapOf("version" to project.version)) + } + + doLast { + val resourcePath = sourceSets.main.get().resources.srcDirs.first() + val iconFile = File(resourcePath, "assets/pupper/logo.png") + if (!iconFile.exists()) { + throw GradleException("Pupper icon not found: ${iconFile.absolutePath}") + } + } +} + +tasks.withType().configureEach { + options.release = 25 +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(25) + } + withSourcesJar() +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..d9e197d --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,74 @@ +[versions] +# base +jdk = "25" +minecraft = "26.1.2" +fabric-loader = "0.18.6" +fabric-api = "0.145.4+26.1.2" + +# fabric +loom = "1.16-SNAPSHOT" + +# mod +sodium = "mc26.1.1-0.8.9-fabric" +lithium = "mc26.1.1-0.23.0-fabric" +iris = "1.10.9+26.1-fabric" +modmenu = "18.0.0-alpha.8" +viafabricplus = "4.5.1" +immediatelyfast = "1.15.1+26.1.1-fabric" +# entityculling = "YSbzFHRt" + +# lib +lwjgl = "3.4.1" +smartboot-aio = "1.7.1" +caffeine = "3.1.8" +humbleui-types = "0.2.0" +skija-windows = "0.143.12" +junixsocket = "2.10.1" +java-websocket = "1.6.0" +mp3agic = "0.9.1" +jlayer = "1.0.1" +mp3spi = "1.9.5.4" +jaudiotagger = "2.0.3" +jlayer-google = "1.0.1.4" +mcping = "1.4.2" +reflect = "1.4.0" +jna = "5.12.1" + +[libraries] +# Fabric +minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } +fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" } +fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" } + +# mod +sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" } +lithium = { module = "maven.modrinth:lithium", version.ref = "lithium" } +iris = { module = "maven.modrinth:iris", version.ref = "iris" } +modmenu = { module = "maven.modrinth:modmenu", version.ref = "modmenu" } +viafabricplus = { module = "com.viaversion:viafabricplus", version.ref = "viafabricplus" } +viafabricplus-api = { module = "com.viaversion:viafabricplus-api", version.ref = "viafabricplus" } +immediatelyfast = { module = "maven.modrinth:immediatelyfast", version.ref = "immediatelyfast" } +# entityculling = { module = "maven.modrinth:entityculling", version.ref = "entityculling" } + +# lib +smartboot-aio = { module = "io.github.smartboot.socket:aio-core", version.ref = "smartboot-aio" } +caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" } +humbleui-types = { module = "io.github.humbleui:types", version.ref = "humbleui-types" } +skija-windows = { module = "io.github.humbleui:skija-windows-x64", version.ref = "skija-windows" } +junixsocket-common = { module = "com.kohlschutter.junixsocket:junixsocket-common", version.ref = "junixsocket" } +java-websocket = { module = "org.java-websocket:Java-WebSocket", version.ref = "java-websocket" } +mp3agic = { module = "com.mpatric:mp3agic", version.ref = "mp3agic" } +jlayer = { module = "javazoom:jlayer", version.ref = "jlayer" } +mp3spi = { module = "com.googlecode.soundlibs:mp3spi", version.ref = "mp3spi" } +jaudiotagger = { module = "org:jaudiotagger", version.ref = "jaudiotagger" } +jlayer-google = { module = "com.googlecode.soundlibs:jlayer", version.ref = "jlayer-google" } +mcping = { module = "net.lenni0451:MCPing", version.ref = "mcping" } +reflect = { module = "net.lenni0451:Reflect", version.ref = "reflect" } +jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } +jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" } + +# LWJGL NFD +lwjgl-nfd = { module = "org.lwjgl:lwjgl-nfd", version.ref = "lwjgl" } + +[plugins] +fabric-loom = { id = "net.fabricmc.fabric-loom", version.ref = "loom" } diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 75c4d72..0000000 --- a/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -pluginManagement { - repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - mavenCentral() - gradlePluginPortal() - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..a7f3f56 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + mavenCentral() + gradlePluginPortal() + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b87fef6..2c13ba8 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,7 +21,11 @@ "depends": { "fabricloader": ">=0.16.10", "fabric": "*", - "minecraft": "26.1.2", + "minecraft": [ + "26.1", + "26.1.1", + "${minecraft_version}" + ], "viafabricplus": "*", "ias": "*" }, From 7a6cee5385b226e721aa1b6aacf546acbf562c1e Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 21:33:27 +0800 Subject: [PATCH 24/45] chore: expand minecraft_version in fabric.mod.json during build --- build.gradle.kts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1921f0a..f73c4a7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -92,9 +92,15 @@ dependencies { tasks.processResources { inputs.property("version", project.version) + inputs.property("minecraft_version", minecraftVersion) filesMatching("fabric.mod.json") { - expand(mapOf("version" to project.version)) + expand( + mapOf( + "version" to project.version, + "minecraft_version" to minecraftVersion + ) + ) } doLast { From 1ce27a152e3d83f7b0d4c8609aa6a24aab1379aa Mon Sep 17 00:00:00 2001 From: oneachina Date: Sat, 11 Apr 2026 21:56:26 +0800 Subject: [PATCH 25/45] fix: resolve mod compatibility issues and missing dependencies - Update mod version to Minecraft 26.1.2 - Fix fabric-api dependency - Remove unused ias requirement --- build.gradle.kts | 4 +--- gradle/libs.versions.toml | 10 +++++----- src/main/resources/fabric.mod.json | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f73c4a7..29b8221 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,3 @@ -import net.fabricmc.loom.task.RemapJarTask - plugins { alias(libs.plugins.fabric.loom) } @@ -52,7 +50,7 @@ dependencies { runtimeOnly(libs.iris) runtimeOnly(libs.lithium) runtimeOnly(libs.immediatelyfast) - // runtimeOnly(libs.entityculling) + runtimeOnly(libs.entityculling) implementation(libs.modmenu) implementation(libs.viafabricplus) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d9e197d..dd16e6d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,12 +10,12 @@ loom = "1.16-SNAPSHOT" # mod sodium = "mc26.1.1-0.8.9-fabric" -lithium = "mc26.1.1-0.23.0-fabric" +lithium = "mc26.1.2-0.24.1-fabric" iris = "1.10.9+26.1-fabric" modmenu = "18.0.0-alpha.8" -viafabricplus = "4.5.1" -immediatelyfast = "1.15.1+26.1.1-fabric" -# entityculling = "YSbzFHRt" +viafabricplus = "4.5.2" +immediatelyfast = "1.15.2+26.1.2-fabric" +entityculling = "NaRJu6ah" # lib lwjgl = "3.4.1" @@ -48,7 +48,7 @@ modmenu = { module = "maven.modrinth:modmenu", version.ref = "modmenu" } viafabricplus = { module = "com.viaversion:viafabricplus", version.ref = "viafabricplus" } viafabricplus-api = { module = "com.viaversion:viafabricplus-api", version.ref = "viafabricplus" } immediatelyfast = { module = "maven.modrinth:immediatelyfast", version.ref = "immediatelyfast" } -# entityculling = { module = "maven.modrinth:entityculling", version.ref = "entityculling" } +entityculling = { module = "maven.modrinth:entityculling", version.ref = "entityculling" } # lib smartboot-aio = { module = "io.github.smartboot.socket:aio-core", version.ref = "smartboot-aio" } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 2c13ba8..a28cd31 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -19,15 +19,14 @@ "pupper.mixins.json" ], "depends": { - "fabricloader": ">=0.16.10", - "fabric": "*", + "fabricloader": ">=0.18.6", + "fabric-api": ">=0.145.4+26.1.2", "minecraft": [ "26.1", "26.1.1", "${minecraft_version}" ], - "viafabricplus": "*", - "ias": "*" + "viafabricplus": "*" }, "breaks": { "optifabric": "*", From 0f2bcd014cc400dae3b4a0a7ea4f97cd0330b00b Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 12 Apr 2026 17:47:04 +0800 Subject: [PATCH 26/45] made it can use (maybe only use command to enabled mod) --- .../pupperclient/gui/api/SimpleSoarGui.java | 2 +- .../accessors/EntityRenderStateAccessor.java | 15 -- .../client/MixinMinecraftClient.java | 11 +- .../client/gui/MixinSplashScreen.java | 147 +++++++++++++++--- .../client/gui/MixinTitleScreen.java | 6 +- .../client/render/GuiRendererMixin.java | 28 +++- .../minecraft/client/util/MixinWindow.java | 2 +- .../mixins/minecraft/entity/MixinAvatar.java | 25 +++ .../mixins/minecraft/entity/MixinEntity.java | 41 ++--- .../minecraft/entity/MixinPlayerEntity.java | 20 +-- .../shader/PupperRenderPipelines.java | 89 +++++------ .../skia/context/SkiaContext.java | 111 ++++++++++--- .../cn/pupperclient/skia/gl/Properties.java | 1 + .../java/cn/pupperclient/skia/gl/State.java | 2 + .../utils/render/PupperGuiRenderer.java | 20 +++ src/main/resources/pupper.mixins.json | 5 +- 16 files changed, 365 insertions(+), 160 deletions(-) delete mode 100644 src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java create mode 100644 src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAvatar.java create mode 100644 src/main/java/cn/pupperclient/utils/render/PupperGuiRenderer.java diff --git a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java index 51f1837..af1de95 100644 --- a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java @@ -36,7 +36,7 @@ protected void init() { @Override public void extractRenderState(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta) { - SkiaContext.draw((skiaContext) -> { + SkiaContext.draw((_) -> { Skia.save(); if (mcScale) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java b/src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java deleted file mode 100644 index 01fd132..0000000 --- a/src/main/java/cn/pupperclient/mixin/mixins/accessors/EntityRenderStateAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @Author: oneachina - * @link: github.com/oneachina - */ -package cn.pupperclient.mixin.mixins.accessors; - -import net.minecraft.client.renderer.entity.state.EntityRenderState; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(EntityRenderState.class) -public interface EntityRenderStateAccessor { - @Accessor("id") - int getEntityId(); -} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index 14ed1a2..9df49ff 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -26,6 +26,7 @@ import cn.pupperclient.gui.api.SimpleSoarGui; import com.mojang.blaze3d.platform.Window; import org.jetbrains.annotations.Nullable; +import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -151,10 +152,18 @@ public void updateTitle() { @Inject(method = "", at = @At("TAIL")) public void init(CallbackInfo ci) throws IOException { - SkiaContext.createSurface(window.getScreenWidth(), window.getScreenHeight()); PupperClient.getInstance().start(); } + @Inject(method = "", at = @At("RETURN")) + public void skia(CallbackInfo ci) throws IOException { + int[] width = new int[1]; + int[] height = new int[1]; + + GLFW.glfwGetFramebufferSize(Minecraft.getInstance().getWindow().handle(), width, height); + SkiaContext.createSurface(width[0] > 0 ? width[0] : 1, height[0] > 0 ? height[0] : 1); + } + @Inject(method = "destroy", at = @At("HEAD")) public void onShutdown(CallbackInfo ci) { PupperClient.getInstance().onShutdown(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java index a4177d9..eb366e4 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java @@ -9,11 +9,12 @@ import io.github.humbleui.skija.Font; import io.github.humbleui.types.Rect; import java.awt.Color; - import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.resources.Identifier; import net.minecraft.util.Util; import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL30; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -59,6 +60,15 @@ public abstract class MixinSplashScreen { @Unique private long welcomeStartTime = -1L; @Unique private long tapPromptStartTime = -1L; @Unique private long tapClickTime = -1L; + @Unique private long lastDebugLogTime = 0L; + @Unique private long lastGlErrorLogTime = 0L; + @Unique private boolean loggedInit = false; + @Unique private boolean loggedLogoType = false; + @Unique private int lastLoggedFbo = Integer.MIN_VALUE; + @Unique private int lastLoggedGlError = Integer.MIN_VALUE; + @Unique private int lastLoggedBoundFbo = Integer.MIN_VALUE; + @Unique private int lastLoggedDrawFbo = Integer.MIN_VALUE; + @Unique private int lastLoggedReadFbo = Integer.MIN_VALUE; @Unique private void ensureLogoTexture() { @@ -66,30 +76,110 @@ private void ensureLogoTexture() { tm.getTexture(CUSTOM_LOGO); } - @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void pupper_takeOverAndRender(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - int width = Minecraft.getInstance().getWindow().getScreenWidth(); - int height = Minecraft.getInstance().getWindow().getScreenHeight(); - - // Recreate surface if window size changed - if (lastWindowWidth != width || lastWindowHeight != height) { - SkiaContext.createSurface(width, height); - lastWindowWidth = width; - lastWindowHeight = height; + @Unique + private void debug(String message) { + long now = Util.getMillis(); + if (now - lastDebugLogTime > 1000L) { + lastDebugLogTime = now; + PupperLogger.info("Splash", message); } + } - if (width <= 0 || height <= 0) { - return; + @Unique + private void debugOnce(String message) { + if (!loggedInit) { + loggedInit = true; + PupperLogger.info("Splash", message); + } + } + + @Unique + private void logGlErrors(String stage) { + int err; + int count = 0; + while ((err = GL11.glGetError()) != GL11.GL_NO_ERROR && count < 16) { + count++; + long now = Util.getMillis(); + boolean shouldLog = err != lastLoggedGlError || (now - lastGlErrorLogTime) > 1000L; + if (shouldLog) { + lastGlErrorLogTime = now; + lastLoggedGlError = err; + PupperLogger.error("Splash", "GL error @" + stage + ": " + err); + } + } + } + + @Unique + private void logFramebufferBindings(String stage) { + int mainFbo = 0; + + int boundFbo = glGetIntSafe(GL30.GL_FRAMEBUFFER_BINDING, -1); + int drawFbo = glGetIntSafe(GL30.GL_DRAW_FRAMEBUFFER_BINDING, -1); + int readFbo = glGetIntSafe(GL30.GL_READ_FRAMEBUFFER_BINDING, -1); + + boolean shouldLog = false; + if (mainFbo != lastLoggedFbo || boundFbo != lastLoggedBoundFbo || drawFbo != lastLoggedDrawFbo || readFbo != lastLoggedReadFbo) { + shouldLog = true; + } else { + long now = Util.getMillis(); + if (now - lastDebugLogTime > 1000L) { + shouldLog = true; + } } - ci.cancel(); + if (shouldLog) { + lastLoggedFbo = mainFbo; + lastLoggedBoundFbo = boundFbo; + lastLoggedDrawFbo = drawFbo; + lastLoggedReadFbo = readFbo; + PupperLogger.info("Splash", stage + " fbo(main=" + mainFbo + ", bound=" + boundFbo + ", draw=" + drawFbo + ", read=" + readFbo + ")"); + } + } - SkiaContext.draw(canvas -> renderWithSkia(canvas, width, height, mouseX, mouseY)); + @Unique + private int glGetIntSafe(int pname, int fallback) { + try { + int[] value = new int[1]; + GL11.glGetIntegerv(pname, value); + return value[0]; + } catch (Throwable t) { + return fallback; + } + } + + @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) + private void pupper_takeOverAndRender(GuiGraphicsExtractor extractor, int mouseX, int mouseY, float delta, CallbackInfo ci) { +// int width = Minecraft.getInstance().getWindow().getScreenWidth(); +// int height = Minecraft.getInstance().getWindow().getScreenHeight(); +// +// if (lastWindowWidth != width || lastWindowHeight != height) { +// PupperLogger.info("Splash", "Framebuffer size changed: " + lastWindowWidth + "x" + lastWindowHeight + " -> " + width + "x" + height); +// // SkiaContext.createSurface already called in Window/Minecraft mixins +// lastWindowWidth = width; +// lastWindowHeight = height; +// } +// +// ci.cancel(); +// +// debugOnce("Splash takeover enabled. fadeIn=" + fadeIn + ", logo=" + CUSTOM_LOGO); +// debug("tick: fadeIn=" + fadeIn + ", w=" + width + ", h=" + height + ", mouse=" + mouseX + "," + mouseY); +// +// logFramebufferBindings("pre-draw"); +// logGlErrors("pre-draw"); +// try { +// SkiaContext.draw(canvas -> renderWithSkia(canvas, width, height, mouseX, mouseY)); +// } catch (Exception e) { +// PupperLogger.error("Splash", "Error during Skia draw: ", e); +// } +// logGlErrors("post-draw"); +// logFramebufferBindings("post-draw"); } @Unique private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, int mouseY) { ensureLogoTexture(); + logGlErrors("ensureLogoTexture"); + logFramebufferBindings("after-ensureLogoTexture"); // Handle reloading state if (this.fadeIn) { @@ -224,6 +314,7 @@ private boolean isTapPromptClicked(int width, int height, int mouseX, int mouseY private void renderLoadingScreen(int width, int height, long timePassed, float alpha, boolean showProgress) { // Background Skia.drawRect(0, 0, width, height, new Color(0, 0, 0, (int)(255 * alpha))); + logGlErrors("drawRect(background)"); // Calculate scaled logo size and position int scaledSize = (int)(LOGO_ACTUAL_SIZE * LOGO_SCALE); @@ -232,26 +323,42 @@ private void renderLoadingScreen(int width, int height, long timePassed, float a // Draw logo drawLogo(logoX, logoY, scaledSize, alpha); + logGlErrors("drawLogo"); if (showProgress) { // Progress bar float progress = Math.min(1f, (float) timePassed / ANIMATION_TOTAL_TIME); drawProgressBar(width, height, progress, alpha); + logGlErrors("drawProgressBar"); } else { // Reloading progress bar drawReloadingProgressBar(width, height, timePassed, alpha); + logGlErrors("drawReloadingProgressBar"); } } @Unique private void drawLogo(int x, int y, int size, float alpha) { - // Draw logo using Skia - var textureId = Minecraft.getInstance().getTextureManager().getTexture(CUSTOM_LOGO).getTexture(); - - if (textureId instanceof GlTexture glTexture) { + var tex = Minecraft.getInstance().getTextureManager().getTexture(CUSTOM_LOGO); + var textureId = tex.getTexture(); + if (!loggedLogoType) { + loggedLogoType = true; + PupperLogger.info("Splash", "Logo texture impl=" + textureId.getClass().getName()); + } + if (textureId instanceof GlTexture glTexture && glTexture.glId() != -1) { + debug("Logo glId=" + glTexture.glId() + ", draw=" + x + "," + y + " size=" + size + " alpha=" + alpha); + logFramebufferBindings("before-drawLogoImage"); + logGlErrors("before-drawLogoImage"); Skia.drawImage(glTexture.glId(), x, y, size, size, alpha); + logGlErrors("after-drawLogoImage"); + logFramebufferBindings("after-drawLogoImage"); } else { - PupperLogger.warn("Splash", "don't have logo GlTexture"); + PupperLogger.warn("Splash", "Logo texture not ready or invalid"); + } + + int err = GL11.glGetError(); + if (err != GL11.GL_NO_ERROR) { + PupperLogger.error("Splash", "GL error after drawLogo: " + err); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java index 77ea983..a012647 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java @@ -19,12 +19,12 @@ protected MixinTitleScreen(Component title) { @Inject(method = "init()V", at = @At("HEAD"), cancellable = true) public void onInit(CallbackInfo ci) { - Minecraft.getInstance().setScreen(new MainMenuGui()); - ci.cancel(); +// Minecraft.getInstance().setScreen(new MainMenuGui()); +// ci.cancel(); } @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) public void onRender(CallbackInfo ci) { - ci.cancel(); +// ci.cancel(); } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java index 8624ba3..8cfa7d9 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java @@ -7,10 +7,14 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.mixin.mixins.accessors.GameRendererAccessor; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; +import cn.pupperclient.utils.render.PupperGuiRenderer; import cn.pupperclient.utils.render.RenderUtils; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.gui.render.GuiRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; import net.minecraft.client.renderer.fog.FogRenderer; import net.minecraft.client.renderer.state.gui.GuiRenderState; import net.minecraft.util.profiling.Profiler; @@ -21,10 +25,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.List; + @Mixin(GuiRenderer.class) public abstract class GuiRendererMixin implements IMinecraft { - @Shadow - public abstract void render(GpuBufferSlice fogBuffer); + @Unique + private PupperGuiRenderer guiRenderer; @Shadow public abstract void endFrame(); @@ -32,8 +38,24 @@ public abstract class GuiRendererMixin implements IMinecraft { @Unique private GuiRenderState renderState; + @Inject(method = "", at = @At("RETURN")) + private void pupper$init(GuiRenderState renderState, MultiBufferSource.BufferSource bufferSource, SubmitNodeCollector submitNodeCollector, FeatureRenderDispatcher featureRenderDispatcher, List pictureInPictureRenderers, CallbackInfo ci) { + if ((GuiRenderer) (Object) this instanceof PupperGuiRenderer) return; + this.renderState = new GuiRenderState(); + + guiRenderer = new PupperGuiRenderer( + this.renderState, + bufferSource, + submitNodeCollector, + featureRenderDispatcher, + pictureInPictureRenderers + ); + } + @Inject(method = "draw", at = @At("HEAD")) private void draw(CallbackInfo ci) { + if (guiRenderer == null) return; + var fogRenderer = ((GameRendererAccessor) client.gameRenderer).pupper$fogRenderer(); if (RenderUtils.canUpdate()) { @@ -41,7 +63,7 @@ private void draw(CallbackInfo ci) { RenderUtils.unscaledProjection(); - this.render(fogRenderer.getBuffer(FogRenderer.FogMode.NONE)); + guiRenderer.render(fogRenderer.getBuffer(FogRenderer.FogMode.NONE)); RenderUtils.scaledProjection(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java index bb36d88..1b5a626 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java @@ -28,7 +28,7 @@ public class MixinWindow { @Inject(method = "onFramebufferResize", at = @At("RETURN")) private void onFramebufferSizeChanged(long window, int width, int height, CallbackInfo ci) { - SkiaContext.createSurface(width, height); + SkiaContext.createSurface(width > 0 ? width : 1, height > 0 ? height : 1); } @Inject(method = "", at = @At("RETURN")) diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAvatar.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAvatar.java new file mode 100644 index 0000000..fe5c66a --- /dev/null +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinAvatar.java @@ -0,0 +1,25 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.mixin.mixins.minecraft.entity; + +import cn.pupperclient.management.mod.impl.player.ForceMainHandMod; +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.Avatar; +import net.minecraft.world.entity.HumanoidArm; +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(Avatar.class) +public class MixinAvatar { + @Inject(method = "getMainArm", at = @At("HEAD"), cancellable = true) + private void forceLeftHand(CallbackInfoReturnable cir) { + var self = (Object) this; + if (self != Minecraft.getInstance().player) { + cir.setReturnValue(ForceMainHandMod.getInstance().isRightHand() ? HumanoidArm.RIGHT : HumanoidArm.LEFT); + } + } +} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java index 1878ad2..1325ccf 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinEntity.java @@ -2,11 +2,9 @@ import cn.pupperclient.utils.misc.SoundEventHelper; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.nbt.CompoundTag; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -21,9 +19,6 @@ @Mixin(Entity.class) public abstract class MixinEntity implements IMixinCameraEntity { - @Unique - protected Vec3 stuckSpeedMultiplier; - @Unique private float cameraPitch; @@ -36,24 +31,6 @@ public abstract class MixinEntity implements IMixinCameraEntity { @Shadow public abstract float getYRot(); - @Shadow - public abstract boolean equals(Object o); - - @Shadow - public abstract float getViewXRot(float tickDelta); - - @Shadow - public abstract float getViewYRot(float tickDelta); - - @Shadow - public abstract Vec3 calculateViewVector(float pitch, float yaw); - - @Shadow - public abstract boolean save(CompoundTag nbt); - - @Shadow - public abstract int getId(); - @Inject(method = "turn", at = @At("HEAD")) private void onPlayerDirectionChange(double cursorDeltaX, double cursorDeltaY, CallbackInfo ci) { @@ -68,17 +45,17 @@ private void onPlayerDirectionChange(double cursorDeltaX, double cursorDeltaY, C @Inject(method = "turn", at = @At("HEAD"), cancellable = true) public void changeCameraLookDirection(double xDelta, double yDelta, CallbackInfo ci) { - if (FreelookMod.getInstance().isEnabled() && FreelookMod.getInstance().isActive() - && (Entity) (Object) this instanceof LocalPlayer) { - double pitchDelta = (yDelta * 0.15); - double yawDelta = (xDelta * 0.15); - - this.cameraPitch = Mth.clamp(this.cameraPitch + (float) pitchDelta, -90.0f, 90.0f); - this.cameraYaw += (float) yawDelta; + if (FreelookMod.getInstance().isEnabled() && FreelookMod.getInstance().isActive()) { + if ((Entity) (Object) this instanceof LocalPlayer) { + double pitchDelta = (yDelta * 0.15); + double yawDelta = (xDelta * 0.15); - ci.cancel(); + this.cameraPitch = Mth.clamp(this.cameraPitch + (float) pitchDelta, -90.0f, 90.0f); + this.cameraYaw += (float) yawDelta; - } + ci.cancel(); + } + } } @Override diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java index dc181db..09522b6 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/entity/MixinPlayerEntity.java @@ -5,31 +5,15 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import cn.pupperclient.management.mod.impl.player.ForceMainHandMod; import cn.pupperclient.management.mod.impl.player.OldAnimationsMod; -import net.minecraft.client.Minecraft; -import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.player.Player; @Mixin(Player.class) -public class MixinPlayerEntity { - - @Inject(method = "getAttackStrengthScale", at = @At("HEAD"), cancellable = true) +public abstract class MixinPlayerEntity { + @Inject(method = "getAttackStrengthScale", at = @At("HEAD"), cancellable = true) public void disableCooldown(CallbackInfoReturnable cir) { if (OldAnimationsMod.getInstance().isEnabled() && OldAnimationsMod.getInstance().isDisableAttackCooldown()) { cir.setReturnValue(1F); } } - - @Inject(method = "getMainArm", at = @At("HEAD"), cancellable = true) - private void injectGetMainArm(CallbackInfoReturnable cir) { - - Minecraft client = Minecraft.getInstance(); - Player player = client.player; - Player e = ((Player) (Object) this); - - if (ForceMainHandMod.getInstance().isEnabled() && e.getId() != player.getId()) { - cir.setReturnValue(ForceMainHandMod.getInstance().isRightHand() ? HumanoidArm.RIGHT : HumanoidArm.LEFT); - } - } } diff --git a/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java b/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java index f17765a..0e8b52e 100644 --- a/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java +++ b/src/main/java/cn/pupperclient/shader/PupperRenderPipelines.java @@ -67,50 +67,51 @@ public abstract class PupperRenderPipelines { .build() ); - // UI - public static final RenderPipeline UI_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(getLocation("pipeline/ui_colored")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.Mode.TRIANGLES) - .withVertexShader(getLocation("ui_colored")) - .withFragmentShader(getLocation("ui_colored")) - .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) - .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) - .withCull(true) - .build() - ); - - public static final RenderPipeline UI_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLineSmooth() - .withLocation(getLocation("pipeline/ui_colored_lines")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.Mode.LINES) - .withVertexShader(getLocation("ui_colored")) - .withFragmentShader(getLocation("ui_colored")) - .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) - .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) - .withCull(true) - .build() - ); - - public static final RenderPipeline UI_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(getLocation("pipeline/ui_textured")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.Mode.TRIANGLES) - .withVertexShader(getLocation("ui_textured")) - .withFragmentShader(getLocation("ui_textured")) - .withSampler("u_Texture") - .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) - .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) - .withCull(true) - .build() - ); - - public static final RenderPipeline UI_ROUNDED_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) - .withLocation(getLocation("pipeline/ui_rounded_textured")) - .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.Mode.TRIANGLES) - .withVertexShader(getLocation("ui_textured")) - .withFragmentShader(getLocation("ui_rounded_textured")) - .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) - .build() - ); +// +// // UI +// public static final RenderPipeline UI_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) +// .withLocation(getLocation("pipeline/ui_colored")) +// .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.Mode.TRIANGLES) +// .withVertexShader(getLocation("ui_colored")) +// .withFragmentShader(getLocation("ui_colored")) +// .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) +// .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) +// .withCull(true) +// .build() +// ); +// +// public static final RenderPipeline UI_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) +// .withLineSmooth() +// .withLocation(getLocation("pipeline/ui_colored_lines")) +// .withVertexFormat(PupperVertexFormats.POS2_COLOR, VertexFormat.Mode.LINES) +// .withVertexShader(getLocation("ui_colored")) +// .withFragmentShader(getLocation("ui_colored")) +// .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) +// .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) +// .withCull(true) +// .build() +// ); +// +// public static final RenderPipeline UI_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) +// .withLocation(getLocation("pipeline/ui_textured")) +// .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.Mode.TRIANGLES) +// .withVertexShader(getLocation("ui_textured")) +// .withFragmentShader(getLocation("ui_textured")) +// .withSampler("u_Texture") +// .withDepthStencilState(new DepthStencilState(CompareOp.ALWAYS_PASS, false)) +// .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) +// .withCull(true) +// .build() +// ); +// +// public static final RenderPipeline UI_ROUNDED_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) +// .withLocation(getLocation("pipeline/ui_rounded_textured")) +// .withVertexFormat(PupperVertexFormats.POS2_COLOR_TEX, VertexFormat.Mode.TRIANGLES) +// .withVertexShader(getLocation("ui_textured")) +// .withFragmentShader(getLocation("ui_rounded_textured")) +// .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) +// .build() +// ); private static RenderPipeline add(RenderPipeline pipeline) { PIPELINES.add(pipeline); diff --git a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java index acc7eed..30c9962 100644 --- a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java +++ b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java @@ -3,72 +3,141 @@ import java.util.Objects; import java.util.function.Consumer; +import cn.pupperclient.PupperLogger; import cn.pupperclient.skia.api.WrappedBackendRenderTarget; import cn.pupperclient.skia.gl.States; +import com.mojang.blaze3d.opengl.GlTexture; +import com.mojang.blaze3d.pipeline.RenderTarget; import io.github.humbleui.skija.*; +import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL30; +/** + * Skia rendering context manager for Pupper Client. + * Handles Skia DirectContext, Surface, and BackendRenderTarget creation and drawing. + */ public class SkiaContext { - private static DirectContext context = null; - private static Surface surface; - private static BackendRenderTarget renderTarget; + // Skia rendering objects + private static DirectContext context = null; // Skia GPU context + private static Surface surface; // Skia drawing surface + private static BackendRenderTarget renderTarget; // Backend render target for GL + + // GL states to reset before Skia drawing private static final BackendState[] states = { BackendState.GL_BLEND, BackendState.GL_VERTEX, BackendState.GL_PIXEL_STORE, - BackendState.GL_TEXTURE_BINDING, - BackendState.GL_MISC + BackendState.GL_TEXTURE_BINDING + // Removed GL_MISC as it might not be supported in Minecraft 26.1 }; + /** + * Gets the current Skia canvas for drawing. + * @return The Skia Canvas object, or null if surface is not initialized. + */ public static Canvas getCanvas() { return surface.getCanvas(); } + /** + * Creates or recreates the Skia surface with the given dimensions. + * This should be called when the window size changes. + * @param width The width of the surface in pixels. + * @param height The height of the surface in pixels. + */ public static void createSurface(int width, int height) { + // Initialize Skia DirectContext if not already done if (context == null) { context = DirectContext.makeGL(); } + // Clean up existing surface and render target if (surface != null) surface.close(); if (renderTarget != null) renderTarget.close(); - renderTarget = WrappedBackendRenderTarget.makeGL( - width, - height, - 0, - 8, - 0, - FramebufferFormat.GR_GL_RGBA8 - ); - - surface = Surface.wrapBackendRenderTarget( - Objects.requireNonNull(context, "Context must not be null"), - Objects.requireNonNull(renderTarget, "RenderTarget must not be null"), - SurfaceOrigin.BOTTOM_LEFT, - ColorType.RGBA_8888, - ColorSpace.getSRGB() - ); + try { + // Get current framebuffer binding + int currentFbo = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING); + + // Create GL backend render target using current framebuffer + renderTarget = WrappedBackendRenderTarget.makeGL( + width, + height, + 0, // sample count + 8, // stencil bits + currentFbo, // framebuffer ID (use current) + FramebufferFormat.GR_GL_RGBA8 // RGBA8 format + ); + + // Wrap the render target into a Skia surface + surface = Surface.wrapBackendRenderTarget( + Objects.requireNonNull(context, "Context must not be null"), + Objects.requireNonNull(renderTarget, "RenderTarget must not be null"), + SurfaceOrigin.BOTTOM_LEFT, // Origin for GL + ColorType.RGBA_8888, // Color format + ColorSpace.getSRGB() // sRGB color space + ); + + PupperLogger.info("Skia", "Created surface with fbo=" + currentFbo + ", size=" + width + "x" + height); + } catch (Exception e) { + PupperLogger.error("Skia", "Failed to create Skia surface: ", e); + } } + /** + * Performs Skia drawing operations. + * Pushes GL states, resets Skia context, executes drawing logic, and submits to GL. + * @param drawingLogic A consumer that takes a Canvas and performs drawing operations. + */ public static void draw(Consumer drawingLogic) { + // Check if Skia context and surface are initialized if (context == null || surface == null) { + PupperLogger.warn("Skia", "Context or surface is null, skipping draw"); + return; + } + + if (renderTarget == null) { + PupperLogger.warn("Skia", "RenderTarget is null, skipping draw"); return; } + PupperLogger.info("Skia", "Starting draw"); + + // Push current GL states States.push(); + // Disable culling for 2D drawing GL11.glDisable(GL11.GL_CULL_FACE); + // Clear color buffer (though Skia will overwrite) GL11.glClearColor(0f, 0f, 0f, 0f); + // Reset Skia GL states context.reset(states); + PupperLogger.info("Skia", "Before drawing logic"); + + // Get canvas and execute drawing logic Canvas canvas = getCanvas(); drawingLogic.accept(canvas); + PupperLogger.info("Skia", "After drawing logic"); + + // Flush and submit Skia commands to GL context.flushAndSubmit(surface); + + PupperLogger.info("Skia", "After flushAndSubmit"); + + // Restore GL states States.pop(); + + PupperLogger.info("Skia", "Draw completed"); } + /** + * Gets the current Skia DirectContext. + * @return The DirectContext, or null if not initialized. + */ public static DirectContext getContext() { return context; } diff --git a/src/main/java/cn/pupperclient/skia/gl/Properties.java b/src/main/java/cn/pupperclient/skia/gl/Properties.java index 96f20e4..6f8555d 100644 --- a/src/main/java/cn/pupperclient/skia/gl/Properties.java +++ b/src/main/java/cn/pupperclient/skia/gl/Properties.java @@ -19,6 +19,7 @@ public class Properties { public final int[] lastActiveTexture = new int[1]; + public final int[] lastFramebuffer = new int[1]; public final int[] lastProgram = new int[1]; public final int[] lastTexture = new int[1]; public final int[] lastSampler = new int[1]; diff --git a/src/main/java/cn/pupperclient/skia/gl/State.java b/src/main/java/cn/pupperclient/skia/gl/State.java index e403938..4e44a4f 100644 --- a/src/main/java/cn/pupperclient/skia/gl/State.java +++ b/src/main/java/cn/pupperclient/skia/gl/State.java @@ -54,6 +54,7 @@ public State(int glVersion) { */ public State push() { glGetIntegerv(GL_ACTIVE_TEXTURE, props.lastActiveTexture); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, props.lastFramebuffer); glActiveTexture(GL_TEXTURE0); glGetIntegerv(GL_CURRENT_PROGRAM, props.lastProgram); glGetIntegerv(GL_TEXTURE_BINDING_2D, props.lastTexture); @@ -136,6 +137,7 @@ public State pop() { } glActiveTexture(props.lastActiveTexture[0]); + glBindFramebuffer(GL_FRAMEBUFFER, props.lastFramebuffer[0]); glBindVertexArray(props.lastVertexArrayObject[0]); glBindBuffer(GL_ARRAY_BUFFER, props.lastArrayBuffer[0]); diff --git a/src/main/java/cn/pupperclient/utils/render/PupperGuiRenderer.java b/src/main/java/cn/pupperclient/utils/render/PupperGuiRenderer.java new file mode 100644 index 0000000..feb32c9 --- /dev/null +++ b/src/main/java/cn/pupperclient/utils/render/PupperGuiRenderer.java @@ -0,0 +1,20 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.utils.render; + +import net.minecraft.client.gui.render.GuiRenderer; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.minecraft.client.renderer.state.gui.GuiRenderState; + +import java.util.List; + +public class PupperGuiRenderer extends GuiRenderer { + public PupperGuiRenderer(GuiRenderState renderState, MultiBufferSource.BufferSource bufferSource, SubmitNodeCollector submitNodeCollector, FeatureRenderDispatcher featureRenderDispatcher, List> pictureInPictureRenderers) { + super(renderState, bufferSource, submitNodeCollector, featureRenderDispatcher, pictureInPictureRenderers); + } +} diff --git a/src/main/resources/pupper.mixins.json b/src/main/resources/pupper.mixins.json index 2ca530d..91e3a8b 100644 --- a/src/main/resources/pupper.mixins.json +++ b/src/main/resources/pupper.mixins.json @@ -41,5 +41,8 @@ ], "injectors": { "defaultRequire": 1 - } + }, + "mixins": [ + "minecraft.entity.MixinAvatar" + ] } From 383c08be96720a3ed5b6340af8afbda904fdb063 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 12 Apr 2026 17:49:42 +0800 Subject: [PATCH 27/45] clean useless logger --- .../cn/pupperclient/skia/context/SkiaContext.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java index 30c9962..3381ad9 100644 --- a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java +++ b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java @@ -6,11 +6,8 @@ import cn.pupperclient.PupperLogger; import cn.pupperclient.skia.api.WrappedBackendRenderTarget; import cn.pupperclient.skia.gl.States; -import com.mojang.blaze3d.opengl.GlTexture; -import com.mojang.blaze3d.pipeline.RenderTarget; import io.github.humbleui.skija.*; -import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; @@ -104,8 +101,6 @@ public static void draw(Consumer drawingLogic) { return; } - PupperLogger.info("Skia", "Starting draw"); - // Push current GL states States.push(); // Disable culling for 2D drawing @@ -115,23 +110,15 @@ public static void draw(Consumer drawingLogic) { // Reset Skia GL states context.reset(states); - PupperLogger.info("Skia", "Before drawing logic"); - // Get canvas and execute drawing logic Canvas canvas = getCanvas(); drawingLogic.accept(canvas); - PupperLogger.info("Skia", "After drawing logic"); - // Flush and submit Skia commands to GL context.flushAndSubmit(surface); - PupperLogger.info("Skia", "After flushAndSubmit"); - // Restore GL states States.pop(); - - PupperLogger.info("Skia", "Draw completed"); } /** From 3bf3dc48ff03e84566cd6b7caeb0eaa89423822e Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 12 Apr 2026 17:55:17 +0800 Subject: [PATCH 28/45] feat: javadoc --- src/main/java/cn/pupperclient/skia/Skia.java | 361 +++++++++++++++++++ 1 file changed, 361 insertions(+) diff --git a/src/main/java/cn/pupperclient/skia/Skia.java b/src/main/java/cn/pupperclient/skia/Skia.java index 8dd0e50..ae339cf 100644 --- a/src/main/java/cn/pupperclient/skia/Skia.java +++ b/src/main/java/cn/pupperclient/skia/Skia.java @@ -24,19 +24,49 @@ import io.github.humbleui.types.RRect; import io.github.humbleui.types.Rect; +/** + * Skia Graphics Drawing Utility Class + * Provides Skia-based 2D graphics drawing API for Pupper Client UI rendering + * All methods get Canvas through SkiaContext + */ public class Skia { + // Image loading helper for managing textures and image resources private static final ImageHelper imageHelper = new ImageHelper(); + // Shared Paint object to avoid repeated creation and improve performance private static final Paint SHARED_PAINT = new Paint(); + /** + * Draws a filled rectangle with the specified color. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param color The color to fill the rectangle + */ public static void drawRect(float x, float y, float width, float height, Color color) { getCanvas().drawRect(Rect.makeXYWH(x, y, width, height), setupPaint(color)); } + /** + * Draws a filled circle with the specified color. + * @param x The x-coordinate of the circle's center + * @param y The y-coordinate of the circle's center + * @param radius The radius of the circle + * @param color The color to fill the circle + */ public static void drawCircle(float x, float y, float radius, Color color) { getCanvas().drawCircle(x, y, radius, setupPaint(color)); } + /** + * Draws a circle outline with the specified stroke width and color. + * @param x The x-coordinate of the circle's center + * @param y The y-coordinate of the circle's center + * @param radius The radius of the circle + * @param strokeWidth The width of the stroke + * @param color The color of the stroke + */ public static void drawCircle(float x, float y, float radius, float strokeWidth, Color color) { Paint paint = setupPaint(color); paint.setMode(PaintMode.STROKE); @@ -45,10 +75,31 @@ public static void drawCircle(float x, float y, float radius, float strokeWidth, paint.setMode(PaintMode.FILL); // Reset } + /** + * Draws a filled rounded rectangle with the specified radius and color. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param radius The corner radius + * @param color The color to fill the rectangle + */ public static void drawRoundedRect(float x, float y, float width, float height, float radius, Color color) { getCanvas().drawRRect(RRect.makeXYWH(x, y, width, height, radius), setupPaint(color)); } + /** + * Draws a filled rounded rectangle with varying corner radii. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param topLeft The top-left corner radius + * @param topRight The top-right corner radius + * @param bottomRight The bottom-right corner radius + * @param bottomLeft The bottom-left corner radius + * @param color The color to fill the rectangle + */ public static void drawRoundedRectVarying(float x, float y, float width, float height, float topLeft, float topRight, float bottomRight, float bottomLeft, Color color) { @@ -74,6 +125,7 @@ public static void drawBlur(float x, float y, float width, float height) { } } + // TODO: fix Draw Blur Texture in anywhere public static void drawRoundedBlur(float x, float y, float width, float height, float radius) { if (HUDModSettings.getInstance().getBlurSetting().isEnabled()) { @@ -89,6 +141,14 @@ public static void drawRoundedBlur(float x, float y, float width, float height, } } + /** + * Draws a drop shadow effect behind a rounded rectangle. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param radius The corner radius + */ public static void drawShadow(float x, float y, float width, float height, float radius) { try (Paint paint = new Paint(); @@ -104,6 +164,16 @@ public static void drawShadow(float x, float y, float width, float height, float } } + /** + * Draws an outline (stroke) around a rounded rectangle. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param radius The corner radius + * @param strokeWidth The width of the outline stroke + * @param color The color of the outline + */ public static void drawOutline(float x, float y, float width, float height, float radius, float strokeWidth, Color color) { @@ -121,6 +191,14 @@ public static void drawOutline(float x, float y, float width, float height, floa } } + /** + * Draws an image from the assets/pupper/ directory. + * @param path The path to the image file relative to assets/pupper/ + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + */ public static void drawImage(String path, float x, float y, float width, float height) { path = "/assets/pupper/" + path; @@ -130,6 +208,16 @@ public static void drawImage(String path, float x, float y, float width, float h } } + /** + * Draws an image from a texture ID with specified alpha and origin. + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param alpha The alpha transparency (0.0 to 1.0) + * @param origin The surface origin for the image + */ public static void drawImage(int textureId, float x, float y, float width, float height, float alpha, SurfaceOrigin origin) { @@ -141,16 +229,42 @@ public static void drawImage(int textureId, float x, float y, float width, float } } + /** + * Draws an image from a texture ID with specified alpha (default origin TOP_LEFT). + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param alpha The alpha transparency (0.0 to 1.0) + */ public static void drawImage(int textureId, float x, float y, float width, float height, float alpha) { drawImage(textureId, x, y, width, height, alpha, SurfaceOrigin.TOP_LEFT); } + /** + * Draws an image from a file. + * @param file The image file + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + */ public static void drawImage(File file, float x, float y, float width, float height) { if (imageHelper.load(file)) { getCanvas().drawImageRect(imageHelper.get(file.getName()), Rect.makeXYWH(x, y, width, height)); } } + /** + * Draws an image from a texture ID with specified origin. + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param origin The surface origin for the image + */ public static void drawImage(int textureId, float x, float y, float width, float height, SurfaceOrigin origin) { if (imageHelper.load(textureId, width, height, origin)) { @@ -158,10 +272,27 @@ public static void drawImage(int textureId, float x, float y, float width, float } } + /** + * Draws an image from a texture ID (default origin TOP_LEFT). + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + */ public static void drawImage(int textureId, float x, float y, float width, float height) { drawImage(textureId, x, y, width, height, SurfaceOrigin.TOP_LEFT); } + /** + * Draws a rounded image from a texture ID. + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param radius The corner radius for clipping + */ public static void drawRoundedImage(int textureId, float x, float y, float width, float height, float radius) { try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { @@ -172,6 +303,15 @@ public static void drawRoundedImage(int textureId, float x, float y, float width } } + /** + * Draws a rounded image from a file path. + * @param filePath The path to the image file + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param radius The corner radius for clipping + */ public static void drawRoundedImage(String filePath, float x, float y, float width, float height, float radius) { try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { @@ -182,6 +322,15 @@ public static void drawRoundedImage(String filePath, float x, float y, float wid } } + /** + * Draws a rounded image from a file. + * @param file The image file + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param radius The corner radius for clipping + */ public static void drawRoundedImage(File file, float x, float y, float width, float height, float radius) { try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { @@ -192,6 +341,17 @@ public static void drawRoundedImage(File file, float x, float y, float width, fl } } + /** + * Draws a rounded image from a texture ID with alpha and origin. + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param radius The corner radius for clipping + * @param alpha The alpha transparency (0.0 to 1.0) + * @param origin The surface origin for the image + */ public static void drawRoundedImage(int textureId, float x, float y, float width, float height, float radius, float alpha, SurfaceOrigin origin) { try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { @@ -202,11 +362,30 @@ public static void drawRoundedImage(int textureId, float x, float y, float width } } + /** + * Draws a rounded image from a texture ID with alpha (default origin TOP_LEFT). + * @param textureId The OpenGL texture ID + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + * @param radius The corner radius for clipping + * @param alpha The alpha transparency (0.0 to 1.0) + */ public static void drawRoundedImage(int textureId, float x, float y, float width, float height, float radius, float alpha) { drawRoundedImage(textureId, x, y, width, height, radius, alpha, SurfaceOrigin.TOP_LEFT); } + /** + * Draws a player's head from a skin file with rounded corners. + * @param file The skin file + * @param x The x-coordinate of the head's top-left corner + * @param y The y-coordinate of the head's top-left corner + * @param width The width to draw the head + * @param height The height to draw the head + * @param radius The corner radius for clipping + */ public static void drawPlayerHead(File file, float x, float y, float width, float height, float radius) { if (imageHelper.load(file)) { @@ -224,6 +403,13 @@ public static void drawPlayerHead(File file, float x, float y, float width, floa } } + /** + * Draws a full player skin at the specified position and scale. + * @param file The skin file + * @param x The x-coordinate of the skin's top-left corner + * @param y The y-coordinate of the skin's top-left corner + * @param scale The scale factor for the skin + */ public static void drawSkin(File file, float x, float y, float scale) { if (imageHelper.load(file)) { @@ -286,6 +472,15 @@ public static void drawSkin(File file, float x, float y, float scale) { restore(); } } + + /** + * Draws an image from Minecraft's resources. + * @param path The path to the image in Minecraft's namespace + * @param x The x-coordinate of the image's top-left corner + * @param y The y-coordinate of the image's top-left corner + * @param width The width to draw the image + * @param height The height to draw the image + */ public static void drawMinecraftImage(String path, float x, float y, float width, float height) { Identifier identifier = Identifier.fromNamespaceAndPath("minecraft", path); @@ -294,6 +489,16 @@ public static void drawMinecraftImage(String path, float x, float y, float width } } + /** + * Draws an arc (partial circle outline) with the specified parameters. + * @param x The x-coordinate of the arc's center + * @param y The y-coordinate of the arc's center + * @param radius The radius of the arc + * @param startAngle The starting angle in degrees + * @param endAngle The ending angle in degrees + * @param strokeWidth The width of the arc stroke + * @param color The color of the arc + */ public static void drawArc(float x, float y, float radius, float startAngle, float endAngle, float strokeWidth, Color color) { @@ -305,6 +510,15 @@ public static void drawArc(float x, float y, float radius, float startAngle, flo paint.setMode(PaintMode.FILL); // Reset } + /** + * Draws a line between two points with the specified width and color. + * @param x The x-coordinate of the starting point + * @param y The y-coordinate of the starting point + * @param endX The x-coordinate of the ending point + * @param endY The y-coordinate of the ending point + * @param width The width of the line + * @param color The color of the line + */ public static void drawLine(float x, float y, float endX, float endY, float width, Color color) { Paint paint = setupPaint(color); @@ -317,6 +531,16 @@ public static void drawLine(float x, float y, float endX, float endY, float widt paint.setStroke(false); // Reset } + /** + * Draws a rounded rectangle with an animated gradient fill. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param radius The corner radius + * @param color1 The first color of the gradient + * @param color2 The second color of the gradient + */ public static void drawGradientRoundedRect(float x, float y, float width, float height, float radius, Color color1, Color color2) { @@ -350,14 +574,33 @@ public static void drawGradientRoundedRect(float x, float y, float width, float } } + /** + * Clips the drawing area to the specified path. + * @param path The path to clip to + * @param mode The clipping mode + * @param arg Additional clipping argument + */ public static void clipPath(Path path, ClipMode mode, boolean arg) { getCanvas().clipPath(path, mode, arg); } + /** + * Clips the drawing area to the specified path (default intersect mode). + * @param path The path to clip to + */ public static void clipPath(Path path) { getCanvas().clipPath(path, ClipMode.INTERSECT, true); } + /** + * Clips the drawing area to a rounded rectangle. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param radius The corner radius + * @param mode The clipping mode + */ public static void clip(float x, float y, float width, float height, float radius, ClipMode mode) { try (Path path = Path.makeRRect(RRect.makeXYWH(x, y, width, height, radius))) { @@ -365,6 +608,17 @@ public static void clip(float x, float y, float width, float height, float radiu } } + /** + * Clips the drawing area to a rounded rectangle with varying corner radii. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param topLeft The top-left corner radius + * @param topRight The top-right corner radius + * @param bottomRight The bottom-right corner radius + * @param bottomLeft The bottom-left corner radius + */ public static void clip(float x, float y, float width, float height, float topLeft, float topRight, float bottomRight, float bottomLeft) { @@ -376,21 +630,53 @@ public static void clip(float x, float y, float width, float height, float topLe } } + /** + * Clips the drawing area to a rounded rectangle (default intersect mode). + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param radius The corner radius + */ public static void clip(float x, float y, float width, float height, float radius) { clip(x, y, width, height, radius, ClipMode.INTERSECT); } + /** + * Draws text at the specified position. + * @param text The text to draw + * @param x The x-coordinate of the text's baseline start + * @param y The y-coordinate of the text's baseline + * @param color The color of the text + * @param font The font to use + */ public static void drawText(String text, float x, float y, Color color, Font font) { Rect bounds = font.measureText(text); getCanvas().drawString(text, x - bounds.getLeft(), y - bounds.getTop(), font, setupPaint(color)); } + /** + * Draws text centered horizontally at the specified position. + * @param text The text to draw + * @param x The x-coordinate of the text's center + * @param y The y-coordinate of the text's baseline + * @param color The color of the text + * @param font The font to use + */ public static void drawCenteredText(String text, float x, float y, Color color, Font font) { Rect bounds = font.measureText(text); getCanvas().drawString(text, x - bounds.getLeft() - (bounds.getWidth() / 2), y - bounds.getTop(), font, setupPaint(color)); } + /** + * Draws text centered vertically at the specified position. + * @param text The text to draw + * @param x The x-coordinate of the text's baseline start + * @param y The y-coordinate of the text's vertical center + * @param color The color of the text + * @param font The font to use + */ public static void drawHeightCenteredText(String text, float x, float y, Color color, Font font) { FontMetrics metrics = font.getMetrics(); @@ -401,6 +687,14 @@ public static void drawHeightCenteredText(String text, float x, float y, Color c getCanvas().drawString(text, x - bounds.getLeft(), textCenterY, font, setupPaint(color)); } + /** + * Draws text centered both horizontally and vertically at the specified position. + * @param text The text to draw + * @param x The x-coordinate of the text's center + * @param y The y-coordinate of the text's vertical center + * @param color The color of the text + * @param font The font to use + */ public static void drawFullCenteredText(String text, float x, float y, Color color, Font font) { Rect bounds = font.measureText(text); @@ -413,10 +707,23 @@ public static void drawFullCenteredText(String text, float x, float y, Color col getCanvas().drawString(text, textCenterX, textCenterY, font, setupPaint(color)); } + /** + * Gets the bounding rectangle of the specified text with the given font. + * @param text The text to measure + * @param font The font to use + * @return The bounding rectangle of the text + */ public static Rect getTextBounds(String text, Font font) { return font.measureText(text); } + /** + * Truncates text to fit within the specified width, adding ellipsis if necessary. + * @param text The original text + * @param font The font to use + * @param width The maximum width + * @return The truncated text with ellipsis if needed + */ public static String getLimitText(String text, Font font, float width) { boolean isInRange = false; @@ -435,29 +742,58 @@ public static String getLimitText(String text, Font font, float width) { return text + (isRemoved ? "..." : ""); } + /** + * Sets up a Paint object with the specified color. + * @param color The color to set + * @return The configured Paint object + */ public static Paint setupPaint(Color color) { SHARED_PAINT.setARGB(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue()); return SHARED_PAINT; } + /** + * Saves the current canvas state (transformation matrix, clip, etc.). + */ public static void save() { getCanvas().save(); } + /** + * Restores the previously saved canvas state. + */ public static void restore() { getCanvas().restore(); } + /** + * Scales the canvas by the specified factor from the origin. + * @param scale The scale factor + */ public static void scale(float scale) { getCanvas().scale(scale, scale); } + /** + * Scales the canvas by the specified factor from the specified point. + * @param x The x-coordinate of the scaling center + * @param y The y-coordinate of the scaling center + * @param scale The scale factor + */ public static void scale(float x, float y, float scale) { getCanvas().translate(x, y); getCanvas().scale(scale, scale); getCanvas().translate(-x, -y); } + /** + * Scales the canvas by the specified factor from the center of the given rectangle. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param scale The scale factor + */ public static void scale(float x, float y, float width, float height, float scale) { float centerX = x + width / 2; @@ -468,10 +804,23 @@ public static void scale(float x, float y, float width, float height, float scal getCanvas().translate(-centerX, -centerY); } + /** + * Translates (moves) the canvas by the specified offset. + * @param x The x-offset + * @param y The y-offset + */ public static void translate(float x, float y) { getCanvas().translate(x, y); } + /** + * Rotates the canvas by the specified angle around the center of the given rectangle. + * @param x The x-coordinate of the rectangle's top-left corner + * @param y The y-coordinate of the rectangle's top-left corner + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param rotate The rotation angle in degrees + */ public static void rotate(float x, float y, float width, float height, float rotate) { float centerX = x + width / 2; @@ -482,6 +831,10 @@ public static void rotate(float x, float y, float width, float height, float rot getCanvas().translate(-centerX, -centerY); } + /** + * Sets the global alpha (transparency) for subsequent drawing operations. + * @param alpha The alpha value (0-255) + */ public static void setAlpha(int alpha) { try (Paint paint = new Paint()) { paint.setAlpha(alpha); @@ -489,10 +842,18 @@ public static void setAlpha(int alpha) { } } + /** + * Gets the current Skia Canvas for drawing. + * @return The Skia Canvas object + */ public static Canvas getCanvas() { return SkiaContext.getCanvas(); } + /** + * Gets the ImageHelper instance for managing images and textures. + * @return The ImageHelper instance + */ public static ImageHelper getImageHelper() { return imageHelper; } From 022446b687d0f446dba46e78f019f9c552894e12 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 12 Apr 2026 19:35:31 +0800 Subject: [PATCH 29/45] eee --- .../java/cn/pupperclient/event/EventBus.java | 7 +- .../cn/pupperclient/event/EventListener.java | 20 ++- .../event/MethodEventListener.java | 2 +- .../event/skia/DrawSkiaEvent.java | 10 ++ .../{client => skia}/RenderSkiaEvent.java | 4 +- .../management/mod/impl/fun/FakeFpsMod.java | 2 +- .../management/mod/impl/fun/TotemTracker.java | 2 +- .../management/mod/impl/hud/ArrayListMod.java | 5 +- .../mod/impl/hud/BedwarsStatsOverlayMod.java | 2 +- .../mod/impl/hud/CPSDisplayMod.java | 2 +- .../management/mod/impl/hud/ClockMod.java | 2 +- .../mod/impl/hud/CloudMusicHudMod.java | 2 +- .../mod/impl/hud/ComboCounterMod.java | 2 +- .../mod/impl/hud/CooldownHudMod.java | 2 +- .../management/mod/impl/hud/CoordsMod.java | 2 +- .../mod/impl/hud/DayCounterMod.java | 2 +- .../mod/impl/hud/DynamicIsland.java | 2 +- .../mod/impl/hud/FPSDisplayMod.java | 2 +- .../mod/impl/hud/FallDamageHelp.java | 2 +- .../mod/impl/hud/GameModeDisplayMod.java | 2 +- .../mod/impl/hud/HealthDisplayMod.java | 2 +- .../mod/impl/hud/JumpResetIndicatorMod.java | 2 +- .../mod/impl/hud/KeystrokesMod.java | 2 +- .../mod/impl/hud/MemoryUsageMod.java | 2 +- .../mod/impl/hud/MouseStrokesMod.java | 2 +- .../management/mod/impl/hud/MusicInfoMod.java | 2 +- .../mod/impl/hud/NameDisplayMod.java | 2 +- .../mod/impl/hud/PingDisplayMod.java | 2 +- .../mod/impl/hud/PitchDisplayMod.java | 2 +- .../mod/impl/hud/PlayTimeDisplayMod.java | 2 +- .../mod/impl/hud/PlayerCounterMod.java | 2 +- .../management/mod/impl/hud/PotionHudMod.java | 2 +- .../mod/impl/hud/ProtocolVersionMod.java | 2 +- .../mod/impl/hud/ReachDisplayMod.java | 2 +- .../management/mod/impl/hud/Scoreboard.java | 2 +- .../mod/impl/hud/ServerIPDisplayMod.java | 2 +- .../mod/impl/hud/SpeedometerMod.java | 2 +- .../management/mod/impl/hud/StopwatchMod.java | 2 +- .../management/mod/impl/hud/TargetHUDMod.java | 2 +- .../management/mod/impl/hud/Test.java | 2 +- .../management/mod/impl/hud/WatermarkMod.java | 2 +- .../mod/impl/hud/WeatherDisplayMod.java | 2 +- .../mod/impl/hud/YawDisplayMod.java | 2 +- .../mod/impl/render/ClickEffectMod.java | 2 +- .../mod/impl/render/MusicWaveformMod.java | 2 +- .../client/MixinMinecraftClient.java | 17 +-- .../client/gui/MixinSplashScreen.java | 122 ++++-------------- .../minecraft/client/util/MixinWindow.java | 2 +- .../skia/context/SkiaContext.java | 28 +--- 49 files changed, 112 insertions(+), 183 deletions(-) create mode 100644 src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java rename src/main/java/cn/pupperclient/event/{client => skia}/RenderSkiaEvent.java (67%) diff --git a/src/main/java/cn/pupperclient/event/EventBus.java b/src/main/java/cn/pupperclient/event/EventBus.java index da0a806..c04a5c7 100644 --- a/src/main/java/cn/pupperclient/event/EventBus.java +++ b/src/main/java/cn/pupperclient/event/EventBus.java @@ -1,5 +1,7 @@ package cn.pupperclient.event; +import org.apache.logging.log4j.util.InternalApi; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; @@ -58,9 +60,9 @@ public void register(final Object object) { } } + @Deprecated private void registerFieldListeners(final Object object, List> handlers) { for (final Field field : getCachedDeclaredFields(object.getClass())) { - // 修改这里:使用 EventListener 而不是 EventListener if (field.getType() == EventListener.class) { final EventListener eventListener = getEventHandler(object, field); if (eventListener != null) { @@ -96,9 +98,6 @@ private void registerMethodListeners(final Object object, List> } } - /** - * 注册单个监听器到映射中 - */ private void registerListener(Type eventType, EventListener listener) { listenerMap.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()).add(listener); sortCallback.accept(listenerMap.get(eventType), priorityOrder); diff --git a/src/main/java/cn/pupperclient/event/EventListener.java b/src/main/java/cn/pupperclient/event/EventListener.java index 081f131..3a5fdc4 100644 --- a/src/main/java/cn/pupperclient/event/EventListener.java +++ b/src/main/java/cn/pupperclient/event/EventListener.java @@ -8,5 +8,23 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface EventListener { - int priority() default 0; + Priority priority() default Priority.NORMAL; + + enum Priority { + LOWEST(-100), + LOW(-50), + NORMAL(0), + HIGH(50), + HIGHEST(1001); + + private final int value; + + Priority(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } } diff --git a/src/main/java/cn/pupperclient/event/MethodEventListener.java b/src/main/java/cn/pupperclient/event/MethodEventListener.java index 6615b5b..d81d52b 100644 --- a/src/main/java/cn/pupperclient/event/MethodEventListener.java +++ b/src/main/java/cn/pupperclient/event/MethodEventListener.java @@ -15,7 +15,7 @@ public MethodEventListener(Object target, Method method) { this.eventType = (Class) method.getParameterTypes()[0]; EventListener annotation = method.getAnnotation(EventListener.class); - this.priority = annotation != null ? annotation.priority() : 0; + this.priority = annotation != null ? annotation.priority().getValue() : 0; if (!method.canAccess(target)) { method.setAccessible(true); diff --git a/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java b/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java new file mode 100644 index 0000000..05c0803 --- /dev/null +++ b/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java @@ -0,0 +1,10 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.event.skia; + +import cn.pupperclient.event.Event; + +public class DrawSkiaEvent extends Event { +} diff --git a/src/main/java/cn/pupperclient/event/client/RenderSkiaEvent.java b/src/main/java/cn/pupperclient/event/skia/RenderSkiaEvent.java similarity index 67% rename from src/main/java/cn/pupperclient/event/client/RenderSkiaEvent.java rename to src/main/java/cn/pupperclient/event/skia/RenderSkiaEvent.java index a544594..bfb3bf8 100644 --- a/src/main/java/cn/pupperclient/event/client/RenderSkiaEvent.java +++ b/src/main/java/cn/pupperclient/event/skia/RenderSkiaEvent.java @@ -1,7 +1,9 @@ -package cn.pupperclient.event.client; +package cn.pupperclient.event.skia; import cn.pupperclient.event.Event; +import cn.pupperclient.skia.api.WrappedBackendRenderTarget; import io.github.humbleui.skija.Canvas; +import io.github.humbleui.skija.DirectContext; public class RenderSkiaEvent extends Event { private final Canvas canvas; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java b/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java index fcb3707..263665e 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/fun/FakeFpsMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.fun; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.ComboSetting; import cn.pupperclient.management.mod.settings.impl.NumberSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java b/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java index e400185..5981d65 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/fun/TotemTracker.java @@ -62,7 +62,7 @@ public void onTotem(TotemEvent event) { } } - @EventListener(priority = 1001) + @EventListener(priority = EventListener.Priority.HIGHEST) public void onPacketReceive(ReceivePacketEvent event) { if (event.getPacket() instanceof ClientboundEntityEventPacket packet) { if (packet.getEventId() == EntityEvent.PROTECTED_FROM_DEATH) { diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ArrayListMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ArrayListMod.java index 85bc3e9..139ba72 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ArrayListMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ArrayListMod.java @@ -3,15 +3,12 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.libraries.material3.hct.Hct; -import cn.pupperclient.libraries.material3.hct.HctSolver; import cn.pupperclient.management.mod.Mod; import cn.pupperclient.management.mod.ModCategory; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.event.mod.ModStateChangeEvent; -import cn.pupperclient.management.mod.api.hud.design.HUDDesign; -import cn.pupperclient.management.mod.impl.settings.HUDModSettings; import cn.pupperclient.management.mod.impl.settings.ModMenuSettings; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; import cn.pupperclient.management.mod.settings.impl.ComboSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java index 8ff06eb..5c7a09b 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/BedwarsStatsOverlayMod.java @@ -6,7 +6,7 @@ import net.minecraft.client.multiplayer.PlayerInfo; import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.hypixel.api.HypixelUser; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.management.mod.settings.impl.NumberSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/CPSDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/CPSDisplayMod.java index 5ebf24c..3a68bf9 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/CPSDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/CPSDisplayMod.java @@ -6,7 +6,7 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; import cn.pupperclient.skia.Skia; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ClockMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ClockMod.java index 3a41a0c..13b3607 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ClockMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ClockMod.java @@ -6,7 +6,7 @@ import java.util.Locale; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/CloudMusicHudMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/CloudMusicHudMod.java index e6db92a..d4502cd 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/CloudMusicHudMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/CloudMusicHudMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.ComboSetting; import cn.pupperclient.skia.Skia; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java index cf987bd..70637b2 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ComboCounterMod.java @@ -2,7 +2,7 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.event.server.impl.AttackEntityEvent; import cn.pupperclient.event.server.impl.DamageEntityEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java index 5eee548..a1ebba3 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/CooldownHudMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; public class CooldownHudMod extends SimpleHUDMod { diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java index e744c28..998cd83 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/CoordsMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java index 2388303..c1b64b5 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/DayCounterMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java index 8679f23..070729f 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/DynamicIsland.java @@ -2,7 +2,7 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.event.mod.AutoAgainEvent; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.event.mod.ModStateChangeEvent; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java index 326ea77..c57a969 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/FPSDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java index 4e1056c..845d7bd 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/FallDamageHelp.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; import net.minecraft.client.Minecraft; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java index b472c05..aea52ac 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/GameModeDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java index b0c4831..5add4f9 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/HealthDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/JumpResetIndicatorMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/JumpResetIndicatorMod.java index 4faad98..cf4b7ac 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/JumpResetIndicatorMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/JumpResetIndicatorMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java index dfdbfc0..fa52673 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/KeystrokesMod.java @@ -8,7 +8,7 @@ import cn.pupperclient.animation.cubicbezier.impl.EaseStandard; import cn.pupperclient.animation.other.DummyAnimation; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.management.mod.impl.settings.HUDModSettings; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/MemoryUsageMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/MemoryUsageMod.java index 9615ecf..c5604cb 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/MemoryUsageMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/MemoryUsageMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java index 5de86d7..a0d08b5 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/MouseStrokesMod.java @@ -4,7 +4,7 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; import cn.pupperclient.event.client.PlayerDirectionChangeEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/MusicInfoMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/MusicInfoMod.java index 8ab5e75..212b06d 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/MusicInfoMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/MusicInfoMod.java @@ -11,7 +11,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.gui.edithud.api.HUDCore; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java index 58f6189..efb92f2 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/NameDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java index 5d736e4..70e908e 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PingDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.NumberSetting; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java index fde5591..0b5a6cd 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PitchDisplayMod.java @@ -3,7 +3,7 @@ import java.text.DecimalFormat; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayTimeDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayTimeDisplayMod.java index 7b79bb3..4eb1ae7 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayTimeDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayTimeDisplayMod.java @@ -2,7 +2,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java index 4c12255..d508d82 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PlayerCounterMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java index 1444de1..ed1d66f 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/PotionHudMod.java @@ -2,7 +2,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; import cn.pupperclient.management.mod.settings.impl.ComboSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ProtocolVersionMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ProtocolVersionMod.java index a6b58ba..2accf76 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ProtocolVersionMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ProtocolVersionMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; import com.viaversion.viafabricplus.ViaFabricPlus; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java index e41baf6..b8a22da 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ReachDisplayMod.java @@ -5,7 +5,7 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.event.server.impl.AttackEntityEvent; import cn.pupperclient.event.server.impl.DamageEntityEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java index 7f32573..9b0289f 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/Scoreboard.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleListHUDMod; import cn.pupperclient.skia.font.Icon; import java.util.ArrayList; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/ServerIPDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/ServerIPDisplayMod.java index 5d59ee3..33dcef7 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/ServerIPDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/ServerIPDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.server.ServerUtils; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java index 93856e3..f63f4ce 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/SpeedometerMod.java @@ -4,7 +4,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java index 08da80a..37dad33 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/StopwatchMod.java @@ -7,7 +7,7 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.management.mod.settings.impl.KeybindSetting; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java index cec7a24..10326bd 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/TargetHUDMod.java @@ -7,7 +7,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.ClientTickEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.gui.edithud.api.HUDCore; import cn.pupperclient.management.color.api.ColorPalette; import cn.pupperclient.management.mod.api.hud.HUDMod; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/Test.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/Test.java index 6fc3d3c..a9f671d 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/Test.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/Test.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventListener; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleListHUDMod; import java.util.List; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/WatermarkMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/WatermarkMod.java index cecd4eb..56c1088 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/WatermarkMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/WatermarkMod.java @@ -7,7 +7,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.PupperLogger; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.color.api.ColorPalette; import cn.pupperclient.management.mod.api.hud.HUDMod; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java index 7813554..95ff2e1 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/WeatherDisplayMod.java @@ -1,7 +1,7 @@ package cn.pupperclient.management.mod.impl.hud; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java b/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java index ffcf1f1..65d9f01 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/hud/YawDisplayMod.java @@ -3,7 +3,7 @@ import java.text.DecimalFormat; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.api.hud.SimpleHUDMod; import cn.pupperclient.skia.font.Icon; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java index c2fe378..419b6d5 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/ClickEffectMod.java @@ -2,7 +2,7 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.MouseClickEvent; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.Mod; import cn.pupperclient.management.mod.ModCategory; import cn.pupperclient.management.mod.settings.impl.BooleanSetting; diff --git a/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java b/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java index 9a1243d..e151ea0 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/render/MusicWaveformMod.java @@ -2,7 +2,7 @@ import cn.pupperclient.PupperClient; import cn.pupperclient.event.EventBus; -import cn.pupperclient.event.client.RenderSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.management.mod.Mod; import cn.pupperclient.management.mod.ModCategory; import cn.pupperclient.management.music.Music; diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index 9df49ff..e27cce7 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -22,8 +22,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult.Type; -import cn.pupperclient.event.client.RenderSkiaEvent; -import cn.pupperclient.gui.api.SimpleSoarGui; +import cn.pupperclient.event.skia.RenderSkiaEvent; import com.mojang.blaze3d.platform.Window; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -161,7 +160,7 @@ public void skia(CallbackInfo ci) throws IOException { int[] height = new int[1]; GLFW.glfwGetFramebufferSize(Minecraft.getInstance().getWindow().handle(), width, height); - SkiaContext.createSurface(width[0] > 0 ? width[0] : 1, height[0] > 0 ? height[0] : 1); + SkiaContext.createSurface(width[0] > 0 ? width[0] : 1, height[0] > 0 ? height[0] : 1, null); } @Inject(method = "destroy", at = @At("HEAD")) @@ -180,24 +179,20 @@ public void onGameLoop(CallbackInfo ci) { } @Inject( - method = { "renderFrame", "runTick" }, + method = {"renderFrame"}, at = @At( value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;flipFrame(Lcom/mojang/blaze3d/TracyFrameCapture;)V" - ), - require = 0 + ) ) private void onBeforeFlipFrame(CallbackInfo ci) { if (level == null) { return; } - if (screen instanceof SimpleSoarGui) { - return; - } - SkiaContext.draw((context) -> { + SkiaContext.draw((canvas) -> { Skia.save(); Skia.scale((float) Minecraft.getInstance().getWindow().getGuiScale()); - EventBus.getInstance().post(new RenderSkiaEvent(context)); + EventBus.getInstance().post(new RenderSkiaEvent(canvas)); Skia.restore(); }); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java index eb366e4..5a3ccdf 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java @@ -8,13 +8,13 @@ import io.github.humbleui.skija.Canvas; import io.github.humbleui.skija.Font; import io.github.humbleui.types.Rect; -import java.awt.Color; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.screens.LoadingOverlay; import net.minecraft.resources.Identifier; import net.minecraft.util.Util; import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL30; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -23,10 +23,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.awt.*; import java.util.Optional; import java.util.function.Consumer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.LoadingOverlay; @Mixin(LoadingOverlay.class) public abstract class MixinSplashScreen { @@ -61,14 +60,13 @@ public abstract class MixinSplashScreen { @Unique private long tapPromptStartTime = -1L; @Unique private long tapClickTime = -1L; @Unique private long lastDebugLogTime = 0L; - @Unique private long lastGlErrorLogTime = 0L; @Unique private boolean loggedInit = false; @Unique private boolean loggedLogoType = false; - @Unique private int lastLoggedFbo = Integer.MIN_VALUE; - @Unique private int lastLoggedGlError = Integer.MIN_VALUE; - @Unique private int lastLoggedBoundFbo = Integer.MIN_VALUE; - @Unique private int lastLoggedDrawFbo = Integer.MIN_VALUE; - @Unique private int lastLoggedReadFbo = Integer.MIN_VALUE; + + @Unique private int mouseX = 0; + @Unique private int mouseY = 0; + @Unique private int width = 0; + @Unique private int height = 0; @Unique private void ensureLogoTexture() { @@ -93,93 +91,29 @@ private void debugOnce(String message) { } } - @Unique - private void logGlErrors(String stage) { - int err; - int count = 0; - while ((err = GL11.glGetError()) != GL11.GL_NO_ERROR && count < 16) { - count++; - long now = Util.getMillis(); - boolean shouldLog = err != lastLoggedGlError || (now - lastGlErrorLogTime) > 1000L; - if (shouldLog) { - lastGlErrorLogTime = now; - lastLoggedGlError = err; - PupperLogger.error("Splash", "GL error @" + stage + ": " + err); - } - } - } - - @Unique - private void logFramebufferBindings(String stage) { - int mainFbo = 0; - - int boundFbo = glGetIntSafe(GL30.GL_FRAMEBUFFER_BINDING, -1); - int drawFbo = glGetIntSafe(GL30.GL_DRAW_FRAMEBUFFER_BINDING, -1); - int readFbo = glGetIntSafe(GL30.GL_READ_FRAMEBUFFER_BINDING, -1); - - boolean shouldLog = false; - if (mainFbo != lastLoggedFbo || boundFbo != lastLoggedBoundFbo || drawFbo != lastLoggedDrawFbo || readFbo != lastLoggedReadFbo) { - shouldLog = true; - } else { - long now = Util.getMillis(); - if (now - lastDebugLogTime > 1000L) { - shouldLog = true; - } - } + @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) + private void pupper_takeOverAndRender(GuiGraphicsExtractor extractor, int mouseX, int mouseY, float delta, CallbackInfo ci) { + int width = extractor.guiWidth(); + int height = extractor.guiHeight(); - if (shouldLog) { - lastLoggedFbo = mainFbo; - lastLoggedBoundFbo = boundFbo; - lastLoggedDrawFbo = drawFbo; - lastLoggedReadFbo = readFbo; - PupperLogger.info("Splash", stage + " fbo(main=" + mainFbo + ", bound=" + boundFbo + ", draw=" + drawFbo + ", read=" + readFbo + ")"); - } - } + this.mouseX = mouseX; + this.mouseY = mouseY; + this.width = width; + this.height = height; - @Unique - private int glGetIntSafe(int pname, int fallback) { - try { - int[] value = new int[1]; - GL11.glGetIntegerv(pname, value); - return value[0]; - } catch (Throwable t) { - return fallback; - } - } + SkiaContext.draw((canvas) -> { + Skia.save(); + renderWithSkia(canvas, width, height, mouseX, mouseY); + Skia.restore(); + }); - @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void pupper_takeOverAndRender(GuiGraphicsExtractor extractor, int mouseX, int mouseY, float delta, CallbackInfo ci) { -// int width = Minecraft.getInstance().getWindow().getScreenWidth(); -// int height = Minecraft.getInstance().getWindow().getScreenHeight(); -// -// if (lastWindowWidth != width || lastWindowHeight != height) { -// PupperLogger.info("Splash", "Framebuffer size changed: " + lastWindowWidth + "x" + lastWindowHeight + " -> " + width + "x" + height); -// // SkiaContext.createSurface already called in Window/Minecraft mixins -// lastWindowWidth = width; -// lastWindowHeight = height; -// } -// -// ci.cancel(); -// -// debugOnce("Splash takeover enabled. fadeIn=" + fadeIn + ", logo=" + CUSTOM_LOGO); -// debug("tick: fadeIn=" + fadeIn + ", w=" + width + ", h=" + height + ", mouse=" + mouseX + "," + mouseY); -// -// logFramebufferBindings("pre-draw"); -// logGlErrors("pre-draw"); -// try { -// SkiaContext.draw(canvas -> renderWithSkia(canvas, width, height, mouseX, mouseY)); -// } catch (Exception e) { -// PupperLogger.error("Splash", "Error during Skia draw: ", e); -// } -// logGlErrors("post-draw"); -// logFramebufferBindings("post-draw"); + ci.cancel(); } - @Unique private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, int mouseY) { + debug("start renderWithSkia, mouse=" + mouseX + "," + mouseY + " size=" + width + "x" + height); + ensureLogoTexture(); - logGlErrors("ensureLogoTexture"); - logFramebufferBindings("after-ensureLogoTexture"); // Handle reloading state if (this.fadeIn) { @@ -314,7 +248,6 @@ private boolean isTapPromptClicked(int width, int height, int mouseX, int mouseY private void renderLoadingScreen(int width, int height, long timePassed, float alpha, boolean showProgress) { // Background Skia.drawRect(0, 0, width, height, new Color(0, 0, 0, (int)(255 * alpha))); - logGlErrors("drawRect(background)"); // Calculate scaled logo size and position int scaledSize = (int)(LOGO_ACTUAL_SIZE * LOGO_SCALE); @@ -323,17 +256,14 @@ private void renderLoadingScreen(int width, int height, long timePassed, float a // Draw logo drawLogo(logoX, logoY, scaledSize, alpha); - logGlErrors("drawLogo"); if (showProgress) { // Progress bar float progress = Math.min(1f, (float) timePassed / ANIMATION_TOTAL_TIME); drawProgressBar(width, height, progress, alpha); - logGlErrors("drawProgressBar"); } else { // Reloading progress bar drawReloadingProgressBar(width, height, timePassed, alpha); - logGlErrors("drawReloadingProgressBar"); } } @@ -347,11 +277,7 @@ private void drawLogo(int x, int y, int size, float alpha) { } if (textureId instanceof GlTexture glTexture && glTexture.glId() != -1) { debug("Logo glId=" + glTexture.glId() + ", draw=" + x + "," + y + " size=" + size + " alpha=" + alpha); - logFramebufferBindings("before-drawLogoImage"); - logGlErrors("before-drawLogoImage"); Skia.drawImage(glTexture.glId(), x, y, size, size, alpha); - logGlErrors("after-drawLogoImage"); - logFramebufferBindings("after-drawLogoImage"); } else { PupperLogger.warn("Splash", "Logo texture not ready or invalid"); } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java index 1b5a626..7ec8305 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/util/MixinWindow.java @@ -28,7 +28,7 @@ public class MixinWindow { @Inject(method = "onFramebufferResize", at = @At("RETURN")) private void onFramebufferSizeChanged(long window, int width, int height, CallbackInfo ci) { - SkiaContext.createSurface(width > 0 ? width : 1, height > 0 ? height : 1); + SkiaContext.createSurface(width > 0 ? width : 1, height > 0 ? height : 1, null); } @Inject(method = "", at = @At("RETURN")) diff --git a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java index 3381ad9..27f3044 100644 --- a/src/main/java/cn/pupperclient/skia/context/SkiaContext.java +++ b/src/main/java/cn/pupperclient/skia/context/SkiaContext.java @@ -16,20 +16,9 @@ * Handles Skia DirectContext, Surface, and BackendRenderTarget creation and drawing. */ public class SkiaContext { - - // Skia rendering objects private static DirectContext context = null; // Skia GPU context private static Surface surface; // Skia drawing surface - private static BackendRenderTarget renderTarget; // Backend render target for GL - - // GL states to reset before Skia drawing - private static final BackendState[] states = { - BackendState.GL_BLEND, - BackendState.GL_VERTEX, - BackendState.GL_PIXEL_STORE, - BackendState.GL_TEXTURE_BINDING - // Removed GL_MISC as it might not be supported in Minecraft 26.1 - }; + private static WrappedBackendRenderTarget renderTarget; // Backend render target for GL /** * Gets the current Skia canvas for drawing. @@ -44,8 +33,9 @@ public static Canvas getCanvas() { * This should be called when the window size changes. * @param width The width of the surface in pixels. * @param height The height of the surface in pixels. + * @param fboid framebuffer object id, if 0 or null, will use currently bound framebuffer */ - public static void createSurface(int width, int height) { + public static void createSurface(int width, int height, Integer fboid) { // Initialize Skia DirectContext if not already done if (context == null) { context = DirectContext.makeGL(); @@ -57,7 +47,7 @@ public static void createSurface(int width, int height) { try { // Get current framebuffer binding - int currentFbo = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING); + int currentFbo = fboid == null || fboid == 0 ? GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING) : fboid; // Create GL backend render target using current framebuffer renderTarget = WrappedBackendRenderTarget.makeGL( @@ -90,7 +80,6 @@ public static void createSurface(int width, int height) { * @param drawingLogic A consumer that takes a Canvas and performs drawing operations. */ public static void draw(Consumer drawingLogic) { - // Check if Skia context and surface are initialized if (context == null || surface == null) { PupperLogger.warn("Skia", "Context or surface is null, skipping draw"); return; @@ -101,23 +90,16 @@ public static void draw(Consumer drawingLogic) { return; } - // Push current GL states States.push(); - // Disable culling for 2D drawing GL11.glDisable(GL11.GL_CULL_FACE); - // Clear color buffer (though Skia will overwrite) GL11.glClearColor(0f, 0f, 0f, 0f); - // Reset Skia GL states - context.reset(states); + context.resetGLAll(); - // Get canvas and execute drawing logic Canvas canvas = getCanvas(); drawingLogic.accept(canvas); - // Flush and submit Skia commands to GL context.flushAndSubmit(surface); - // Restore GL states States.pop(); } From 35c8ffac1d06df8a76f98ee101bca65a8011e4e3 Mon Sep 17 00:00:00 2001 From: oneachina Date: Fri, 17 Apr 2026 19:45:02 +0800 Subject: [PATCH 30/45] ai agents --- AGENTS.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0439f79 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,36 @@ +# Pupper Client AI Agent Guide + +## Architecture Overview +- **Mod Structure**: Fabric mod with singleton `PupperClient` managing specialized managers (ModManager, EventBus, etc.) +- **Event System**: Custom `EventBus` using reflection for `@EventListener` methods and `EventListener` fields +- **Mods**: Categorized features (HUD, player, render, misc) in `management/mod/impl/` +- **Rendering**: Skia-based UI in `skia/` package, custom shaders in `shader/` +- **Integration**: ViaFabricPlus for version switching, WebSocket for real-time features + +## Key Workflows +- **Build**: `./gradlew build` (Loom plugin, Java 25, Minecraft 26.1.2) +- **Run Client**: `./gradlew runClient` (outputs to `run/` directory) +- **First Launch**: Creates `pupper.ok` config file and shows terms screen +- **Mod Initialization**: `ModManager.init()` registers all mods and settings + +## Project Conventions +- **Package**: `cn.pupperclient` with subpackages by feature (animation, event, gui, management, mixin, shader, skia, ui, utils) +- **Managers**: Singleton pattern for core systems (e.g., `EventBus.getInstance()`) +- **Events**: Extend `Event` class, post via `EventBus.getInstance().post(event)` +- **Mixins**: Located in `mixin/mixins/` with accessors in `mixin/interfaces/` +- **Dependencies**: Managed via `gradle/libs.versions.toml` version catalog +- **Resources**: Assets in `src/main/resources/assets/pupper/`, configs processed by Gradle + +## Integration Points +- **ViaFabricPlus**: Version protocol management via `PupperClient.getProtocolVersion()` +- **WebSocket**: Real-time communication in `management/websocket/` +- **Hypixel**: Server-specific features in `management/hypixel/` +- **Music**: MP3 playback with JLayer in `management/music/` +- **UI**: Custom GUI screens in `gui/`, HUD mods in `management/mod/impl/hud/` + +## Examples +- Add mod: Extend `Mod` class, register in `ModManager.initHudMods()` +- Handle event: Annotate method `@EventListener` or use `EventListener` +- Access Minecraft: Use mixins like `MixinMinecraftClient` for client modifications +- Add setting: Create `Setting` subclass, add via `ModManager.addSetting()` + From 64d4d253ddc4450f5cbaab8bd97a6dde9c7698ba Mon Sep 17 00:00:00 2001 From: oneachina Date: Fri, 17 Apr 2026 19:45:55 +0800 Subject: [PATCH 31/45] Remove Pupper Title Screen and Splash Screen --- .../java/cn/pupperclient/gui/MainMenuGui.java | 660 ------------------ .../client/gui/MixinSplashScreen.java | 413 ----------- .../client/gui/MixinTitleScreen.java | 11 +- 3 files changed, 4 insertions(+), 1080 deletions(-) delete mode 100644 src/main/java/cn/pupperclient/gui/MainMenuGui.java diff --git a/src/main/java/cn/pupperclient/gui/MainMenuGui.java b/src/main/java/cn/pupperclient/gui/MainMenuGui.java deleted file mode 100644 index da9ce12..0000000 --- a/src/main/java/cn/pupperclient/gui/MainMenuGui.java +++ /dev/null @@ -1,660 +0,0 @@ -package cn.pupperclient.gui; - -import java.util.ArrayList; -import java.util.List; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; - -import cn.pupperclient.PupperClient; -import com.google.gson.JsonObject; -import cn.pupperclient.animation.SimpleAnimation; -import cn.pupperclient.gui.api.SimpleSoarGui; -import cn.pupperclient.management.color.api.ColorPalette; -import cn.pupperclient.management.config.ConfigType; -import cn.pupperclient.management.mod.impl.settings.ModMenuSettings; -import cn.pupperclient.skia.Skia; -import cn.pupperclient.skia.font.Fonts; -import cn.pupperclient.skia.font.Icon; -import cn.pupperclient.ui.component.api.PressAnimation; -import cn.pupperclient.ui.component.impl.Button; -import cn.pupperclient.ui.component.impl.IconButton; -import cn.pupperclient.ui.component.impl.Switch; -import cn.pupperclient.ui.component.handler.impl.ButtonHandler; -import cn.pupperclient.ui.component.handler.impl.SwitchHandler; -import cn.pupperclient.utils.color.ColorUtils; -import cn.pupperclient.utils.language.I18n; -import cn.pupperclient.utils.mouse.MouseUtils; -import cn.pupperclient.utils.thread.Multithreading; -import cn.pupperclient.utils.file.FileDialog; -import cn.pupperclient.utils.file.FileLocation; -import cn.pupperclient.utils.mouse.ScrollHelper; -import com.terraformersmc.modmenu.gui.ModsScreen; -import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; - -import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; -import net.minecraft.client.gui.screens.options.OptionsScreen; -import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; -import com.mojang.realmsclient.RealmsMainScreen; - -public class MainMenuGui extends SimpleSoarGui { - - private final List buttons = new ArrayList<>(); - private MainMenuButton settingsButton; - private MainMenuButton backgroundButton; - private boolean showCustomizationWindow = false; - private boolean showBackgroundWindow = false; - private Switch darkModeSwitch; - private Button exitCustomizationButton; - private Button exitBackgroundButton; - private IconButton addBackgroundButton; - private final List backgroundItems = new ArrayList<>(); - private String selectedBackgroundId = "background.png"; - private final ScrollHelper backgroundScrollHelper = new ScrollHelper(); - private float parallaxX = 0; - private float parallaxY = 0; - - public MainMenuGui() { - super(false); - } - - @Override - public void init() { - loadBackgroundSettings(); - rebuildLayout(); - loadExistingBackgrounds(); - } - - @Override - public void resize(int width, int height) { - super.resize(width, height); - rebuildLayout(); - } - - private void loadBackgroundSettings() { - JsonObject config = PupperClient.getInstance().getConfigManager().getConfig(ConfigType.MOD).getJsonObject(); - try { - if (config.has("mainmenu.background")) { - selectedBackgroundId = config.get("mainmenu.background").getAsString(); - } - } catch (Exception e) { - selectedBackgroundId = "background.png"; - } - } - - private void saveBackgroundSettings() { - JsonObject config = PupperClient.getInstance().getConfigManager().getConfig(ConfigType.MOD).getJsonObject(); - config.addProperty("mainmenu.background", selectedBackgroundId); - PupperClient.getInstance().getConfigManager().save(ConfigType.MOD); - } - - private void rebuildLayout() { - buttons.clear(); - - float scaleFactor = calculateScaleFactor(); - - float centerX = client.getWindow().getWidth() / 2f; - float centerY = client.getWindow().getHeight() / 2f; - float buttonWidth = 240 * scaleFactor; - - buttons.add(new MainMenuButton("menu.singleplayer", Icon.HOME, - centerX - buttonWidth / 2, centerY - (120 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new SelectWorldScreen(this)))); - - buttons.add(new MainMenuButton("menu.multiplayer", Icon.GROUPS, - centerX - buttonWidth / 2, centerY - (60 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new JoinMultiplayerScreen(this)))); - - buttons.add(new MainMenuButton("menu.realms", Icon.DNS, - centerX - buttonWidth / 2, centerY, buttonWidth, scaleFactor, () -> client.setScreen(new RealmsMainScreen(this)))); - - buttons.add(new MainMenuButton("menu.ias", Icon.ACCOUNT_BALANCE, - centerX - buttonWidth / 2, centerY + (60 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new JoinMultiplayerScreen(this)))); - - buttons.add(new MainMenuButton("menu.modmenu", Icon.LIST, - centerX - buttonWidth / 2, centerY + (120 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new ModsScreen(this)))); - - buttons.add(new MainMenuButton("menu.options", Icon.SETTINGS, - centerX - buttonWidth / 2, centerY + (180 * scaleFactor), buttonWidth, scaleFactor, () -> client.setScreen(new OptionsScreen(this, client.options, false)))); - - buttons.add(new MainMenuButton("menu.quit", Icon.CLOSE, - centerX - buttonWidth / 2, centerY + (240 * scaleFactor), buttonWidth, scaleFactor, client::stop)); - - float buttonSize = 40 * scaleFactor; - float buttonSpacing = 10 * scaleFactor; - - backgroundButton = new MainMenuButton("", Icon.IMAGE, - client.getWindow().getWidth() - (buttonSize * 2) - buttonSpacing - (20 * scaleFactor), - 20 * scaleFactor, buttonSize, scaleFactor, () -> showBackgroundWindow = true); - - settingsButton = new MainMenuButton("", Icon.SETTINGS, - client.getWindow().getWidth() - buttonSize - (20 * scaleFactor), - 20 * scaleFactor, buttonSize - 5, scaleFactor, () -> showCustomizationWindow = true); - - for (MainMenuButton button : buttons) { - button.setEnabled(true); - } - - initCustomizationComponents(); - } - - private void initCustomizationComponents() { - float centerX = client.getWindow().getWidth() / 2f; - float centerY = client.getWindow().getHeight() / 2f; - float panelWidth = 450; - float panelX = centerX - panelWidth / 2; - - darkModeSwitch = new Switch(panelX + panelWidth - 72, centerY - 50, ModMenuSettings.getInstance().getDarkModeSetting().isEnabled()); - darkModeSwitch.setHandler(new SwitchHandler() { - @Override - public void onEnabled() { - ModMenuSettings.getInstance().getDarkModeSetting().setEnabled(true); - } - - @Override - public void onDisabled() { - ModMenuSettings.getInstance().getDarkModeSetting().setEnabled(false); - } - }); - - exitCustomizationButton = new Button("gui.done", centerX - 50, centerY + 50, Button.Style.TONAL); - exitCustomizationButton.setHandler(new ButtonHandler() { - @Override - public void onAction() { - showCustomizationWindow = false; - } - }); - - float backgroundPanelWidth = 600; - float backgroundPanelHeight = 400; - float backgroundPanelX = centerX - backgroundPanelWidth / 2; - float backgroundPanelY = centerY - backgroundPanelHeight / 2; - - exitBackgroundButton = new Button("gui.done", centerX - 50, backgroundPanelY + backgroundPanelHeight - 60, Button.Style.TONAL); - exitBackgroundButton.setHandler(new ButtonHandler() { - @Override - public void onAction() { - showBackgroundWindow = false; - } - }); - - addBackgroundButton = new IconButton(Icon.ADD, - backgroundPanelX + backgroundPanelWidth - 70, - backgroundPanelY + backgroundPanelHeight - 70, - IconButton.Size.NORMAL, - IconButton.Style.PRIMARY); - addBackgroundButton.setHandler(new ButtonHandler() { - @Override - public void onAction() { - Multithreading.runAsync(() -> { - ObjectObjectImmutablePair result = FileDialog.chooseFile("Select Background Image", "png", "jpg"); - - if (result.left()) { - File selectedFile = result.right(); - copyBackgroundFile(selectedFile); - } - }); - } - }); - } - - private void loadExistingBackgrounds() { - backgroundItems.clear(); - - backgroundItems.add(new BackgroundItem("background.png", null, true)); - - File backgroundDir = FileLocation.BACKGROUND_DIR; - if (!backgroundDir.exists()) { - backgroundDir.mkdirs(); - } - if (backgroundDir.exists() && backgroundDir.isDirectory()) { - File[] backgroundFiles = backgroundDir.listFiles((dir, name) -> - name.toLowerCase().endsWith(".png") || name.toLowerCase().endsWith(".jpg")); - if (backgroundFiles != null) { - for (File backgroundFile : backgroundFiles) { - String backgroundId = backgroundFile.getName(); - backgroundItems.add(new BackgroundItem(backgroundId, backgroundFile, false)); - } - } - } - } - - private void copyBackgroundFile(File selectedFile) { - try { - String originalName = selectedFile.getName(); - String processedName = originalName.replace(" ", "_"); - File targetFile = new File(FileLocation.BACKGROUND_DIR, processedName); - - if (targetFile.exists()) { - PupperClient.LOGGER.warn("background file already exists: {}", processedName); - return; - } - - Files.copy(selectedFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - client.execute(() -> { - loadExistingBackgrounds(); - selectedBackgroundId = processedName; - saveBackgroundSettings(); - }); - - } catch (IOException e) { - PupperClient.LOGGER.error("Error copying background file: {}", e.getMessage(), e); - } - } - - private boolean isWindowMinimized() { - return client.getWindow().getWidth() < 100 || client.getWindow().getHeight() < 100; - } - - private float calculateScaleFactor() { - float currentWidth = client.getWindow().getWidth(); - float currentHeight = client.getWindow().getHeight(); - - if (isWindowMinimized()) { - return 0.5f; - } - - float windowArea = currentWidth * currentHeight; - - if (windowArea < 800 * 600) { - return 1.4f; - } else if (windowArea < 1280 * 720) { - return 1.2f; - } else if (windowArea < 1920 * 1080) { - return 1.0f; - } else { - return 0.9f; - } - } - - @Override - public void draw(double mouseX, double mouseY) { - if (isWindowMinimized()) { - return; - } - - PupperClient instance = PupperClient.getInstance(); - ColorPalette palette = instance.getColorManager().getPalette(); - - drawCustomBackground(); - drawLogoIcon(); - - for (MainMenuButton button : buttons) { - button.draw((int) mouseX, (int) mouseY); - } - - backgroundButton.draw((int) mouseX, (int) mouseY); - settingsButton.draw((int) mouseX, (int) mouseY); - - if (showCustomizationWindow) { - drawCustomizationWindow(mouseX, mouseY, palette); - } - - if (showBackgroundWindow) { - drawBackgroundWindow(mouseX, mouseY, palette); - } - } - - private void drawCustomizationWindow(double mouseX, double mouseY, ColorPalette palette) { - float centerX = client.getWindow().getWidth() / 2f; - float centerY = client.getWindow().getHeight() / 2f; - float panelWidth = 450; - float panelHeight = 200; - float panelX = centerX - panelWidth / 2; - float panelY = centerY - panelHeight / 2; - - Skia.drawRect(0, 0, client.getWindow().getWidth(), client.getWindow().getHeight(), - ColorUtils.applyAlpha(palette.getSurface(), 0.3f)); - - Skia.drawRoundedRect(panelX, panelY, panelWidth, panelHeight, 20, palette.getSurfaceContainer()); - - Skia.drawCenteredText(I18n.get("gui.mainmenu.customization"), centerX, panelY + 25, - palette.getOnSurface(), Fonts.getRegular(20)); - - Skia.drawText(I18n.get("setting.darkmode"), panelX + 20, centerY - 35, - palette.getOnSurface(), Fonts.getRegular(16)); - - darkModeSwitch.draw(mouseX, mouseY); - exitCustomizationButton.draw(mouseX, mouseY); - } - - private void drawBackgroundWindow(double mouseX, double mouseY, ColorPalette palette) { - float centerX = client.getWindow().getWidth() / 2f; - float centerY = client.getWindow().getHeight() / 2f; - float panelWidth = 600; - float panelHeight = 400; - float panelX = centerX - panelWidth / 2; - float panelY = centerY - panelHeight / 2; - - backgroundScrollHelper.onUpdate(); - - Skia.drawRect(0, 0, client.getWindow().getWidth(), client.getWindow().getHeight(), - ColorUtils.applyAlpha(palette.getSurface(), 0.3f)); - - Skia.drawRoundedRect(panelX, panelY, panelWidth, panelHeight, 20, palette.getSurfaceContainer()); - - Skia.drawText(I18n.get("setting.background"), panelX + 20, panelY + 30, - palette.getOnSurface(), Fonts.getRegular(20)); - - double adjustedMouseY = mouseY - backgroundScrollHelper.getValue(); - - Skia.save(); - Skia.translate(0, backgroundScrollHelper.getValue()); - - float startX = panelX + 20; - float startY = panelY + 60; - float itemWidth = 160; - float itemHeight = 90; - float spacing = 15; - int itemsPerRow = 3; - - for (int i = 0; i < backgroundItems.size(); i++) { - BackgroundItem item = backgroundItems.get(i); - - int row = i / itemsPerRow; - int col = i % itemsPerRow; - - float itemX = startX + col * (itemWidth + spacing); - float itemY = startY + row * (itemHeight + spacing); - - item.xAnimation.onTick(itemX, 14); - item.yAnimation.onTick(itemY, 14); - - itemX = item.xAnimation.getValue(); - itemY = item.yAnimation.getValue(); - - boolean isSelected = item.backgroundId.equals(selectedBackgroundId); - boolean isHovered = MouseUtils.isInside(mouseX, adjustedMouseY, itemX, itemY, itemWidth, itemHeight); - - item.focusAnimation.onTick(isHovered ? 1 : 0, 10); - - java.awt.Color bgColor = palette.getSurface(); - Skia.drawRoundedRect(itemX, itemY, itemWidth, itemHeight, 8, bgColor); - - if (isSelected) { - Skia.drawOutline(itemX - 2, itemY - 2, itemWidth + 4, itemHeight + 4, 10, 3, palette.getPrimary()); - } - - if (!isSelected && isHovered) { - Skia.drawRoundedRect(itemX, itemY, itemWidth, itemHeight, 8, - ColorUtils.applyAlpha(palette.getPrimary(), item.focusAnimation.getValue() * 0.12f)); - } - - if (item.isDefault) { - Skia.drawRoundedImage("background.png", itemX, itemY, itemWidth, itemHeight, 8); - } else if (item.backgroundFile != null && item.backgroundFile.exists()) { - Skia.drawRoundedImage(item.backgroundFile, itemX, itemY, itemWidth, itemHeight, 8); - } - } - - int totalRows = (int) Math.ceil((double) backgroundItems.size() / itemsPerRow); - float totalHeight = totalRows * (itemHeight + spacing); - backgroundScrollHelper.setMaxScroll(totalHeight, panelHeight - 120); - - Skia.restore(); - - exitBackgroundButton.draw(mouseX, mouseY); - addBackgroundButton.draw(mouseX, mouseY); - } - - private void drawCustomBackground() { - float parallaxStrength = 40; - float targetParallaxX = (float) (client.mouseHandler.xpos() - client.getWindow().getWidth() / 2F) / client.getWindow().getWidth() * parallaxStrength; - float targetParallaxY = (float) (client.mouseHandler.ypos() - client.getWindow().getHeight() / 2F) / client.getWindow().getHeight() * parallaxStrength; - - parallaxX += (targetParallaxX - parallaxX) * 0.1f; - parallaxY += (targetParallaxY - parallaxY) * 0.1f; - - float backgroundScale = 1.2f; - float scaledWidth = client.getWindow().getWidth() * backgroundScale; - float scaledHeight = client.getWindow().getHeight() * backgroundScale; - - float offsetX = (scaledWidth - client.getWindow().getWidth()) / 2 - parallaxX; - float offsetY = (scaledHeight - client.getWindow().getHeight()) / 2 - parallaxY; - - if (selectedBackgroundId.equals("background.png")) { - Skia.drawImage("background.png", -offsetX, -offsetY, scaledWidth, scaledHeight); - } else { - for (BackgroundItem item : backgroundItems) { - if (item.backgroundId.equals(selectedBackgroundId) && !item.isDefault) { - if (item.backgroundFile != null && item.backgroundFile.exists()) { - Skia.drawImage(item.backgroundFile, -offsetX, -offsetY, scaledWidth, scaledHeight); - return; - } - } - } - Skia.drawImage("background.png", -offsetX, -offsetY, scaledWidth, scaledHeight); - } - } - - private void drawLogoIcon() { - float scaleFactor = calculateScaleFactor(); - float logoSize = 170 * scaleFactor + 25; - float logoX = client.getWindow().getWidth() / 2f - logoSize / 2; - - float centerY = client.getWindow().getHeight() / 2f; - float singleplayerButtonY = centerY - (120 * scaleFactor); - float logoY = singleplayerButtonY - logoSize - (1 * scaleFactor); - - Skia.drawRoundedImage("logo.png", logoX, logoY, logoSize, logoSize, 10 * scaleFactor); - } - - @Override - public boolean onMouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - if (showBackgroundWindow) { - backgroundScrollHelper.onScroll(verticalAmount); - return true; - } - return super.onMouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); - } - - @Override - public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { - if (isWindowMinimized()) { - return false; - } - - if (showBackgroundWindow) { - exitBackgroundButton.mousePressed(mouseX, mouseY, button); - addBackgroundButton.mousePressed(mouseX, mouseY, button); - - float adjustedMouseY = (float) (mouseY - backgroundScrollHelper.getValue()); - float panelX = client.getWindow().getWidth() / 2f - 300; - float panelY = client.getWindow().getHeight() / 2f - 200; - float startX = panelX + 20; - float startY = panelY + 60; - float itemWidth = 160; - float itemHeight = 90; - float spacing = 15; - int itemsPerRow = 3; - - for (int i = 0; i < backgroundItems.size(); i++) { - BackgroundItem item = backgroundItems.get(i); - int row = i / itemsPerRow; - int col = i % itemsPerRow; - float itemX = startX + col * (itemWidth + spacing); - float itemY = startY + row * (itemHeight + spacing); - - if (MouseUtils.isInside(mouseX, adjustedMouseY, itemX, itemY, itemWidth, itemHeight)) { - selectedBackgroundId = item.backgroundId; - saveBackgroundSettings(); - break; - } - } - return true; - } - - if (showCustomizationWindow) { - darkModeSwitch.mousePressed(mouseX, mouseY, button); - exitCustomizationButton.mousePressed(mouseX, mouseY, button); - return true; - } - - for (MainMenuButton menuButton : buttons) { - menuButton.mousePressed((int) mouseX, (int) mouseY, button); - } - - backgroundButton.mousePressed((int) mouseX, (int) mouseY, button); - settingsButton.mousePressed((int) mouseX, (int) mouseY, button); - return true; - } - - @Override - public boolean onMouseReleased(double mouseX, double mouseY, int button) { - if (isWindowMinimized()) { - return false; - } - - if (showBackgroundWindow) { - exitBackgroundButton.mouseReleased(mouseX, mouseY, button); - addBackgroundButton.mouseReleased(mouseX, mouseY, button); - return true; - } - - if (showCustomizationWindow) { - darkModeSwitch.mouseReleased(mouseX, mouseY, button); - exitCustomizationButton.mouseReleased(mouseX, mouseY, button); - return true; - } - - for (MainMenuButton menuButton : buttons) { - menuButton.mouseReleased((int) mouseX, (int) mouseY, button); - } - - backgroundButton.mouseReleased((int) mouseX, (int) mouseY, button); - settingsButton.mouseReleased((int) mouseX, (int) mouseY, button); - return true; - } - - @Override - public boolean onCharTyped(int chr) { - if (showBackgroundWindow) { - exitBackgroundButton.charTyped(chr); - addBackgroundButton.charTyped(chr); - } - - if (showCustomizationWindow) { - darkModeSwitch.charTyped(chr); - exitCustomizationButton.charTyped(chr); - } - return true; - } - - @Override - public boolean onKeyPressed(int keyCode, int scanCode, int modifiers) { - if (showBackgroundWindow) { - exitBackgroundButton.keyPressed(keyCode, scanCode, modifiers); - addBackgroundButton.keyPressed(keyCode, scanCode, modifiers); - } - - if (showCustomizationWindow) { - darkModeSwitch.keyPressed(keyCode, scanCode, modifiers); - exitCustomizationButton.keyPressed(keyCode, scanCode, modifiers); - } - return super.onKeyPressed(keyCode, scanCode, modifiers); - } - - static class BackgroundItem { - String backgroundId; - File backgroundFile; - private final SimpleAnimation xAnimation = new SimpleAnimation(); - private final SimpleAnimation yAnimation = new SimpleAnimation(); - private final SimpleAnimation focusAnimation = new SimpleAnimation(); - boolean isDefault; - - public BackgroundItem(String backgroundId, File backgroundFile, boolean isDefault) { - this.backgroundId = backgroundId; - this.backgroundFile = backgroundFile; - this.isDefault = isDefault; - } - } - - private static class MainMenuButton { - private final PressAnimation pressAnimation = new PressAnimation(); - private final SimpleAnimation focusAnimation = new SimpleAnimation(); - private final String title; - private final String icon; - private final float x; - private final float y; - private final float width; - private final float height; - private final float scaleFactor; - private int[] pressedPos; - private final Runnable action; - - public MainMenuButton(String title, String icon, float x, float y, float width, float scaleFactor, Runnable action) { - this.title = title; - this.icon = icon; - this.x = x; - this.y = y; - this.width = width; - this.height = 50 * scaleFactor; - this.scaleFactor = scaleFactor; - this.action = action; - this.pressedPos = new int[]{0, 0}; - } - - private boolean enabled = true; - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void draw(int mouseX, int mouseY) { - ColorPalette palette = PupperClient.getInstance().getColorManager().getPalette(); - boolean hovered = enabled && MouseUtils.isInside(mouseX, mouseY, x, y, width, height); - - focusAnimation.onTick(hovered ? 1.0F : 0, 12); - - float radius = 20 * scaleFactor; - - java.awt.Color bgColor = enabled ? palette.getSurface() : - ColorUtils.applyAlpha(palette.getSurface(), 0.5f); - java.awt.Color textColor = enabled ? - (hovered ? ColorUtils.blend(palette.getOnSurfaceVariant(), palette.getPrimary(), focusAnimation.getValue()) : - palette.getOnSurfaceVariant()) : - ColorUtils.applyAlpha(palette.getOnSurfaceVariant(), 0.5f); - - Skia.drawRoundedRect(x, y, width, height, radius, bgColor); - - if (enabled && hovered) { - java.awt.Color hoverColor = palette.getPrimary(); - Skia.drawRoundedRect(x, y, width, height, radius, - ColorUtils.applyAlpha(hoverColor, focusAnimation.getValue() * 0.12F)); - } - - if (enabled) { - Skia.save(); - Skia.clip(x, y, width, height, radius); - pressAnimation.draw(x + pressedPos[0], y + pressedPos[1], width, height, palette.getPrimary(), 1); - Skia.restore(); - } - - float fontSize = 18 * scaleFactor; - float iconSize = 22 * scaleFactor; - float iconPadding = 16 * scaleFactor; - - if (!title.isEmpty()) { - Skia.drawFullCenteredText(I18n.get(title), x + (width / 2), y + (height / 2), textColor, - Fonts.getRegular(fontSize)); - - Skia.drawHeightCenteredText(icon, x + iconPadding, y + (height / 2), textColor, Fonts.getIcon(iconSize)); - } else { - Skia.drawFullCenteredText(icon, x + (width / 2), y + (height / 2), textColor, Fonts.getIcon(iconSize)); - } - } - - public void mousePressed(int mouseX, int mouseY, int mouseButton) { - if (enabled && MouseUtils.isInside(mouseX, mouseY, x, y, width, height) && mouseButton == 0) { - pressedPos = new int[]{mouseX - (int) x, mouseY - (int) y}; - pressAnimation.onPressed(mouseX, mouseY, x, y); - } - } - - public void mouseReleased(int mouseX, int mouseY, int mouseButton) { - if (enabled && MouseUtils.isInside(mouseX, mouseY, x, y, width, height) && mouseButton == 0) { - action.run(); - } - pressAnimation.onReleased(mouseX, mouseY, x, y); - } - } -} diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java index 5a3ccdf..318c1fa 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinSplashScreen.java @@ -1,422 +1,9 @@ package cn.pupperclient.mixin.mixins.minecraft.client.gui; -import cn.pupperclient.PupperLogger; -import cn.pupperclient.skia.Skia; -import cn.pupperclient.skia.context.SkiaContext; -import cn.pupperclient.skia.font.Fonts; -import com.mojang.blaze3d.opengl.GlTexture; -import io.github.humbleui.skija.Canvas; -import io.github.humbleui.skija.Font; -import io.github.humbleui.types.Rect; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.LoadingOverlay; -import net.minecraft.resources.Identifier; -import net.minecraft.util.Util; -import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.GL11; -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.callback.CallbackInfo; - -import java.awt.*; -import java.util.Optional; -import java.util.function.Consumer; @Mixin(LoadingOverlay.class) public abstract class MixinSplashScreen { - @Shadow @Final private Minecraft minecraft; - @Shadow @Final private boolean fadeIn; - @Shadow @Final private Consumer> onFinish; - - // Animation timing variables - @Unique private long soar_animationStartTime = -1L; - @Unique private long soar_reloadStartTime = -1L; - @Unique private static final long MAX_RELOAD_TIME = 15_000L; - @Unique private static final Identifier CUSTOM_LOGO = Identifier.fromNamespaceAndPath("pupper", "logo.png"); - @Unique private static final int LOGO_ACTUAL_SIZE = 1080; - @Unique private static final float LOGO_SCALE = 0.15f; - @Unique private static final long ANIMATION_TOTAL_TIME = 4500L; - @Unique private static final long FADE_DURATION = 500L; - @Unique private static final long WELCOME_DISPLAY_TIME = 5000L; // 5 second display time - @Unique private static final long TAP_PROMPT_DELAY = 0; - @Unique private static final long TTS_CYCLE_DURATION = 2000L; // 2-second cycle for TTS animation - @Unique private static final long CLICK_FADE_DURATION = 2000L; // 2 second fade out after click - @Unique private static final int PROGRESS_BAR_HEIGHT = 8; - - // State variables - @Unique private int lastWindowWidth = -1; - @Unique private int lastWindowHeight = -1; - @Unique private boolean skipNextFrame = false; - @Unique private boolean welcomeDisplayed = false; - @Unique private boolean tapPromptDisplayed = false; - @Unique private boolean tapClicked = false; - @Unique private long welcomeStartTime = -1L; - @Unique private long tapPromptStartTime = -1L; - @Unique private long tapClickTime = -1L; - @Unique private long lastDebugLogTime = 0L; - @Unique private boolean loggedInit = false; - @Unique private boolean loggedLogoType = false; - - @Unique private int mouseX = 0; - @Unique private int mouseY = 0; - @Unique private int width = 0; - @Unique private int height = 0; - - @Unique - private void ensureLogoTexture() { - var tm = this.minecraft.getTextureManager(); - tm.getTexture(CUSTOM_LOGO); - } - - @Unique - private void debug(String message) { - long now = Util.getMillis(); - if (now - lastDebugLogTime > 1000L) { - lastDebugLogTime = now; - PupperLogger.info("Splash", message); - } - } - - @Unique - private void debugOnce(String message) { - if (!loggedInit) { - loggedInit = true; - PupperLogger.info("Splash", message); - } - } - - @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void pupper_takeOverAndRender(GuiGraphicsExtractor extractor, int mouseX, int mouseY, float delta, CallbackInfo ci) { - int width = extractor.guiWidth(); - int height = extractor.guiHeight(); - - this.mouseX = mouseX; - this.mouseY = mouseY; - this.width = width; - this.height = height; - - SkiaContext.draw((canvas) -> { - Skia.save(); - renderWithSkia(canvas, width, height, mouseX, mouseY); - Skia.restore(); - }); - - ci.cancel(); - } - @Unique - private void renderWithSkia(Canvas canvas, int width, int height, int mouseX, int mouseY) { - debug("start renderWithSkia, mouse=" + mouseX + "," + mouseY + " size=" + width + "x" + height); - - ensureLogoTexture(); - - // Handle reloading state - if (this.fadeIn) { - if (this.soar_reloadStartTime == -1L) this.soar_reloadStartTime = Util.getMillis(); - this.soar_animationStartTime = -1L; - this.welcomeDisplayed = false; - this.tapPromptDisplayed = false; - this.tapClicked = false; - this.welcomeStartTime = -1L; - this.tapPromptStartTime = -1L; - this.tapClickTime = -1L; - - long reloadElapsed = Util.getMillis() - this.soar_reloadStartTime; - if (reloadElapsed > MAX_RELOAD_TIME) { - try { - this.minecraft.setOverlay(null); - this.onFinish.accept(Optional.empty()); - } catch (Exception ignored) {} - this.soar_reloadStartTime = -1L; - return; - } - - renderLoadingScreen(width, height, reloadElapsed, 1.0f, false); - return; - } - - this.soar_reloadStartTime = -1L; - if (this.soar_animationStartTime == -1L) { - this.soar_animationStartTime = Util.getMillis(); - } - - long timePassed = Util.getMillis() - this.soar_animationStartTime; - - // Check if welcome screen should be displayed - if (timePassed >= ANIMATION_TOTAL_TIME && !welcomeDisplayed) { - welcomeDisplayed = true; - welcomeStartTime = Util.getMillis(); - tapPromptDisplayed = false; - tapClicked = false; - } - - // Welcome screen logic - if (welcomeDisplayed) { - long welcomeTimePassed = Util.getMillis() - welcomeStartTime; - - // Check if tap prompt should be displayed (1-second delay) - if (!tapPromptDisplayed) { - tapPromptDisplayed = true; - tapPromptStartTime = Util.getMillis(); - } - - // Check if tap prompt was clicked - if (!tapClicked && GLFW.glfwGetMouseButton(this.minecraft.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS) { - tapClicked = true; - tapClickTime = Util.getMillis(); - } - - if (tapClicked) { - long clickTimePassed = Util.getMillis() - tapClickTime; - - if (clickTimePassed >= CLICK_FADE_DURATION) { - // After fade out, close splash screen - try { - this.minecraft.setOverlay(null); - this.onFinish.accept(Optional.empty()); - } catch (Exception ignored) {} - this.soar_animationStartTime = -1L; - this.welcomeDisplayed = false; - this.tapPromptDisplayed = false; - this.tapClicked = false; - this.welcomeStartTime = -1L; - this.tapPromptStartTime = -1L; - this.tapClickTime = -1L; - return; - } - - renderWelcomeScreen(width, height, welcomeTimePassed, true, clickTimePassed); - return; - } - - // Check if timeout (auto exit after display time) - if (welcomeTimePassed >= WELCOME_DISPLAY_TIME) { - try { - this.minecraft.setOverlay(null); - this.onFinish.accept(Optional.empty()); - } catch (Exception ignored) {} - this.soar_animationStartTime = -1L; - this.welcomeDisplayed = false; - this.tapPromptDisplayed = false; - this.tapClicked = false; - this.welcomeStartTime = -1L; - this.tapPromptStartTime = -1L; - this.tapClickTime = -1L; - return; - } - - renderWelcomeScreen(width, height, welcomeTimePassed, false, 0); - return; - } - - // Normal loading animation - float alpha = 1f; - long fadeStartTime = ANIMATION_TOTAL_TIME - FADE_DURATION; - if (timePassed > fadeStartTime) { - long fadeTimePassed = timePassed - fadeStartTime; - alpha = 1f - (float)fadeTimePassed / FADE_DURATION; - } - alpha = Math.max(0f, alpha); - - renderLoadingScreen(width, height, timePassed, alpha, true); - } - - @Unique - private boolean isTapPromptClicked(int width, int height, int mouseX, int mouseY) { - // Calculate tap prompt text position and size - String tapText = "Tap to start"; - Font tapFont = Fonts.getMedium(24f); - Rect tapBounds = tapFont.measureText(tapText); - - float tapX = (width - tapBounds.getWidth()) / 2; - float tapY = height / 2f + 15; // Adjusted to height/2 + 15 - - // Check if mouse is within text area (with padding) - float padding = 15f; - return mouseX >= tapX - padding && - mouseX <= tapX + tapBounds.getWidth() + padding && - mouseY >= tapY - padding && - mouseY <= tapY + tapBounds.getHeight() + padding; - } - - @Unique - private void renderLoadingScreen(int width, int height, long timePassed, float alpha, boolean showProgress) { - // Background - Skia.drawRect(0, 0, width, height, new Color(0, 0, 0, (int)(255 * alpha))); - - // Calculate scaled logo size and position - int scaledSize = (int)(LOGO_ACTUAL_SIZE * LOGO_SCALE); - int logoX = (width - scaledSize) / 2; - int logoY = (height - scaledSize) / 3; - - // Draw logo - drawLogo(logoX, logoY, scaledSize, alpha); - - if (showProgress) { - // Progress bar - float progress = Math.min(1f, (float) timePassed / ANIMATION_TOTAL_TIME); - drawProgressBar(width, height, progress, alpha); - } else { - // Reloading progress bar - drawReloadingProgressBar(width, height, timePassed, alpha); - } - } - - @Unique - private void drawLogo(int x, int y, int size, float alpha) { - var tex = Minecraft.getInstance().getTextureManager().getTexture(CUSTOM_LOGO); - var textureId = tex.getTexture(); - if (!loggedLogoType) { - loggedLogoType = true; - PupperLogger.info("Splash", "Logo texture impl=" + textureId.getClass().getName()); - } - if (textureId instanceof GlTexture glTexture && glTexture.glId() != -1) { - debug("Logo glId=" + glTexture.glId() + ", draw=" + x + "," + y + " size=" + size + " alpha=" + alpha); - Skia.drawImage(glTexture.glId(), x, y, size, size, alpha); - } else { - PupperLogger.warn("Splash", "Logo texture not ready or invalid"); - } - - int err = GL11.glGetError(); - if (err != GL11.GL_NO_ERROR) { - PupperLogger.error("Splash", "GL error after drawLogo: " + err); - } - } - - @Unique - private void drawProgressBar(int width, int height, float progress, float alpha) { - int barWidth = width / 2; - int barHeight = PROGRESS_BAR_HEIGHT; - int barX = (width - barWidth) / 2; - int barY = height - 200; - - // Progress bar background - Skia.drawRect(barX, barY, barWidth, barHeight, - new Color(0x30, 0x30, 0x30, (int)(255 * alpha))); - - // Progress bar foreground - int progressWidth = (int)(barWidth * progress); - Skia.drawRect(barX, barY, progressWidth, barHeight, - new Color(255, 255, 255, (int)(255 * alpha))); - } - - @Unique - private void drawReloadingProgressBar(int width, int height, long time, float alpha) { - int barWidth = width / 2; - int barHeight = PROGRESS_BAR_HEIGHT; - int barX = (width - barWidth) / 2; - int barY = height - 200; - - // Progress bar background - Skia.drawRect(barX, barY, barWidth, barHeight, - new Color(0x30, 0x30, 0x30, (int)(255 * alpha))); - - // Dynamic progress indicator - long cycle = 1500L; - float p = (float)(time % cycle) / (float)cycle; - int indicatorWidth = barWidth / 4; - int start = (int)((barWidth + indicatorWidth) * p) - indicatorWidth; - int end = Math.min(start + indicatorWidth, barWidth); - - Skia.drawRect(barX + Math.max(0, start), barY, - barX + end, barHeight, - new Color(255, 255, 255, (int)(255 * alpha))); - } - - @Unique - private void renderWelcomeScreen(int width, int height, long welcomeTimePassed, boolean clicked, long clickTimePassed) { - // Background (always full opacity) - Skia.drawRect(0, 0, width, height, new Color(0, 0, 0, 255)); - - // Text transparency calculations - float welcomeAlpha = 1.0f; // Welcome text always full opacity (no animation) - float ttsAlpha; // TTS text alpha - - if (clicked) { - // After click: 2-second fade out for all text - float clickFadeAlpha = 1f - (float)clickTimePassed / CLICK_FADE_DURATION; - welcomeAlpha = Math.max(0f, clickFadeAlpha); - ttsAlpha = Math.max(0f, clickFadeAlpha); - } else { - // Before click: TTS text has continuous fade in/out animation - if (tapPromptDisplayed) { - long ttsTimePassed = Util.getMillis() - tapPromptStartTime; - ttsAlpha = getTTSAnimationAlpha(ttsTimePassed); - } else { - ttsAlpha = 0f; // Not displayed yet - } - // Welcome text remains at full opacity - } - - // Draw welcome text (no animation, just fade out after click) - String welcomeText = "Welcome to Pupper Client"; - Font welcomeFont = Fonts.getMedium(32f); - - // Calculate text position (centered) - Rect welcomeBounds = welcomeFont.measureText(welcomeText); - float welcomeX = (width - welcomeBounds.getWidth()) / 2; - float welcomeY = height / 2f - welcomeBounds.getHeight() / 2; - - // Draw welcome text (with transparency only after click) - Color welcomeColor = new Color(1.0f, 1.0f, 1.0f, welcomeAlpha); - Skia.drawText(welcomeText, welcomeX, welcomeY, welcomeColor, welcomeFont); - - // Draw TTS text (if displayed) - if (tapPromptDisplayed) { - String ttsText = "Tap to start"; - Font ttsFont = Fonts.getMedium(24f); - - // Calculate text position (height/2 + 15) - Rect ttsBounds = ttsFont.measureText(ttsText); - float ttsX = (width - ttsBounds.getWidth()) / 2; - float ttsY = height / 2f + 180; - - // Draw subtle white shadow for TTS text (very light shadow) - if (ttsAlpha > 0) { - // White shadow with reduced opacity and smaller offset - float shadowOpacity = ttsAlpha * 0.3f; // Very subtle shadow - Color shadowColor = new Color(1.0f, 1.0f, 1.0f, shadowOpacity); - - // Very small offset for subtle shadow - float shadowOffset = 0.7f; - - // Draw just one offset shadow for subtle effect - Skia.drawText(ttsText, ttsX + shadowOffset, ttsY, shadowColor, ttsFont); - - // Optional: draw a second layer with even smaller offset for smoother shadow - float shadowOffset2 = 0.3f; - Skia.drawText(ttsText, ttsX + shadowOffset2, ttsY, shadowColor, ttsFont); - } - - // Draw TTS text main layer - // Use white color for main text to contrast with black background - Color ttsColor = new Color(1.0f, 1.0f, 1.0f, ttsAlpha); - Skia.drawText(ttsText, ttsX, ttsY, ttsColor, ttsFont); - } - } - - @Unique - private static float getTTSAnimationAlpha(long ttsTimePassed) { - // Calculate pulse animation: fade in and out, 2-second cycle - long cycle = TTS_CYCLE_DURATION; - float timeInCycle = ttsTimePassed % cycle; - - // Use sine wave for smooth fade in/out animation - // sin(2π * time / period) mapped to [0.3, 1.0] range - float sinValue = (float) Math.sin(2 * Math.PI * timeInCycle / cycle); - float alpha = 0.65f + 0.35f * sinValue; // Varies between 0.3 and 1.0 - - // Ensure smooth start - float fadeInDuration = 500f; - if (ttsTimePassed < fadeInDuration) { - alpha *= (float)ttsTimePassed / fadeInDuration; - } - - return Math.max(0f, Math.min(1f, alpha)); - } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java index a012647..2d13ab0 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/gui/MixinTitleScreen.java @@ -1,7 +1,5 @@ package cn.pupperclient.mixin.mixins.minecraft.client.gui; -import cn.pupperclient.gui.MainMenuGui; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.network.chat.Component; @@ -17,14 +15,13 @@ protected MixinTitleScreen(Component title) { super(title); } - @Inject(method = "init()V", at = @At("HEAD"), cancellable = true) + @Inject(method = "init()V", at = @At("HEAD")) public void onInit(CallbackInfo ci) { -// Minecraft.getInstance().setScreen(new MainMenuGui()); -// ci.cancel(); + } - @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) + @Inject(method = "extractRenderState", at = @At("HEAD")) public void onRender(CallbackInfo ci) { -// ci.cancel(); + } } From 9a0a97c5d7729699c54478acd2dd1d8c25c70d3a Mon Sep 17 00:00:00 2001 From: oneachina Date: Fri, 17 Apr 2026 19:48:00 +0800 Subject: [PATCH 32/45] Remove smtc native dll (use the implementation in future) --- .../resources/assets/pupper/natives/smtc.dll | Bin 65024 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/resources/assets/pupper/natives/smtc.dll diff --git a/src/main/resources/assets/pupper/natives/smtc.dll b/src/main/resources/assets/pupper/natives/smtc.dll deleted file mode 100644 index e5bcc2c993584422d62228e84e81a381b08257b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65024 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 E1B~gAW&i*H From f8d57436f8b02a9b8af9b1b698f98fd6e841e5bc Mon Sep 17 00:00:00 2001 From: oneachina Date: Fri, 17 Apr 2026 19:48:20 +0800 Subject: [PATCH 33/45] Remove useless logo --- src/main/resources/assets/pupper/oldlogo.png | Bin 65274 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/resources/assets/pupper/oldlogo.png diff --git a/src/main/resources/assets/pupper/oldlogo.png b/src/main/resources/assets/pupper/oldlogo.png deleted file mode 100644 index c89326406a7491a7d0be5e6b4603c52098723c7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65274 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 F{}0TT@FxHO From ee50dd25590f4fb59f079e6505879a7de979b3a5 Mon Sep 17 00:00:00 2001 From: oneachina Date: Fri, 17 Apr 2026 19:50:34 +0800 Subject: [PATCH 34/45] clean --- .../java/cn/pupperclient/PupperClient.java | 24 ---- .../gui/welcomegui/TermsScreen.java | 119 ------------------ 2 files changed, 143 deletions(-) delete mode 100644 src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java diff --git a/src/main/java/cn/pupperclient/PupperClient.java b/src/main/java/cn/pupperclient/PupperClient.java index 8f9432b..a3f360a 100644 --- a/src/main/java/cn/pupperclient/PupperClient.java +++ b/src/main/java/cn/pupperclient/PupperClient.java @@ -3,7 +3,6 @@ import cn.pupperclient.animation.Delta; import cn.pupperclient.event.EventBus; import cn.pupperclient.event.server.PacketHandler; -import cn.pupperclient.gui.welcomegui.TermsScreen; import cn.pupperclient.management.cape.CapeManager; import cn.pupperclient.management.color.ColorManager; import cn.pupperclient.management.command.PupperCommand; @@ -19,10 +18,6 @@ import cn.pupperclient.utils.thread.Multithreading; import cn.pupperclient.utils.file.FileLocation; import cn.pupperclient.utils.language.*; -import com.viaversion.viafabricplus.ViaFabricPlus; -import com.viaversion.viafabricplus.api.ViaFabricPlusBase; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import org.apache.logging.log4j.Logger; import java.io.IOException; @@ -43,7 +38,6 @@ public class PupperClient implements IMinecraft { public static boolean firstLaunch = false; public static final Logger LOGGER = PupperLogger.getLogger(); - private final ViaFabricPlusBase viaPlatform = ViaFabricPlus.getImpl(); private long launchTime; private ModManager modManager; @@ -112,7 +106,6 @@ private void handleFirstLaunch() throws IOException { firstLaunch = true; createConfigFile(configFile); } - registerTermsScreenCheck(); } private void createConfigFile(Path configFile) throws IOException { @@ -129,15 +122,6 @@ private void createConfigFile(Path configFile) throws IOException { } } - private void registerTermsScreenCheck() { - ClientTickEvents.END_CLIENT_TICK.register(client -> { - if (firstLaunch && client.level != null && !hasAcceptedTerms) { - TermsScreen termsScreen = new TermsScreen(); - client.setScreen(termsScreen); - } - }); - } - private void checkResources() { if (getClass().getClassLoader().getResource(ICON_PATH) == null) { LOGGER.error("PupperClient icon not found in resources!"); @@ -194,14 +178,6 @@ public HypixelManager getHypixelManager() { return hypixelManager; } - public ProtocolVersion getProtocolVersion() { - return viaPlatform.getTargetVersion(); - } - - public void setProtocolVersion(ProtocolVersion version) { - viaPlatform.setTargetVersion(version); - } - public CapeManager getCapeManager() { return capeManager; } diff --git a/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java b/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java deleted file mode 100644 index e44b615..0000000 --- a/src/main/java/cn/pupperclient/gui/welcomegui/TermsScreen.java +++ /dev/null @@ -1,119 +0,0 @@ -package cn.pupperclient.gui.welcomegui; - -import cn.pupperclient.PupperClient; -import cn.pupperclient.gui.api.SimpleSoarGui; -import cn.pupperclient.skia.Skia; -import cn.pupperclient.skia.font.Fonts; -import cn.pupperclient.ui.component.handler.impl.ButtonHandler; -import cn.pupperclient.ui.component.impl.Button; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.sounds.SoundEvents; - -import java.awt.Color; - -public class TermsScreen extends SimpleSoarGui { - private int centerX; - private int centerY; - private boolean accepted = false; - - private Button acceptButton; - private Button declineButton; - - public TermsScreen() { - super(false); - } - - @Override - public void init() { - acceptButton = new Button("text.accept", 0, 0, Button.Style.TONAL); - acceptButton.setHandler(new ButtonHandler() { - @Override - public void onAction() { - accepted = true; - if (client.player != null) { - client.player.playSound(SoundEvents.UI_TOAST_IN, 1.0f, 1.0f); - } - PupperClient.hasAcceptedTerms = true; - client.setScreen(null); - } - }); - - declineButton = new Button("text.decline", 0, 0, Button.Style.TONAL); - declineButton.setHandler(new ButtonHandler() { - @Override - public void onAction() { - client.setScreen(new TitleScreen()); - } - }); - - rebuildLayout(); - } - - @Override - public void resize(int width, int height) { - super.resize(width, height); - rebuildLayout(); - } - - private void updatePositions() { - centerX = client.getWindow().getWidth() / 2; - centerY = client.getWindow().getHeight() / 2; - } - - private void rebuildLayout() { - updatePositions(); - - float acceptWidth = acceptButton.getWidth(); - float declineWidth = declineButton.getWidth(); - - float totalWidth = acceptWidth + declineWidth + 10; - float startX = centerX - totalWidth / 2; - - acceptButton.setX(startX); - acceptButton.setY(centerY + 20); - - declineButton.setX(startX + acceptWidth + 10); - declineButton.setY(centerY + 20); - } - - @Override - public void draw(double mouseX, double mouseY) { - drawTranslucentBackground(); - - renderSkijaWelcome(mouseX, mouseY); - } - - private void drawTranslucentBackground() { - Color translucentBlack = new Color(0, 0, 0, 180); - Skia.drawRect(0, 0, client.getWindow().getWidth(), client.getWindow().getHeight(), translucentBlack); - } - - private void renderSkijaWelcome(double mouseX, double mouseY) { - Skia.drawFullCenteredText("Terms of Service", centerX, centerY - 60, Color.WHITE, Fonts.getRegular(20)); - - Skia.drawFullCenteredText("Please read and accept the Terms of Service", - centerX, centerY - 20, Color.WHITE, Fonts.getRegular(14)); - - acceptButton.draw(mouseX, mouseY); - declineButton.draw(mouseX, mouseY); - } - - @Override - public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { - acceptButton.mousePressed(mouseX, mouseY, button); - declineButton.mousePressed(mouseX, mouseY, button); - return true; - } - - @Override - public boolean onMouseReleased(double mouseX, double mouseY, int button) { - acceptButton.mouseReleased(mouseX, mouseY, button); - declineButton.mouseReleased(mouseX, mouseY, button); - return true; - } - - public boolean isAccepted() { - return accepted; - } -} From f692c72905989f41e1c06a87e19060c9605c3aa5 Mon Sep 17 00:00:00 2001 From: oneachina Date: Fri, 17 Apr 2026 20:28:46 +0800 Subject: [PATCH 35/45] clean --- .../mod/impl/settings/ModMenuSettings.java | 26 +++++----------- .../client/render/GuiRendererMixin.java | 3 +- .../client/render/MixinInGameHud.java | 18 +++++------ .../client/render/PupperInGameHud.java | 30 +------------------ 4 files changed, 19 insertions(+), 58 deletions(-) diff --git a/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java b/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java index 3c9ab66..31a0c0c 100644 --- a/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java +++ b/src/main/java/cn/pupperclient/management/mod/impl/settings/ModMenuSettings.java @@ -31,20 +31,20 @@ public class ModMenuSettings extends Mod { private String previousLanguageOption = "language.english"; private boolean languageInitialized = false; - private KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", + private final KeybindSetting keybindSetting = new KeybindSetting("setting.keybind", "setting.keybind.description", Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_RIGHT_SHIFT, 0, 0))); - private KeybindSetting keybindSetting_music = new KeybindSetting("setting.keybind_music", "setting.keybind_music.description", + private final KeybindSetting keybindSetting_music = new KeybindSetting("setting.keybind_music", "setting.keybind_music.description", Icon.KEYBOARD, this, InputConstants.getKey(new KeyEvent(GLFW.GLFW_KEY_M, 0, 0))); - private BooleanSetting darkModeSetting = new BooleanSetting("setting.darkmode", "setting.darkmode.description", + private final BooleanSetting darkModeSetting = new BooleanSetting("setting.darkmode", "setting.darkmode.description", Icon.DARK_MODE, this, false); - private HctColorSetting hctColorSetting = new HctColorSetting("setting.color", "setting.color.description", + private final HctColorSetting hctColorSetting = new HctColorSetting("setting.color", "setting.color.description", Icon.PALETTE, this, Hct.from(220, 26, 6)); - private BooleanSetting blurSetting = new BooleanSetting("setting.blur", "setting.blur.description", Icon.LENS_BLUR, + private final BooleanSetting blurSetting = new BooleanSetting("setting.blur", "setting.blur.description", Icon.LENS_BLUR, this, true); - private NumberSetting blurIntensitySetting = new NumberSetting("setting.blurintensity", + private final NumberSetting blurIntensitySetting = new NumberSetting("setting.blurintensity", "setting.blurintensity.description", Icon.BLUR_LINEAR, this, 5, 1, 20, 1); - private ComboSetting languageSetting = new ComboSetting("setting.language", "setting.language.description", + private final ComboSetting languageSetting = new ComboSetting("setting.language", "setting.language.description", Icon.LANGUAGE, this, Arrays.asList("language.english", "language.chinese"), "language.english"); private Screen modMenu; @@ -156,19 +156,7 @@ public NumberSetting getBlurIntensitySetting() { return blurIntensitySetting; } - public ComboSetting getLanguageSetting() { - return languageSetting; - } - public Screen getModMenu() { return modMenu; } - - public KeybindSetting getKeybindSetting_music() { - return keybindSetting_music; - } - - public void setKeybindSetting_music(KeybindSetting keybindSetting_music) { - this.keybindSetting_music = keybindSetting_music; - } } diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java index 8cfa7d9..9c76714 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/GuiRendererMixin.java @@ -12,6 +12,7 @@ import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.gui.render.GuiRenderer; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; @@ -39,7 +40,7 @@ public abstract class GuiRendererMixin implements IMinecraft { private GuiRenderState renderState; @Inject(method = "", at = @At("RETURN")) - private void pupper$init(GuiRenderState renderState, MultiBufferSource.BufferSource bufferSource, SubmitNodeCollector submitNodeCollector, FeatureRenderDispatcher featureRenderDispatcher, List pictureInPictureRenderers, CallbackInfo ci) { + private void pupper$init(GuiRenderState renderState, MultiBufferSource.BufferSource bufferSource, SubmitNodeCollector submitNodeCollector, FeatureRenderDispatcher featureRenderDispatcher, List> pictureInPictureRenderers, CallbackInfo ci) { if ((GuiRenderer) (Object) this instanceof PupperGuiRenderer) return; this.renderState = new GuiRenderState(); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java index 37f5f59..17ae541 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/MixinInGameHud.java @@ -18,15 +18,15 @@ @Mixin(Gui.class) public class MixinInGameHud { - /** - * @author EldoDebug - * @reason drawHeart - */ - @Overwrite - private void extractHeart(final GuiGraphicsExtractor graphics, final Gui.HeartType type, final int xo, final int yo, final boolean isHardcore, final boolean blinks, final boolean half) { - OldAnimationsMod mod = OldAnimationsMod.getInstance(); - graphics.blitSprite(RenderPipelines.GUI, type.getSprite(isHardcore, half, (!mod.isEnabled() || !mod.isDisableHeartFlash()) && blinks), xo, yo, 9, 9); - } +// /** +// * @author EldoDebug +// * @reason drawHeart +// */ +// @Overwrite +// private void extractHeart(final GuiGraphicsExtractor graphics, final Gui.HeartType type, final int xo, final int yo, final boolean isHardcore, final boolean blinks, final boolean half) { +// // OldAnimationsMod mod = OldAnimationsMod.getInstance(); +// // graphics.blitSprite(RenderPipelines.GUI, type.getSprite(isHardcore, half, (!mod.isEnabled() || !mod.isDisableHeartFlash()) && blinks), xo, yo, 9, 9); +// } @Inject(method = "extractHotbarAndDecorations", at = @At("TAIL")) private void renderMainHud(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java index 129dfa7..d8af8c9 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/render/PupperInGameHud.java @@ -2,46 +2,18 @@ import cn.pupperclient.event.EventBus; import cn.pupperclient.event.client.DrawItemHotbarEvent; -import net.minecraft.client.AttackIndicatorStatus; import net.minecraft.client.DeltaTracker; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.HumanoidArm; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -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.callback.CallbackInfo; @Mixin(Gui.class) public class PupperInGameHud { - @Shadow @Final private Minecraft minecraft; - - @Shadow - private Player getCameraPlayer() { - Entity var2 = this.minecraft.getCameraEntity(); - Player var10000; - if (var2 instanceof Player playerEntity) { - var10000 = playerEntity; - } else { - var10000 = null; - } - return var10000; - } - - @Unique private long lastHotbarUpdate = 0; - @Unique private int lastSelectedSlot = 0; - @Unique private float slotAnimationProgress = 0f; - @Unique private float offhandAlpha = 0f; - @Inject(method = "extractItemHotbar", at = @At("HEAD"), cancellable = true) - private void replaceHotbarRender(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { + private void HotbarRender(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { DrawItemHotbarEvent event = new DrawItemHotbarEvent(); EventBus.getInstance().post(event); From b27fe7753a6b117dca6e10c3c9e60348c370aeba Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 10 May 2026 16:20:05 +0800 Subject: [PATCH 36/45] new gui api --- build.gradle.kts | 11 +++ .../event/skia/DrawSkiaEvent.java | 10 +++ .../cn/pupperclient/gui/MusicPlayGui.java | 37 ++++++---- .../pupperclient/gui/api/PupperGuiUtil.java | 66 +++++++++++++++++ .../pupperclient/gui/api/SimpleSoarGui.java | 73 +++++++++++-------- .../pupperclient/gui/modmenu/GuiModMenu.java | 6 +- .../mod/api/hud/SimpleListHUDMod.java | 4 +- .../client/MixinMinecraftClient.java | 7 ++ .../pupperclient/shader/impl/Kawaseblur.java | 2 +- src/main/java/cn/pupperclient/skia/Skia.java | 4 +- 10 files changed, 165 insertions(+), 55 deletions(-) create mode 100644 src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java diff --git a/build.gradle.kts b/build.gradle.kts index 29b8221..774e9b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,17 @@ base { loom { accessWidenerPath = file("src/main/resources/pupper.classtweaker") + runs { + named("client") { + vmArgs.addAll( + listOf( + "-Xms512M", + "-Xmx4G", + "-XX:HeapBaseMinAddress=34g" + ) + ) + } + } } repositories { diff --git a/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java b/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java index 05c0803..5854e17 100644 --- a/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java +++ b/src/main/java/cn/pupperclient/event/skia/DrawSkiaEvent.java @@ -5,6 +5,16 @@ package cn.pupperclient.event.skia; import cn.pupperclient.event.Event; +import io.github.humbleui.skija.Canvas; public class DrawSkiaEvent extends Event { + private final Canvas canvas; + + public DrawSkiaEvent(Canvas canvas) { + this.canvas = canvas; + } + + public Canvas getCanvas() { + return canvas; + } } diff --git a/src/main/java/cn/pupperclient/gui/MusicPlayGui.java b/src/main/java/cn/pupperclient/gui/MusicPlayGui.java index 7c8346e..0671fdb 100644 --- a/src/main/java/cn/pupperclient/gui/MusicPlayGui.java +++ b/src/main/java/cn/pupperclient/gui/MusicPlayGui.java @@ -1,31 +1,42 @@ package cn.pupperclient.gui; -import cn.pupperclient.gui.api.SimpleSoarGui; +import cn.pupperclient.event.EventListener; +import cn.pupperclient.event.skia.DrawSkiaEvent; +import cn.pupperclient.event.skia.RenderSkiaEvent; +import cn.pupperclient.gui.api.PupperGuiUtil; import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.font.Fonts; import cn.pupperclient.skia.font.Icon; +import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import cn.pupperclient.utils.mouse.MouseUtils; import io.github.humbleui.types.Rect; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import org.jspecify.annotations.NonNull; import java.awt.*; -public class MusicPlayGui extends SimpleSoarGui { +public class MusicPlayGui extends PupperGuiUtil implements IMinecraft { private boolean isfullscreen = false; public MusicPlayGui() { - super(false); + super(Component.literal("MusicPlay")); } @Override - public void draw(double mouseX, double mouseY) { - int windowWidth = client.getWindow().getWidth(); - int windowHeight = client.getWindow().getHeight(); + public void extractRenderState(final @NonNull GuiGraphicsExtractor graphics, final int mouseX, final int mouseY, final float a) { + checkWindow(); + eventRegister(); + } - float uiWidth = 1350; - float uiHeight = 900; + @EventListener + public void draw(DrawSkiaEvent event) { + int uiWidth = 1350; + int uiHeight = 900; - float offsetX = (windowWidth - uiWidth) / 2; - float offsetY = (windowHeight - uiHeight) / 2; + int offsetX = (windowWidth - uiWidth) / 2; + int offsetY = (windowHeight - uiHeight) / 2; Skia.translate(offsetX, offsetY); Skia.drawRect(0, 0, 340, uiHeight, new Color(20, 20, 20, 240)); @@ -43,9 +54,9 @@ public void draw(double mouseX, double mouseY) { } @Override - public boolean onMousePressed(double mouseX, double mouseY, int button, boolean doubled) { - int windowWidth = client.getWindow().getWidth(); - int windowHeight = client.getWindow().getHeight(); + public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { + var mouseX = click.x(); + var mouseY = click.y(); float uiWidth = 1350; float uiHeight = 900; diff --git a/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java b/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java new file mode 100644 index 0000000..7ae55b8 --- /dev/null +++ b/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java @@ -0,0 +1,66 @@ +/** + * @Author: oneachina + * @link: github.com/oneachina + */ +package cn.pupperclient.gui.api; + +import cn.pupperclient.event.EventBus; +import cn.pupperclient.skia.Skia; +import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +public abstract class PupperGuiUtil extends Screen implements IMinecraft { + public int windowWidth = 0; + public int windowHeight = 0; + + protected boolean isEventRegister; + + protected PupperGuiUtil(final Component title) { + super(title); + } + + protected void checkWindow() { + if (windowHeight == 0 || windowWidth == 0) { + this.windowHeight = client.getWindow().getHeight(); + this.windowHeight = client.getWindow().getWidth(); + } + } + + protected void initWindow() { + this.windowWidth = client.getWindow().getWidth(); + this.windowHeight = client.getWindow().getHeight(); + } + + protected void eventRegister() { + if (!isEventRegister) { + EventBus.getInstance().register(this); + isEventRegister = true; + } + } + + @Override + public void onClose() { + EventBus.getInstance().unregister(this); + isEventRegister = false; + super.onClose(); + } + + @Override + public void removed() { + EventBus.getInstance().unregister(this); + isEventRegister = false; + super.removed(); + } + + @Override + public void init() { + initWindow(); + eventRegister(); + } + + @Override + public boolean isPauseScreen() { + return false; + } +} diff --git a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java index af1de95..0df07b6 100644 --- a/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java +++ b/src/main/java/cn/pupperclient/gui/api/SimpleSoarGui.java @@ -1,7 +1,9 @@ package cn.pupperclient.gui.api; +import cn.pupperclient.event.EventBus; +import cn.pupperclient.event.EventListener; +import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.skia.Skia; -import cn.pupperclient.skia.context.SkiaContext; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.Screen; @@ -18,15 +20,19 @@ public abstract class SimpleSoarGui extends Screen { protected final Minecraft client = Minecraft.getInstance(); protected final boolean mcScale; + private boolean registered; protected SimpleSoarGui(boolean mcScale) { super(Component.empty()); - this.mcScale = mcScale; + this.mcScale = true; } @Override protected void init() { - // Base init logic if any + if (client.level != null && !registered) { + EventBus.getInstance().register(this); + registered = true; + } } /** @@ -36,47 +42,28 @@ protected void init() { @Override public void extractRenderState(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta) { - SkiaContext.draw((_) -> { - Skia.save(); - - if (mcScale) { - Skia.scale((float) client.getWindow().getGuiScale()); - } - - double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); - double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); - - draw(finalMouseX, finalMouseY); - - Skia.restore(); - }); + if (client.level != null && !registered) { + EventBus.getInstance().register(this); + registered = true; + } } @Override public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { - double mouseX = click.x(); - double mouseY = click.y(); - - double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); - double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); - return onMousePressed(finalMouseX, finalMouseY, click.button(), doubled); + double guiScale = client.getWindow().getGuiScale(); + return onMousePressed(client.mouseHandler.xpos() / guiScale, client.mouseHandler.ypos() / guiScale, click.button(), doubled); } @Override public boolean mouseReleased(MouseButtonEvent click) { - double mouseX = click.x(); - double mouseY = click.y(); - - double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); - double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); - return onMouseReleased(finalMouseX, finalMouseY, click.button()); + double guiScale = client.getWindow().getGuiScale(); + return onMouseReleased(client.mouseHandler.xpos() / guiScale, client.mouseHandler.ypos() / guiScale, click.button()); } @Override public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - double finalMouseX = mcScale ? mouseX : client.mouseHandler.xpos(); - double finalMouseY = mcScale ? mouseY : client.mouseHandler.ypos(); - return onMouseScrolled(finalMouseX, finalMouseY, horizontalAmount, verticalAmount); + double guiScale = client.getWindow().getGuiScale(); + return onMouseScrolled(client.mouseHandler.xpos() / guiScale, client.mouseHandler.ypos() / guiScale, horizontalAmount, verticalAmount); } @Override @@ -97,8 +84,30 @@ public boolean charTyped(CharacterEvent input) { public boolean onKeyPressed(int keyCode, int scanCode, int modifiers) { return super.keyPressed(new KeyEvent(keyCode, scanCode, modifiers)); } public boolean onCharTyped(int chr) { return super.charTyped(new CharacterEvent(chr)); } + @Override + public void removed() { + if (registered) { + EventBus.getInstance().unregister(this); + registered = false; + } + super.removed(); + } + @Override public boolean isPauseScreen() { return false; } + + @EventListener + public void onRenderSkia(RenderSkiaEvent event) { + if (client.level == null) { + return; + } + if (client.screen == this) { + double guiScale = client.getWindow().getGuiScale(); + Skia.save(); + draw(client.mouseHandler.xpos() / guiScale, client.mouseHandler.ypos() / guiScale); + Skia.restore(); + } + } } diff --git a/src/main/java/cn/pupperclient/gui/modmenu/GuiModMenu.java b/src/main/java/cn/pupperclient/gui/modmenu/GuiModMenu.java index 8695252..b4b9629 100644 --- a/src/main/java/cn/pupperclient/gui/modmenu/GuiModMenu.java +++ b/src/main/java/cn/pupperclient/gui/modmenu/GuiModMenu.java @@ -13,7 +13,7 @@ public class GuiModMenu extends SoarGui { private NavigationRail navigationRail; public GuiModMenu() { - super(false); + super(true); } @Override @@ -49,12 +49,12 @@ public List createPages() { @Override public float getX() { - return ((float) client.getWindow().getWidth() / 2) - (getWidth() / 2); + return ((float) client.getWindow().getGuiScaledWidth() / 2) - (getWidth() / 2); } @Override public float getY() { - return ((float) client.getWindow().getHeight() / 2) - (getHeight() / 2); + return ((float) client.getWindow().getGuiScaledHeight() / 2) - (getHeight() / 2); } @Override diff --git a/src/main/java/cn/pupperclient/management/mod/api/hud/SimpleListHUDMod.java b/src/main/java/cn/pupperclient/management/mod/api/hud/SimpleListHUDMod.java index eaf072f..395ee13 100644 --- a/src/main/java/cn/pupperclient/management/mod/api/hud/SimpleListHUDMod.java +++ b/src/main/java/cn/pupperclient/management/mod/api/hud/SimpleListHUDMod.java @@ -13,13 +13,11 @@ public SimpleListHUDMod (String name, String description, String icon) { } protected void draw() { - float fontSize = 9; float padding = 5; float maxWidth = 0; float height = 0; - float lineHeight = 5; // 空行的间隔 - // EN: Line height spacing + float lineHeight = 5; for (int i = 0; i < getText().size(); i++) { Rect textBounds = Skia.getTextBounds(getText().get(i), Fonts.getRegular(fontSize)); diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java index e27cce7..4edd8b5 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinMinecraftClient.java @@ -4,6 +4,7 @@ import java.io.IOException; import cn.pupperclient.event.client.ResolutionChangedEvent; +import cn.pupperclient.event.skia.DrawSkiaEvent; import cn.pupperclient.skia.Skia; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; @@ -195,6 +196,12 @@ private void onBeforeFlipFrame(CallbackInfo ci) { EventBus.getInstance().post(new RenderSkiaEvent(canvas)); Skia.restore(); }); + + SkiaContext.draw((canvas) -> { + Skia.save(); + EventBus.getInstance().post(new DrawSkiaEvent(canvas)); + Skia.restore(); + }); } @Override diff --git a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java index ace89ef..24b6849 100644 --- a/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java +++ b/src/main/java/cn/pupperclient/shader/impl/Kawaseblur.java @@ -24,7 +24,7 @@ import java.nio.ByteBuffer; public class Kawaseblur { - // public static final Kawaseblur INGAME_BLUR = new Kawaseblur(); + public static final Kawaseblur instance = new Kawaseblur(); private final Minecraft mc = Minecraft.getInstance(); private final IntFloatImmutablePair[] strengths = new IntFloatImmutablePair[]{ diff --git a/src/main/java/cn/pupperclient/skia/Skia.java b/src/main/java/cn/pupperclient/skia/Skia.java index ae339cf..939632f 100644 --- a/src/main/java/cn/pupperclient/skia/Skia.java +++ b/src/main/java/cn/pupperclient/skia/Skia.java @@ -2,13 +2,11 @@ import java.awt.Color; import java.io.File; -import net.minecraft.client.Minecraft; + import net.minecraft.resources.Identifier; import cn.pupperclient.management.mod.impl.settings.HUDModSettings; -import cn.pupperclient.shader.impl.Kawaseblur; import cn.pupperclient.skia.context.SkiaContext; import cn.pupperclient.skia.image.ImageHelper; -import com.mojang.blaze3d.platform.Window; import io.github.humbleui.skija.Canvas; import io.github.humbleui.skija.ClipMode; import io.github.humbleui.skija.FilterTileMode; From f569353897f647ed38ccb0bd146ba4ae699b1dbf Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:17:37 +0800 Subject: [PATCH 37/45] chore: deleted eldodebug license --- OLD_ELDODEBUG_LICENSE | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 OLD_ELDODEBUG_LICENSE diff --git a/OLD_ELDODEBUG_LICENSE b/OLD_ELDODEBUG_LICENSE deleted file mode 100644 index 9a9c51c..0000000 --- a/OLD_ELDODEBUG_LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 Soar Client - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From 71b04ec779cb515cf144b812a1042e6b1f35c4df Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:17:48 +0800 Subject: [PATCH 38/45] refactor: optimize MusicPlayGui rendering and mouse handling --- .../cn/pupperclient/gui/MusicPlayGui.java | 47 ++++++++----------- .../pupperclient/gui/api/PupperGuiUtil.java | 11 ++++- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/main/java/cn/pupperclient/gui/MusicPlayGui.java b/src/main/java/cn/pupperclient/gui/MusicPlayGui.java index 0671fdb..3c62fc1 100644 --- a/src/main/java/cn/pupperclient/gui/MusicPlayGui.java +++ b/src/main/java/cn/pupperclient/gui/MusicPlayGui.java @@ -2,15 +2,12 @@ import cn.pupperclient.event.EventListener; import cn.pupperclient.event.skia.DrawSkiaEvent; -import cn.pupperclient.event.skia.RenderSkiaEvent; import cn.pupperclient.gui.api.PupperGuiUtil; import cn.pupperclient.skia.Skia; import cn.pupperclient.skia.font.Fonts; import cn.pupperclient.skia.font.Icon; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; import cn.pupperclient.utils.mouse.MouseUtils; -import io.github.humbleui.types.Rect; -import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; import org.jspecify.annotations.NonNull; @@ -20,23 +17,17 @@ public class MusicPlayGui extends PupperGuiUtil implements IMinecraft { private boolean isfullscreen = false; + private final int uiWidth = 1350; + private final int uiHeight = 900; + public MusicPlayGui() { super(Component.literal("MusicPlay")); } - @Override - public void extractRenderState(final @NonNull GuiGraphicsExtractor graphics, final int mouseX, final int mouseY, final float a) { - checkWindow(); - eventRegister(); - } - @EventListener public void draw(DrawSkiaEvent event) { - int uiWidth = 1350; - int uiHeight = 900; - - int offsetX = (windowWidth - uiWidth) / 2; - int offsetY = (windowHeight - uiHeight) / 2; + var offsetX = (windowWidth - uiWidth) / 2; + var offsetY = (windowHeight - uiHeight) / 2; Skia.translate(offsetX, offsetY); Skia.drawRect(0, 0, 340, uiHeight, new Color(20, 20, 20, 240)); @@ -45,6 +36,7 @@ public void draw(DrawSkiaEvent event) { Skia.drawText("Minecraft Jagget MusicPlay", 20, 26, Color.WHITE, Fonts.getRegular(23)); Skia.drawText(Icon.CLOSE, 1320, 20, Color.WHITE, Fonts.getIconFill(21)); + if (!isfullscreen) { Skia.drawText(Icon.FULLSCREEN, 1285, 19, Color.WHITE, Fonts.getIconFill(21)); } else { @@ -54,28 +46,27 @@ public void draw(DrawSkiaEvent event) { } @Override - public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { + public boolean mouseClicked(@NonNull MouseButtonEvent click, boolean doubled) { var mouseX = click.x(); var mouseY = click.y(); - float uiWidth = 1350; - float uiHeight = 900; + var offsetX = (windowWidth - uiWidth) / 2; + var offsetY = (windowHeight - uiHeight) / 2; - float startX = (windowWidth - uiWidth) / 2; - float startY = (windowHeight - uiHeight) / 2; + var icon_CLOSE_rect = Skia.getTextBounds(Icon.CLOSE, Fonts.getIconFill(21)); + var icon_FULLSCREEN_rect = Skia.getTextBounds(Icon.FULLSCREEN, Fonts.getIconFill(21)); + var icon_MINIMIZE_rect = Skia.getTextBounds(Icon.MINIMIZE, Fonts.getIconFill(21)); - Rect icon_CLOSE_rect = Skia.getTextBounds(Icon.CLOSE, Fonts.getIconFill(21)); - Rect icon_FULLSCREEN_rect = Skia.getTextBounds(Icon.FULLSCREEN, Fonts.getIconFill(21)); - Rect icon_FULLSCREEN_EXIT_rect = Skia.getTextBounds(Icon.FULLSCREEN_EXIT, Fonts.getIconFill(21)); - Rect icon_MINIMIZE_rect = Skia.getTextBounds(Icon.MINIMIZE, Fonts.getIconFill(21)); - - if (MouseUtils.isInside(mouseX, mouseY, startX + 1320, startY + 20, icon_CLOSE_rect.getWidth(), icon_CLOSE_rect.getHeight()) || - MouseUtils.isInside(mouseX, mouseY, startX + 1251, startY + 25, icon_MINIMIZE_rect.getWidth(), icon_MINIMIZE_rect.getHeight()) + if (MouseUtils.isInside(mouseX, mouseY, offsetX + 1320, offsetY + 20, icon_CLOSE_rect.getWidth(), icon_CLOSE_rect.getHeight()) || + MouseUtils.isInside(mouseX, mouseY, offsetX + 1251, offsetY + 25, icon_MINIMIZE_rect.getWidth(), icon_MINIMIZE_rect.getHeight()) ) { client.setScreen(null); - } else if (MouseUtils.isInside(mouseX, mouseY, startX + 1285, startY + 19, icon_FULLSCREEN_rect.getWidth() + 1, icon_FULLSCREEN_rect.getHeight() + 1)) { + return true; + } + if (MouseUtils.isInside(mouseX, mouseY, offsetX + 1285, offsetY + 19, icon_FULLSCREEN_rect.getWidth() + 1, icon_FULLSCREEN_rect.getHeight() + 1)) { isfullscreen = !isfullscreen; + return true; } - return true; + return false; } } diff --git a/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java b/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java index 7ae55b8..65d1216 100644 --- a/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java +++ b/src/main/java/cn/pupperclient/gui/api/PupperGuiUtil.java @@ -5,10 +5,11 @@ package cn.pupperclient.gui.api; import cn.pupperclient.event.EventBus; -import cn.pupperclient.skia.Skia; import cn.pupperclient.utils.minecraft.interfaces.IMinecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; +import org.jspecify.annotations.NonNull; public abstract class PupperGuiUtil extends Screen implements IMinecraft { public int windowWidth = 0; @@ -22,8 +23,8 @@ protected PupperGuiUtil(final Component title) { protected void checkWindow() { if (windowHeight == 0 || windowWidth == 0) { + this.windowWidth = client.getWindow().getWidth(); this.windowHeight = client.getWindow().getHeight(); - this.windowHeight = client.getWindow().getWidth(); } } @@ -63,4 +64,10 @@ public void init() { public boolean isPauseScreen() { return false; } + + @Override + public void extractRenderState(final @NonNull GuiGraphicsExtractor graphics, final int mouseX, final int mouseY, final float a) { + checkWindow(); + eventRegister(); + } } From 1cf6948df54f0b7981a7e7fb5b8064a9d863c5b6 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:20:14 +0800 Subject: [PATCH 39/45] fix: adjust formatting in getClientModName method --- .../mixins/minecraft/client/MixinClientBrandRetriever.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java index a2d1d45..03dce26 100644 --- a/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java +++ b/src/main/java/cn/pupperclient/mixin/mixins/minecraft/client/MixinClientBrandRetriever.java @@ -13,6 +13,6 @@ public class MixinClientBrandRetriever { */ @Overwrite public static String getClientModName() { - return PupperClient.getInstance().getName() + "(" + PupperClient.getInstance().getVersion() + ")"; + return PupperClient.getInstance().getName() + " (" + PupperClient.getInstance().getVersion() + ") "; } } From e84b3ae7e2054fdaf49c77af0ce0abd9dba638c0 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:25:59 +0800 Subject: [PATCH 40/45] fix: update CLIENT_VERSION to 9.0.0a --- src/main/java/cn/pupperclient/PupperClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/pupperclient/PupperClient.java b/src/main/java/cn/pupperclient/PupperClient.java index a3f360a..a585bdb 100644 --- a/src/main/java/cn/pupperclient/PupperClient.java +++ b/src/main/java/cn/pupperclient/PupperClient.java @@ -29,7 +29,7 @@ public class PupperClient implements IMinecraft { private static final String CONFIG_FILE_NAME = "pupper.ok"; private static final String ICON_PATH = "assets/pupper/logo.png"; private static final String CLIENT_NAME = "Pupper Client"; - private static final String CLIENT_VERSION = "mc26.1.2-pupper26.4.1"; + private static final String CLIENT_VERSION = "mc26.1.2-9.0.0a"; private static final String MOD_ID = "pupper"; private static final PupperClient INSTANCE = new PupperClient(); From cebecbc274854559eee4f8f1a3296fdba8342d29 Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:26:16 +0800 Subject: [PATCH 41/45] feat: add ias mod for in-game account switching --- build.gradle.kts | 1 + gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 774e9b5..5daab3c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -62,6 +62,7 @@ dependencies { runtimeOnly(libs.lithium) runtimeOnly(libs.immediatelyfast) runtimeOnly(libs.entityculling) + runtimeOnly(libs.ias) implementation(libs.modmenu) implementation(libs.viafabricplus) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd16e6d..9b32e13 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ modmenu = "18.0.0-alpha.8" viafabricplus = "4.5.2" immediatelyfast = "1.15.2+26.1.2-fabric" entityculling = "NaRJu6ah" +ias = "2ea1OpDg" # lib lwjgl = "3.4.1" @@ -49,6 +50,7 @@ viafabricplus = { module = "com.viaversion:viafabricplus", version.ref = "viafab viafabricplus-api = { module = "com.viaversion:viafabricplus-api", version.ref = "viafabricplus" } immediatelyfast = { module = "maven.modrinth:immediatelyfast", version.ref = "immediatelyfast" } entityculling = { module = "maven.modrinth:entityculling", version.ref = "entityculling" } +ias = { module = "maven.modrinth:in-game-account-switcher", version.ref = "ias" } # lib smartboot-aio = { module = "io.github.smartboot.socket:aio-core", version.ref = "smartboot-aio" } From b568f8df07cc90d674e59163733e99e7c23d56ee Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:34:24 +0800 Subject: [PATCH 42/45] docs: rename README.MD to README.md and update installation instructions --- README.MD | 45 --------------------------------------------- README.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 45 deletions(-) delete mode 100644 README.MD create mode 100644 README.md diff --git a/README.MD b/README.MD deleted file mode 100644 index 65abbc4..0000000 --- a/README.MD +++ /dev/null @@ -1,45 +0,0 @@ -# Pupper Client - -A Better, Faster Minecraft Client for 1.21.4 - -## Features -- Optimized performance and gameplay experience -- Custom HUD and UI elements -- Built-in ViaFabricPlus for multi-version support -- In-game account switching capability -- Enhanced rendering and visual effects - -## Installation - -1. Download the mod from modrinth -2. Download the modpack from modrinth - -## Requirements -- **Minecraft**: 1.21.4 -- **Required Mods**: - - [IAS] In-Game Account Switcher - - ViaFabricPlus - - ModMenu - -## Download & Support - -**Official QQ Group**: 1023334402 - -**Developer Contacts**: -- oneachina - - QQ: 3565723760 - - Bilibili: https://space.bilibili.com/1582724340 - -**Official Links**: -- GitHub: https://github.com/PupperClient/ -- Fabric Version: https://github.com/PupperClient/Pupper-Client -- Neoforge Version: PupperClient/Pupper-Client-Neoforge (Coming Soon) -- Discord: https://discord.gg/8FbSHb7F - -## Notice -All resources are available in our official group files. Please download and use according to your needs. - ---- - -Pupper Client Official -2025/12/13 18:28 (Beijing time) diff --git a/README.md b/README.md new file mode 100644 index 0000000..961ba4f --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# Pupper Client + +A Better, Faster Minecraft Client + +## Features +- Optimized performance and gameplay experience +- Custom HUD and UI elements +- Built-in ViaFabricPlus for multi-version support +- In-game account switching capability +- Enhanced rendering and visual effects + +## Installation + +1. Ensure you have Fabric Loader version 0.18.6 or higher installed. +2. Download the latest version of Pupper Client from the [Modrinth](https://modrinth.com/mod/pupper-client) page. +3. Place the downloaded JAR file into your Minecraft `mods` folder. +4. Launch Minecraft with the Fabric Loader profile to enjoy the client. + +## Requirements +- **Minecraft** +- **Fabric Loader**: Version 0.18.6 or higher +- **Required Mods**: + - ViaFabricPlus + - ModMenu + +## License +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details + +## Contributing +Contributions are welcome! Please fork the repository and submit a pull request with your changes. + +For major changes, please open an issue first to discuss what you would like to change. From 93e3bce54296745474779f15bec4aecd4e6c706b Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:34:37 +0800 Subject: [PATCH 43/45] ci: update build configuration to ignore markdown files and GitHub directory --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7058301..02ecd97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,9 @@ name: Build JAR on: push: branches: [ main, master ] + paths-ignore: + - '*.md' + - '.github/**' pull_request: branches: [ main, master ] release: From 0edbaf463f477f574758b3c82cfc6e2af83d017c Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:40:16 +0800 Subject: [PATCH 44/45] docs: update LICENSE.md to reflect new copyright year and remove outdated information --- LICENSE.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 91bfa39..4c857c4 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,19 +1,11 @@ -# Pupper Client LICENSE -Version November 29, 2025 - -This License is GPL 3.0 - -The new license shall prevail. - -The original license is retained because Eldodebug opted for the MIT license, but it will have no effect. - - ## GPL 3.0 LICENSE Version 3, 29 June 2025 Copyright (C) 2007 Free Software Foundation, Inc. +Copyright (C) 2026 Pupper Client + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. From 181989a1db66fc9e4f07808de58f57725c2471ee Mon Sep 17 00:00:00 2001 From: oneachina Date: Sun, 24 May 2026 22:40:40 +0800 Subject: [PATCH 45/45] docs: update LICENSE.md to reflect new copyright year and remove outdated information --- LICENSE.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 4c857c4..b22b075 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,11 +1,8 @@ ## GPL 3.0 LICENSE -Version 3, 29 June 2025 - -Copyright (C) 2007 Free Software Foundation, Inc. - - Copyright (C) 2026 Pupper Client +Version 3, 29 June 2025 + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.