From 0f0ee90bd6bdfd910aa231a3304abf8db01d4b15 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sat, 1 Aug 2026 23:00:29 +0800 Subject: [PATCH 01/22] =?UTF-8?q?feat(saturation):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=A5=B1=E5=92=8C=E5=BA=A6=E6=98=BE=E7=A4=BA=20HUD=EF=BC=8C?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=E5=8E=9F=E7=89=88=E9=A5=A5=E9=A5=BF=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 SaturationDisplay InterfaceModule + SaturationDisplayComponent: - 默认定位在原版饥饿栏处,可拖动/缩放/换背景 - 绘制原版风格食物图标并按实际饥饿值填充,附带饱和度数值 - 开启模块时通过 MixinGuiIngameForge 取消原版 renderFood,关闭即恢复原版 --- .../impl/interfaces/SaturationDisplay.java | 27 +++++++ .../features/manager/ModuleManager.java | 3 + .../forge/mixin/MixinGuiIngameForge.java | 8 ++ .../ui/custom/ComponentsManager.java | 1 + .../impl/SaturationDisplayComponent.java | 77 +++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java create mode 100644 src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java new file mode 100644 index 00000000..38213657 --- /dev/null +++ b/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java @@ -0,0 +1,27 @@ +package top.fpsmaster.features.impl.interfaces; + +import top.fpsmaster.features.impl.InterfaceModule; +import top.fpsmaster.features.manager.Category; + +/** + * Replaces the vanilla food HUD with a movable saturation display. + */ +public class SaturationDisplay extends InterfaceModule { + public static boolean using; + + public SaturationDisplay() { + super("SaturationDisplay", Category.Interface, Trait.BACKGROUND, Trait.TEXT); + } + + @Override + public void onEnable() { + using = true; + super.onEnable(); + } + + @Override + public void onDisable() { + using = false; + super.onDisable(); + } +} diff --git a/src/main/java/top/fpsmaster/features/manager/ModuleManager.java b/src/main/java/top/fpsmaster/features/manager/ModuleManager.java index ede51dc8..ab6f7306 100644 --- a/src/main/java/top/fpsmaster/features/manager/ModuleManager.java +++ b/src/main/java/top/fpsmaster/features/manager/ModuleManager.java @@ -93,6 +93,7 @@ public void init() { modules.add(new MoreParticles()); modules.add(new ChatAvatars()); modules.add(new FPSDisplay()); + modules.add(new SaturationDisplay()); modules.add(new ArmorDisplay()); modules.add(new BetterChat()); modules.add(new BlockIndicator()); @@ -113,6 +114,7 @@ public void init() { modules.add(new FireModifier()); modules.add(new FreeLook()); modules.add(new AutoGG()); + modules.add(new AutoText()); modules.add(new TimeChanger()); modules.add(new TNTTimer()); modules.add(new Hitboxes()); @@ -121,6 +123,7 @@ public void init() { modules.add(new Crosshair()); modules.add(new CustomTitles()); modules.add(new CustomFOV()); + modules.add(new CustomFog()); modules.add(new InventoryDisplay()); modules.add(new PlayerDisplay()); modules.add(new TargetDisplay()); diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java index e34c5c37..b7a97e17 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java @@ -12,6 +12,7 @@ import top.fpsmaster.event.events.EventMotionBlur; import top.fpsmaster.event.events.EventRender2D; import top.fpsmaster.features.impl.interfaces.CustomTitles; +import top.fpsmaster.features.impl.interfaces.SaturationDisplay; @Mixin(GuiIngameForge.class) public class MixinGuiIngameForge { @@ -25,6 +26,13 @@ private void renderTooltipPost(ScaledResolution sr, float partialTicks, Callback EventDispatcher.dispatchEvent(new EventRender2D(partialTicks)); } + @Inject(method = "renderFood", at = @At("HEAD"), cancellable = true) + private void hideVanillaFood(int width, int height, CallbackInfo callbackInfo) { + if (SaturationDisplay.using) { + callbackInfo.cancel(); + } + } + @Redirect(method = "renderTitle", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;translate(FFF)V")) public void drawString(float x, float y, float z) { GlStateManager.translate(x + CustomTitles.getX(), y + CustomTitles.getY(), z); diff --git a/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java b/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java index b0c39058..e856280a 100644 --- a/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java +++ b/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java @@ -35,6 +35,7 @@ public enum DragMode { // Initialize all components public void init() { addComponentSafely("FPSDisplayComponent", FPSDisplayComponent::new); + addComponentSafely("SaturationDisplayComponent", SaturationDisplayComponent::new); addComponentSafely("ArmorDisplayComponent", ArmorDisplayComponent::new); addComponentSafely("ScoreboardComponent", ScoreboardComponent::new); addComponentSafely("PotionDisplayComponent", PotionDisplayComponent::new); diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java new file mode 100644 index 00000000..919c1572 --- /dev/null +++ b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java @@ -0,0 +1,77 @@ +package top.fpsmaster.ui.custom.impl; + +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; +import top.fpsmaster.features.impl.interfaces.SaturationDisplay; +import top.fpsmaster.ui.custom.Component; +import top.fpsmaster.ui.custom.Position; + +import java.awt.Color; + +import static top.fpsmaster.utils.core.Utility.mc; + +/** Draws the food icons and the exact saturation value in the HUD editor coordinate space. */ +public class SaturationDisplayComponent extends Component { + private static final ResourceLocation ICONS = new ResourceLocation("textures/gui/icons.png"); + private static final float ICON_SIZE = 9f; + private static final float ICON_ROW_WIDTH = 90f; + private static final float VALUE_GAP = 4f; + + public SaturationDisplayComponent() { + super(SaturationDisplay.class); + position = Position.RB; + // Vanilla food HUD right edge is 10 px from the screen edge; HUD coordinates are doubled. + x = 0.02f; + y = 0.075f; + allowScale = true; + } + + @Override + public void measure() { + String value = saturationText(); + width = ICON_ROW_WIDTH + VALUE_GAP + getStringWidth(14, value) + 4f; + height = 12f; + } + + @Override + public void draw(float x, float y) { + super.draw(x, y); + if (mc == null || mc.thePlayer == null) { + return; + } + + drawRect(x, y, width, height, mod.backgroundColor.getColor()); + + int food = Math.max(0, Math.min(20, mc.thePlayer.getFoodStats().getFoodLevel())); + GlStateManager.enableBlend(); + GlStateManager.color(1f, 1f, 1f, 1f); + mc.getTextureManager().bindTexture(ICONS); + for (int icon = 0; icon < 10; icon++) { + float iconX = x + icon * ICON_SIZE * scale; + drawIcon(iconX, y + 1f * scale, 16, 27); + int halfFood = food - icon * 2; + if (halfFood >= 2) { + drawIcon(iconX, y + 1f * scale, 52, 27); + } else if (halfFood == 1) { + drawIcon(iconX, y + 1f * scale, 61, 27); + } + } + GlStateManager.disableBlend(); + + drawString(14, saturationText(), x + ICON_ROW_WIDTH * scale + VALUE_GAP * scale, y + 1f * scale, Color.WHITE.getRGB()); + GlStateManager.color(1f, 1f, 1f, 1f); + } + + private void drawIcon(float x, float y, int textureX, int textureY) { + Gui.drawModalRectWithCustomSizedTexture(x, y, textureX, textureY, ICON_SIZE * scale, ICON_SIZE * scale, 256f, 256f); + } + + private String saturationText() { + if (mc == null || mc.thePlayer == null) { + return "0.0"; + } + return String.format(java.util.Locale.ROOT, "%.1f", mc.thePlayer.getFoodStats().getSaturationLevel()); + } +} From 2b038cdd38a3e89f817f5a088ec335a15e94db03 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sat, 1 Aug 2026 23:00:58 +0800 Subject: [PATCH 02/22] =?UTF-8?q?feat(fog):=20=E6=96=B0=E5=A2=9E=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E8=BF=B7=E9=9B=BE=E6=A8=A1=E5=9D=97=EF=BC=88?= =?UTF-8?q?=E9=A2=9C=E8=89=B2/=E8=B7=9D=E7=A6=BB/=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CustomFog Render 模块:线性/指数两种模式,颜色、起始距离、结束距离可调 - 在 MixinEntityRenderer.setupFog RETURN 处覆盖雾色与 GL 雾参数 - 默认不影响水下/岩浆迷雾,开启后仅在世界迷雾生效 --- .../features/impl/render/CustomFog.java | 38 +++++++++++++++++++ .../forge/mixin/MixinEntityRenderer.java | 30 +++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/main/java/top/fpsmaster/features/impl/render/CustomFog.java diff --git a/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java b/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java new file mode 100644 index 00000000..5ba09575 --- /dev/null +++ b/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java @@ -0,0 +1,38 @@ +package top.fpsmaster.features.impl.render; + +import top.fpsmaster.features.manager.Category; +import top.fpsmaster.features.manager.Module; +import top.fpsmaster.features.settings.impl.BooleanSetting; +import top.fpsmaster.features.settings.impl.ColorSetting; +import top.fpsmaster.features.settings.impl.NumberSetting; +import top.fpsmaster.features.settings.impl.ModeSetting; + +import java.awt.*; + +public class CustomFog extends Module { + public static boolean using; + + public static ColorSetting color = new ColorSetting("Color", new Color(0, 200, 255)); + public static NumberSetting startDistance = new NumberSetting("StartDistance", 0.0, 0, 20, 0.5); + public static NumberSetting endDistance = new NumberSetting("EndDistance", 20, 1, 200, 1); + public static ModeSetting fogMode = new ModeSetting("FogMode", 0, "Linear", "Exponential"); + public static BooleanSetting affectWater = new BooleanSetting("AffectWater", false); + public static BooleanSetting affectLava = new BooleanSetting("AffectLava", false); + + public CustomFog() { + super("CustomFog", Category.RENDER); + addSettings(color, fogMode, startDistance, endDistance, affectWater, affectLava); + } + + @Override + public void onEnable() { + using = true; + super.onEnable(); + } + + @Override + public void onDisable() { + using = false; + super.onDisable(); + } +} \ No newline at end of file diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java index 69851871..378a74dc 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java @@ -36,6 +36,7 @@ import top.fpsmaster.features.impl.optimizes.SmoothZoom; import top.fpsmaster.features.impl.render.FreeLook; import top.fpsmaster.features.impl.render.MinimizedBobbing; +import top.fpsmaster.features.impl.render.CustomFog; import top.fpsmaster.utils.math.MathUtils; import java.util.List; @@ -301,6 +302,35 @@ public void freelook(float partialTicks, long nanoTime, CallbackInfo ci) { FreeLook.overrideMouse(); } + @Inject(method = "setupFog", at = @At("RETURN")) + private void overrideFog(int startCoords, float partialTicks, CallbackInfo ci) { + if (!CustomFog.using) return; + if (mc.thePlayer == null) return; + + // Check if in water or lava — only override if the user opted in + if (!CustomFog.affectWater.getValue()) { + net.minecraft.block.material.Material eye = mc.thePlayer.getEye().getMaterial(); + if (eye == net.minecraft.block.material.Material.water) return; + } + if (!CustomFog.affectLava.getValue()) { + net.minecraft.block.material.Material eye = mc.thePlayer.getEye().getMaterial(); + if (eye == net.minecraft.block.material.Material.lava) return; + } + + java.awt.Color fogColor = CustomFog.color.getColor(); + GlStateManager.color(fogColor.getRed() / 255f, fogColor.getGreen() / 255f, fogColor.getBlue() / 255f); + + if (CustomFog.fogMode.isMode("Linear")) { + GlStateManager.setFog(GlStateManager.FogMode.LINEAR); + GlStateManager.setFogStart(CustomFog.startDistance.getValue().floatValue()); + GlStateManager.setFogEnd(CustomFog.endDistance.getValue().floatValue()); + } else { + GlStateManager.setFog(GlStateManager.FogMode.EXP); + float density = 1.0f / Math.max(0.1f, CustomFog.endDistance.getValue().floatValue()); + GlStateManager.setFogDensity(density); + } + } + @Shadow private Entity pointedEntity; From 32ac8fcb254b0f4371283efecc68355ab106bbe9 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sat, 1 Aug 2026 23:01:57 +0800 Subject: [PATCH 03/22] =?UTF-8?q?feat(autotext):=20=E6=96=B0=E5=A2=9E=20Au?= =?UTF-8?q?toText=20=E5=BF=AB=E6=8D=B7=E5=8F=91=E9=80=81=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=88=E6=8C=89=E5=BF=AB=E6=8D=B7=E9=94=AE=E5=8F=91=E9=80=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=B6=88=E6=81=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AutoText Utility 模块:默认 G→gg,最多 20 条,禁止重复快捷键 - AutoTextSetting(ArrayList)+ AutoTextEntry 不可变对象 - ClickGUI 编辑器:每行 快捷键绑定 + 消息输入框 + 删除×,底部居中 + 新增 - ConfigManager 增加 autoText 类型的序列化/反序列化,去重并丢弃畸形条目 - Setting.copyValue 对 AutoTextEntry 列表做深拷贝,reset 不会泄漏编辑 --- .../features/impl/utility/AutoText.java | 53 ++++ .../fpsmaster/features/settings/Setting.java | 12 +- .../features/settings/impl/AutoTextEntry.java | 22 ++ .../settings/impl/AutoTextSetting.java | 85 +++++++ .../modules/config/ConfigManager.java | 42 +++- .../ui/click/modules/ModuleRenderer.java | 2 + .../modules/impl/AutoTextSettingRender.java | 227 ++++++++++++++++++ 7 files changed, 435 insertions(+), 8 deletions(-) create mode 100644 src/main/java/top/fpsmaster/features/impl/utility/AutoText.java create mode 100644 src/main/java/top/fpsmaster/features/settings/impl/AutoTextEntry.java create mode 100644 src/main/java/top/fpsmaster/features/settings/impl/AutoTextSetting.java create mode 100644 src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java diff --git a/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java b/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java new file mode 100644 index 00000000..bed703d6 --- /dev/null +++ b/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java @@ -0,0 +1,53 @@ +package top.fpsmaster.features.impl.utility; + +import top.fpsmaster.event.Subscribe; +import top.fpsmaster.event.events.EventKey; +import top.fpsmaster.features.manager.Category; +import top.fpsmaster.features.manager.Module; +import top.fpsmaster.features.settings.impl.AutoTextEntry; +import top.fpsmaster.features.settings.impl.AutoTextSetting; +import top.fpsmaster.utils.core.Utility; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Editable shortcut-to-chat entries. Each entry binds a key to a message. + * When the key is pressed (and the module is enabled, the screen is null, + * and the player is alive), the message is sent via {@link Utility#sendChatMessage}. + * + *

Default: G → gg. Cap: 20 entries. Duplicate key bindings are rejected at the editor. + */ +public class AutoText extends Module { + private static final ArrayList DEFAULT = new ArrayList<>(); + static { + DEFAULT.add(new AutoTextEntry(0x2C /* G key LWJGL */, "gg")); + } + + public final AutoTextSetting entries = new AutoTextSetting("Entries", new ArrayList<>(DEFAULT)); + + public AutoText() { + super("AutoText", Category.Utility); + addSettings(entries); + } + + @Subscribe + public void onKey(EventKey e) { + if (e.key == 0) return; + if (net.minecraft.client.Minecraft.getMinecraft().currentScreen != null) return; + if (net.minecraft.client.Minecraft.getMinecraft().thePlayer == null) return; + + List snapshot; + synchronized (entries) { + snapshot = new ArrayList<>(entries.getValue()); + } + + for (AutoTextEntry entry : snapshot) { + if (entry.keyCode == e.key && !entry.message.isEmpty()) { + Utility.sendChatMessage(entry.message); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/top/fpsmaster/features/settings/Setting.java b/src/main/java/top/fpsmaster/features/settings/Setting.java index 2c7ed689..6510840c 100644 --- a/src/main/java/top/fpsmaster/features/settings/Setting.java +++ b/src/main/java/top/fpsmaster/features/settings/Setting.java @@ -2,6 +2,7 @@ import top.fpsmaster.event.EventDispatcher; import top.fpsmaster.event.events.EventValueChange; +import top.fpsmaster.features.settings.impl.AutoTextEntry; import top.fpsmaster.features.settings.impl.utils.CustomColor; import java.util.ArrayList; @@ -95,7 +96,16 @@ private T copyValue(T source) { return (T) ((CustomColor) source).copy(); } if (source instanceof ArrayList) { - return (T) new ArrayList<>((ArrayList) source); + ArrayList src = (ArrayList) source; + // AutoTextEntry lists need deep copies so each entry is immutable. + if (!src.isEmpty() && src.get(0) instanceof AutoTextEntry) { + ArrayList copy = new ArrayList<>(src.size()); + for (Object o : src) { + copy.add(new AutoTextEntry((AutoTextEntry) o)); + } + return (T) copy; + } + return (T) new ArrayList<>(src); } return source; } diff --git a/src/main/java/top/fpsmaster/features/settings/impl/AutoTextEntry.java b/src/main/java/top/fpsmaster/features/settings/impl/AutoTextEntry.java new file mode 100644 index 00000000..25bfca9b --- /dev/null +++ b/src/main/java/top/fpsmaster/features/settings/impl/AutoTextEntry.java @@ -0,0 +1,22 @@ +package top.fpsmaster.features.settings.impl; + +/** + * One AutoText entry: a key that sends {@code message} when pressed. + * + *

Immutable on purpose — entries are stored inside the {@code ArrayList} a {@link AutoTextSetting} + * owns, and {@link top.fpsmaster.features.settings.Setting#copyValue(Object)} shallow-copies that list. + * With immutable entries the copy is a safe deep copy, so reset-to-default can never leak edits. + */ +public final class AutoTextEntry { + public final int keyCode; + public final String message; + + public AutoTextEntry(int keyCode, String message) { + this.keyCode = keyCode; + this.message = message == null ? "" : message; + } + + public AutoTextEntry(AutoTextEntry other) { + this(other.keyCode, other.message); + } +} diff --git a/src/main/java/top/fpsmaster/features/settings/impl/AutoTextSetting.java b/src/main/java/top/fpsmaster/features/settings/impl/AutoTextSetting.java new file mode 100644 index 00000000..5b999b1e --- /dev/null +++ b/src/main/java/top/fpsmaster/features/settings/impl/AutoTextSetting.java @@ -0,0 +1,85 @@ +package top.fpsmaster.features.settings.impl; + +import top.fpsmaster.features.settings.Setting; + +import java.util.ArrayList; +import java.util.List; + +/** + * A setting that stores an ordered list of {@link AutoTextEntry}s exposed to the ClickGUI. + * + *

Each entry bundles a key code and a chat message. The list is capped at 20, and duplicate + * key codes (other than 0) are rejected at the editor level. This class enforces the cap and + * provides shallow-copy snapshots for the reset-to-default lifecycle. + */ +public class AutoTextSetting extends Setting> { + public static final int MAX_CAPACITY = 20; + + public AutoTextSetting(String name, ArrayList defaultValue) { + super(name, clamp(defaultValue)); + } + + public AutoTextSetting(String name, ArrayList defaultValue, VisibleCondition visible) { + super(name, clamp(defaultValue), visible); + } + + private static ArrayList clamp(ArrayList list) { + if (list == null) { + list = new ArrayList<>(); + } + if (list.size() > MAX_CAPACITY) { + list = new ArrayList<>(list.subList(0, MAX_CAPACITY)); + } + return list; + } + + /** Returns true if the entry was added at the end. */ + public boolean addEntry(AutoTextEntry entry) { + ArrayList current = getValue(); + if (current.size() >= MAX_CAPACITY) { + return false; + } + ArrayList oldSnapshot = new ArrayList<>(current); + ArrayList newSnapshot = new ArrayList<>(current); + newSnapshot.add(new AutoTextEntry(entry)); + if (!fireValueChangeEvent(oldSnapshot, newSnapshot)) { + return false; + } + current.add(new AutoTextEntry(entry)); + notifyChangeListeners(oldSnapshot, newSnapshot); + return true; + } + + /** Removes the entry at {@code index}, no-op if out of bounds. */ + public void removeEntry(int index) { + ArrayList current = getValue(); + if (index < 0 || index >= current.size()) { + return; + } + ArrayList oldSnapshot = new ArrayList<>(current); + ArrayList newSnapshot = new ArrayList<>(current); + newSnapshot.remove(index); + if (!fireValueChangeEvent(oldSnapshot, newSnapshot)) { + return; + } + current.remove(index); + notifyChangeListeners(oldSnapshot, newSnapshot); + } + + /** Replaces the entry at {@code index}. Returns false if the edit was rejected. */ + public boolean editEntry(int index, AutoTextEntry entry) { + ArrayList current = getValue(); + if (index < 0 || index >= current.size()) { + return false; + } + ArrayList oldSnapshot = new ArrayList<>(current); + ArrayList newSnapshot = new ArrayList<>(current); + newSnapshot.set(index, new AutoTextEntry(entry)); + if (!fireValueChangeEvent(oldSnapshot, newSnapshot)) { + return false; + } + current.set(index, new AutoTextEntry(entry)); + notifyChangeListeners(oldSnapshot, newSnapshot); + return true; + } +} \ No newline at end of file diff --git a/src/main/java/top/fpsmaster/modules/config/ConfigManager.java b/src/main/java/top/fpsmaster/modules/config/ConfigManager.java index 78a70f70..cb06e84a 100644 --- a/src/main/java/top/fpsmaster/modules/config/ConfigManager.java +++ b/src/main/java/top/fpsmaster/modules/config/ConfigManager.java @@ -11,13 +11,7 @@ import top.fpsmaster.features.impl.render.ItemPhysics; import top.fpsmaster.features.manager.Module; import top.fpsmaster.features.settings.Setting; -import top.fpsmaster.features.settings.impl.BindSetting; -import top.fpsmaster.features.settings.impl.BooleanSetting; -import top.fpsmaster.features.settings.impl.ColorSetting; -import top.fpsmaster.features.settings.impl.ModeSetting; -import top.fpsmaster.features.settings.impl.MultipleItemSetting; -import top.fpsmaster.features.settings.impl.NumberSetting; -import top.fpsmaster.features.settings.impl.TextSetting; +import top.fpsmaster.features.settings.impl.*; import top.fpsmaster.features.settings.impl.utils.CustomColor; import top.fpsmaster.modules.config.migration.ConfigMigration; import top.fpsmaster.modules.config.migration.ConfigMigrationRegistry; @@ -117,6 +111,19 @@ public void saveConfig(String name) throws FileException { settingJson.addProperty("type", "multiItem"); settingJson.add("value", items); settingsJson.add(setting.name, settingJson); + } else if (setting instanceof AutoTextSetting) { + AutoTextSetting autoText = (AutoTextSetting) setting; + JsonArray arr = new JsonArray(); + for (AutoTextEntry entry : autoText.getValue()) { + JsonObject obj = new JsonObject(); + obj.addProperty("key", entry.keyCode); + obj.addProperty("msg", entry.message); + arr.add(obj); + } + JsonObject settingJson = new JsonObject(); + settingJson.addProperty("type", "autoText"); + settingJson.add("value", arr); + settingsJson.add(setting.name, settingJson); } else { JsonObject settingJson = new JsonObject(); if (setting instanceof BooleanSetting) { @@ -343,6 +350,27 @@ public void loadConfig(String name) throws Exception { } } multipleItemSetting.setValue(items); + } else if (setting instanceof AutoTextSetting && "autoText".equals(type)) { + AutoTextSetting autoText = (AutoTextSetting) setting; + ArrayList entries = new ArrayList<>(); + java.util.Set usedKeys = new java.util.HashSet<>(); + for (JsonElement entryElement : value.getAsJsonArray()) { + if (entries.size() >= AutoTextSetting.MAX_CAPACITY) { + break; + } + try { + JsonObject obj = entryElement.getAsJsonObject(); + int key = obj.has("key") ? obj.get("key").getAsInt() : 0; + String msg = obj.has("msg") ? obj.get("msg").getAsString() : ""; + if (key != 0 && !usedKeys.add(key)) { + continue; // duplicate key: drop + } + entries.add(new AutoTextEntry(key, msg)); + } catch (Throwable t) { + ClientLogger.warn("Skipping malformed AutoText entry in " + module.name + "/" + setting.name); + } + } + autoText.setValue(entries); } } } catch (Throwable throwable) { diff --git a/src/main/java/top/fpsmaster/ui/click/modules/ModuleRenderer.java b/src/main/java/top/fpsmaster/ui/click/modules/ModuleRenderer.java index 25e64598..52a29d51 100644 --- a/src/main/java/top/fpsmaster/ui/click/modules/ModuleRenderer.java +++ b/src/main/java/top/fpsmaster/ui/click/modules/ModuleRenderer.java @@ -52,6 +52,8 @@ public ModuleRenderer(Module module) { settingsRenderers.add(new BindSettingRender(module, (BindSetting) setting)); } else if(setting instanceof MultipleItemSetting) { settingsRenderers.add(new MultipleItemSettingRender(module,(MultipleItemSetting)setting)); + } else if(setting instanceof AutoTextSetting) { + settingsRenderers.add(new AutoTextSettingRender(module,(AutoTextSetting)setting)); } }); } diff --git a/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java b/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java new file mode 100644 index 00000000..ab56103a --- /dev/null +++ b/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java @@ -0,0 +1,227 @@ +package top.fpsmaster.ui.click.modules.impl; + +import org.lwjgl.input.Keyboard; +import top.fpsmaster.FPSMaster; +import top.fpsmaster.features.manager.Module; +import top.fpsmaster.features.settings.impl.AutoTextEntry; +import top.fpsmaster.features.settings.impl.AutoTextSetting; +import top.fpsmaster.ui.click.ClickGuiTheme; +import top.fpsmaster.ui.click.MainPanel; +import top.fpsmaster.ui.click.modules.SettingRender; +import top.fpsmaster.ui.common.TextField; +import top.fpsmaster.utils.render.draw.Hover; +import top.fpsmaster.utils.render.draw.Rects; +import top.fpsmaster.utils.render.gui.ScaledGuiScreen; + +import java.awt.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * ClickGUI editor for {@link AutoTextSetting}. + * + *

Each row: a bind button, a message text field, and a delete (×) button. + * A centered + button below the last row adds a new entry (up to 20). + * Duplicate non-zero bindings are rejected with an inline warning. + */ +public class AutoTextSettingRender extends SettingRender { + private static final int ROW_H = 16; + private static final int CORNER = 3; + + private int capturingRow = -1; + private String duplicateWarning = ""; + private final ArrayList textFields = new ArrayList<>(); + + public AutoTextSettingRender(Module module, AutoTextSetting setting) { + super(setting); + this.mod = module; + rebuildTextFields(); + } + + private void rebuildTextFields() { + textFields.clear(); + for (AutoTextEntry entry : setting.getValue()) { + TextField tf = new TextField(FPSMaster.fontManager.s16, false, "", + ClickGuiTheme.textFieldBg().getRGB(), ClickGuiTheme.textFieldText().getRGB(), 256); + tf.setText(entry.message); + textFields.add(tf); + } + } + + @Override + public void render(ScaledGuiScreen screen, float x, float y, float width, float height, float mouseX, float mouseY, boolean custom) { + ArrayList entries = setting.getValue(); + + // Rebuild text fields if entry count changed externally + while (textFields.size() < entries.size()) { + TextField tf = new TextField(FPSMaster.fontManager.s16, false, "", + ClickGuiTheme.textFieldBg().getRGB(), ClickGuiTheme.textFieldText().getRGB(), 256); + tf.setText(entries.get(textFields.size()).message); + textFields.add(tf); + } + while (textFields.size() > entries.size()) { + textFields.remove(textFields.size() - 1); + } + + // Sync text field contents back to entries only when the field is focused + for (int i = 0; i < entries.size() && i < textFields.size(); i++) { + TextField tf = textFields.get(i); + if (tf.isFocused()) { + String currentText = tf.getText(); + if (!currentText.equals(entries.get(i).message)) { + setting.editEntry(i, new AutoTextEntry(entries.get(i).keyCode, currentText)); + } + } + } + + duplicateWarning = ""; + + // Detect duplicate keys + Set usedKeys = new HashSet<>(); + for (int i = 0; i < entries.size(); i++) { + int k = entries.get(i).keyCode; + if (k != 0) { + if (!usedKeys.add(k)) { + duplicateWarning = "Duplicate key: " + Keyboard.getKeyName(k); + } + } + } + + float rowX = x + 10; + float rowY = y + 2; + + FPSMaster.fontManager.s16.drawString( + FPSMaster.i18n.get((mod.name + "." + setting.name).toLowerCase(java.util.Locale.getDefault())), + rowX, rowY, ClickGuiTheme.textSecondary().getRGB() + ); + rowY += 14; + + if (entries.isEmpty()) { + FPSMaster.fontManager.s14.drawString( + FPSMaster.i18n.get("autotext.empty"), + rowX + (width - 20 - FPSMaster.fontManager.s14.getStringWidth(FPSMaster.i18n.get("autotext.empty"))) / 2, + rowY + 4, ClickGuiTheme.textSecondary().getRGB() + ); + this.height = 38; + } else { + for (int i = 0; i < entries.size(); i++) { + AutoTextEntry entry = entries.get(i); + float rX = rowX + 8; + float rY = rowY + i * (ROW_H + 3); + + // Bind button + String keyName = entry.keyCode != 0 ? Keyboard.getKeyName(entry.keyCode) : "None"; + float bindW = FPSMaster.fontManager.s16.getStringWidth(keyName) + 6; + boolean isCapturing = capturingRow == i; + Color bindBg = isCapturing + ? ClickGuiTheme.bindBgActive() + : (Hover.is(rX, rY, bindW, ROW_H, (int) mouseX, (int) mouseY) + ? ClickGuiTheme.bindBgInactive() : ClickGuiTheme.textFieldBg()); + Rects.rounded(Math.round(rX), Math.round(rY), Math.round(bindW), ROW_H, CORNER, bindBg); + FPSMaster.fontManager.s16.drawString(keyName, rX + 3, rY + 3, ClickGuiTheme.textPrimary().getRGB()); + + ScaledGuiScreen.PointerEvent bindClick = screen.consumePressInBounds(rX, rY, bindW, ROW_H, 0); + if (bindClick != null) { + capturingRow = (capturingRow == i) ? -1 : i; + MainPanel.bindLock = capturingRow >= 0 ? (setting.name + i) : ""; + } + + // Text field + float tfX = rX + bindW + 4; + float tfW = width - 20 - bindW - 4 - 14; + TextField tf = textFields.get(i); + tf.drawTextBox(tfX, rY, tfW, ROW_H); + + ScaledGuiScreen.PointerEvent tfClick = screen.consumePressInBounds(tfX, rY, tfW, ROW_H, 0); + if (tfClick != null) { + tf.mouseClicked((int) tfClick.x, (int) tfClick.y, 0); + capturingRow = -1; + } + + // Delete button + float delX = tfX + tfW + 2; + boolean delHover = Hover.is(delX, rY, 12, ROW_H, (int) mouseX, (int) mouseY); + Rects.rounded(Math.round(delX), Math.round(rY), 12, ROW_H, CORNER, + delHover ? ClickGuiTheme.buttonHoverBg() : ClickGuiTheme.buttonBg()); + FPSMaster.fontManager.s16.drawString("x", delX + 3, rY + 2, ClickGuiTheme.textPrimary().getRGB()); + + ScaledGuiScreen.PointerEvent delClick = screen.consumePressInBounds(delX, rY, 12, ROW_H, 0); + if (delClick != null) { + setting.removeEntry(i); + textFields.remove(i); + if (capturingRow == i) capturingRow = -1; + rebuildTextFields(); + return; + } + } + + // Capacity indicator + String capText = entries.size() + "/" + AutoTextSetting.MAX_CAPACITY; + FPSMaster.fontManager.s14.drawString(capText, x + width - 20 - 50, y + 2, ClickGuiTheme.textSecondary().getRGB()); + + this.height = 16 + entries.size() * (ROW_H + 3) + 4; + } + + // + button + float addY = y + 16 + entries.size() * (ROW_H + 3) + 4; + float addX = x + (width - 20 - 14) / 2; + boolean canAdd = entries.size() < AutoTextSetting.MAX_CAPACITY; + boolean addHover = Hover.is(addX, addY, 14, 14, (int) mouseX, (int) mouseY); + Color addBg = canAdd && addHover ? ClickGuiTheme.buttonHoverBg() : (canAdd ? ClickGuiTheme.buttonBg() : ClickGuiTheme.textFieldBg()); + Rects.rounded(Math.round(addX), Math.round(addY), 14, 14, CORNER, addBg); + FPSMaster.fontManager.s16.drawString("+", addX + 3, addY + 2, canAdd ? ClickGuiTheme.textPrimary().getRGB() : ClickGuiTheme.textSecondary().getRGB()); + + if (canAdd) { + ScaledGuiScreen.PointerEvent addClick = screen.consumePressInBounds(addX, addY, 14, 14, 0); + if (addClick != null) { + // Find first unused key code + int newKey = 0; + for (int k = 2; k < 256; k++) { + int finalK = k; + if (entries.stream().noneMatch(e -> e.keyCode == finalK)) { + newKey = k; + break; + } + } + setting.addEntry(new AutoTextEntry(newKey, "")); + rebuildTextFields(); + return; + } + } + + // Duplicate warning + if (!duplicateWarning.isEmpty()) { + FPSMaster.fontManager.s14.drawString(duplicateWarning, x + 10, addY + 16, new Color(255, 80, 80).getRGB()); + this.height += 14; + } + + this.height += 24; + } + + @Override + public void keyTyped(char typedChar, int keyCode) { + if (capturingRow >= 0) { + ArrayList entries = setting.getValue(); + if (capturingRow < entries.size()) { + boolean duplicate = false; + for (int i = 0; i < entries.size(); i++) { + if (i != capturingRow && entries.get(i).keyCode == keyCode && keyCode != 0) { + duplicate = true; + break; + } + } + if (!duplicate) { + setting.editEntry(capturingRow, new AutoTextEntry(keyCode, entries.get(capturingRow).message)); + } + } + capturingRow = -1; + MainPanel.bindLock = ""; + return; + } + + for (TextField tf : textFields) { + tf.textboxKeyTyped(typedChar, keyCode); + } + } +} \ No newline at end of file From 7227eb03264bfe689cce16655222d23c2aa92d9d Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sat, 1 Aug 2026 23:03:18 +0800 Subject: [PATCH 04/22] =?UTF-8?q?feat(smtc):=20=E6=96=B0=E5=A2=9E=20Window?= =?UTF-8?q?s=20=E7=B3=BB=E7=BB=9F=E5=AA=92=E4=BD=93=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6=EF=BC=88SMTC=EF=BC=89=E9=9B=86=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Java 侧:SystemMediaTransportControls 门面 + 工厂(非 Windows 自动降级 no-op) - WindowsSystemMediaTransportControls:JNA 加载 fpsmaster-smtc.dll(native/smtc), C++/WinRT 实现 SMTC 会话,发布标题/歌手/封面/进度,暴露 播放/暂停/上一首/下一首 - SmtcMusicBridge:轮询当前曲目状态并发布快照,封面后台下载为 PNG - MusicManager 构造时创建桥接,shutdown 时释放;控制事件回主线程调度 - build.gradle.kts 增加 JNA 依赖;原生 DLL 资源目录与构建脚本占位 --- build.gradle.kts | 4 + native/smtc/smtc.cpp | 197 ++++++++++++++++++ src/main/java/top/fpsmaster/FPSMaster.java | 6 + .../fpsmaster/modules/music/MusicManager.java | 55 +++++ .../music/smtc/MediaControlListener.java | 17 ++ .../music/smtc/MediaPlaybackSnapshot.java | 35 ++++ .../NoopSystemMediaTransportControls.java | 24 +++ .../modules/music/smtc/SmtcMusicBridge.java | 192 +++++++++++++++++ .../smtc/SystemMediaTransportControls.java | 24 +++ .../SystemMediaTransportControlsFactory.java | 38 ++++ .../WindowsSystemMediaTransportControls.java | 191 +++++++++++++++++ .../resources/native/windows/x64/.gitkeep | 0 .../resources/native/windows/x86/.gitkeep | 0 13 files changed, 783 insertions(+) create mode 100644 native/smtc/smtc.cpp create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/MediaControlListener.java create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/NoopSystemMediaTransportControls.java create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControls.java create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControlsFactory.java create mode 100644 src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java create mode 100644 src/main/resources/native/windows/x64/.gitkeep create mode 100644 src/main/resources/native/windows/x86/.gitkeep diff --git a/build.gradle.kts b/build.gradle.kts index b0f973a0..5f67d295 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -123,6 +123,10 @@ dependencies { shadowImpl("com.google.zxing:core:3.5.3") { isTransitive = false } + // Windows SMTC 桥接:JNA 加载原生 DLL 调用 WinRT。 + shadowImpl("net.java.dev.jna:jna:5.17.0") { + isTransitive = true + } // If you don't want to log in with your real minecraft account, remove this line runtimeOnly("me.djtheredstoner:DevAuth-forge-legacy:1.1.2") compileOnly("org.projectlombok:lombok:1.18.38") diff --git a/native/smtc/smtc.cpp b/native/smtc/smtc.cpp new file mode 100644 index 00000000..d14ff0dc --- /dev/null +++ b/native/smtc/smtc.cpp @@ -0,0 +1,197 @@ +// fpsmaster-smtc - Windows System Media Transport Controls bridge DLL +// C++/WinRT native library for FPSMaster Edge music integration. +// +// Build: open in Visual Studio 2022 with "Universal Windows Platform" workload, +// or build from command line: +// cl /EHsc /std:c++17 /DUNICODE /D_UNICODE smtc.cpp /LD /EHsc /MD +// /reference "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd" +// /FU "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll" +// /link /OUT:fpsmaster-smtc.dll +// +// The DLL exports a tiny C ABI that the Java side (JNA) calls. +// Callbacks from SMTC button events are dispatched to a function pointer +// provided by the Java side. + +#include +#include +#include + +// WinRT headers +#include +#include +#include + +using namespace winrt; +using namespace Windows::Media; +using namespace Windows::Storage::Streams; + +// --------------------------------------------------------------------------- +// Callback types (Java sets these via JNA) +// --------------------------------------------------------------------------- +typedef void(__stdcall* ControlCallback)(int action); +static ControlCallback g_callback = nullptr; + +// --------------------------------------------------------------------------- +// SMTC session state +// --------------------------------------------------------------------------- +static SystemMediaTransportControls g_smtc = nullptr; +static bool g_initialized = false; + +// --------------------------------------------------------------------------- +// C ABI exports +// --------------------------------------------------------------------------- + +extern "C" { + +/// Initialize the SMTC session. Call once; idempotent. +/// hwnd: parent window handle (0 = use desktop window). +__declspec(dllexport) void __stdcall smtc_start(HWND hwnd) { + if (g_initialized) return; + try { + // Initialize WinRT apartment + winrt::init_apartment(winrt::apartment_type::single_threaded); + + // Get the system transport controls + g_smtc = SystemMediaTransportControls::GetForCurrentView(); + if (!g_smtc) return; + + // Enable all supported buttons + g_smtc.IsPlayEnabled(true); + g_smtc.IsPauseEnabled(true); + g_smtc.IsNextEnabled(true); + g_smtc.IsPreviousEnabled(true); + + // Subscribe to button events + auto token = g_smtc.ButtonPressed( + [](const SystemMediaTransportControls& sender, + const SystemMediaTransportControlsButtonPressedEventArgs& args) { + if (!g_callback) return; + switch (args.Button()) { + case SystemMediaTransportControlsButton::Play: + case SystemMediaTransportControlsButton::Pause: + g_callback(1); // play/pause toggle + break; + case SystemMediaTransportControlsButton::Next: + g_callback(2); + break; + case SystemMediaTransportControlsButton::Previous: + g_callback(3); + break; + case SystemMediaTransportControlsButton::Stop: + g_callback(4); + break; + } + }); + + g_initialized = true; + } catch (...) { + g_initialized = false; + } +} + +/// Register the Java callback function pointer. +__declspec(dllexport) void __stdcall smtc_set_callback(ControlCallback cb) { + g_callback = cb; +} + +/// Publish playback metadata and state. +/// artwork_data / artwork_len: PNG bytes or NULL/0 for no art. +__declspec(dllexport) void __stdcall smtc_publish( + const wchar_t* title, + const wchar_t* artist, + const wchar_t* album, + int64_t positionMs, + int64_t durationMs, + bool playing, + bool hasCurrentTrack, + const unsigned char* artwork_data, + int artwork_len +) { + if (!g_smtc) return; + + try { + auto updater = g_smtc.DisplayUpdater(); + updater.Type(MediaPlaybackType::Music); + updater.MusicProperties().Title(winrt::hstring(title)); + updater.MusicProperties().Artist(winrt::hstring(artist)); + updater.MusicProperties().AlbumTitle(winrt::hstring(album)); + updater.Thumbnail(nullptr); + + // Set album art if available + if (artwork_data && artwork_len > 0) { + try { + auto stream = InMemoryRandomAccessStream(); + stream.WriteAsync(winrt::array_view( + artwork_data, artwork_data + artwork_len)).get(); + stream.Seek(0); + auto ref = RandomAccessStreamReference::CreateFromStream(stream); + updater.Thumbnail(ref); + } catch (...) { + // Artwork is best-effort + } + } + + updater.Update(); + + // Timeline properties + auto timeline = g_smtc.GetTimelineProperties(); + // Position and duration are set via the SystemMediaTransportControlsTimelineProperties + auto props = SystemMediaTransportControlsTimelineProperties(); + props.StartTime(0); + props.Position(std::chrono::milliseconds(positionMs)); + props.EndTime(std::chrono::milliseconds(durationMs > 0 ? durationMs : 1)); + props.MinSeekTime(0); + props.MaxSeekTime(std::chrono::milliseconds(durationMs > 0 ? durationMs : 1)); + g_smtc.UpdateTimelineProperties(props); + + // Playback status + if (!hasCurrentTrack) { + g_smtc.PlaybackStatus(MediaPlaybackStatus::Stopped); + } else if (playing) { + g_smtc.PlaybackStatus(MediaPlaybackStatus::Playing); + } else { + g_smtc.PlaybackStatus(MediaPlaybackStatus::Paused); + } + } catch (...) { + // Best-effort + } +} + +/// Enable/disable which buttons are shown. +__declspec(dllexport) void __stdcall smtc_set_buttons( + bool playPause, bool next, bool prev +) { + if (!g_smtc) return; + try { + g_smtc.IsPlayEnabled(playPause); + g_smtc.IsPauseEnabled(playPause); + g_smtc.IsNextEnabled(next); + g_smtc.IsPreviousEnabled(prev); + } catch (...) { + } +} + +/// Release the SMTC session. Safe to call multiple times. +__declspec(dllexport) void __stdcall smtc_close() { + if (!g_initialized) return; + try { + if (g_smtc) { + g_smtc.ButtonPressed({}); + g_smtc = nullptr; + } + g_initialized = false; + } catch (...) { + g_initialized = false; + } + g_callback = nullptr; +} + +/// Get the last error message (for debugging). +__declspec(dllexport) void __stdcall smtc_get_last_error(wchar_t* buf, int bufLen) { + (void)buf; + (void)bufLen; + // Simplified: just clear + if (buf && bufLen > 0) buf[0] = 0; +} + +} // extern "C" \ No newline at end of file diff --git a/src/main/java/top/fpsmaster/FPSMaster.java b/src/main/java/top/fpsmaster/FPSMaster.java index 359b6881..ccabe713 100644 --- a/src/main/java/top/fpsmaster/FPSMaster.java +++ b/src/main/java/top/fpsmaster/FPSMaster.java @@ -140,6 +140,12 @@ public void initialize() { public void shutdown() { PlayTimeStatistics.flush(); + // Release SMTC native session before tearing down async/audio + try { + top.fpsmaster.modules.music.MusicManager.get().shutdownSmtc(); + } catch (Throwable t) { + ClientLogger.warn("SMTC shutdown skipped: " + t.getMessage()); + } telemetryReporter.shutdown(); async.close(); try { diff --git a/src/main/java/top/fpsmaster/modules/music/MusicManager.java b/src/main/java/top/fpsmaster/modules/music/MusicManager.java index 9885f502..6caf4c16 100644 --- a/src/main/java/top/fpsmaster/modules/music/MusicManager.java +++ b/src/main/java/top/fpsmaster/modules/music/MusicManager.java @@ -91,6 +91,9 @@ private static java.nio.file.Path resolveAuthFile() { private final MusicOverlay overlay = new MusicOverlay(this); private volatile boolean showLyricsInGame = false; + // 系统媒体传输控件(Windows SMTC):平台不可用时自动降级为 no-op。 + private final top.fpsmaster.modules.music.smtc.SmtcMusicBridge smtcBridge; + // 二维码登录轮询 private volatile Thread qrThread; private volatile QrCode qrCode; @@ -98,6 +101,51 @@ private static java.nio.file.Path resolveAuthFile() { public MusicManager() { routeLogging(); + // Initialize SMTC bridge (no-op on non-Windows or when native fails) + smtcBridge = new top.fpsmaster.modules.music.smtc.SmtcMusicBridge( + this, + top.fpsmaster.modules.music.smtc.SystemMediaTransportControlsFactory.create( + new top.fpsmaster.modules.music.smtc.MediaControlListener() { + @Override + public void onPlayPause() { + post(new Runnable() { + @Override + public void run() { + togglePause(); + } + }); + } + @Override + public void onNext() { + post(new Runnable() { + @Override + public void run() { + next(); + } + }); + } + @Override + public void onPrevious() { + post(new Runnable() { + @Override + public void run() { + prev(); + } + }); + } + @Override + public void onStop() { + post(new Runnable() { + @Override + public void run() { + engine().stop(); + } + }); + } + } + ) + ); + smtcBridge.start(); try { store.load(); String cookie = store.getNeteaseCookie(); @@ -586,4 +634,11 @@ private void post(Runnable r) { r.run(); } } + + /** Releases the SMTC bridge and its native session. Safe to call multiple times. */ + public void shutdownSmtc() { + if (smtcBridge != null) { + smtcBridge.stop(); + } + } } diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/MediaControlListener.java b/src/main/java/top/fpsmaster/modules/music/smtc/MediaControlListener.java new file mode 100644 index 00000000..9e094879 --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/MediaControlListener.java @@ -0,0 +1,17 @@ +package top.fpsmaster.modules.music.smtc; + +/** + * Receives transport-control events from the system media UI (Windows SMTC buttons). + * + *

Implementations must not touch Minecraft or music state directly — the bridge may + * invoke these callbacks on a native/COM thread. The caller schedules them onto the main thread. + */ +public interface MediaControlListener { + void onPlayPause(); + + void onNext(); + + void onPrevious(); + + void onStop(); +} diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java b/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java new file mode 100644 index 00000000..76a540ea --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java @@ -0,0 +1,35 @@ +package top.fpsmaster.modules.music.smtc; + +/** + * A single immutable snapshot of the currently playing track, as exposed to the system media + * transport (Windows SMTC). Values are read on the main thread and handed to the bridge, which + * is free to coalesce/throttle them. + * + *

{@link #artworkPng} carries the album art as PNG bytes when available (loaded off-thread), + * or {@code null} when no art has loaded yet. + */ +public final class MediaPlaybackSnapshot { + public final String title; + public final String artist; + public final String album; + public final long positionMs; + public final long durationMs; + public final boolean playing; + public final boolean hasCurrentTrack; + public final byte[] artworkPng; + + public MediaPlaybackSnapshot( + String title, String artist, String album, + long positionMs, long durationMs, + boolean playing, boolean hasCurrentTrack, + byte[] artworkPng) { + this.title = title == null ? "" : title; + this.artist = artist == null ? "" : artist; + this.album = album == null ? "" : album; + this.positionMs = Math.max(0, positionMs); + this.durationMs = Math.max(0, durationMs); + this.playing = playing; + this.hasCurrentTrack = hasCurrentTrack; + this.artworkPng = artworkPng; + } +} diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/NoopSystemMediaTransportControls.java b/src/main/java/top/fpsmaster/modules/music/smtc/NoopSystemMediaTransportControls.java new file mode 100644 index 00000000..1e4a67bc --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/NoopSystemMediaTransportControls.java @@ -0,0 +1,24 @@ +package top.fpsmaster.modules.music.smtc; + +/** + * No-op transport facade used on platforms where SMTC is unavailable (non-Windows), or when the + * Windows bridge fails to load. Keeps the music system fully functional with zero side effects. + */ +final class NoopSystemMediaTransportControls implements SystemMediaTransportControls { + @Override + public void start() { + } + + @Override + public void publish(MediaPlaybackSnapshot snapshot) { + } + + @Override + public void close() { + } + + @Override + public boolean isAvailable() { + return false; + } +} diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java new file mode 100644 index 00000000..64f4c3b6 --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java @@ -0,0 +1,192 @@ +package top.fpsmaster.modules.music.smtc; + +import top.fpsmaster.FPSMaster; +import top.fpsmaster.modules.logger.ClientLogger; +import top.fpsmaster.modules.music.MusicManager; +import top.fpsmaster.music.Track; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Bridges the music player into the system media transport. + * + *

Runs a lightweight polling loop (separate daemon thread) that samples the current track and + * forwards a snapshot to the transport facade. Control events from the system are marshalled back + * onto the Minecraft main thread before calling {@link MusicManager} so queue/UI state stays + * main-thread consistent. Cover art is downloaded off-thread with the established UA/referer path. + */ +public final class SmtcMusicBridge { + + private static final String UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Chrome/123.0.0.0 Safari/537.36"; + + private final MusicManager music; + private final SystemMediaTransportControls controls; + private final AtomicReference artwork = new AtomicReference<>(); + + private volatile boolean running; + private Thread pollThread; + private volatile Track lastTrack; + + public SmtcMusicBridge(MusicManager music, SystemMediaTransportControls controls) { + this.music = music; + this.controls = controls; + } + + /** Starts the polling loop (idempotent). Does not block the caller. */ + public void start() { + if (running) { + return; + } + running = true; + controls.start(); + pollThread = new Thread(this::pollLoop, "FPSMaster-Smtc-Poll"); + pollThread.setDaemon(true); + pollThread.start(); + } + + public void stop() { + running = false; + Thread t = pollThread; + if (t != null) { + t.interrupt(); + } + pollThread = null; + controls.close(); + } + + private void pollLoop() { + long lastPos = -1; + boolean lastPlaying = false; + while (running) { + try { + Track cur = music.getCurrent(); + if (cur == null) { + if (lastTrack != null || lastPos >= 0) { + // No current track → publish cleared state + controls.publish(new MediaPlaybackSnapshot("", "", "", 0, 0, false, false, null)); + lastTrack = null; + lastPos = -1; + lastPlaying = false; + } + Thread.sleep(500); + continue; + } + + if (cur != lastTrack) { + lastTrack = cur; + lastPos = -1; + // New track: kick off cover download if not already cached + maybeLoadArtwork(cur.getCoverUrl()); + } + + long pos = music.engine().getPositionMs(); + long dur = music.engine().getDurationMs(); + if (dur <= 0) { + dur = cur.getDurationMs(); + } + boolean playing = music.engine().isPlaying(); + + boolean positionChanged = Math.abs(pos - lastPos) >= 500 || lastPos == -1; + boolean stateChanged = playing != lastPlaying; + if (positionChanged || stateChanged) { + lastPos = pos; + lastPlaying = playing; + controls.publish(new MediaPlaybackSnapshot( + cur.getName(), + cur.getArtists(), + "", + pos, + dur, + playing, + true, + artwork.get() + )); + } + + Thread.sleep(250); + } catch (InterruptedException e) { + return; + } catch (Throwable t) { + ClientLogger.error("SMTC poll error: " + t.getMessage()); + try { + Thread.sleep(500); + } catch (InterruptedException ie) { + return; + } + } + } + } + + /** Downloads and caches album art as PNG bytes, off-thread. */ + private void maybeLoadArtwork(final String coverUrl) { + if (coverUrl == null || coverUrl.isEmpty()) { + artwork.set(null); + return; + } + // Only refresh when we don't already have art for the current track + if (artwork.get() != null) { + return; + } + final Thread t = new Thread(() -> { + try { + byte[] png = downloadPng(coverUrl); + artwork.set(png); + // Publish again so SMTC picks up the art + controls.publish(snapshotFromCurrent()); + } catch (Throwable e) { + ClientLogger.error("SMTC artwork load failed: " + e.getMessage()); + } + }, "FPSMaster-Smtc-Art"); + t.setDaemon(true); + t.start(); + } + + private byte[] downloadPng(String url) throws Exception { + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setInstanceFollowRedirects(true); + conn.setConnectTimeout(8000); + conn.setReadTimeout(12000); + conn.setRequestProperty("User-Agent", UA); + try (InputStream in = conn.getInputStream()) { + BufferedImage img = ImageIO.read(in); + if (img == null) { + return null; + } + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ImageIO.write(img, "png", bos); + return bos.toByteArray(); + } finally { + conn.disconnect(); + } + } + + private MediaPlaybackSnapshot snapshotFromCurrent() { + Track cur = music.getCurrent(); + if (cur == null) { + return new MediaPlaybackSnapshot("", "", "", 0, 0, false, false, null); + } + long pos = music.engine().getPositionMs(); + long dur = music.engine().getDurationMs(); + if (dur <= 0) { + dur = cur.getDurationMs(); + } + return new MediaPlaybackSnapshot( + cur.getName(), + cur.getArtists(), + "", + pos, + dur, + music.engine().isPlaying(), + true, + artwork.get() + ); + } +} diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControls.java b/src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControls.java new file mode 100644 index 00000000..b9789864 --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControls.java @@ -0,0 +1,24 @@ +package top.fpsmaster.modules.music.smtc; + +/** + * Platform-neutral facade for the system media transport controls (SMTC on Windows). + * + *

On non-Windows platforms the returned no-op implementation is used, so the music system and + * the rest of the client behave exactly as before. The concrete bridge only activates after an + * explicit {@code os.name} Windows check and a successful native-library load; every public method + * degrades gracefully (no-op) if the bridge is unavailable. + */ +public interface SystemMediaTransportControls { + + /** Initializes the transport. Safe to call multiple times; idempotent. */ + void start(); + + /** Publishes the current playback snapshot. Safe/no-op when unavailable. */ + void publish(MediaPlaybackSnapshot snapshot); + + /** Releases the transport and its session. Safe/no-op when never started. */ + void close(); + + /** True when this bridge actually backed the transport (Windows + load success). */ + boolean isAvailable(); +} diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControlsFactory.java b/src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControlsFactory.java new file mode 100644 index 00000000..dfd5db87 --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/SystemMediaTransportControlsFactory.java @@ -0,0 +1,38 @@ +package top.fpsmaster.modules.music.smtc; + +import top.fpsmaster.modules.logger.ClientLogger; + +/** + * Factory that picks the real Windows SMTC bridge when the OS is Windows and the native library + * loads, and a no-op otherwise. Never throws from the factory path — the caller (music) must never + * crash because of media integration. + */ +public final class SystemMediaTransportControlsFactory { + + private SystemMediaTransportControlsFactory() { + } + + /** + * Creates the platform-appropriate transport. + * + * @param listener control-event listener; may be invoked on a native thread, schedule it to the + * main thread before touching Minecraft/music state. + */ + public static SystemMediaTransportControls create(MediaControlListener listener) { + try { + String os = System.getProperty("os.name", ""); + if (os.toLowerCase(java.util.Locale.ROOT).contains("win")) { + try { + return new WindowsSystemMediaTransportControls(listener); + } catch (Throwable t) { + ClientLogger.error("Windows SMTC bridge unavailable, using no-op: " + t.getMessage()); + return new NoopSystemMediaTransportControls(); + } + } + return new NoopSystemMediaTransportControls(); + } catch (Throwable t) { + ClientLogger.error("SMTC factory error, using no-op: " + t.getMessage()); + return new NoopSystemMediaTransportControls(); + } + } +} diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java new file mode 100644 index 00000000..2ba6e98a --- /dev/null +++ b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java @@ -0,0 +1,191 @@ +package top.fpsmaster.modules.music.smtc; + +import com.sun.jna.Callback; +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.NativeLibrary; +import com.sun.jna.WString; +import top.fpsmaster.modules.logger.ClientLogger; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Windows System Media Transport Controls bridge backed by the bundled {@code fpsmaster-smtc.dll} + * native library. The DLL is shipped inside the mod jar at {@code native/windows/fpsmaster-smtc.dll} + * and extracted to a per-run temp directory on first access. + * + *

If the OS is not Windows, the DLL is missing, or any native call fails, the instance degrades + * to a safe no-op. Never blocks the render thread, and never crashes music or the game. + */ +final class WindowsSystemMediaTransportControls implements SystemMediaTransportControls { + + private interface SmtcNative extends Library { + void smtc_start(long hwnd); + void smtc_set_callback(ControlCallback cb); + void smtc_publish(WString title, WString artist, WString album, long positionMs, long durationMs, + boolean playing, boolean hasCurrentTrack, byte[] artworkData, int artworkLen); + void smtc_set_buttons(boolean playPause, boolean next, boolean prev); + void smtc_close(); + } + + private interface ControlCallback extends Callback { + void invoke(int action); + } + + private static final AtomicReference API = new AtomicReference<>(null); + private static boolean extractionAttempted = false; + + private final AtomicBoolean available = new AtomicBoolean(false); + private final MediaControlListener listener; + private final ControlCallback callback; + + WindowsSystemMediaTransportControls(MediaControlListener listener) { + this.listener = listener; + this.callback = action -> { + try { + if (listener != null) { + switch (action) { + case 1: listener.onPlayPause(); break; + case 2: listener.onNext(); break; + case 3: listener.onPrevious(); break; + case 4: listener.onStop(); break; + default: break; + } + } + } catch (Throwable t) { + ClientLogger.error("SMTC control callback error: " + t.getMessage()); + } + }; + loadAndInit(); + } + + private static synchronized SmtcNative resolveNative() { + SmtcNative existing = API.get(); + if (existing != null) { + return existing; + } + if (extractionAttempted) { + return null; + } + extractionAttempted = true; + + try { + extractAndLoad(); + SmtcNative lib = Native.load("fpsmaster-smtc", SmtcNative.class); + API.compareAndSet(null, lib); + return lib; + } catch (Throwable t) { + ClientLogger.error("SMTC native load failed: " + t.getMessage()); + return null; + } + } + + private static void extractAndLoad() throws Exception { + String bitness = System.getProperty("os.arch", "").contains("64") ? "x64" : "x86"; + String resourcePath = "/native/windows/" + bitness + "/fpsmaster-smtc.dll"; + + File extractDir = new File(System.getProperty("java.io.tmpdir", ""), "fpsmaster-smtc"); + extractDir.mkdirs(); + File dllFile = new File(extractDir, "fpsmaster-smtc.dll"); + + // Extract from classpath + try (InputStream in = WindowsSystemMediaTransportControls.class.getResourceAsStream(resourcePath)) { + if (in == null) { + ClientLogger.warn("SMTC DLL not found in classpath: " + resourcePath); + throw new Exception("DLL resource not found: " + resourcePath); + } + try (FileOutputStream out = new FileOutputStream(dllFile)) { + byte[] buf = new byte[8192]; + int n; + while ((n = in.read(buf)) != -1) { + out.write(buf, 0, n); + } + } + } + + // Add to JNA search path + NativeLibrary.addSearchPath("fpsmaster-smtc", extractDir.getAbsolutePath()); + } + + private void loadAndInit() { + try { + SmtcNative nativeLib = resolveNative(); + if (nativeLib == null) { + return; + } + nativeLib.smtc_set_callback(callback); + nativeLib.smtc_start(0L); + available.set(true); + } catch (Throwable t) { + ClientLogger.error("SMTC native start failed: " + t.getMessage()); + available.set(false); + } + } + + @Override + public void start() { + if (!available.get()) { + return; + } + try { + SmtcNative nativeLib = API.get(); + if (nativeLib != null) { + nativeLib.smtc_start(0L); + } + } catch (Throwable t) { + ClientLogger.error("SMTC start failed: " + t.getMessage()); + } + } + + @Override + public void publish(MediaPlaybackSnapshot snapshot) { + SmtcNative nativeLib = API.get(); + if (!available.get() || nativeLib == null || snapshot == null) { + return; + } + try { + boolean hasTrack = snapshot.hasCurrentTrack; + nativeLib.smtc_set_buttons(hasTrack, hasTrack, hasTrack); + byte[] art = snapshot.artworkPng; + nativeLib.smtc_publish( + new WString(snapshot.title), + new WString(snapshot.artist), + new WString(snapshot.album), + snapshot.positionMs, + snapshot.durationMs, + snapshot.playing, + hasTrack, + art, + art == null ? 0 : art.length + ); + } catch (Throwable t) { + ClientLogger.error("SMTC publish failed: " + t.getMessage()); + } + } + + @Override + public void close() { + if (!available.get()) { + return; + } + try { + SmtcNative nativeLib = API.get(); + if (nativeLib != null) { + nativeLib.smtc_close(); + } + } catch (Throwable t) { + ClientLogger.error("SMTC close failed: " + t.getMessage()); + } finally { + available.set(false); + } + } + + @Override + public boolean isAvailable() { + return available.get(); + } +} \ No newline at end of file diff --git a/src/main/resources/native/windows/x64/.gitkeep b/src/main/resources/native/windows/x64/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/native/windows/x86/.gitkeep b/src/main/resources/native/windows/x86/.gitkeep new file mode 100644 index 00000000..e69de29b From a8365606b1f46a6c4c73593620d153bb8ed642a7 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sat, 1 Aug 2026 23:04:13 +0800 Subject: [PATCH 05/22] =?UTF-8?q?fix(blockoverlay):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=9E=84=E5=87=86=E5=AE=9E=E4=BD=93=E6=97=B6=20objectMouseOver?= =?UTF-8?q?.getBlockPos()=20=E4=B8=BA=20null=20=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 同时为饱和度显示/自定义迷雾/AutoText 新增中英文翻译 --- .../features/impl/render/BlockOverlay.java | 1 + .../assets/minecraft/client/lang/en_us.lang | 22 +++++++++++++++++++ .../assets/minecraft/client/lang/zh_cn.lang | 22 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/src/main/java/top/fpsmaster/features/impl/render/BlockOverlay.java b/src/main/java/top/fpsmaster/features/impl/render/BlockOverlay.java index a35f8437..d40bca03 100644 --- a/src/main/java/top/fpsmaster/features/impl/render/BlockOverlay.java +++ b/src/main/java/top/fpsmaster/features/impl/render/BlockOverlay.java @@ -51,6 +51,7 @@ public void onRender3D(EventRender3D e) { // Use raw world for block state access if (Minecraft.getMinecraft().theWorld != null && Minecraft.getMinecraft().objectMouseOver != null) { BlockPos mcPos = Minecraft.getMinecraft().objectMouseOver.getBlockPos(); + if (mcPos == null) return; IBlockState state = Minecraft.getMinecraft().theWorld.getBlockState(mcPos); Block block = state.getBlock(); diff --git a/src/main/resources/assets/minecraft/client/lang/en_us.lang b/src/main/resources/assets/minecraft/client/lang/en_us.lang index 12041472..c31da3d0 100644 --- a/src/main/resources/assets/minecraft/client/lang/en_us.lang +++ b/src/main/resources/assets/minecraft/client/lang/en_us.lang @@ -809,6 +809,28 @@ betterfishingrod=Better Fishing Rod betterfishingrod.desc=Modify the fishing rod betterfishingrod.stringwidth=String Width +saturationdisplay=Saturation HUD +saturationdisplay.desc=Replace the vanilla food bar with a movable saturation display +saturationdisplay.background=Show Background +saturationdisplay.backgroundcolor=Background Color +saturationdisplay.round=Rounded Corners +saturationdisplay.roundradius=Corner Radius +saturationdisplay.betterfont=Better Font +saturationdisplay.fontshadow=Font Shadow + +customfog=Custom Fog +customfog.desc=Customize the color and distance of world fog +customfog.color=Fog Color +customfog.fogmode=Fog Mode +customfog.fogmode.linear=Linear +customfog.fogmode.exponential=Exponential +customfog.startdistance=Start Distance +customfog.enddistance=End Distance +autotext=AutoText +autotext.desc=Send a saved chat message when a configured key is pressed +autotext.entries=Entries +autotext.empty=No AutoText entries. Click + to add one. + # Categories category.optimize=Performance diff --git a/src/main/resources/assets/minecraft/client/lang/zh_cn.lang b/src/main/resources/assets/minecraft/client/lang/zh_cn.lang index 2ca4dc23..73e76589 100644 --- a/src/main/resources/assets/minecraft/client/lang/zh_cn.lang +++ b/src/main/resources/assets/minecraft/client/lang/zh_cn.lang @@ -809,6 +809,28 @@ betterfishingrod=更好的鱼竿 betterfishingrod.desc=修改钓鱼竿 betterfishingrod.stringwidth=线宽度 +saturationdisplay=饱和度显示 +saturationdisplay.desc=用可自由移动的饱和度显示替代原版饥饿条 +saturationdisplay.background=背景 +saturationdisplay.backgroundcolor=背景颜色 +saturationdisplay.round=背景圆角 +saturationdisplay.roundradius=圆角半径 +saturationdisplay.betterfont=更好的字体 +saturationdisplay.fontshadow=字体阴影 + +customfog=自定义迷雾 +customfog.desc=自定义世界迷雾的颜色和距离 +customfog.color=迷雾颜色 +customfog.fogmode=迷雾模式 +customfog.fogmode.linear=线性 +customfog.fogmode.exponential=指数 +customfog.startdistance=起始距离 +customfog.enddistance=结束距离 +autotext=自动文本 +autotext.desc=按下设定的快捷键时发送保存的聊天消息 +autotext.entries=条目 +autotext.empty=暂无自动文本条目,点击 + 添加。 + # 类别 category.optimize=优化 From f62b4c9dab2a99198928f6bd18096245faa1eec2 Mon Sep 17 00:00:00 2001 From: Serendisand <2742754621@qq.com> Date: Sat, 1 Aug 2026 23:11:53 +0800 Subject: [PATCH 06/22] Update task list with completed items --- docs/tasks.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tasks.md b/docs/tasks.md index c86f5724..794bed37 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -31,14 +31,14 @@ FPSMaster v4将会在此列表任务大部分完成后发布 - [ ] 全局搜索 - [x] 新的OOBE - [ ] 功能完整的饰品界面 -- [ ] AutoText -- [ ] 饱和度显示 +- [x] AutoText +- [x] 饱和度显示 - [ ] 账号管理界面 -- [ ] SMTC支持 +- [x] SMTC支持 - [ ] 时间更改模块改为世界更改,添加天气选项(是否和WorldColor模块合并?) - [ ] 修复歌词渲染等特殊组件可能因glflags状态导致的渲染问题 - [ ] 添加异步光照性能优化 -- [ ] 添加自定义迷雾(颜色,距离等) +- [x] 添加自定义迷雾(颜色,距离等) - [ ] 为客户端的组件颜色选择添加彩色选项 - [x] 在聊天栏显示头像 - [ ] HypixelMod(合并AutoGG,AutoPlay以及聊天栏实用功能等) From a7a211a22879d2e6867117053cc1ad4adce5f7cf Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sun, 2 Aug 2026 12:18:26 +0800 Subject: [PATCH 07/22] =?UTF-8?q?fix(smtc):=20=E4=BF=AE=E5=A4=8D=20SMTC=20?= =?UTF-8?q?=E5=8E=9F=E7=94=9F=20ABI=20=E4=B8=8E=E5=B0=81=E9=9D=A2=E5=9B=BE?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - smtc.cpp: 切换到 GetForWindow 桌面互操作路径,smtc_start 返回状态码 - 修复 __stdcall→__cdecl 后导出符号与 JNA 绑定不匹配的问题(DLL 重编译) - 封面图下载改走 MusicTextures 单线程 AWT/ImageIO 队列,避免 macOS 并发崩溃 - 新增 smtc.def 导出定义 --- native/smtc/smtc.cpp | 100 ++++++++++++++---- native/smtc/smtc.def | 7 ++ .../modules/music/MusicTextures.java | 33 +++++- .../modules/music/smtc/SmtcMusicBridge.java | 65 ++++-------- .../WindowsSystemMediaTransportControls.java | 8 +- .../native/windows/x64/fpsmaster-smtc.dll | Bin 0 -> 156672 bytes .../native/windows/x86/fpsmaster-smtc.dll | Bin 0 -> 123904 bytes 7 files changed, 140 insertions(+), 73 deletions(-) create mode 100644 native/smtc/smtc.def create mode 100644 src/main/resources/native/windows/x64/fpsmaster-smtc.dll create mode 100644 src/main/resources/native/windows/x86/fpsmaster-smtc.dll diff --git a/native/smtc/smtc.cpp b/native/smtc/smtc.cpp index d14ff0dc..c1e5812b 100644 --- a/native/smtc/smtc.cpp +++ b/native/smtc/smtc.cpp @@ -11,15 +11,22 @@ // The DLL exports a tiny C ABI that the Java side (JNA) calls. // Callbacks from SMTC button events are dispatched to a function pointer // provided by the Java side. +// +// Desktop (Win32 JVM) integration goes through the +// ISystemMediaTransportControlsInterop::GetForWindow(hwnd) path. The UWP +// GetForCurrentView() API requires a CoreWindow and therefore always fails +// in the Minecraft JVM; it is deliberately not used here. #include #include #include +#include // WinRT headers #include #include #include +#include using namespace winrt; using namespace Windows::Media; @@ -28,32 +35,78 @@ using namespace Windows::Storage::Streams; // --------------------------------------------------------------------------- // Callback types (Java sets these via JNA) // --------------------------------------------------------------------------- -typedef void(__stdcall* ControlCallback)(int action); +typedef void(__cdecl* ControlCallback)(int action); static ControlCallback g_callback = nullptr; // --------------------------------------------------------------------------- // SMTC session state // --------------------------------------------------------------------------- static SystemMediaTransportControls g_smtc = nullptr; +static winrt::event_token g_buttonToken{}; static bool g_initialized = false; +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +// Find a visible top-level window owned by this process. GetForWindow needs a +// real HWND; the Java side passes 0 when it has no window handle to hand over. +static HWND find_process_window() { + static HWND found = nullptr; + found = nullptr; + DWORD pid = GetCurrentProcessId(); + EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL { + DWORD wpid = 0; + GetWindowThreadProcessId(hwnd, &wpid); + if (wpid == (DWORD)lParam && IsWindowVisible(hwnd)) { + found = hwnd; + return FALSE; + } + return TRUE; + }, (LPARAM)pid); + return found; +} + // --------------------------------------------------------------------------- // C ABI exports // --------------------------------------------------------------------------- extern "C" { -/// Initialize the SMTC session. Call once; idempotent. -/// hwnd: parent window handle (0 = use desktop window). -__declspec(dllexport) void __stdcall smtc_start(HWND hwnd) { - if (g_initialized) return; +/// Initialize the SMTC session for a desktop window. Call once; idempotent. +/// hwnd: parent window handle (0 = auto-detect the process main window). +/// Returns 1 on success, 0 on failure (so the Java side can surface it). +__declspec(dllexport) int __cdecl smtc_start(HWND hwnd) { + if (g_initialized) return 1; try { - // Initialize WinRT apartment - winrt::init_apartment(winrt::apartment_type::single_threaded); + // Initialize WinRT apartment (MTA so callbacks can fire on any thread) + winrt::init_apartment(winrt::apartment_type::multi_threaded); + + HWND target = hwnd; + if (target == nullptr) { + target = find_process_window(); + } + if (target == nullptr) { + g_initialized = false; + return 0; + } - // Get the system transport controls - g_smtc = SystemMediaTransportControls::GetForCurrentView(); - if (!g_smtc) return; + // Desktop interop: get the transport controls bound to a window. + auto interop = get_activation_factory(); + SystemMediaTransportControls controls = nullptr; + HRESULT hr = interop->GetForWindow(target, + winrt::guid_of(), + winrt::put_abi(controls)); + if (FAILED(hr)) { + g_initialized = false; + return 0; + } + g_smtc = controls; + if (!g_smtc) { + g_initialized = false; + return 0; + } // Enable all supported buttons g_smtc.IsPlayEnabled(true); @@ -62,7 +115,7 @@ __declspec(dllexport) void __stdcall smtc_start(HWND hwnd) { g_smtc.IsPreviousEnabled(true); // Subscribe to button events - auto token = g_smtc.ButtonPressed( + g_buttonToken = g_smtc.ButtonPressed( [](const SystemMediaTransportControls& sender, const SystemMediaTransportControlsButtonPressedEventArgs& args) { if (!g_callback) return; @@ -84,19 +137,21 @@ __declspec(dllexport) void __stdcall smtc_start(HWND hwnd) { }); g_initialized = true; + return 1; } catch (...) { g_initialized = false; + return 0; } } /// Register the Java callback function pointer. -__declspec(dllexport) void __stdcall smtc_set_callback(ControlCallback cb) { +__declspec(dllexport) void __cdecl smtc_set_callback(ControlCallback cb) { g_callback = cb; } /// Publish playback metadata and state. /// artwork_data / artwork_len: PNG bytes or NULL/0 for no art. -__declspec(dllexport) void __stdcall smtc_publish( +__declspec(dllexport) void __cdecl smtc_publish( const wchar_t* title, const wchar_t* artist, const wchar_t* album, @@ -121,8 +176,9 @@ __declspec(dllexport) void __stdcall smtc_publish( if (artwork_data && artwork_len > 0) { try { auto stream = InMemoryRandomAccessStream(); - stream.WriteAsync(winrt::array_view( - artwork_data, artwork_data + artwork_len)).get(); + auto buffer = Buffer(static_cast(artwork_len)); + memcpy(buffer.data(), artwork_data, artwork_len); + stream.WriteAsync(buffer).get(); stream.Seek(0); auto ref = RandomAccessStreamReference::CreateFromStream(stream); updater.Thumbnail(ref); @@ -134,13 +190,11 @@ __declspec(dllexport) void __stdcall smtc_publish( updater.Update(); // Timeline properties - auto timeline = g_smtc.GetTimelineProperties(); - // Position and duration are set via the SystemMediaTransportControlsTimelineProperties auto props = SystemMediaTransportControlsTimelineProperties(); - props.StartTime(0); + props.StartTime(std::chrono::milliseconds(0)); props.Position(std::chrono::milliseconds(positionMs)); props.EndTime(std::chrono::milliseconds(durationMs > 0 ? durationMs : 1)); - props.MinSeekTime(0); + props.MinSeekTime(std::chrono::milliseconds(0)); props.MaxSeekTime(std::chrono::milliseconds(durationMs > 0 ? durationMs : 1)); g_smtc.UpdateTimelineProperties(props); @@ -158,7 +212,7 @@ __declspec(dllexport) void __stdcall smtc_publish( } /// Enable/disable which buttons are shown. -__declspec(dllexport) void __stdcall smtc_set_buttons( +__declspec(dllexport) void __cdecl smtc_set_buttons( bool playPause, bool next, bool prev ) { if (!g_smtc) return; @@ -172,11 +226,11 @@ __declspec(dllexport) void __stdcall smtc_set_buttons( } /// Release the SMTC session. Safe to call multiple times. -__declspec(dllexport) void __stdcall smtc_close() { +__declspec(dllexport) void __cdecl smtc_close() { if (!g_initialized) return; try { if (g_smtc) { - g_smtc.ButtonPressed({}); + g_smtc.ButtonPressed(g_buttonToken); g_smtc = nullptr; } g_initialized = false; @@ -187,7 +241,7 @@ __declspec(dllexport) void __stdcall smtc_close() { } /// Get the last error message (for debugging). -__declspec(dllexport) void __stdcall smtc_get_last_error(wchar_t* buf, int bufLen) { +__declspec(dllexport) void __cdecl smtc_get_last_error(wchar_t* buf, int bufLen) { (void)buf; (void)bufLen; // Simplified: just clear diff --git a/native/smtc/smtc.def b/native/smtc/smtc.def new file mode 100644 index 00000000..52597d75 --- /dev/null +++ b/native/smtc/smtc.def @@ -0,0 +1,7 @@ +EXPORTS + smtc_start + smtc_set_callback + smtc_publish + smtc_set_buttons + smtc_close + smtc_get_last_error diff --git a/src/main/java/top/fpsmaster/modules/music/MusicTextures.java b/src/main/java/top/fpsmaster/modules/music/MusicTextures.java index 7f444ae2..df65ee0a 100644 --- a/src/main/java/top/fpsmaster/modules/music/MusicTextures.java +++ b/src/main/java/top/fpsmaster/modules/music/MusicTextures.java @@ -14,6 +14,7 @@ import java.awt.Color; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Base64; @@ -104,8 +105,7 @@ public void run() { } /** 由文本(网易云登录 codekey URL)生成二维码纹理。 */ - public static synchronized ResourceLocation qr(final String text) { - if (text == null || text.isEmpty()) return null; + public static synchronized ResourceLocation qr(final String text) { if (text == null || text.isEmpty()) return null; final String key = "qr:" + text; ResourceLocation loc = READY.get(key); if (loc != null) return loc; @@ -135,6 +135,35 @@ public static synchronized void invalidate(String rawKey) { } } + /** + * 在 {@link #IMG_EXEC} 单线程上下载图片并重新编码为 PNG 字节,结果通过回调返回。 + * 供 SMTC 等需要原始字节(而非 GL 纹理)的调用方复用同一套下载/解码路径, + * 避免自起线程并发调用 AWT/ImageIO 在 macOS 上触发崩溃。 + */ + public static void downloadPngAsync(final String url, final java.util.function.Consumer callback) { + if (url == null || url.isEmpty() || callback == null) { + return; + } + IMG_EXEC.execute(new Runnable() { + @Override + public void run() { + try { + BufferedImage img = downloadImage(url); + if (img == null) { + callback.accept(null); + return; + } + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ImageIO.write(img, "png", bos); + callback.accept(bos.toByteArray()); + } catch (Throwable e) { + ClientLogger.error("Music PNG download failed: " + e.getMessage()); + callback.accept(null); + } + } + }); + } + private static synchronized void unmark(String key) { LOADING.remove(key); } diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java index 64f4c3b6..1caa2e38 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java @@ -1,16 +1,10 @@ package top.fpsmaster.modules.music.smtc; -import top.fpsmaster.FPSMaster; import top.fpsmaster.modules.logger.ClientLogger; import top.fpsmaster.modules.music.MusicManager; +import top.fpsmaster.modules.music.MusicTextures; import top.fpsmaster.music.Track; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.concurrent.atomic.AtomicReference; /** @@ -19,17 +13,15 @@ *

Runs a lightweight polling loop (separate daemon thread) that samples the current track and * forwards a snapshot to the transport facade. Control events from the system are marshalled back * onto the Minecraft main thread before calling {@link MusicManager} so queue/UI state stays - * main-thread consistent. Cover art is downloaded off-thread with the established UA/referer path. + * main-thread consistent. Cover art is downloaded on the shared single-threaded + * {@link MusicTextures} decoder queue to avoid concurrent AWT/ImageIO crashes on macOS. */ public final class SmtcMusicBridge { - private static final String UA = - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " - + "Chrome/123.0.0.0 Safari/537.36"; - private final MusicManager music; private final SystemMediaTransportControls controls; private final AtomicReference artwork = new AtomicReference<>(); + private volatile String artworkUrl; private volatile boolean running; private Thread pollThread; @@ -83,8 +75,9 @@ private void pollLoop() { if (cur != lastTrack) { lastTrack = cur; lastPos = -1; - // New track: kick off cover download if not already cached - maybeLoadArtwork(cur.getCoverUrl()); + // New track: kick off cover download (cache is keyed by URL, so a track change + // always refreshes the art instead of reusing the previous track's thumbnail) + requestArtwork(cur.getCoverUrl()); } long pos = music.engine().getPositionMs(); @@ -125,47 +118,27 @@ private void pollLoop() { } } - /** Downloads and caches album art as PNG bytes, off-thread. */ - private void maybeLoadArtwork(final String coverUrl) { + /** + * Requests album art for {@code coverUrl}. Empty/duplicate URLs clear or keep the cache; any + * other URL triggers a re-download because the previous track's art no longer matches. + */ + private void requestArtwork(final String coverUrl) { if (coverUrl == null || coverUrl.isEmpty()) { artwork.set(null); + artworkUrl = null; return; } - // Only refresh when we don't already have art for the current track - if (artwork.get() != null) { + if (coverUrl.equals(artworkUrl)) { return; } - final Thread t = new Thread(() -> { - try { - byte[] png = downloadPng(coverUrl); + artworkUrl = coverUrl; + MusicTextures.downloadPngAsync(coverUrl, png -> { + // Only accept the result if the track hasn't changed while we were downloading + if (png != null && coverUrl.equals(artworkUrl)) { artwork.set(png); - // Publish again so SMTC picks up the art controls.publish(snapshotFromCurrent()); - } catch (Throwable e) { - ClientLogger.error("SMTC artwork load failed: " + e.getMessage()); - } - }, "FPSMaster-Smtc-Art"); - t.setDaemon(true); - t.start(); - } - - private byte[] downloadPng(String url) throws Exception { - HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); - conn.setInstanceFollowRedirects(true); - conn.setConnectTimeout(8000); - conn.setReadTimeout(12000); - conn.setRequestProperty("User-Agent", UA); - try (InputStream in = conn.getInputStream()) { - BufferedImage img = ImageIO.read(in); - if (img == null) { - return null; } - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ImageIO.write(img, "png", bos); - return bos.toByteArray(); - } finally { - conn.disconnect(); - } + }); } private MediaPlaybackSnapshot snapshotFromCurrent() { diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java index 2ba6e98a..595c625b 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java @@ -24,7 +24,7 @@ final class WindowsSystemMediaTransportControls implements SystemMediaTransportControls { private interface SmtcNative extends Library { - void smtc_start(long hwnd); + int smtc_start(long hwnd); void smtc_set_callback(ControlCallback cb); void smtc_publish(WString title, WString artist, WString album, long positionMs, long durationMs, boolean playing, boolean hasCurrentTrack, byte[] artworkData, int artworkLen); @@ -118,7 +118,11 @@ private void loadAndInit() { return; } nativeLib.smtc_set_callback(callback); - nativeLib.smtc_start(0L); + int status = nativeLib.smtc_start(0L); + if (status != 1) { + ClientLogger.warn("SMTC native start returned failure status, SMTC unavailable"); + return; + } available.set(true); } catch (Throwable t) { ClientLogger.error("SMTC native start failed: " + t.getMessage()); diff --git a/src/main/resources/native/windows/x64/fpsmaster-smtc.dll b/src/main/resources/native/windows/x64/fpsmaster-smtc.dll new file mode 100644 index 0000000000000000000000000000000000000000..a1b55b7ad6f05383821c65ba07eb3089e4a72657 GIT binary patch literal 156672 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/native/windows/x86/fpsmaster-smtc.dll b/src/main/resources/native/windows/x86/fpsmaster-smtc.dll new file mode 100644 index 0000000000000000000000000000000000000000..2cd0fdddba93050bc032414e5c9ebf6cd6634bd6 GIT binary patch literal 123904 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�E6CC_kU^{e9_TjewfQD%za>91l@09G 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 NbYRY*!u{{Q{vWOwF%$p* literal 0 HcmV?d00001 From 643fd318531a8781940cfa25304db4846fdf80ba Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sun, 2 Aug 2026 12:18:36 +0800 Subject: [PATCH 08/22] =?UTF-8?q?fix(render):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=BF=B7=E9=9B=BE=E9=9B=BE=E8=89=B2?= =?UTF-8?q?/=E5=A4=B1=E6=98=8E=E8=B7=B3=E8=BF=87=E4=B8=8E=20HUD=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MixinEntityRenderer: 雾色改用 glFog(GL_FOG_COLOR),复位顶点色防污染后续渲染; 失明药水跳过覆盖;水/岩浆材质检查改用 isInsideOfMaterial - MixinGuiIngameForge: renderFood 被 cancel 时手动补 right_height += 10,修复 血量/氧气条整体下移 10px - MixinSplashScreen: @Overwrite 补 remap = false - SaturationDisplayComponent: 图标绘制改走 Images 全 float 版本 --- .../forge/mixin/MixinEntityRenderer.java | 32 ++++++++++++------- .../forge/mixin/MixinGuiIngameForge.java | 9 +++++- .../forge/mixin/MixinSplashScreen.java | 2 +- .../impl/SaturationDisplayComponent.java | 4 +-- .../fpsmaster/utils/render/draw/Images.java | 3 +- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java index 378a74dc..a802afc4 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java @@ -13,12 +13,15 @@ import net.minecraft.client.shader.ShaderGroup; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.Potion; import net.minecraft.entity.item.EntityItemFrame; import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.util.*; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.event.EntityViewRenderEvent; import net.minecraftforge.common.MinecraftForge; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -39,6 +42,7 @@ import top.fpsmaster.features.impl.render.CustomFog; import top.fpsmaster.utils.math.MathUtils; +import java.nio.FloatBuffer; import java.util.List; import static top.fpsmaster.utils.core.Utility.mc; @@ -307,25 +311,31 @@ private void overrideFog(int startCoords, float partialTicks, CallbackInfo ci) { if (!CustomFog.using) return; if (mc.thePlayer == null) return; + // 失明药水:原版强制成极短线性雾,覆盖它会变成服务器判定上的优势,跳过 + if (mc.thePlayer.isPotionActive(Potion.blindness)) return; + // Check if in water or lava — only override if the user opted in - if (!CustomFog.affectWater.getValue()) { - net.minecraft.block.material.Material eye = mc.thePlayer.getEye().getMaterial(); - if (eye == net.minecraft.block.material.Material.water) return; - } - if (!CustomFog.affectLava.getValue()) { - net.minecraft.block.material.Material eye = mc.thePlayer.getEye().getMaterial(); - if (eye == net.minecraft.block.material.Material.lava) return; - } + if (!CustomFog.affectWater.getValue() && mc.thePlayer.isInsideOfMaterial(net.minecraft.block.material.Material.water)) return; + if (!CustomFog.affectLava.getValue() && mc.thePlayer.isInsideOfMaterial(net.minecraft.block.material.Material.lava)) return; + // 雾色只能用 glFog(GL_FOG_COLOR, buffer) 设置,不能走顶点色 java.awt.Color fogColor = CustomFog.color.getColor(); - GlStateManager.color(fogColor.getRed() / 255f, fogColor.getGreen() / 255f, fogColor.getBlue() / 255f); + FloatBuffer fogColorBuffer = BufferUtils.createFloatBuffer(4); + fogColorBuffer.put(fogColor.getRed() / 255f) + .put(fogColor.getGreen() / 255f) + .put(fogColor.getBlue() / 255f) + .put(1.0f) + .flip(); + GL11.glFog(GL11.GL_FOG_COLOR, fogColorBuffer); + // 复位顶点色,避免残留颜色污染后续 renderSky/云/实体渲染 + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); if (CustomFog.fogMode.isMode("Linear")) { - GlStateManager.setFog(GlStateManager.FogMode.LINEAR); + GlStateManager.setFog(GL11.GL_LINEAR); GlStateManager.setFogStart(CustomFog.startDistance.getValue().floatValue()); GlStateManager.setFogEnd(CustomFog.endDistance.getValue().floatValue()); } else { - GlStateManager.setFog(GlStateManager.FogMode.EXP); + GlStateManager.setFog(GL11.GL_EXP); float density = 1.0f / Math.max(0.1f, CustomFog.endDistance.getValue().floatValue()); GlStateManager.setFogDensity(density); } diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java index 15260acd..d8ed290a 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java @@ -15,9 +15,13 @@ import top.fpsmaster.event.events.EventRender2D; import top.fpsmaster.features.impl.interfaces.CustomTitles; import top.fpsmaster.features.impl.interfaces.SaturationDisplay; +import org.spongepowered.asm.mixin.Shadow; @Mixin(GuiIngameForge.class) public class MixinGuiIngameForge { + @Shadow(remap = false) + public static int right_height; + @Inject(method = "renderGameOverlay", at = @At("HEAD")) private void fpsmasterBeginHud(float partialTicks, CallbackInfo ci) { if (BenchmarkMode.ACTIVE) { @@ -38,9 +42,12 @@ private void renderTooltipPost(ScaledResolution sr, float partialTicks, Callback EventDispatcher.dispatchEvent(new EventRender2D(partialTicks)); } - @Inject(method = "renderFood", at = @At("HEAD"), cancellable = true) + @Inject(method = "renderFood", at = @At("HEAD"), cancellable = true, remap = false) private void hideVanillaFood(int width, int height, CallbackInfo callbackInfo) { if (SaturationDisplay.using) { + // renderFood 末尾的 right_height += 10 会在 cancel 时被跳过, + // 手动补上以免 renderHealthMount/renderAir 整体下移 10px。 + right_height += 10; callbackInfo.cancel(); } } diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinSplashScreen.java b/src/main/java/top/fpsmaster/forge/mixin/MixinSplashScreen.java index 07e9e756..a44c65d9 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinSplashScreen.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinSplashScreen.java @@ -22,7 +22,7 @@ public class MixinSplashScreen { * @author SuperSkidder * @reason Custom Loading Screen */ - @Overwrite + @Overwrite(remap = false) public static void start() { ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); int i = scaledresolution.getScaleFactor(); diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java index 919c1572..c2baa63a 100644 --- a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java +++ b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java @@ -1,12 +1,12 @@ package top.fpsmaster.ui.custom.impl; -import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; import top.fpsmaster.features.impl.interfaces.SaturationDisplay; import top.fpsmaster.ui.custom.Component; import top.fpsmaster.ui.custom.Position; +import top.fpsmaster.utils.render.draw.Images; import java.awt.Color; @@ -65,7 +65,7 @@ public void draw(float x, float y) { } private void drawIcon(float x, float y, int textureX, int textureY) { - Gui.drawModalRectWithCustomSizedTexture(x, y, textureX, textureY, ICON_SIZE * scale, ICON_SIZE * scale, 256f, 256f); + Images.drawModalRectWithCustomSizedTexture(x, y, textureX, textureY, ICON_SIZE * scale, ICON_SIZE * scale, 256f, 256f); } private String saturationText() { diff --git a/src/main/java/top/fpsmaster/utils/render/draw/Images.java b/src/main/java/top/fpsmaster/utils/render/draw/Images.java index 9e2fa54d..05021fff 100644 --- a/src/main/java/top/fpsmaster/utils/render/draw/Images.java +++ b/src/main/java/top/fpsmaster/utils/render/draw/Images.java @@ -166,7 +166,8 @@ public static void scaleEnd() { glPopMatrix(); } - private static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float textureWidth, float textureHeight) { + /** 全 float 版本的自定义尺寸纹理四边形,保留亚像素坐标。坐标按 HUD 组件传入的已缩放值使用。 */ + public static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float textureWidth, float textureHeight) { float f = 1.0F / textureWidth; float f1 = 1.0F / textureHeight; net.minecraft.client.renderer.Tessellator tessellator = net.minecraft.client.renderer.Tessellator.getInstance(); From 90e33b1f2235443e1b0cdada055ca4b4b963a392 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sun, 2 Aug 2026 12:18:43 +0800 Subject: [PATCH 09/22] =?UTF-8?q?fix(autotext):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=20G=20=E9=94=AE=E7=BB=91=E5=AE=9A=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E6=9D=A1=E7=9B=AE=E4=B8=8D=E5=86=8D=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=BB=91=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 默认快捷键从错误的 0x2C(Z) 修正为 0x22(G) - 新增条目 keyCode 保持 0(None),由用户显式绑定,避免误占键位 --- .../fpsmaster/features/impl/utility/AutoText.java | 2 +- .../click/modules/impl/AutoTextSettingRender.java | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java b/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java index bed703d6..28f8fb30 100644 --- a/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java +++ b/src/main/java/top/fpsmaster/features/impl/utility/AutoText.java @@ -23,7 +23,7 @@ public class AutoText extends Module { private static final ArrayList DEFAULT = new ArrayList<>(); static { - DEFAULT.add(new AutoTextEntry(0x2C /* G key LWJGL */, "gg")); + DEFAULT.add(new AutoTextEntry(0x22 /* G key LWJGL */, "gg")); } public final AutoTextSetting entries = new AutoTextSetting("Entries", new ArrayList<>(DEFAULT)); diff --git a/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java b/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java index ab56103a..9309a8f3 100644 --- a/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java +++ b/src/main/java/top/fpsmaster/ui/click/modules/impl/AutoTextSettingRender.java @@ -175,16 +175,9 @@ public void render(ScaledGuiScreen screen, float x, float y, float width, float if (canAdd) { ScaledGuiScreen.PointerEvent addClick = screen.consumePressInBounds(addX, addY, 14, 14, 0); if (addClick != null) { - // Find first unused key code - int newKey = 0; - for (int k = 2; k < 256; k++) { - int finalK = k; - if (entries.stream().noneMatch(e -> e.keyCode == finalK)) { - newKey = k; - break; - } - } - setting.addEntry(new AutoTextEntry(newKey, "")); + // 新条目不自动绑键:keyCode 保持 0(None),避免误占快捷栏键位, + // 由用户点击 Bind 按钮显式绑定。 + setting.addEntry(new AutoTextEntry(0, "")); rebuildTextFields(); return; } From 9edcceb617b74ed568d503d6fbf4b4669deda999 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sun, 2 Aug 2026 12:52:53 +0800 Subject: [PATCH 10/22] =?UTF-8?q?i18n:=20=E8=A1=A5=E5=85=A8=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E6=96=87=E4=BB=B6=E7=BC=BA=E5=A4=B1=E9=94=AE=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - performance.reuselevel 及其模式值(保守/均衡/激进) - customfog.affectwater/affectlava - performancehud 共享外观设置(背景/圆角/字体阴影等) - modslist.round/fontshadow、togglesneak.fontshadow、sprint.fontshadow - betterchat.round、betterscreen、blockindicator、hideindicator、 inventorydisplay、taboverlay、targetdisplay 的共享设置 - minimap.fastrender.disable.title(小地图与快速渲染不兼容提示) --- .../assets/minecraft/client/lang/en_us.lang | 44 +++++++++++++++++++ .../assets/minecraft/client/lang/zh_cn.lang | 44 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/main/resources/assets/minecraft/client/lang/en_us.lang b/src/main/resources/assets/minecraft/client/lang/en_us.lang index d9c33cda..ecf85af9 100644 --- a/src/main/resources/assets/minecraft/client/lang/en_us.lang +++ b/src/main/resources/assets/minecraft/client/lang/en_us.lang @@ -210,6 +210,7 @@ betterchat.fontshadow=Font Shadow betterchat.betterfont=Clean Font betterchat.roundradius=Corner Radius betterchat.background=Show Background +betterchat.round=Rounded Corners betterchat.foldmessage=Fold Message betterchat.copymessage=Copy Message @@ -252,6 +253,7 @@ fpsdisplay.betterfont=Clean Font minimap=Minimap minimap.desc=Minimap overlay +minimap.fastrender.disable.title=Minimap is not compatible with Fast Render. Fast Render has been disabled. hotbar=Hotbar hotbar.desc=Enhanced hotbar visuals @@ -409,6 +411,10 @@ performance.textureresolution.sixteenth=Sixteenth performance.fastcollision=Fast Entity Collision performance.fasttextureupload=Fast Texture Upload performance.reusevisiblechunks=Reuse Visible Chunk List +performance.reuselevel=Reuse Visible Chunk Level +performance.reuselevel.conservative=Conservative +performance.reuselevel.balanced=Balanced +performance.reuselevel.aggressive=Aggressive performance.composedmodeltransform=Composed Model Transform performance.batchvanillafont=Batch Vanilla Font performance.fastglyphlookup=Fast Glyph Lookup @@ -422,6 +428,13 @@ performancehud.showdistribution=Show Frame Time Distribution performancehud.showmemory=Show Memory performancehud.showgc=Show Garbage Collection performancehud.colorbyhealth=Color By Health +performancehud.background=Show Background +performancehud.backgroundcolor=Background Color +performancehud.round=Rounded Corners +performancehud.roundradius=Corner Radius +performancehud.betterfont=Clean Font +performancehud.fontshadow=Font Shadow +performancehud.spacing=Spacing fullbright=Fullbright fullbright.desc=Keep brightness at max @@ -458,12 +471,14 @@ sprint=Sprint sprint.desc=Stay sprinting at all times sprint.togglesprint=Toggle Sprint sprint.betterfont=Clean Font +sprint.fontshadow=Font Shadow togglesneak=Toggle Sneak togglesneak.desc=Press the toggle key once to keep sneaking togglesneak.togglesneak=Toggle Sneak togglesneak.togglekey=Toggle Key togglesneak.betterfont=Clean Font +togglesneak.fontshadow=Font Shadow autogg=AutoGG autogg.desc=Automatically send a custom message after a game has ended. @@ -524,6 +539,12 @@ hitcolor.color=Color hideindicator=Hide Attack Indicator hideindicator.desc=Hides the attack cooldown bar +hideindicator.background=Show Background +hideindicator.backgroundcolor=Background Color +hideindicator.round=Rounded Corners +hideindicator.roundradius=Corner Radius +hideindicator.betterfont=Clean Font +hideindicator.fontshadow=Font Shadow lyricsdisplay=Lyrics Display lyricsdisplay.desc=Show synced lyrics @@ -591,6 +612,8 @@ blockindicator.roundradius=Round Radius blockindicator.backgroundcolor=Background Color blockindicator.panelcolor=Block Panel Color blockindicator.accentcolor=Accent Color +blockindicator.betterfont=Clean Font +blockindicator.fontshadow=Font Shadow playtime=Play Time playtime.desc=Track and display your play time @@ -660,6 +683,12 @@ nametags.background=Show Background taboverlay=Tab Overlay taboverlay.desc=Customize the tab list taboverlay.showping=Show Ping +taboverlay.background=Show Background +taboverlay.backgroundcolor=Background Color +taboverlay.round=Rounded Corners +taboverlay.roundradius=Corner Radius +taboverlay.betterfont=Clean Font +taboverlay.fontshadow=Font Shadow inventorydisplay=Inventory Display inventorydisplay.desc=Show inventory items on screen @@ -667,6 +696,8 @@ inventorydisplay.round=Rounded Corners inventorydisplay.backgroundcolor=Background Color inventorydisplay.roundradius=Corner Radius inventorydisplay.background=Show Background +inventorydisplay.betterfont=Clean Font +inventorydisplay.fontshadow=Font Shadow playerdisplay=Player Display playerdisplay.desc=Show nearby player info @@ -690,6 +721,10 @@ targetdisplay.espcolor=ESP Color targetdisplay.roundradius=Corner Radius targetdisplay.background=Show Background targetdisplay.omitname=Omit Long Names +targetdisplay.backgroundcolor=Background Color +targetdisplay.round=Rounded Corners +targetdisplay.betterfont=Clean Font +targetdisplay.fontshadow=Font Shadow itemcountdisplay=Item Count Display itemcountdisplay.desc=Quick show your items count in hud @@ -784,6 +819,8 @@ modslist.betterfont=Clean Font modslist.roundradius=Corner Radius modslist.background=Show Background modslist.spacing=Spacing +modslist.round=Rounded Corners +modslist.fontshadow=Font Shadow betterscreen=Enhanced UI betterscreen.desc=Improves vanilla UI visuals @@ -791,6 +828,11 @@ betterscreen.blur=Blur betterscreen.background=Enable Background betterscreen.backgroundanimation=Background Animation betterscreen.noflickering=No Flickering +betterscreen.backgroundcolor=Background Color +betterscreen.round=Rounded Corners +betterscreen.roundradius=Corner Radius +betterscreen.betterfont=Clean Font +betterscreen.fontshadow=Font Shadow clientcommand=Client Commands clientcommand.desc=Use commands to control modules @@ -880,6 +922,8 @@ customfog.fogmode.linear=Linear customfog.fogmode.exponential=Exponential customfog.startdistance=Start Distance customfog.enddistance=End Distance +customfog.affectwater=Affect Water Fog +customfog.affectlava=Affect Lava Fog autotext=AutoText autotext.desc=Send a saved chat message when a configured key is pressed autotext.entries=Entries diff --git a/src/main/resources/assets/minecraft/client/lang/zh_cn.lang b/src/main/resources/assets/minecraft/client/lang/zh_cn.lang index 7723e7bc..9e149223 100644 --- a/src/main/resources/assets/minecraft/client/lang/zh_cn.lang +++ b/src/main/resources/assets/minecraft/client/lang/zh_cn.lang @@ -210,6 +210,7 @@ betterchat.fontshadow=字体阴影 betterchat.betterfont=更好的字体 betterchat.roundradius=圆角半径 betterchat.background=背景 +betterchat.round=背景圆角 betterchat.foldmessage=折叠消息 betterchat.copymessage=复制消息 @@ -252,6 +253,7 @@ fpsdisplay.betterfont=更好的字体 minimap=小地图 minimap.desc=小地图组件 +minimap.fastrender.disable.title=小地图与快速渲染不兼容,已为您自动关闭快速渲染。 hotbar=物品栏 hotbar.desc=更好的物品栏 @@ -409,6 +411,10 @@ performance.textureresolution.sixteenth=十六分之一 performance.fastcollision=快速实体碰撞 performance.fasttextureupload=快速纹理上传 performance.reusevisiblechunks=复用可见区块列表 +performance.reuselevel=复用可见区块级别 +performance.reuselevel.conservative=保守 +performance.reuselevel.balanced=均衡 +performance.reuselevel.aggressive=激进 performance.composedmodeltransform=合成模型变换 performance.batchvanillafont=原版字体批量绘制 performance.fastglyphlookup=字形查表加速 @@ -422,6 +428,13 @@ performancehud.showdistribution=显示帧时间分布 performancehud.showmemory=显示内存占用 performancehud.showgc=显示垃圾回收 performancehud.colorbyhealth=按健康度着色 +performancehud.background=背景 +performancehud.backgroundcolor=背景颜色 +performancehud.round=背景圆角 +performancehud.roundradius=圆角半径 +performancehud.betterfont=更好的字体 +performancehud.fontshadow=字体阴影 +performancehud.spacing=间距 fullbright=保持亮度 fullbright.desc=保持视野明亮 @@ -458,12 +471,14 @@ sprint=强制疾跑 sprint.desc=保持疾跑 sprint.togglesprint=切换疾跑 sprint.betterfont=更好的字体 +sprint.fontshadow=字体阴影 togglesneak=切换潜行 togglesneak.desc=按下切换键即可保持潜行 togglesneak.togglesneak=切换潜行 togglesneak.togglekey=切换按键 togglesneak.betterfont=更好的字体 +togglesneak.fontshadow=字体阴影 autogg=自动GG autogg.desc=游戏结束后自动地在发送你自定义的消息 @@ -523,6 +538,12 @@ hitcolor.color=颜色 hideindicator=隐藏攻击指示器 hideindicator.desc=隐藏攻击指示器 +hideindicator.background=背景 +hideindicator.backgroundcolor=背景颜色 +hideindicator.round=背景圆角 +hideindicator.roundradius=圆角半径 +hideindicator.betterfont=更好的字体 +hideindicator.fontshadow=字体阴影 lyricsdisplay=歌词显示 lyricsdisplay.desc=歌词显示 @@ -591,6 +612,8 @@ blockindicator.roundradius=圆角半径 blockindicator.backgroundcolor=背景颜色 blockindicator.panelcolor=方块面板颜色 blockindicator.accentcolor=强调色 +blockindicator.betterfont=更好的字体 +blockindicator.fontshadow=字体阴影 playtime=游玩时间 playtime.desc=统计并显示你的游玩时间 @@ -660,6 +683,12 @@ nametags.background=背景 taboverlay=Tab显示 taboverlay.desc=自定义Tab界面 taboverlay.showping=显示数字延迟 +taboverlay.background=背景 +taboverlay.backgroundcolor=背景颜色 +taboverlay.round=背景圆角 +taboverlay.roundradius=圆角半径 +taboverlay.betterfont=更好的字体 +taboverlay.fontshadow=字体阴影 inventorydisplay=物品栏显示 inventorydisplay.desc=显示物品栏内物品 @@ -667,6 +696,8 @@ inventorydisplay.round=背景圆角 inventorydisplay.backgroundcolor=背景颜色 inventorydisplay.roundradius=圆角半径 inventorydisplay.background=背景 +inventorydisplay.betterfont=更好的字体 +inventorydisplay.fontshadow=字体阴影 playerdisplay=玩家显示 playerdisplay.desc=显示附近玩家的信息 @@ -690,6 +721,10 @@ targetdisplay.espcolor=ESP颜色 targetdisplay.roundradius=圆角半径 targetdisplay.background=背景 targetdisplay.omitname=省略过长的名字 +targetdisplay.backgroundcolor=背景颜色 +targetdisplay.round=背景圆角 +targetdisplay.betterfont=更好的字体 +targetdisplay.fontshadow=字体阴影 itemcountdisplay=物品数量 itemcountdisplay.desc=便捷的展示你的物品数量 @@ -785,6 +820,8 @@ modslist.betterfont=更好的字体 modslist.roundradius=圆角半径 modslist.background=背景 modslist.spacing=间距 +modslist.round=背景圆角 +modslist.fontshadow=字体阴影 betterscreen=更好的界面 betterscreen.desc=让原版的部分界面看起来更好 @@ -792,6 +829,11 @@ betterscreen.blur=模糊 betterscreen.background=开启背景 betterscreen.backgroundanimation=背景动画 betterscreen.noflickering=防止闪烁 +betterscreen.backgroundcolor=背景颜色 +betterscreen.round=背景圆角 +betterscreen.roundradius=圆角半径 +betterscreen.betterfont=更好的字体 +betterscreen.fontshadow=字体阴影 clientcommand=客户端命令 clientcommand.desc=使用命令执行客户端功能 @@ -880,6 +922,8 @@ customfog.fogmode.linear=线性 customfog.fogmode.exponential=指数 customfog.startdistance=起始距离 customfog.enddistance=结束距离 +customfog.affectwater=影响水面迷雾 +customfog.affectlava=影响岩浆迷雾 autotext=自动文本 autotext.desc=按下设定的快捷键时发送保存的聊天消息 autotext.entries=条目 From e00cd091b80156d71e0e03e64b804a672d38af24 Mon Sep 17 00:00:00 2001 From: Ukiyograin Date: Sun, 2 Aug 2026 12:52:59 +0800 Subject: [PATCH 11/22] =?UTF-8?q?fix(render):=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=BF=B7=E9=9B=BE=E7=BA=BF=E6=80=A7=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E6=8E=A8=E8=BF=9C=E9=BB=98=E8=AE=A4=E8=B7=9D=E7=A6=BB=E5=B9=B6?= =?UTF-8?q?=E9=98=B2=E5=8F=8D=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 线性雾默认 StartDistance 0 / EndDistance 20 让雾色覆盖 0~20 格 近景,近地面整体被染色。默认值推远为 32/64 格,StartDistance 上限从 20 扩到 200 便于拉开区间;mixin 中 end<=start 时自动 修正,避免线性雾公式反转导致近处更浓。 --- .../top/fpsmaster/features/impl/render/CustomFog.java | 4 ++-- .../fpsmaster/forge/mixin/MixinEntityRenderer.java | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java b/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java index 5ba09575..f26deb12 100644 --- a/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java +++ b/src/main/java/top/fpsmaster/features/impl/render/CustomFog.java @@ -13,8 +13,8 @@ public class CustomFog extends Module { public static boolean using; public static ColorSetting color = new ColorSetting("Color", new Color(0, 200, 255)); - public static NumberSetting startDistance = new NumberSetting("StartDistance", 0.0, 0, 20, 0.5); - public static NumberSetting endDistance = new NumberSetting("EndDistance", 20, 1, 200, 1); + public static NumberSetting startDistance = new NumberSetting("StartDistance", 32.0, 0, 200, 1); + public static NumberSetting endDistance = new NumberSetting("EndDistance", 64, 1, 200, 1); public static ModeSetting fogMode = new ModeSetting("FogMode", 0, "Linear", "Exponential"); public static BooleanSetting affectWater = new BooleanSetting("AffectWater", false); public static BooleanSetting affectLava = new BooleanSetting("AffectLava", false); diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java index a802afc4..4fc78eaa 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java @@ -332,8 +332,15 @@ private void overrideFog(int startCoords, float partialTicks, CallbackInfo ci) { if (CustomFog.fogMode.isMode("Linear")) { GlStateManager.setFog(GL11.GL_LINEAR); - GlStateManager.setFogStart(CustomFog.startDistance.getValue().floatValue()); - GlStateManager.setFogEnd(CustomFog.endDistance.getValue().floatValue()); + float start = CustomFog.startDistance.getValue().floatValue(); + float end = CustomFog.endDistance.getValue().floatValue(); + // 防反转:end 必须比 start 大,否则线性雾公式 (end - z)/(end - start) 会反过来, + // 近处反而更浓。顺带把范围钳制在渲染距离内,避免雾一直延伸到可视边界外。 + if (end <= start) { + end = start + 1.0f; + } + GlStateManager.setFogStart(start); + GlStateManager.setFogEnd(end); } else { GlStateManager.setFog(GL11.GL_EXP); float density = 1.0f / Math.max(0.1f, CustomFog.endDistance.getValue().floatValue()); From efd97f1f4307abd662351047357397ece57c6372 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:04:48 -0700 Subject: [PATCH 12/22] =?UTF-8?q?fix(smtc):=20WriteAsync=20=E5=89=8D?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=20Buffer.Length?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Buffer(capacity) 只设置 Capacity,Length 仍为 0,而 IOutputStream::WriteAsync 只传输 Length 个字节,导致缩略图流永远是 0 字节、媒体控件显示空白封面。 注意:src/main/resources/native/windows/ 下的预编译 DLL 需要重新编译才会包含此修复。 Co-Authored-By: Claude --- native/smtc/smtc.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/native/smtc/smtc.cpp b/native/smtc/smtc.cpp index c1e5812b..15105618 100644 --- a/native/smtc/smtc.cpp +++ b/native/smtc/smtc.cpp @@ -178,6 +178,9 @@ __declspec(dllexport) void __cdecl smtc_publish( auto stream = InMemoryRandomAccessStream(); auto buffer = Buffer(static_cast(artwork_len)); memcpy(buffer.data(), artwork_data, artwork_len); + // Buffer(capacity) 只设置 Capacity,Length 仍是 0;WriteAsync 只写 Length 个字节, + // 不显式设置 Length 会写出一个 0 字节的流(缩略图永远空白) + buffer.Length(static_cast(artwork_len)); stream.WriteAsync(buffer).get(); stream.Seek(0); auto ref = RandomAccessStreamReference::CreateFromStream(stream); From f71a95f697ab80154168e8260f99b41cbe62ab4d Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:04:48 -0700 Subject: [PATCH 13/22] =?UTF-8?q?fix(smtc):=20=E5=88=87=E6=AD=8C=E6=97=B6?= =?UTF-8?q?=E6=B8=85=E7=A9=BA=E5=B0=81=E9=9D=A2=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit requestArtwork 之前只更新 artworkUrl 不清 artwork,新歌的标题会配着上一首的封面 发布;若新封面下载失败(404/超时),回调里的 png != null 守卫直接跳过,旧图会 一直留到会话结束。 Co-Authored-By: Claude --- .../fpsmaster/modules/music/smtc/SmtcMusicBridge.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java index 1caa2e38..b99c9471 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java @@ -132,12 +132,16 @@ private void requestArtwork(final String coverUrl) { return; } artworkUrl = coverUrl; + // 换曲目就立刻丢掉上一首的封面,否则新歌的标题会配着旧歌的图发布出去 + artwork.set(null); MusicTextures.downloadPngAsync(coverUrl, png -> { // Only accept the result if the track hasn't changed while we were downloading - if (png != null && coverUrl.equals(artworkUrl)) { - artwork.set(png); - controls.publish(snapshotFromCurrent()); + if (!coverUrl.equals(artworkUrl)) { + return; } + // png 为 null(404/超时)时也要落库,保持"无封面"而不是留着上一首的图 + artwork.set(png); + controls.publish(snapshotFromCurrent()); }); } From c23a8ee54a6fe8f5a13798f5c14c77ab417f0aa2 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:04:48 -0700 Subject: [PATCH 14/22] =?UTF-8?q?fix(fog):=20=E5=A4=8D=E7=94=A8=20fog=20co?= =?UTF-8?q?lor=20buffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setupFog 每帧被调用多次(renderWorldPass 两次 + renderCloudsCheck),每次新建 direct FloatBuffer 会持续走 Bits.reserveMemory 和 Cleaner 注册。原版自身也是缓存 fogColorBuffer 复用的。 Co-Authored-By: Claude --- .../fpsmaster/forge/mixin/MixinEntityRenderer.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java index 4fc78eaa..464b3263 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java @@ -306,6 +306,9 @@ public void freelook(float partialTicks, long nanoTime, CallbackInfo ci) { FreeLook.overrideMouse(); } + @Unique + private static FloatBuffer fpsmaster$fogColorBuffer; + @Inject(method = "setupFog", at = @At("RETURN")) private void overrideFog(int startCoords, float partialTicks, CallbackInfo ci) { if (!CustomFog.using) return; @@ -320,7 +323,13 @@ private void overrideFog(int startCoords, float partialTicks, CallbackInfo ci) { // 雾色只能用 glFog(GL_FOG_COLOR, buffer) 设置,不能走顶点色 java.awt.Color fogColor = CustomFog.color.getColor(); - FloatBuffer fogColorBuffer = BufferUtils.createFloatBuffer(4); + FloatBuffer fogColorBuffer = fpsmaster$fogColorBuffer; + if (fogColorBuffer == null) { + // setupFog 每帧被调用多次,direct buffer 只分配一次后复用(原版同样缓存 fogColorBuffer) + fogColorBuffer = BufferUtils.createFloatBuffer(4); + fpsmaster$fogColorBuffer = fogColorBuffer; + } + fogColorBuffer.clear(); fogColorBuffer.put(fogColor.getRed() / 255f) .put(fogColor.getGreen() / 255f) .put(fogColor.getBlue() / 255f) From 47fef9b3c95c4a4d34d5d5de7d44f8e3328c1337 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:04:48 -0700 Subject: [PATCH 15/22] =?UTF-8?q?fix(saturation):=20=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E9=87=87=E6=A0=B7=E8=B7=A8=E5=BA=A6=E4=B8=8E=E7=BC=A9=E6=94=BE?= =?UTF-8?q?=E8=A7=A3=E8=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Images.drawModalRectWithCustomSizedTexture 用 width/height 同时决定四边形尺寸和 UV 跨度,HUD scale != 1 时会把 icons.png 里相邻的饥饿/护甲图标一起采样进来。新增 可单独指定 UV 跨度的重载,饱和度图标固定采样 9x9。 Co-Authored-By: Claude --- .../impl/SaturationDisplayComponent.java | 4 +++- .../fpsmaster/utils/render/draw/Images.java | 22 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java index c2baa63a..2ce8ef1d 100644 --- a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java +++ b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java @@ -65,7 +65,9 @@ public void draw(float x, float y) { } private void drawIcon(float x, float y, int textureX, int textureY) { - Images.drawModalRectWithCustomSizedTexture(x, y, textureX, textureY, ICON_SIZE * scale, ICON_SIZE * scale, 256f, 256f); + // 四边形按 scale 放大,但采样跨度固定 ICON_SIZE,否则会把 icons.png 里相邻的图标一起采进来 + Images.drawModalRectWithCustomSizedTexture(x, y, textureX, textureY, + ICON_SIZE * scale, ICON_SIZE * scale, ICON_SIZE, ICON_SIZE, 256f, 256f); } private String saturationText() { diff --git a/src/main/java/top/fpsmaster/utils/render/draw/Images.java b/src/main/java/top/fpsmaster/utils/render/draw/Images.java index 05021fff..5beae68b 100644 --- a/src/main/java/top/fpsmaster/utils/render/draw/Images.java +++ b/src/main/java/top/fpsmaster/utils/render/draw/Images.java @@ -166,16 +166,30 @@ public static void scaleEnd() { glPopMatrix(); } - /** 全 float 版本的自定义尺寸纹理四边形,保留亚像素坐标。坐标按 HUD 组件传入的已缩放值使用。 */ + /** + * 全 float 版本的自定义尺寸纹理四边形,保留亚像素坐标。坐标按 HUD 组件传入的已缩放值使用。 + * + *

注意采样区域与四边形尺寸相同:只适用于"渲染尺寸 == 源图尺寸"的场景。缩放绘制精灵图请用 + * {@link #drawModalRectWithCustomSizedTexture(float, float, float, float, float, float, float, float, float, float)} + * 单独传 UV 跨度,否则放大四边形会把相邻精灵一起采样进来。 + */ public static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float textureWidth, float textureHeight) { + drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, width, height, textureWidth, textureHeight); + } + + /** + * 同上,但四边形尺寸(width/height)与纹理采样跨度(uWidth/vHeight)解耦, + * 用于把固定大小的精灵按任意比例放大绘制。 + */ + public static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float uWidth, float vHeight, float textureWidth, float textureHeight) { float f = 1.0F / textureWidth; float f1 = 1.0F / textureHeight; net.minecraft.client.renderer.Tessellator tessellator = net.minecraft.client.renderer.Tessellator.getInstance(); net.minecraft.client.renderer.WorldRenderer bufferbuilder = tessellator.getWorldRenderer(); bufferbuilder.begin(7, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); - bufferbuilder.pos(x, y + height, 0.0D).tex(u * f, (v + height) * f1).endVertex(); - bufferbuilder.pos(x + width, y + height, 0.0D).tex((u + width) * f, (v + height) * f1).endVertex(); - bufferbuilder.pos(x + width, y, 0.0D).tex((u + width) * f, v * f1).endVertex(); + bufferbuilder.pos(x, y + height, 0.0D).tex(u * f, (v + vHeight) * f1).endVertex(); + bufferbuilder.pos(x + width, y + height, 0.0D).tex((u + uWidth) * f, (v + vHeight) * f1).endVertex(); + bufferbuilder.pos(x + width, y, 0.0D).tex((u + uWidth) * f, v * f1).endVertex(); bufferbuilder.pos(x, y, 0.0D).tex(u * f, v * f1).endVertex(); tessellator.draw(); } From 2694fe8ba98b9065f1fc92aa82e9cfb4d6662532 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:28:20 -0700 Subject: [PATCH 16/22] =?UTF-8?q?build(smtc):=20=E7=94=A8=20CMake=20+=20CI?= =?UTF-8?q?=20=E6=9E=84=E5=BB=BA=E5=8E=9F=E7=94=9F=E5=BA=93=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E6=8F=90=E4=BA=A4=20DLL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit native/smtc/CMakeLists.txt 用 MSVC 静态 CRT 编 x64/Win32 两份 DLL;CI 新增 build-native 作业(windows-latest)构建后作为 artifact 传给打包作业,注入 src/main/resources/native/windows/ 再执行 gradle build,并校验两个 DLL 非空。 已提交的二进制随之删除并加入 .gitignore:此前无法确认发布的 DLL 是否与当前 smtc.cpp 一致,改 .cpp 也会静默发布陈旧二进制。 Co-Authored-By: Claude --- .github/workflows/ci-release.yml | 52 ++++++++++++++++++ .gitignore | 4 ++ native/smtc/CMakeLists.txt | 40 ++++++++++++++ .../native/windows/x64/fpsmaster-smtc.dll | Bin 156672 -> 0 bytes .../native/windows/x86/fpsmaster-smtc.dll | Bin 123904 -> 0 bytes 5 files changed, 96 insertions(+) create mode 100644 native/smtc/CMakeLists.txt delete mode 100644 src/main/resources/native/windows/x64/fpsmaster-smtc.dll delete mode 100644 src/main/resources/native/windows/x86/fpsmaster-smtc.dll diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index a83a278d..a54951e7 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -23,7 +23,39 @@ env: ARTIFACT_SOURCE_TYPE: external_url jobs: + # Windows SMTC bridge DLL. The binaries are not committed to the repository — + # they are built here and injected into src/main/resources before packaging, + # so the shipped jar can never contain a stale binary built from older C++. + build-native: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Build fpsmaster-smtc (x64 + x86) + shell: pwsh + run: | + cmake -S native/smtc -B native/smtc/build-x64 -A x64 + cmake --build native/smtc/build-x64 --config Release + cmake -S native/smtc -B native/smtc/build-win32 -A Win32 + cmake --build native/smtc/build-win32 --config Release + + - name: Collect DLLs + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path dist/x64, dist/x86 | Out-Null + Copy-Item native/smtc/build-x64/Release/fpsmaster-smtc.dll dist/x64/ + Copy-Item native/smtc/build-win32/Release/fpsmaster-smtc.dll dist/x86/ + Get-ChildItem -Recurse dist | Select-Object FullName, Length + + - name: Upload native artifacts + uses: actions/upload-artifact@v4 + with: + name: smtc-native + path: dist + if-no-files-found: error + build: + needs: build-native runs-on: ubuntu-latest outputs: should_publish: ${{ steps.decision.outputs.should_publish }} @@ -133,6 +165,26 @@ jobs: if: steps.decision.outputs.should_build == 'true' uses: gradle/actions/setup-gradle@v3 + - name: Inject SMTC native libraries + if: steps.decision.outputs.should_build == 'true' + uses: actions/download-artifact@v4 + with: + name: smtc-native + path: src/main/resources/native/windows + + - name: Verify native libraries are present + if: steps.decision.outputs.should_build == 'true' + shell: bash + run: | + for arch in x64 x86; do + dll="src/main/resources/native/windows/$arch/fpsmaster-smtc.dll" + if [ ! -s "$dll" ]; then + echo "Missing or empty $dll — the jar would silently ship without SMTC" >&2 + exit 1 + fi + echo "$arch: $(stat -c%s "$dll") bytes, sha256 $(sha256sum "$dll" | awk '{print $1}')" + done + - name: Build with Gradle Wrapper if: steps.decision.outputs.should_build == 'true' shell: bash diff --git a/.gitignore b/.gitignore index 4e6b98b8..1ffa21a8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ remeasure.ps1 /usercache.json /usernamecache.json /FPSMaster Edge/ + +# SMTC 原生库由 CI 构建后注入(native/smtc/CMakeLists.txt),不提交二进制 +src/main/resources/native/windows/*/*.dll +native/smtc/build-*/ diff --git a/native/smtc/CMakeLists.txt b/native/smtc/CMakeLists.txt new file mode 100644 index 00000000..2bc09a10 --- /dev/null +++ b/native/smtc/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.20) +project(fpsmaster-smtc CXX) + +# Windows-only: the whole point of this target is the WinRT SMTC bridge. +if(NOT WIN32) + message(FATAL_ERROR "fpsmaster-smtc is a Windows-only target") +endif() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Architecture is selected by the generator platform, e.g. +# cmake -B build-x64 -A x64 +# cmake -B build-win32 -A Win32 +add_library(fpsmaster-smtc SHARED + smtc.cpp + smtc.def +) + +set_target_properties(fpsmaster-smtc PROPERTIES + PREFIX "" + OUTPUT_NAME "fpsmaster-smtc" +) + +target_compile_definitions(fpsmaster-smtc PRIVATE + UNICODE + _UNICODE + WIN32_LEAN_AND_MEAN + NOMINMAX +) + +if(MSVC) + # /EHsc: C++/WinRT throws; /MT: static CRT so the DLL does not need the + # VC++ redistributable on the player's machine. + target_compile_options(fpsmaster-smtc PRIVATE /EHsc /W3) + set_property(TARGET fpsmaster-smtc PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded") +endif() + +# WindowsApp.lib provides the WinRT activation/interop entry points. +target_link_libraries(fpsmaster-smtc PRIVATE WindowsApp) diff --git a/src/main/resources/native/windows/x64/fpsmaster-smtc.dll b/src/main/resources/native/windows/x64/fpsmaster-smtc.dll deleted file mode 100644 index a1b55b7ad6f05383821c65ba07eb3089e4a72657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156672 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 diff --git a/src/main/resources/native/windows/x86/fpsmaster-smtc.dll b/src/main/resources/native/windows/x86/fpsmaster-smtc.dll deleted file mode 100644 index 2cd0fdddba93050bc032414e5c9ebf6cd6634bd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123904 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�E6CC_kU^{e9_TjewfQD%za>91l@09G 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 NbYRY*!u{{Q{vWOwF%$p* From 0540a5ff6c0c7a3dfe587a10a9cd726d98a4aa43 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:28:20 -0700 Subject: [PATCH 17/22] =?UTF-8?q?fix(smtc):=20=E4=B8=93=E7=94=A8=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E6=8C=81=E6=9C=89=20WinRT=20=E5=A5=97=E9=97=B4?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E4=BC=A0=E5=85=A5=E7=9C=9F=E5=AE=9E=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E5=8F=A5=E6=9F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 套间状态是线程私有的:在游戏线程上 init_apartment 要么撞 RPC_E_CHANGED_MODE (别的模组已把该线程初始化成 STA)静默失败,要么把游戏线程永久并入 MTA。改为 所有 native 调用都走单线程 FPSMaster-SMTC,顺带把阻塞的 smtc_publish 从调用方 线程上摘下来(发布用最新快照覆盖,不排队)。 同时: - smtc_start 的 hwnd 改传 LWJGL 窗口句柄(反射 WindowsDisplay.hwnd),JNA 侧 由 long 改为 Pointer,x86 下 HWND 是 32 位,long 会传错宽度 - native 兜底的窗口搜索加上可见/无 owner/有标题过滤,并去掉非重入的函数内 static,避免绑到马上就被销毁的 Forge 启动画面窗口 - 实现 smtc_get_last_error 并在启动失败时打进日志,此前它是空实现且没绑进 JNA - init_apartment 成功时才在 smtc_close 里 uninit_apartment Co-Authored-By: Claude --- native/smtc/smtc.cpp | 126 ++++++++++--- .../WindowsSystemMediaTransportControls.java | 177 +++++++++++++----- 2 files changed, 224 insertions(+), 79 deletions(-) diff --git a/native/smtc/smtc.cpp b/native/smtc/smtc.cpp index 15105618..44990e8e 100644 --- a/native/smtc/smtc.cpp +++ b/native/smtc/smtc.cpp @@ -1,12 +1,10 @@ // fpsmaster-smtc - Windows System Media Transport Controls bridge DLL // C++/WinRT native library for FPSMaster Edge music integration. // -// Build: open in Visual Studio 2022 with "Universal Windows Platform" workload, -// or build from command line: -// cl /EHsc /std:c++17 /DUNICODE /D_UNICODE smtc.cpp /LD /EHsc /MD -// /reference "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd" -// /FU "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll" -// /link /OUT:fpsmaster-smtc.dll +// Build: see CMakeLists.txt in this directory (cmake -A x64|Win32 && cmake --build). +// CI builds both architectures in .github/workflows/ci-release.yml; the +// resulting DLLs are injected into src/main/resources/native/windows/ at +// package time and are deliberately NOT committed to the repository. // // The DLL exports a tiny C ABI that the Java side (JNA) calls. // Callbacks from SMTC button events are dispatched to a function pointer @@ -16,10 +14,17 @@ // ISystemMediaTransportControlsInterop::GetForWindow(hwnd) path. The UWP // GetForCurrentView() API requires a CoreWindow and therefore always fails // in the Minecraft JVM; it is deliberately not used here. +// +// Threading: every export is called from a single dedicated Java thread +// ("FPSMaster-SMTC"), never from the game thread. That thread owns the WinRT +// apartment this DLL initializes, so the game thread is never joined to an +// apartment it did not ask for. #include #include #include +#include +#include #include // WinRT headers @@ -44,27 +49,61 @@ static ControlCallback g_callback = nullptr; static SystemMediaTransportControls g_smtc = nullptr; static winrt::event_token g_buttonToken{}; static bool g_initialized = false; +static bool g_apartmentOwned = false; + +// Last failure reason, surfaced to Java through smtc_get_last_error so a bug +// report can tell "no window found" apart from "GetForWindow returned E_FAIL". +static wchar_t g_lastError[256] = {0}; + +static void set_last_error(const wchar_t* msg) { + if (!msg) { + g_lastError[0] = 0; + return; + } + wcsncpy_s(g_lastError, msg, _TRUNCATE); +} + +static void set_last_error_hr(const wchar_t* msg, HRESULT hr) { + swprintf_s(g_lastError, L"%s (hr=0x%08X)", msg, (unsigned int)hr); +} // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- -// Find a visible top-level window owned by this process. GetForWindow needs a -// real HWND; the Java side passes 0 when it has no window handle to hand over. +namespace { + +struct WindowSearch { + DWORD pid; + HWND result; +}; + +// Only accept a real top-level application window: owned by this process, +// visible, no owner window, and with a caption. Without these filters the very +// first EnumWindows hit during Forge start-up can be the splash screen or a +// stray AWT frame, and SMTC would bind its session to a window that is about to +// be destroyed. +BOOL CALLBACK enum_window_proc(HWND hwnd, LPARAM lParam) { + auto* search = reinterpret_cast(lParam); + DWORD wpid = 0; + GetWindowThreadProcessId(hwnd, &wpid); + if (wpid != search->pid) return TRUE; + if (!IsWindowVisible(hwnd)) return TRUE; + if (GetWindow(hwnd, GW_OWNER) != nullptr) return TRUE; + if (GetWindowTextLengthW(hwnd) == 0) return TRUE; + + search->result = hwnd; + return FALSE; +} + +} // namespace + +// Find a top-level window owned by this process. GetForWindow needs a real +// HWND; the Java side passes 0 only when it could not obtain the LWJGL handle. static HWND find_process_window() { - static HWND found = nullptr; - found = nullptr; - DWORD pid = GetCurrentProcessId(); - EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL { - DWORD wpid = 0; - GetWindowThreadProcessId(hwnd, &wpid); - if (wpid == (DWORD)lParam && IsWindowVisible(hwnd)) { - found = hwnd; - return FALSE; - } - return TRUE; - }, (LPARAM)pid); - return found; + WindowSearch search{GetCurrentProcessId(), nullptr}; + EnumWindows(enum_window_proc, reinterpret_cast(&search)); + return search.result; } // --------------------------------------------------------------------------- @@ -78,15 +117,32 @@ extern "C" { /// Returns 1 on success, 0 on failure (so the Java side can surface it). __declspec(dllexport) int __cdecl smtc_start(HWND hwnd) { if (g_initialized) return 1; + set_last_error(nullptr); try { - // Initialize WinRT apartment (MTA so callbacks can fire on any thread) - winrt::init_apartment(winrt::apartment_type::multi_threaded); + // Initialize the WinRT apartment on the calling thread (the dedicated + // Java SMTC thread). MTA so button callbacks can fire on any thread and + // we never need a message pump. + try { + winrt::init_apartment(winrt::apartment_type::multi_threaded); + g_apartmentOwned = true; + } catch (winrt::hresult_error const& e) { + // RPC_E_CHANGED_MODE means the thread was already initialized as an + // STA by someone else. SMTC works from an STA too, so carry on — + // but do not claim ownership, since we must not uninitialize it. + if (static_cast(e.code()) != RPC_E_CHANGED_MODE) { + set_last_error_hr(L"init_apartment failed", static_cast(e.code())); + g_initialized = false; + return 0; + } + g_apartmentOwned = false; + } HWND target = hwnd; if (target == nullptr) { target = find_process_window(); } if (target == nullptr) { + set_last_error(L"no top-level window found for this process"); g_initialized = false; return 0; } @@ -99,11 +155,13 @@ __declspec(dllexport) int __cdecl smtc_start(HWND hwnd) { winrt::guid_of(), winrt::put_abi(controls)); if (FAILED(hr)) { + set_last_error_hr(L"GetForWindow failed", hr); g_initialized = false; return 0; } g_smtc = controls; if (!g_smtc) { + set_last_error(L"GetForWindow returned a null interface"); g_initialized = false; return 0; } @@ -138,7 +196,12 @@ __declspec(dllexport) int __cdecl smtc_start(HWND hwnd) { g_initialized = true; return 1; + } catch (winrt::hresult_error const& e) { + set_last_error_hr(L"smtc_start threw", static_cast(e.code())); + g_initialized = false; + return 0; } catch (...) { + set_last_error(L"smtc_start threw an unknown exception"); g_initialized = false; return 0; } @@ -241,14 +304,21 @@ __declspec(dllexport) void __cdecl smtc_close() { g_initialized = false; } g_callback = nullptr; + // Only leave the apartment if smtc_start is the one that entered it. + if (g_apartmentOwned) { + g_apartmentOwned = false; + try { + winrt::uninit_apartment(); + } catch (...) { + } + } } -/// Get the last error message (for debugging). +/// Copy the last failure reason into buf (wide, NUL-terminated). Empty if the +/// last operation succeeded. __declspec(dllexport) void __cdecl smtc_get_last_error(wchar_t* buf, int bufLen) { - (void)buf; - (void)bufLen; - // Simplified: just clear - if (buf && bufLen > 0) buf[0] = 0; + if (!buf || bufLen <= 0) return; + wcsncpy_s(buf, (size_t)bufLen, g_lastError, _TRUNCATE); } } // extern "C" \ No newline at end of file diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java index 595c625b..2cc68c82 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java @@ -2,14 +2,21 @@ import com.sun.jna.Callback; import com.sun.jna.Library; +import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.NativeLibrary; +import com.sun.jna.Pointer; import com.sun.jna.WString; import top.fpsmaster.modules.logger.ClientLogger; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -24,12 +31,13 @@ final class WindowsSystemMediaTransportControls implements SystemMediaTransportControls { private interface SmtcNative extends Library { - int smtc_start(long hwnd); + int smtc_start(Pointer hwnd); void smtc_set_callback(ControlCallback cb); void smtc_publish(WString title, WString artist, WString album, long positionMs, long durationMs, boolean playing, boolean hasCurrentTrack, byte[] artworkData, int artworkLen); void smtc_set_buttons(boolean playPause, boolean next, boolean prev); void smtc_close(); + void smtc_get_last_error(Pointer buf, int bufLen); } private interface ControlCallback extends Callback { @@ -39,7 +47,21 @@ private interface ControlCallback extends Callback { private static final AtomicReference API = new AtomicReference<>(null); private static boolean extractionAttempted = false; + /** + * Every native call goes through this single thread. WinRT apartment state is per-thread: + * initializing it on the game thread would either fail (when something already made that + * thread an STA) or permanently join the game thread to the MTA. Owning a thread of our own + * also keeps the blocking {@code smtc_publish} off the caller's thread. + */ + private static final ExecutorService EXEC = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r, "FPSMaster-SMTC"); + t.setDaemon(true); + return t; + }); + private final AtomicBoolean available = new AtomicBoolean(false); + /** Latest snapshot waiting to be published; newer ones overwrite older, so nothing queues up. */ + private final AtomicReference pending = new AtomicReference<>(null); private final MediaControlListener listener; private final ControlCallback callback; @@ -111,80 +133,133 @@ private static void extractAndLoad() throws Exception { NativeLibrary.addSearchPath("fpsmaster-smtc", extractDir.getAbsolutePath()); } - private void loadAndInit() { + /** + * The HWND of the LWJGL game window. SMTC's desktop interop binds the session to a specific + * window, and letting the native side guess via EnumWindows can pick the Forge splash screen, + * which is destroyed moments later. LWJGL 2 keeps the handle private, hence the reflection; + * failing here is not fatal — the native side falls back to its (filtered) window search. + */ + private static Pointer resolveGameWindow() { try { - SmtcNative nativeLib = resolveNative(); - if (nativeLib == null) { - return; - } - nativeLib.smtc_set_callback(callback); - int status = nativeLib.smtc_start(0L); - if (status != 1) { - ClientLogger.warn("SMTC native start returned failure status, SMTC unavailable"); - return; + Method getImpl = Class.forName("org.lwjgl.opengl.Display").getDeclaredMethod("getImplementation"); + getImpl.setAccessible(true); + Object impl = getImpl.invoke(null); + if (impl == null || !impl.getClass().getName().endsWith("WindowsDisplay")) { + return null; } - available.set(true); + Field hwndField = impl.getClass().getDeclaredField("hwnd"); + hwndField.setAccessible(true); + long hwnd = hwndField.getLong(impl); + return hwnd == 0L ? null : new Pointer(hwnd); } catch (Throwable t) { - ClientLogger.error("SMTC native start failed: " + t.getMessage()); - available.set(false); + ClientLogger.warn("SMTC could not resolve the LWJGL window handle: " + t.getMessage()); + return null; } } - @Override - public void start() { - if (!available.get()) { - return; - } + /** Reads the native failure reason; empty when the DLL has nothing to report. */ + private static String lastNativeError(SmtcNative nativeLib) { try { - SmtcNative nativeLib = API.get(); - if (nativeLib != null) { - nativeLib.smtc_start(0L); - } + Memory buf = new Memory(256L * Native.WCHAR_SIZE); + nativeLib.smtc_get_last_error(buf, 256); + String msg = buf.getWideString(0); + return msg == null ? "" : msg; } catch (Throwable t) { - ClientLogger.error("SMTC start failed: " + t.getMessage()); + return ""; } } + private void loadAndInit() { + // Resolve the window handle on the caller's thread: LWJGL's Display state belongs to the + // game thread, and the native call itself is what has to move off it. + final Pointer hwnd = resolveGameWindow(); + EXEC.execute(() -> { + try { + SmtcNative nativeLib = resolveNative(); + if (nativeLib == null) { + return; + } + nativeLib.smtc_set_callback(callback); + int status = nativeLib.smtc_start(hwnd); + if (status != 1) { + String err = lastNativeError(nativeLib); + ClientLogger.warn("SMTC native start failed, SMTC unavailable" + + (err.isEmpty() ? "" : ": " + err)); + return; + } + available.set(true); + } catch (Throwable t) { + ClientLogger.error("SMTC native start failed: " + t.getMessage()); + available.set(false); + } + }); + } + + @Override + public void start() { + // loadAndInit already ran smtc_start on the SMTC thread and the native side is idempotent; + // nothing to redo here. + } + @Override public void publish(MediaPlaybackSnapshot snapshot) { - SmtcNative nativeLib = API.get(); - if (!available.get() || nativeLib == null || snapshot == null) { + if (!available.get() || snapshot == null) { return; } - try { - boolean hasTrack = snapshot.hasCurrentTrack; - nativeLib.smtc_set_buttons(hasTrack, hasTrack, hasTrack); - byte[] art = snapshot.artworkPng; - nativeLib.smtc_publish( - new WString(snapshot.title), - new WString(snapshot.artist), - new WString(snapshot.album), - snapshot.positionMs, - snapshot.durationMs, - snapshot.playing, - hasTrack, - art, - art == null ? 0 : art.length - ); - } catch (Throwable t) { - ClientLogger.error("SMTC publish failed: " + t.getMessage()); + // Publishing is a blocking WinRT call. Hand the newest snapshot to the SMTC thread and + // return immediately; if one is still in flight the newer snapshot simply replaces it. + boolean queued = pending.getAndSet(snapshot) != null; + if (queued) { + return; } + EXEC.execute(() -> { + MediaPlaybackSnapshot latest = pending.getAndSet(null); + SmtcNative nativeLib = API.get(); + if (latest == null || nativeLib == null || !available.get()) { + return; + } + try { + boolean hasTrack = latest.hasCurrentTrack; + nativeLib.smtc_set_buttons(hasTrack, hasTrack, hasTrack); + byte[] art = latest.artworkPng; + nativeLib.smtc_publish( + new WString(latest.title), + new WString(latest.artist), + new WString(latest.album), + latest.positionMs, + latest.durationMs, + latest.playing, + hasTrack, + art, + art == null ? 0 : art.length + ); + } catch (Throwable t) { + ClientLogger.error("SMTC publish failed: " + t.getMessage()); + } + }); } @Override public void close() { - if (!available.get()) { + if (!available.compareAndSet(true, false)) { return; } + pending.set(null); + // Wait briefly: this runs during client shutdown and the session should be released before + // the process exits, but a hung native call must not hold the game open. try { - SmtcNative nativeLib = API.get(); - if (nativeLib != null) { - nativeLib.smtc_close(); - } + EXEC.submit(() -> { + try { + SmtcNative nativeLib = API.get(); + if (nativeLib != null) { + nativeLib.smtc_close(); + } + } catch (Throwable t) { + ClientLogger.error("SMTC close failed: " + t.getMessage()); + } + }).get(2, TimeUnit.SECONDS); } catch (Throwable t) { - ClientLogger.error("SMTC close failed: " + t.getMessage()); - } finally { - available.set(false); + ClientLogger.warn("SMTC close did not finish in time: " + t.getMessage()); } } From 7e1ae61134b192da323c4a0f2615bcc1ad80d415 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:28:20 -0700 Subject: [PATCH 18/22] =?UTF-8?q?fix(saturation):=20=E9=87=8D=E5=AE=9A?= =?UTF-8?q?=E5=90=91=20pre(FOOD)=20=E8=80=8C=E4=B8=8D=E6=98=AF=E5=9C=A8=20?= =?UTF-8?q?HEAD=20=E5=8F=96=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renderFood 第一句就是 if (pre(FOOD)) return;,在 HEAD 取消会让 Pre(FOOD) 事件 根本不派发,别的 HUD 模组的钩子静默失效。改为重定向这次 pre 调用:事件照常触发, 别人已取消时把占位交给他们,只有我们真正接管时才补 right_height += 10。 Co-Authored-By: Claude --- .../forge/mixin/MixinGuiIngameForge.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java index d8ed290a..9d69ca49 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java @@ -3,6 +3,7 @@ import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraftforge.client.GuiIngameForge; +import net.minecraftforge.client.event.RenderGameOverlayEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -42,14 +43,31 @@ private void renderTooltipPost(ScaledResolution sr, float partialTicks, Callback EventDispatcher.dispatchEvent(new EventRender2D(partialTicks)); } - @Inject(method = "renderFood", at = @At("HEAD"), cancellable = true, remap = false) - private void hideVanillaFood(int width, int height, CallbackInfo callbackInfo) { - if (SaturationDisplay.using) { - // renderFood 末尾的 right_height += 10 会在 cancel 时被跳过, - // 手动补上以免 renderHealthMount/renderAir 整体下移 10px。 - right_height += 10; - callbackInfo.cancel(); + @Shadow(remap = false) + private boolean pre(RenderGameOverlayEvent.ElementType type) { + throw new AssertionError(); + } + + /** + * 接管原版饥饿条。 + * + *

不在 HEAD 直接 cancel:renderFood 的第一句是 {@code if (pre(FOOD)) return;},在它之前 + * cancel 会让 Pre(FOOD) 事件根本不派发,别的 HUD 模组的钩子就静默失效了。改成重定向这次 + * {@code pre} 调用:事件照常触发,别人已经取消时把占位交给他们,只有我们真正接管时才补上 + * renderFood 末尾那个被跳过的 {@code right_height += 10},否则氧气条和坐骑血条会错位。 + */ + @Redirect(method = "renderFood", at = @At(value = "INVOKE", + target = "Lnet/minecraftforge/client/GuiIngameForge;pre(Lnet/minecraftforge/client/event/RenderGameOverlayEvent$ElementType;)Z"), + remap = false) + private boolean fpsmaster$takeOverFood(GuiIngameForge self, RenderGameOverlayEvent.ElementType type) { + if (pre(type)) { + return true; + } + if (!SaturationDisplay.using) { + return false; } + right_height += 10; + return true; } @Redirect(method = "renderTitle", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;translate(FFF)V")) From 56cc02962d3c9d575a4ef71e69ab8c0bd5712d5e Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 22:30:29 -0700 Subject: [PATCH 19/22] =?UTF-8?q?build(smtc):=20=E6=94=B9=E7=94=A8=20C++20?= =?UTF-8?q?=20=E7=BC=96=E8=AF=91=E5=8E=9F=E7=94=9F=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C++/WinRT 头文件会拉协程支持,/std:c++17 下解析到 , 当前 MSVC 直接报 STL1011 错误(CI 实测 x64/Win32 均失败)。C++20 走标准 。 Co-Authored-By: Claude --- native/smtc/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/native/smtc/CMakeLists.txt b/native/smtc/CMakeLists.txt index 2bc09a10..97b4a0cb 100644 --- a/native/smtc/CMakeLists.txt +++ b/native/smtc/CMakeLists.txt @@ -6,7 +6,10 @@ if(NOT WIN32) message(FATAL_ERROR "fpsmaster-smtc is a Windows-only target") endif() -set(CMAKE_CXX_STANDARD 17) +# C++20, not 17: C++/WinRT's headers pull in coroutine support, and under /std:c++17 +# that resolves to , which current MSVC rejects outright +# (STL1011). C++20 gives it the standard instead. +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Architecture is selected by the generator platform, e.g. From 352e8bb3951d4623b033bbaa1bd85f14559cc5ce Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 23:26:59 -0700 Subject: [PATCH 20/22] =?UTF-8?q?refactor(saturation):=20=E5=8F=AA?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=A5=B1=E5=92=8C=E5=BA=A6=EF=BC=8C=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E6=8E=A5=E7=AE=A1=E5=8E=9F=E7=89=88=E9=A5=A5=E9=A5=BF?= =?UTF-8?q?=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原实现取消原版 renderFood,然后用同一套 icons.png 贴图把饥饿条原样重画一遍, 右边挂一个饱和度数值。真正新增的信息只有那个数值,但为了重画饥饿条付出的代价是: right_height 补偿、Pre/Post(FOOD) 事件失效、图标 UV 采样、与第三方 HUD 模组冲突。 改为只画饱和度本身(一根 0-20 的条加数值),原版饥饿条照常渲染。随之删除: - MixinGuiIngameForge 对 renderFood 的接管(连同 right_height 影子字段) - Images 里为缩放采样加的 UV 重载(恢复成原来的 private 方法) 新增 BarColor 设置,默认位置移到饥饿条上方。 实机验证:原版饥饿条恢复正常,饱和度条在 HUD scale=2 下不再糊。 Co-Authored-By: Claude --- .../impl/interfaces/SaturationDisplay.java | 8 ++- .../forge/mixin/MixinGuiIngameForge.java | 33 ---------- .../impl/SaturationDisplayComponent.java | 64 +++++++++---------- .../fpsmaster/utils/render/draw/Images.java | 23 ++----- 4 files changed, 40 insertions(+), 88 deletions(-) diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java index 38213657..e37ebd6a 100644 --- a/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java +++ b/src/main/java/top/fpsmaster/features/impl/interfaces/SaturationDisplay.java @@ -2,15 +2,21 @@ import top.fpsmaster.features.impl.InterfaceModule; import top.fpsmaster.features.manager.Category; +import top.fpsmaster.features.settings.impl.ColorSetting; + +import java.awt.Color; /** - * Replaces the vanilla food HUD with a movable saturation display. + * 把原版隐藏的饱和度显示成一根条加数值。原版饥饿条照常渲染,不受影响。 */ public class SaturationDisplay extends InterfaceModule { public static boolean using; + public static ColorSetting barColor = new ColorSetting("BarColor", new Color(255, 190, 60)); + public SaturationDisplay() { super("SaturationDisplay", Category.Interface, Trait.BACKGROUND, Trait.TEXT); + addSettings(barColor); } @Override diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java index 9d69ca49..d099e1ca 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinGuiIngameForge.java @@ -3,7 +3,6 @@ import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraftforge.client.GuiIngameForge; -import net.minecraftforge.client.event.RenderGameOverlayEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -15,14 +14,9 @@ import top.fpsmaster.event.events.EventMotionBlur; import top.fpsmaster.event.events.EventRender2D; import top.fpsmaster.features.impl.interfaces.CustomTitles; -import top.fpsmaster.features.impl.interfaces.SaturationDisplay; -import org.spongepowered.asm.mixin.Shadow; @Mixin(GuiIngameForge.class) public class MixinGuiIngameForge { - @Shadow(remap = false) - public static int right_height; - @Inject(method = "renderGameOverlay", at = @At("HEAD")) private void fpsmasterBeginHud(float partialTicks, CallbackInfo ci) { if (BenchmarkMode.ACTIVE) { @@ -43,33 +37,6 @@ private void renderTooltipPost(ScaledResolution sr, float partialTicks, Callback EventDispatcher.dispatchEvent(new EventRender2D(partialTicks)); } - @Shadow(remap = false) - private boolean pre(RenderGameOverlayEvent.ElementType type) { - throw new AssertionError(); - } - - /** - * 接管原版饥饿条。 - * - *

不在 HEAD 直接 cancel:renderFood 的第一句是 {@code if (pre(FOOD)) return;},在它之前 - * cancel 会让 Pre(FOOD) 事件根本不派发,别的 HUD 模组的钩子就静默失效了。改成重定向这次 - * {@code pre} 调用:事件照常触发,别人已经取消时把占位交给他们,只有我们真正接管时才补上 - * renderFood 末尾那个被跳过的 {@code right_height += 10},否则氧气条和坐骑血条会错位。 - */ - @Redirect(method = "renderFood", at = @At(value = "INVOKE", - target = "Lnet/minecraftforge/client/GuiIngameForge;pre(Lnet/minecraftforge/client/event/RenderGameOverlayEvent$ElementType;)Z"), - remap = false) - private boolean fpsmaster$takeOverFood(GuiIngameForge self, RenderGameOverlayEvent.ElementType type) { - if (pre(type)) { - return true; - } - if (!SaturationDisplay.using) { - return false; - } - right_height += 10; - return true; - } - @Redirect(method = "renderTitle", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;translate(FFF)V")) public void drawString(float x, float y, float z) { GlStateManager.translate(x + CustomTitles.getX(), y + CustomTitles.getY(), z); diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java index 2ce8ef1d..c9534d69 100644 --- a/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java +++ b/src/main/java/top/fpsmaster/ui/custom/impl/SaturationDisplayComponent.java @@ -1,37 +1,40 @@ package top.fpsmaster.ui.custom.impl; -import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.ResourceLocation; import top.fpsmaster.features.impl.interfaces.SaturationDisplay; import top.fpsmaster.ui.custom.Component; import top.fpsmaster.ui.custom.Position; -import top.fpsmaster.utils.render.draw.Images; +import top.fpsmaster.utils.render.draw.Rects; import java.awt.Color; import static top.fpsmaster.utils.core.Utility.mc; -/** Draws the food icons and the exact saturation value in the HUD editor coordinate space. */ +/** + * 饱和度:一根 0–20 的条加精确数值。 + * + *

只画饱和度本身,不碰原版饥饿条——饱和度是原版隐藏的数值,把它显示出来不需要接管一个 + * 本来就正常渲染的 HUD 元素。 + */ public class SaturationDisplayComponent extends Component { - private static final ResourceLocation ICONS = new ResourceLocation("textures/gui/icons.png"); - private static final float ICON_SIZE = 9f; - private static final float ICON_ROW_WIDTH = 90f; - private static final float VALUE_GAP = 4f; + private static final float MAX_SATURATION = 20f; + private static final float BAR_WIDTH = 40f; + private static final float BAR_HEIGHT = 4f; + private static final float GAP = 4f; + private static final float PADDING = 2f; + private static final Color TRACK = new Color(0, 0, 0, 120); public SaturationDisplayComponent() { super(SaturationDisplay.class); position = Position.RB; - // Vanilla food HUD right edge is 10 px from the screen edge; HUD coordinates are doubled. + // 默认落在原版饥饿条上方,视觉上仍然和饥饿相关,但不遮挡它。 x = 0.02f; - y = 0.075f; + y = 0.11f; allowScale = true; } @Override public void measure() { - String value = saturationText(); - width = ICON_ROW_WIDTH + VALUE_GAP + getStringWidth(14, value) + 4f; + width = PADDING * 2f + BAR_WIDTH + GAP + getStringWidth(14, saturationText()); height = 12f; } @@ -44,30 +47,21 @@ public void draw(float x, float y) { drawRect(x, y, width, height, mod.backgroundColor.getColor()); - int food = Math.max(0, Math.min(20, mc.thePlayer.getFoodStats().getFoodLevel())); - GlStateManager.enableBlend(); - GlStateManager.color(1f, 1f, 1f, 1f); - mc.getTextureManager().bindTexture(ICONS); - for (int icon = 0; icon < 10; icon++) { - float iconX = x + icon * ICON_SIZE * scale; - drawIcon(iconX, y + 1f * scale, 16, 27); - int halfFood = food - icon * 2; - if (halfFood >= 2) { - drawIcon(iconX, y + 1f * scale, 52, 27); - } else if (halfFood == 1) { - drawIcon(iconX, y + 1f * scale, 61, 27); - } - } - GlStateManager.disableBlend(); + float saturation = mc.thePlayer.getFoodStats().getSaturationLevel(); + saturation = Math.max(0f, Math.min(MAX_SATURATION, saturation)); - drawString(14, saturationText(), x + ICON_ROW_WIDTH * scale + VALUE_GAP * scale, y + 1f * scale, Color.WHITE.getRGB()); - GlStateManager.color(1f, 1f, 1f, 1f); - } + float barWidth = BAR_WIDTH * scale; + float barHeight = BAR_HEIGHT * scale; + float barX = x + PADDING * scale; + float barY = y + (height * scale - barHeight) / 2f; + + Rects.fill(barX, barY, barWidth, barHeight, TRACK); + if (saturation > 0f) { + Rects.fill(barX, barY, barWidth * (saturation / MAX_SATURATION), barHeight, + SaturationDisplay.barColor.getColor()); + } - private void drawIcon(float x, float y, int textureX, int textureY) { - // 四边形按 scale 放大,但采样跨度固定 ICON_SIZE,否则会把 icons.png 里相邻的图标一起采进来 - Images.drawModalRectWithCustomSizedTexture(x, y, textureX, textureY, - ICON_SIZE * scale, ICON_SIZE * scale, ICON_SIZE, ICON_SIZE, 256f, 256f); + drawString(14, saturationText(), barX + barWidth + GAP * scale, y + 1f * scale, Color.WHITE.getRGB()); } private String saturationText() { diff --git a/src/main/java/top/fpsmaster/utils/render/draw/Images.java b/src/main/java/top/fpsmaster/utils/render/draw/Images.java index 5beae68b..9e2fa54d 100644 --- a/src/main/java/top/fpsmaster/utils/render/draw/Images.java +++ b/src/main/java/top/fpsmaster/utils/render/draw/Images.java @@ -166,30 +166,15 @@ public static void scaleEnd() { glPopMatrix(); } - /** - * 全 float 版本的自定义尺寸纹理四边形,保留亚像素坐标。坐标按 HUD 组件传入的已缩放值使用。 - * - *

注意采样区域与四边形尺寸相同:只适用于"渲染尺寸 == 源图尺寸"的场景。缩放绘制精灵图请用 - * {@link #drawModalRectWithCustomSizedTexture(float, float, float, float, float, float, float, float, float, float)} - * 单独传 UV 跨度,否则放大四边形会把相邻精灵一起采样进来。 - */ - public static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float textureWidth, float textureHeight) { - drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, width, height, textureWidth, textureHeight); - } - - /** - * 同上,但四边形尺寸(width/height)与纹理采样跨度(uWidth/vHeight)解耦, - * 用于把固定大小的精灵按任意比例放大绘制。 - */ - public static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float uWidth, float vHeight, float textureWidth, float textureHeight) { + private static void drawModalRectWithCustomSizedTexture(float x, float y, float u, float v, float width, float height, float textureWidth, float textureHeight) { float f = 1.0F / textureWidth; float f1 = 1.0F / textureHeight; net.minecraft.client.renderer.Tessellator tessellator = net.minecraft.client.renderer.Tessellator.getInstance(); net.minecraft.client.renderer.WorldRenderer bufferbuilder = tessellator.getWorldRenderer(); bufferbuilder.begin(7, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); - bufferbuilder.pos(x, y + height, 0.0D).tex(u * f, (v + vHeight) * f1).endVertex(); - bufferbuilder.pos(x + width, y + height, 0.0D).tex((u + uWidth) * f, (v + vHeight) * f1).endVertex(); - bufferbuilder.pos(x + width, y, 0.0D).tex((u + uWidth) * f, v * f1).endVertex(); + bufferbuilder.pos(x, y + height, 0.0D).tex(u * f, (v + height) * f1).endVertex(); + bufferbuilder.pos(x + width, y + height, 0.0D).tex((u + width) * f, (v + height) * f1).endVertex(); + bufferbuilder.pos(x + width, y, 0.0D).tex((u + width) * f, v * f1).endVertex(); bufferbuilder.pos(x, y, 0.0D).tex(u * f, v * f1).endVertex(); tessellator.draw(); } From 5a10ff2679a757c4cd4ec828997b20ae3cff804c Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sat, 1 Aug 2026 23:26:59 -0700 Subject: [PATCH 21/22] =?UTF-8?q?fix(fog):=20=E4=B8=80=E5=B9=B6=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E5=A4=A9=E7=A9=BA/=E6=B8=85=E5=B1=8F=E8=89=B2?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=A4=8D=E7=94=A8=E5=8E=9F=E7=89=88=20fog=20?= =?UTF-8?q?buffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 雾在 1.8.9 里是两套状态:setupFog 设 GL_FOG_COLOR 只影响几何体,而天空和清屏色 走的是 EntityRenderer.fogColorRed/Green/Blue(renderWorldPass 拿它 glClearColor, renderSky 拿它画地平线雾带)。此前只改了前者,结果是方块被自定义雾吃掉、天空还是 原版蓝,实机看上去割裂。现在注入 updateFogColor 一并覆盖。 顺带: - 覆盖条件抽成 fpsmaster$shouldOverrideFog(),两处注入共用同一套判断 - 雾色 buffer 改用原版 setFogColorBuffer(它写的是 EntityRenderer 自己缓存的 direct buffer),删掉上一版自己加的静态缓存 - 删掉 GlStateManager.color(1,1,1,1) 复位:它是为配套已删除的顶点色写入而加的, 现在这里不再动顶点色,留着反而会覆盖调用方的颜色状态 已知残留:地平线仍有一条原版天空色,那来自 WorldClient.getSkyColor,是独立于 fogColor 的第三处颜色,本次未动。 Co-Authored-By: Claude --- .../forge/mixin/MixinEntityRenderer.java | 75 ++++++++++++------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java index 464b3263..541d0fd4 100644 --- a/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java +++ b/src/main/java/top/fpsmaster/forge/mixin/MixinEntityRenderer.java @@ -306,38 +306,61 @@ public void freelook(float partialTicks, long nanoTime, CallbackInfo ci) { FreeLook.overrideMouse(); } + @Shadow + private float fogColorRed; + @Shadow + private float fogColorGreen; + @Shadow + private float fogColorBlue; + + @Shadow + private FloatBuffer setFogColorBuffer(float red, float green, float blue, float alpha) { + throw new AssertionError(); + } + + /** + * CustomFog 是否应该接管当前这一帧的雾。 + * + *

失明药水那条是硬性的:原版会把雾强制成极短的线性雾,覆盖它等于解除视野限制, + * 在服务器上属于优势而不是外观改动。 + */ @Unique - private static FloatBuffer fpsmaster$fogColorBuffer; + private boolean fpsmaster$shouldOverrideFog() { + if (!CustomFog.using) return false; + if (mc.thePlayer == null) return false; + if (mc.thePlayer.isPotionActive(Potion.blindness)) return false; + if (!CustomFog.affectWater.getValue() && mc.thePlayer.isInsideOfMaterial(Material.water)) return false; + if (!CustomFog.affectLava.getValue() && mc.thePlayer.isInsideOfMaterial(Material.lava)) return false; + return true; + } + + /** + * 天空和清屏色走的是 fogColorRed/Green/Blue 这三个字段(renderWorldPass 拿它 glClearColor, + * renderSky 拿它画天空和地平线的雾带),跟 setupFog 里的 GL_FOG_COLOR 是两套状态。只改后者 + * 会得到"方块被自定义雾吃掉、天空还是原版蓝"的割裂画面,所以这里一并覆盖。 + */ + @Inject(method = "updateFogColor", at = @At("RETURN")) + private void overrideFogColor(float partialTicks, CallbackInfo ci) { + if (!fpsmaster$shouldOverrideFog()) return; + java.awt.Color fogColor = CustomFog.color.getColor(); + fogColorRed = fogColor.getRed() / 255f; + fogColorGreen = fogColor.getGreen() / 255f; + fogColorBlue = fogColor.getBlue() / 255f; + } @Inject(method = "setupFog", at = @At("RETURN")) private void overrideFog(int startCoords, float partialTicks, CallbackInfo ci) { - if (!CustomFog.using) return; - if (mc.thePlayer == null) return; - - // 失明药水:原版强制成极短线性雾,覆盖它会变成服务器判定上的优势,跳过 - if (mc.thePlayer.isPotionActive(Potion.blindness)) return; + if (!fpsmaster$shouldOverrideFog()) return; - // Check if in water or lava — only override if the user opted in - if (!CustomFog.affectWater.getValue() && mc.thePlayer.isInsideOfMaterial(net.minecraft.block.material.Material.water)) return; - if (!CustomFog.affectLava.getValue() && mc.thePlayer.isInsideOfMaterial(net.minecraft.block.material.Material.lava)) return; - - // 雾色只能用 glFog(GL_FOG_COLOR, buffer) 设置,不能走顶点色 + // 雾色只能用 glFog(GL_FOG_COLOR, buffer) 设置,不能走顶点色。 + // 复用原版的 setFogColorBuffer:它写的是 EntityRenderer 自己缓存的 direct buffer, + // 而 setupFog 每帧要跑好几次,这里再新建 buffer 会持续制造 direct 内存分配。 java.awt.Color fogColor = CustomFog.color.getColor(); - FloatBuffer fogColorBuffer = fpsmaster$fogColorBuffer; - if (fogColorBuffer == null) { - // setupFog 每帧被调用多次,direct buffer 只分配一次后复用(原版同样缓存 fogColorBuffer) - fogColorBuffer = BufferUtils.createFloatBuffer(4); - fpsmaster$fogColorBuffer = fogColorBuffer; - } - fogColorBuffer.clear(); - fogColorBuffer.put(fogColor.getRed() / 255f) - .put(fogColor.getGreen() / 255f) - .put(fogColor.getBlue() / 255f) - .put(1.0f) - .flip(); - GL11.glFog(GL11.GL_FOG_COLOR, fogColorBuffer); - // 复位顶点色,避免残留颜色污染后续 renderSky/云/实体渲染 - GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glFog(GL11.GL_FOG_COLOR, setFogColorBuffer( + fogColor.getRed() / 255f, + fogColor.getGreen() / 255f, + fogColor.getBlue() / 255f, + 1.0f)); if (CustomFog.fogMode.isMode("Linear")) { GlStateManager.setFog(GL11.GL_LINEAR); From 1da11ee9bfb36afb2e09d8315ccbc4ec32b981b5 Mon Sep 17 00:00:00 2001 From: gaoyu06 Date: Sun, 2 Aug 2026 00:14:01 -0700 Subject: [PATCH 22/22] =?UTF-8?q?perf(music):=20=E6=8A=8A=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E4=B8=8B=E8=BD=BD=E7=A7=BB=E5=87=BA=E4=B8=B2=E8=A1=8C?= =?UTF-8?q?=E8=A7=A3=E7=A0=81=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IMG_EXEC 是单线程,约束来自 AWT——macOS(尤其 Rosetta) 下并发调 CoreGraphics 会崩。 但 HTTP 下载没有这个约束,却跟着一起排队:一次封面下载超时(连接 10s + 读 15s)会把 后面所有解码堵死,扫码登录的二维码明明不需要联网也要跟着等最多 25 秒。 拆成两个池:NET_EXEC 跑网络,拿到字节再回 IMG_EXEC 解码。串行解码这个约束没有变化, qr()/base64Image() 仍然全程在 IMG_EXEC 上。 顺带把 downloadPngAsync 改成 downloadBytesAsync:SMTC 的 RandomAccessStreamReference 吃的就是图片流,Windows 自己会解码、JPEG 也认,原先「下载 → ImageIO.read → ImageIO.write 编回 PNG」那一读一写是白做的,还把这条路径绑在了串行队列上。现在 SMTC 取封面完全不碰 AWT。相应地 MediaPlaybackSnapshot.artworkPng 改名 artworkBytes。 Co-Authored-By: Claude --- native/smtc/smtc.cpp | 3 +- .../modules/music/MusicTextures.java | 74 +++++++++++++------ .../music/smtc/MediaPlaybackSnapshot.java | 11 +-- .../modules/music/smtc/SmtcMusicBridge.java | 2 +- .../WindowsSystemMediaTransportControls.java | 2 +- 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/native/smtc/smtc.cpp b/native/smtc/smtc.cpp index 44990e8e..9ef952b7 100644 --- a/native/smtc/smtc.cpp +++ b/native/smtc/smtc.cpp @@ -213,7 +213,8 @@ __declspec(dllexport) void __cdecl smtc_set_callback(ControlCallback cb) { } /// Publish playback metadata and state. -/// artwork_data / artwork_len: PNG bytes or NULL/0 for no art. +/// artwork_data / artwork_len: raw image bytes (PNG/JPEG/...) or NULL/0 for no art. +/// The stream is handed to RandomAccessStreamReference as-is; Windows decodes it. __declspec(dllexport) void __cdecl smtc_publish( const wchar_t* title, const wchar_t* artist, diff --git a/src/main/java/top/fpsmaster/modules/music/MusicTextures.java b/src/main/java/top/fpsmaster/modules/music/MusicTextures.java index df65ee0a..4ce2378a 100644 --- a/src/main/java/top/fpsmaster/modules/music/MusicTextures.java +++ b/src/main/java/top/fpsmaster/modules/music/MusicTextures.java @@ -15,6 +15,7 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Base64; @@ -49,6 +50,15 @@ public final class MusicTextures { return t; }); + // 网络下载单独一个池。串行的约束只来自 AWT,HTTP 没有这个问题,混在 IMG_EXEC 上会让一次 + // 超时(连接 10s + 读 15s)把后面所有解码堵死——扫码登录的二维码明明不需要联网,却要排在 + // 某个封面下载后面等最多 25 秒。 + private static final ExecutorService NET_EXEC = Executors.newFixedThreadPool(2, r -> { + Thread t = new Thread(r, "FPSMaster-Music-Net"); + t.setDaemon(true); + return t; + }); + private MusicTextures() { } @@ -60,16 +70,33 @@ public static synchronized ResourceLocation cover(final String url) { if (loc != null) return loc; if (LOADING.contains(key)) return null; LOADING.add(key); - IMG_EXEC.execute(new Runnable() { + NET_EXEC.execute(new Runnable() { @Override public void run() { + final byte[] bytes; try { - BufferedImage img = downloadImage(url); - upload(key, img); + bytes = downloadBytes(url); } catch (Throwable e) { - ClientLogger.error("Music cover load failed: " + e.getMessage()); + ClientLogger.error("Music cover download failed: " + e.getMessage()); unmark(key); + return; } + if (bytes == null) { + unmark(key); + return; + } + // 拿到字节之后才回到串行线程解码 + IMG_EXEC.execute(new Runnable() { + @Override + public void run() { + try { + upload(key, ImageIO.read(new ByteArrayInputStream(bytes))); + } catch (Throwable e) { + ClientLogger.error("Music cover decode failed: " + e.getMessage()); + unmark(key); + } + } + }); } }); return null; @@ -136,28 +163,26 @@ public static synchronized void invalidate(String rawKey) { } /** - * 在 {@link #IMG_EXEC} 单线程上下载图片并重新编码为 PNG 字节,结果通过回调返回。 - * 供 SMTC 等需要原始字节(而非 GL 纹理)的调用方复用同一套下载/解码路径, - * 避免自起线程并发调用 AWT/ImageIO 在 macOS 上触发崩溃。 + * 下载图片的原始字节,结果通过回调返回;下载失败传 {@code null}。 + * + *

供 SMTC 这类只要字节、不要 GL 纹理的调用方使用。这条路径完全不碰 AWT:原先它是 + * 「下载 → ImageIO.read 解成 BufferedImage → ImageIO.write 编回 PNG」,而 SMTC 的 + * {@code RandomAccessStreamReference} 吃的就是图片流,Windows 自己会解码,JPEG 也认—— + * 那一读一写既是白做的,又把这条路径绑上了 {@link #IMG_EXEC} 的串行队列。 + * + *

回调在 {@link #NET_EXEC} 上执行,不要在里面做阻塞的事。 */ - public static void downloadPngAsync(final String url, final java.util.function.Consumer callback) { + public static void downloadBytesAsync(final String url, final java.util.function.Consumer callback) { if (url == null || url.isEmpty() || callback == null) { return; } - IMG_EXEC.execute(new Runnable() { + NET_EXEC.execute(new Runnable() { @Override public void run() { try { - BufferedImage img = downloadImage(url); - if (img == null) { - callback.accept(null); - return; - } - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ImageIO.write(img, "png", bos); - callback.accept(bos.toByteArray()); + callback.accept(downloadBytes(url)); } catch (Throwable e) { - ClientLogger.error("Music PNG download failed: " + e.getMessage()); + ClientLogger.error("Music image download failed: " + e.getMessage()); callback.accept(null); } } @@ -210,14 +235,21 @@ private static BufferedImage toArgb(BufferedImage src) { return out; } - private static BufferedImage downloadImage(String url) throws Exception { + /** 纯网络 IO,不碰 AWT——调用方拿到字节后自行决定在哪解码。 */ + private static byte[] downloadBytes(String url) throws Exception { HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); conn.setInstanceFollowRedirects(true); conn.setConnectTimeout(10_000); conn.setReadTimeout(15_000); conn.setRequestProperty("User-Agent", UA); - try { - return ImageIO.read(conn.getInputStream()); + try (InputStream in = conn.getInputStream()) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[8192]; + int n; + while ((n = in.read(buf)) != -1) { + bos.write(buf, 0, n); + } + return bos.size() == 0 ? null : bos.toByteArray(); } finally { conn.disconnect(); } diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java b/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java index 76a540ea..2f26df9b 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/MediaPlaybackSnapshot.java @@ -5,8 +5,9 @@ * transport (Windows SMTC). Values are read on the main thread and handed to the bridge, which * is free to coalesce/throttle them. * - *

{@link #artworkPng} carries the album art as PNG bytes when available (loaded off-thread), - * or {@code null} when no art has loaded yet. + *

{@link #artworkBytes} carries the raw album art bytes when available (downloaded off-thread), + * or {@code null} when no art has loaded yet. Whatever the server served — PNG, JPEG — is passed + * through untouched; Windows decodes the stream itself. */ public final class MediaPlaybackSnapshot { public final String title; @@ -16,13 +17,13 @@ public final class MediaPlaybackSnapshot { public final long durationMs; public final boolean playing; public final boolean hasCurrentTrack; - public final byte[] artworkPng; + public final byte[] artworkBytes; public MediaPlaybackSnapshot( String title, String artist, String album, long positionMs, long durationMs, boolean playing, boolean hasCurrentTrack, - byte[] artworkPng) { + byte[] artworkBytes) { this.title = title == null ? "" : title; this.artist = artist == null ? "" : artist; this.album = album == null ? "" : album; @@ -30,6 +31,6 @@ public MediaPlaybackSnapshot( this.durationMs = Math.max(0, durationMs); this.playing = playing; this.hasCurrentTrack = hasCurrentTrack; - this.artworkPng = artworkPng; + this.artworkBytes = artworkBytes; } } diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java index b99c9471..6765e498 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/SmtcMusicBridge.java @@ -134,7 +134,7 @@ private void requestArtwork(final String coverUrl) { artworkUrl = coverUrl; // 换曲目就立刻丢掉上一首的封面,否则新歌的标题会配着旧歌的图发布出去 artwork.set(null); - MusicTextures.downloadPngAsync(coverUrl, png -> { + MusicTextures.downloadBytesAsync(coverUrl, png -> { // Only accept the result if the track hasn't changed while we were downloading if (!coverUrl.equals(artworkUrl)) { return; diff --git a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java index 2cc68c82..7e4d1f02 100644 --- a/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java +++ b/src/main/java/top/fpsmaster/modules/music/smtc/WindowsSystemMediaTransportControls.java @@ -221,7 +221,7 @@ public void publish(MediaPlaybackSnapshot snapshot) { try { boolean hasTrack = latest.hasCurrentTrack; nativeLib.smtc_set_buttons(hasTrack, hasTrack, hasTrack); - byte[] art = latest.artworkPng; + byte[] art = latest.artworkBytes; nativeLib.smtc_publish( new WString(latest.title), new WString(latest.artist),