diff --git a/docs/tasks.md b/docs/tasks.md index 46b9f5c8..e3125871 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -66,7 +66,7 @@ FPSMaster v4将会在此列表任务大部分完成后发布 ### 配置系统 1. [x] 重构配置保存格式 2. [ ] 实现配置版本迁移 -3. [ ] 实现多配置文件切换 +3. [x] 实现多配置文件切换 ### UI框架 1. [ ] 开发更模块化的UI组件系统 diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java index 781a28ef..17c27554 100644 --- a/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java +++ b/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java @@ -2,13 +2,18 @@ import top.fpsmaster.features.impl.InterfaceModule; import top.fpsmaster.features.manager.Category; +import top.fpsmaster.features.settings.impl.BooleanSetting; +import top.fpsmaster.features.settings.impl.NumberSetting; public class PotionDisplay extends InterfaceModule { public static boolean using = false; + public static BooleanSetting betterAnimation = new BooleanSetting("BetterAnimation", false); + public static BooleanSetting noticeableReminder = new BooleanSetting("NoticeableReminder", false); + public static NumberSetting reminderTime = new NumberSetting("ReminderTime", 20, 1, 120, 1, () -> noticeableReminder.getValue()); public PotionDisplay() { super("PotionDisplay", Category.Interface); - addSettings(backgroundColor, fontShadow, betterFont, spacing, bg, rounded, roundRadius); + addSettings(backgroundColor, fontShadow, betterFont, betterAnimation, noticeableReminder, reminderTime, spacing, bg, rounded, roundRadius); } @Override diff --git a/src/main/java/top/fpsmaster/modules/config/ConfigManager.java b/src/main/java/top/fpsmaster/modules/config/ConfigManager.java index 2e0cff0c..4a2a5bb0 100644 --- a/src/main/java/top/fpsmaster/modules/config/ConfigManager.java +++ b/src/main/java/top/fpsmaster/modules/config/ConfigManager.java @@ -445,19 +445,6 @@ public void resetProfileToDefaults(String name) throws FileException { } } - public void resetProfileToAllOff(String name) throws FileException { - loadingConfig = true; - try { - configure = new Configure(); - Shortcut.shortcuts.clear(); - resetAllModulesToDefaults(); - saveConfig(name); - } finally { - loadingConfig = false; - configLoaded = true; - } - } - private void resetConfigToDefaults(String name) throws FileException, Exception { File configFile = ConfigProfileUtils.getProfileFile(name); ClientLogger.warn("Resetting config to defaults: " + configFile.getAbsolutePath()); diff --git a/src/main/java/top/fpsmaster/modules/config/ConfigProfileUtils.java b/src/main/java/top/fpsmaster/modules/config/ConfigProfileUtils.java index 91880e11..d716c411 100644 --- a/src/main/java/top/fpsmaster/modules/config/ConfigProfileUtils.java +++ b/src/main/java/top/fpsmaster/modules/config/ConfigProfileUtils.java @@ -29,7 +29,6 @@ public final class ConfigProfileUtils { public static final String CURRENT_CONFIG = "default"; - public static final String ALL_OFF_PRESET = "all_off"; private static final String PROFILE_DIR = "config"; private static final String JSON_SUFFIX = ".json"; private static final String ACTIVE_PROFILE_STATE = "active_profile.txt"; @@ -259,10 +258,10 @@ private static void loadProfile(String name, boolean saveCurrent) throws Excepti ClientLogger.info("Loaded config profile: " + profileName); } - public static void resetActiveProfileToAllOff() throws FileException { + public static void resetActiveProfileToDefaults() throws FileException { String profileName = activeProfileName; - FPSMaster.configManager.resetProfileToAllOff(profileName); - ClientLogger.info("Reset config profile: " + profileName); + FPSMaster.configManager.resetProfileToDefaults(profileName); + ClientLogger.info("Reset config profile to defaults: " + profileName); } public static String renameProfile(String oldName, String newName, String author) throws FileException { diff --git a/src/main/java/top/fpsmaster/ui/click/ConfigProfilesScreen.java b/src/main/java/top/fpsmaster/ui/click/ConfigProfilesScreen.java index cc70e63b..bc85d8bc 100644 --- a/src/main/java/top/fpsmaster/ui/click/ConfigProfilesScreen.java +++ b/src/main/java/top/fpsmaster/ui/click/ConfigProfilesScreen.java @@ -32,7 +32,7 @@ private enum DialogMode { LOAD, RENAME, DELETE, - ALL_OFF + DEFAULTS } private final ScaledGuiScreen parent; @@ -132,7 +132,7 @@ private void renderActionBar(float x, float y, float width, int mouseX, int mous exportCurrentProfile(); } if (renderActionButton(x + (buttonWidth + gap) * 2f, y, buttonWidth, 22f, "configprofiles.preset.alloff", mouseX, mouseY)) { - openConfirmDialog(DialogMode.ALL_OFF, ""); + openConfirmDialog(DialogMode.DEFAULTS, ""); } } @@ -310,7 +310,7 @@ private String getConfirmMessage() { return String.format(FPSMaster.i18n.get("configprofiles.confirm.load"), dialogProfileName); case DELETE: return String.format(FPSMaster.i18n.get("configprofiles.confirm.delete"), dialogProfileName); - case ALL_OFF: + case DEFAULTS: return FPSMaster.i18n.get("configprofiles.confirm.alloff"); default: return ""; @@ -398,8 +398,8 @@ private void runConfirmAction() { case DELETE: deleteProfile(profileName); break; - case ALL_OFF: - applyAllOffPreset(); + case DEFAULTS: + applyDefaultPreset(); break; default: break; @@ -493,10 +493,10 @@ private void deleteProfile(String profileName) { } } - private void applyAllOffPreset() { + private void applyDefaultPreset() { try { String profileName = ConfigProfileUtils.getActiveProfileName(); - ConfigProfileUtils.resetActiveProfileToAllOff(); + ConfigProfileUtils.resetActiveProfileToDefaults(); reloadProfiles(); setStatus(String.format(FPSMaster.i18n.get("configprofiles.status.alloff"), profileName), successColor()); } catch (FileException exception) { diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java index 9dcb683a..2b7eaa1d 100644 --- a/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java +++ b/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java @@ -10,13 +10,26 @@ import top.fpsmaster.features.impl.interfaces.PotionDisplay; import top.fpsmaster.ui.custom.Component; import top.fpsmaster.utils.core.Utility; +import top.fpsmaster.utils.math.anim.AnimClock; +import top.fpsmaster.utils.math.anim.Easings; +import top.fpsmaster.utils.render.draw.Rects; import java.awt.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import static top.fpsmaster.utils.core.Utility.mc; public class PotionDisplayComponent extends Component { + private static final int EXIT_TICKS = 8; + private static final float ENTER_SECONDS = 0.20f; + private static final float EXIT_SECONDS = 0.12f; + private final AnimClock animClock = new AnimClock(); + private final Map effectAnimations = new HashMap<>(); + public PotionDisplayComponent() { super(PotionDisplay.class); allowScale = true; @@ -27,49 +40,135 @@ public PotionDisplayComponent() { @Override public void draw(float x, float y) { super.draw(x, y); + double dt = animClock.tick(); float dY = y - mod.spacing.getValue().intValue(); GlStateManager.pushMatrix(); int index = 0; + Set activeEffects = new HashSet<>(); for (PotionEffect effect : mc.thePlayer.getActivePotionEffects()) { String title = I18n.format(effect.getEffectName()) + " lv." + (effect.getAmplifier() + 1); - String duration = (effect.getDuration() / 20 / 60) + "min" + effect.getDuration() / 20 % 60 + "s"; + String duration = formatDuration(effect.getDuration()); float width = Math.max(getStringWidth(18, title), getStringWidth(16, duration)) + 36; - drawRect(x, dY, width + 10, 32f, mod.backgroundColor.getColor()); - drawString(18, title, x + 34 * scale, dY + 5, -1); - drawString(16, duration, x + 34 * scale, dY + 5 + 13 * scale, new Color(200, 200, 200).getRGB()); - - // Draw potion image - ResourceLocation res = new ResourceLocation("textures/gui/container/inventory.png"); - Utility.mc.getTextureManager().bindTexture(res); - - // Get potion icon index - int potion = getPotionIconIndex(effect); - - // Draw potion - GL11.glTranslatef((int) (x + 8), (int) (dY + 8), 0); - GL11.glScalef(scale, scale, 0); - Gui.drawModalRectWithCustomSizedTexture( - 0, - 0, - (potion % 8 * 18) + 1, - (198 + (float)(potion / 8) * 18) + 1, - 16, - 16, - 256f, - 256f - ); - GL11.glScalef(1 / scale, 1 / scale, 0); - GL11.glTranslatef(-(int) (x + 8), -(int) (dY + 8), 0); + float rowWidth = width + 10; + float visible = getVisibleProgress(effect, dt); + activeEffects.add(getEffectKey(effect)); + + if (PotionDisplay.betterAnimation.getValue()) { + drawAnimatedPotion(effect, title, duration, x, dY, width, rowWidth, visible); + } else { + drawPotion(effect, title, duration, x, dY, width); + } dY += (index * mod.spacing.getValue().intValue() * 2 + POTION_HEIGHT) * scale; this.width = width + 12 * scale; index++; } + effectAnimations.keySet().removeIf(key -> !activeEffects.contains(key)); GlStateManager.popMatrix(); height = index * (mod.spacing.getValue().intValue() + POTION_HEIGHT); } + private void drawAnimatedPotion(PotionEffect effect, String title, String duration, float x, float y, float width, float rowWidth, float visible) { + float scaledWidth = rowWidth * scale; + float scaledHeight = 32f * scale; + if (visible <= 0.01f) { + return; + } + beginScissor(x, y, scaledWidth * visible, scaledHeight); + GlStateManager.pushMatrix(); + GlStateManager.translate((1f - visible) * -6f * scale, 0f, 0f); + drawPotion(effect, title, duration, x, y, width); + drawAccent(effect, x, y); + GlStateManager.popMatrix(); + endScissor(); + } + + private void drawPotion(PotionEffect effect, String title, String duration, float x, float y, float width) { + drawRect(x, y, width + 10, 32f, mod.backgroundColor.getColor()); + drawString(18, title, x + 34 * scale, y + 5, -1); + drawString(16, duration, x + 34 * scale, y + 5 + 13 * scale, getDurationColor(effect)); + + GL11.glColor4f(1f, 1f, 1f, 1f); + ResourceLocation res = new ResourceLocation("textures/gui/container/inventory.png"); + Utility.mc.getTextureManager().bindTexture(res); + + int potion = getPotionIconIndex(effect); + + GL11.glTranslatef((int) (x + 8), (int) (y + 8), 0); + GL11.glScalef(scale, scale, 0); + Gui.drawModalRectWithCustomSizedTexture( + 0, + 0, + (potion % 8 * 18) + 1, + (198 + (float)(potion / 8) * 18) + 1, + 16, + 16, + 256f, + 256f + ); + GL11.glScalef(1 / scale, 1 / scale, 0); + GL11.glTranslatef(-(int) (x + 8), -(int) (y + 8), 0); + } + + private void drawAccent(PotionEffect effect, float x, float y) { + Potion potion = Potion.potionTypes[effect.getPotionID()]; + if (potion == null || !mod.bg.getValue()) { + return; + } + Color potionColor = new Color(potion.getLiquidColor()); + Rects.fill(x, y, Math.max(1.5f, 2f * scale), 32f * scale, new Color(potionColor.getRed(), potionColor.getGreen(), potionColor.getBlue(), 150)); + } + + private float getVisibleProgress(PotionEffect effect, double dt) { + String key = getEffectKey(effect); + boolean exiting = effect.getDuration() <= EXIT_TICKS; + float current = effectAnimations.getOrDefault(key, exiting ? 0f : 1f); + if (exiting) { + current = Math.max(0f, current - (float) (dt / EXIT_SECONDS)); + } else { + current = Math.min(1f, current + (float) (dt / ENTER_SECONDS)); + } + effectAnimations.put(key, current); + + return (float) (exiting ? Easings.CUBIC_IN.ease(current) : Easings.CUBIC_OUT.ease(current)); + } + + private int getDurationColor(PotionEffect effect) { + if (PotionDisplay.noticeableReminder.getValue()) { + int seconds = effect.getDuration() / 20; + if (seconds <= PotionDisplay.reminderTime.getValue().intValue()) { + return new Color(255, 85, 85).getRGB(); + } + } + return new Color(200, 200, 200).getRGB(); + } + + private String formatDuration(int ticks) { + int seconds = Math.max(0, ticks / 20); + if (seconds < 60) { + return seconds + "s"; + } + return seconds / 60 + "min" + seconds % 60 + "s"; + } + + private String getEffectKey(PotionEffect effect) { + return effect.getPotionID() + ":" + effect.getAmplifier(); + } + + private void beginScissor(float x, float y, float width, float height) { + int sx = Math.round(x * 2f); + int sy = Math.round(y * 2f); + int sw = Math.max(0, Math.round(width * 2f)); + int sh = Math.max(0, Math.round(height * 2f)); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + GL11.glScissor(sx, mc.displayHeight - (sy + sh), sw, sh); + } + + private void endScissor() { + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + private int getPotionIconIndex(PotionEffect effect) { Potion p = Potion.potionTypes[effect.getPotionID()]; return p.getStatusIconIndex(); 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 092b8a1d..7494277e 100644 --- a/src/main/resources/assets/minecraft/client/lang/en_us.lang +++ b/src/main/resources/assets/minecraft/client/lang/en_us.lang @@ -10,6 +10,7 @@ mainmenu.notlatest=You're not on the latest version. Click to update! mainmenu.javafail=Cannot access the version of Java mainmenu.oldjava=The Java you're using is outdated! mainmenu.javatip=Please try to use the new version of Java8 as much as possible, otherwise there may be login and other network connectivity issues +mainmenu.back=Back multiplayer.title=Multiplayer multiplayer.serverlist=Server List multiplayer.join=Join Server @@ -82,16 +83,16 @@ configprofiles.status.exported=Exported profile: %s configprofiles.status.loaded=Switched profile: %s configprofiles.status.renamed=Renamed profile: %s configprofiles.status.deleted=Deleted profile: %s -configprofiles.status.alloff=Applied all-off preset +configprofiles.status.alloff=Reset to recommended defaults configprofiles.status.import_failed=Failed to import profile configprofiles.status.export_failed=Failed to export profile configprofiles.status.load_failed=Failed to switch profile configprofiles.status.rename_failed=Failed to rename profile configprofiles.status.delete_failed=Failed to delete profile -configprofiles.status.alloff_failed=Failed to apply preset +configprofiles.status.alloff_failed=Failed to reset defaults configprofiles.confirm.load=Switch to config "%s"? configprofiles.confirm.delete=Delete config "%s"? -configprofiles.confirm.alloff=Apply all-off preset? +configprofiles.confirm.alloff=Reset to recommended defaults? oobe.welcome.title=Welcome oobe.welcome.next=Next @@ -312,6 +313,9 @@ potiondisplay.round=Rounded Corners potiondisplay.backgroundcolor=Background Color potiondisplay.fontshadow=Font Shadow potiondisplay.betterfont=Clean Font +potiondisplay.betteranimation=Better Animation +potiondisplay.noticeablereminder=Noticeable Reminder +potiondisplay.remindertime=Reminder Time potiondisplay.roundradius=Corner Radius potiondisplay.background=Show Background potiondisplay.spacing=Spacing @@ -365,6 +369,8 @@ performance.fontoptimize=Font Optimization performance.staticparticlecolor=Static Particle Color performance.limitchunks=Chunk Load Limit performance.chunkupdatelimit=Chunk Update Limit +performance.batchmodelrendering=Batch Model Rendering +performance.lowanimationtick=Low Animation Tick fullbright=Fullbright fullbright.desc=Keep brightness at max @@ -405,7 +411,7 @@ sprint.betterfont=Clean Font autogg=AutoGG autogg.desc=Automatically send a custom message after a game has ended. autogg.servers=Servers -autogg.servers.hypxiel=Hypxiel +autogg.servers.hypixel=Hypixel autogg.servers.normal=Normal autogg.message=Custom Message autogg.autoplay=Auto Play 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 3e6fd90a..9210ca03 100644 --- a/src/main/resources/assets/minecraft/client/lang/zh_cn.lang +++ b/src/main/resources/assets/minecraft/client/lang/zh_cn.lang @@ -83,16 +83,16 @@ configprofiles.status.exported=已导出配置:%s configprofiles.status.loaded=已切换配置:%s configprofiles.status.renamed=已改名配置:%s configprofiles.status.deleted=已删除配置:%s -configprofiles.status.alloff=已应用全关预设 +configprofiles.status.alloff=已恢复默认配置 configprofiles.status.import_failed=导入配置失败 configprofiles.status.export_failed=导出配置失败 configprofiles.status.load_failed=切换配置失败 configprofiles.status.rename_failed=配置改名失败 configprofiles.status.delete_failed=删除配置失败 -configprofiles.status.alloff_failed=应用预设失败 +configprofiles.status.alloff_failed=恢复默认配置失败 configprofiles.confirm.load=确认切换到配置“%s”吗? configprofiles.confirm.delete=确认删除配置“%s”吗? -configprofiles.confirm.alloff=确认应用全关预设吗? +configprofiles.confirm.alloff=确认恢复默认配置吗? oobe.welcome.title=欢迎 oobe.welcome.next=下一步 @@ -313,6 +313,9 @@ potiondisplay.round=背景圆角 potiondisplay.backgroundcolor=背景颜色 potiondisplay.fontshadow=字体阴影 potiondisplay.betterfont=更好的字体 +potiondisplay.betteranimation=更好的动画 +potiondisplay.noticeablereminder=醒目提醒 +potiondisplay.remindertime=提醒时间 potiondisplay.roundradius=圆角半径 potiondisplay.background=背景 potiondisplay.spacing=间距 @@ -408,7 +411,7 @@ sprint.betterfont=更好的字体 autogg=自动GG autogg.desc=游戏结束后自动地在发送你自定义的消息 autogg.servers=服务器列表 -autogg.servers.hypixel=Hypxiel +autogg.servers.hypixel=Hypixel autogg.servers.normal=普通模式 autogg.message=自定义消息 autogg.autoplay=自动重开 @@ -726,7 +729,7 @@ clientsettings.language.chinese=简体中文 clientsettings.language.english=英语 dragonwings=龙翅膀 -dragonwings.desc=在自己身上龙翅膀 +dragonwings.desc=显示龙翅膀 dragonwings.colored=翅膀上色 dragonwings.color=颜色 dragonwings.scale=大小