diff --git a/.gitignore b/.gitignore index c6d98d1..ba7d9e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,98 +1,48 @@ -# ---> JetBrains -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -# ---> Maven target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -# https://github.com/takari/maven-wrapper#usage-without-binary-jar -.mvn/wrapper/maven-wrapper.jar +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ -# Eclipse m2e generated files -# Eclipse Core -.project -# JDT-specific (Eclipse Java Development Tools) +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated .classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store + +/.minecraft +/.physics_mod_cache +/config +/CustomSkinLoader +/etc +/run +/logs +/jre* +/ForeverMC.yaml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5f337ac --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,4 @@ +# Default ignored files +/shelf/ +/workspace.xml +/developer-tools.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..106fade --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6d42c56 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..bada8b5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..91820a7 --- /dev/null +++ b/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + cn.forevermc.launcher + ForeverMC + 2.3.0 + + + 21 + 21 + UTF-8 + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.7.1 + + + + cn.forevermc.launcher.ForeverMC + + + + jar-with-dependencies + + + + + package + + single + + + + + + + + + + jitpack.io + https://jitpack.io + + + maven2 + https://repo.maven.apache.org/maven2/ + + + + + + com.imyeyu.fx.ui + timi-fx-ui + 0.0.1 + + + com.imyeyu.inject + timi-inject + 0.0.1 + + + org.openjfx + javafx-media + 21.0.2 + + + com.imyeyu.compress + timi-compress + 0.0.1 + + + com.imyeyu.network + timi-network + 0.0.1 + + + com.google.code.gson + gson + 2.10.1 + + + org.projectlombok + lombok + 1.18.34 + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + test + + + \ No newline at end of file diff --git a/src/main/java/cn/forevermc/launcher/ForeverMC.java b/src/main/java/cn/forevermc/launcher/ForeverMC.java new file mode 100644 index 0000000..a103a39 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/ForeverMC.java @@ -0,0 +1,63 @@ +package cn.forevermc.launcher; + +import cn.forevermc.launcher.bean.Config; +import cn.forevermc.launcher.ctrl.Main; +import javafx.application.Application; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import com.imyeyu.config.ConfigLoader; +import com.imyeyu.fx.config.BindingsConfig; +import com.imyeyu.fx.ui.TimiFXUI; +import com.imyeyu.inject.InjectApp; +import com.imyeyu.inject.annotation.TimiInjectApplication; +import com.imyeyu.java.TimiJava; +import com.imyeyu.lang.multi.ResourcesMultilingual; + +import java.util.UUID; + +/** + * Forever Minecraft 启动器 + * + * @author 夜雨 + * @since 2022-11-18 15:36 + */ +@Slf4j +@TimiInjectApplication +public class ForeverMC { + + public static final String VERSION = "2.2.3"; + + @Getter + private static Config config; + + @Getter + private static ConfigLoader configLoader; + + @Getter + private static InjectApp injectApp; + + public static void main(String[] args) { + injectApp = new InjectApp(ForeverMC.class); + try { + { + configLoader = BindingsConfig.build("ForeverMC.yaml", Config.class); + config = configLoader.load(); + if (TimiJava.isEmpty(config.getLauncher().getClientId().get())) { + config.getLauncher().getClientId().set(UUID.randomUUID().toString()); + } + + ResourcesMultilingual multilingual = TimiFXUI.MULTILINGUAL; + multilingual.addAll("lang/timi-fx-ui/%s.lang"); + multilingual.addAll("lang/%s.lang"); + multilingual.setActivated(config.getMain().getLanguage().get()); + + // 禁止系统 DPI 缩放 + System.setProperty("prism.allowhidpi", "false"); + System.setProperty("glass.win.minHiDPI", "1"); + } + Application.launch(Main.class); + } catch (Exception e) { + log.error("fatal error", e); + } + } +} diff --git a/src/main/java/cn/forevermc/launcher/bean/APISetting.java b/src/main/java/cn/forevermc/launcher/bean/APISetting.java new file mode 100644 index 0000000..55f6383 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/APISetting.java @@ -0,0 +1,45 @@ +package cn.forevermc.launcher.bean; + +import lombok.Data; + +import java.util.List; + +/** + * @author 夜雨 + * @since 2024-04-29 20:05 + */ +@Data +public class APISetting { + + public enum Key { + + /** 闪烁标语 */ + FMC_SPLASHES, + + /** 启动器背景 */ + FMC_BG, + + FMC_BGM, + } + + private DynamicList bg; + + private DynamicList bgm; + + private DynamicList splashes; + + /** + * + * @author 夜雨 + * @since 2022-12-01 15:59 + */ + @Data + public static class DynamicList { + + /** 激活的标语 */ + private String active; + + /** 标语列表 */ + private List list; + } +} diff --git a/src/main/java/cn/forevermc/launcher/bean/ComponentSize.java b/src/main/java/cn/forevermc/launcher/bean/ComponentSize.java new file mode 100644 index 0000000..5bb0d82 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/ComponentSize.java @@ -0,0 +1,22 @@ +package cn.forevermc.launcher.bean; + +/** + * 组件大小 + * + * @author 夜雨 + * @since 2023-06-09 16:43 + */ +public class ComponentSize { + + /** 小号 */ + public static final double SMALL = 150; + + /** 正常 */ + public static final double NORMAL = 200; + + /** 中等 */ + public static final double MEDIUM = 300; + + /** 大号 */ + public static final double LARGE = 400; +} diff --git a/src/main/java/cn/forevermc/launcher/bean/Config.java b/src/main/java/cn/forevermc/launcher/bean/Config.java new file mode 100644 index 0000000..01fb5b1 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/Config.java @@ -0,0 +1,94 @@ +package cn.forevermc.launcher.bean; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.StringProperty; +import lombok.Data; +import com.imyeyu.java.bean.Language; + +/** + * 配置 + * + * @author 夜雨 + * @since 2024-04-18 17:55 + */ +@Data +public class Config { + + /** 主配置 */ + private Main main; + + /** 玩家配置 */ + private Player player; + + /** 启动配置 */ + private Launcher launcher; + + /** + * 主配置 + * + * @author 夜雨 + * @since 2024-04-18 18:00 + */ + @Data + public static class Main { + + /** 启动器语言 */ + private ObjectProperty language; + + /** 背景音乐音量,[0, 100] */ + private DoubleProperty bgmVolume; + + /** 音效音量,[0, 100] */ + private DoubleProperty soundVolume; + + /** 游戏下载源 */ + private ObjectProperty gameDownloadSource; + + /** 运行时下载源 */ + private ObjectProperty runtimeDownloadSource; + } + + /** + * 玩家配置 + * + * @author 夜雨 + * @since 2024-04-18 18:00 + */ + @Data + public static class Player { + + /** 登录名 */ + private StringProperty name; + + /** 密码 */ + private StringProperty password; + } + + /** + * 启动器配置 + * + * @author 夜雨 + * @since 2024-04-18 17:59 + */ + @Data + public static class Launcher { + + /** 最大内存 */ + private DoubleProperty memory; + + /** 启动游戏 */ + private StringProperty game; + + /** 客户端 ID */ + private StringProperty clientId; + + /** true 为自动启动 */ + private BooleanProperty autoStartup; + + /** 多线程下载游戏 */ + private IntegerProperty multiDownload; + } +} diff --git a/src/main/java/cn/forevermc/launcher/bean/FabricAPI.java b/src/main/java/cn/forevermc/launcher/bean/FabricAPI.java new file mode 100644 index 0000000..d121ffa --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/FabricAPI.java @@ -0,0 +1,21 @@ +package cn.forevermc.launcher.bean; + +import lombok.Data; + +/** + * + * + * @author 夜雨 + * @since 2024-06-11 19:29 + */ +@Data +public class FabricAPI { + + private String name; + + private String fabricVer; + + private String minecraftVer; + + private String mongoId; +} diff --git a/src/main/java/cn/forevermc/launcher/bean/FileDownload.java b/src/main/java/cn/forevermc/launcher/bean/FileDownload.java new file mode 100644 index 0000000..3c9b830 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/FileDownload.java @@ -0,0 +1,80 @@ +package cn.forevermc.launcher.bean; + +import cn.forevermc.launcher.util.Path; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; +import lombok.Data; +import com.imyeyu.io.IO; +import com.imyeyu.utils.Digest; + +import java.io.File; + +/** + * 文件下载对象 + * + * @author 夜雨 + * @since 2022-11-21 11:22 + */ +@Data +public class FileDownload { + + /** 本地文件对象 */ + private File file; + + /** 大小 */ + private Long size; + + /** 请求 URL */ + private String url; + + /** 哈希 */ + private String hash; + + /** 显示名称 */ + private String displayName; + + /** 进度 */ + private DoubleProperty progress; + + /** true 为下载错误 */ + private BooleanProperty isError; + + /** 重试次数 */ + private int retry = 0; + + public FileDownload(File file) { + this.file = file; + this.displayName = file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(Path.P_ROOT)); + + progress = new SimpleDoubleProperty(0); + isError = new SimpleBooleanProperty(false); + } + + /** @return true 为存在且 HASH 匹配 */ + public boolean exist() throws Exception { + return file.exists() && hash.equals(Digest.sha1(IO.toBytes(file))); + } + + /** @return 文件名 */ + public String getFileName() { + return file.getName(); + } + + /** @return 进度监听 */ + public DoubleProperty progressProperty() { + return progress; + } + + /** @param isError true 为下载错误 */ + public void setError(boolean isError) { + this.isError.set(isError); + } + + /** @return 错误监听,只读 */ + public ReadOnlyBooleanProperty errorProperty() { + return isError; + } +} diff --git a/src/main/java/cn/forevermc/launcher/bean/Game.java b/src/main/java/cn/forevermc/launcher/bean/Game.java new file mode 100644 index 0000000..95c73d1 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/Game.java @@ -0,0 +1,350 @@ +package cn.forevermc.launcher.bean; + +import com.google.gson.JsonObject; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.StringProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import com.imyeyu.fx.ui.TimiFXUI; +import com.imyeyu.java.TimiJava; + +import java.io.File; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 游戏 + * + * @author 夜雨 + * @since 2021-11-26 11:13 + */ +@Data +public class Game { + + /** + * 游戏版本类型 + * + * @author 夜雨 + * @since 2022-11-21 14:54 + */ + public enum Type { + + /** 快照 */ + SNAPSHOT, + + /** 正式版 */ + RELEASE, + + /** 旧的测试版 */ + OLD_BETA, + + /** 旧的实验版 */ + OLD_ALPHA + } + + // ---------- 版本属性,这些属性在解析前就有效 ---------- + + /** 显示名称 */ + private String name; + + /** 版本路径(如:.minecraft/versions/1.20) */ + private File path; + + /** JAR 文件 */ + private File jar; + + /** JSON 文件 */ + private File json; + + /** yaml 文件(ForeverMC 针对此整合包的配置) */ + private File yaml; + + /** JSON 文件的根节点 */ + private JsonObject jsonRoot; + + /** 发布时间 */ + private Long releaseAt; + + /** true 为原版 */ + private boolean isOriginal; + + /** true 为 Fabric 版本 */ + private boolean isFabric; + + /** true 为上古版本 */ + private boolean isLegacy; + + /** 版本设置 */ + private Option option; + + // ---------- 版本 JSON 数据,这些属性在解析后才有效 ---------- + + /** ID(版本号,可能会被修改) */ + private String id; + + /** 游戏版本类型 */ + private Type type; + + /** 元数据 URL */ + private String url; + + /** 版本元数据 */ + private MetaData metaData; + + @Override + public boolean equals(Object object) { + if (this == object) return true; + if (object == null || getClass() != object.getClass()) return false; + + Game game = (Game) object; + return Objects.equals(path, game.path); + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (path != null ? path.hashCode() : 0); + return result; + } + + /** + * 版本元数据,通过 {@link cn.forevermc.launcher.service.GameService#readMetaData(Game)} 解析后有效 + * + * @author 夜雨 + * @since 2022-11-21 11:28 + */ + @Data + public static class MetaData { + + /** + * 真实版本号,目前仅在正式版有效 + * + * @author 夜雨 + * @since 2023-06-17 16:11 + */ + @Getter + public static class RealVersion { + + /** 版本号匹配正则 */ + private static final Pattern PATTERN = Pattern.compile("(\\d)\\.(\\d+)\\.?(\\d+)?"); + + /** 版本号 */ + private String value; + + /** 根版本 */ + private int root = 0; + + /** 主版本 */ + private int main = 0; + + /** BUG 修正版本 */ + private int bug = 0; + + /** + * 设置版本号,通过此方法自动解析详细版本号 + * + * @param value 版本号 + */ + public void setValue(String value) { + this.value = value; + Matcher matcher = PATTERN.matcher(value); + if (matcher.find()) { + root = Integer.parseInt(matcher.group(1)); + main = Integer.parseInt(matcher.group(2)); + if (TimiJava.isNotEmpty(matcher.group(3))) { + bug = Integer.parseInt(matcher.group(3)); + } + } + } + + /** @return true 为支持 Fabric */ + public boolean isSupportFabric() { + return main < 14; + } + + /** @return true 为更现代的样式 */ + public boolean isModernStyle() { + return 19 < main; + } + } + + /** 版本号(可能因模组加载器而改变) */ + private String version; + + /** 真实的 Minecraft 版本号 */ + private RealVersion realVersion; + + /** 标题 */ + private String title; + + /** 启动类 */ + private String mainClass; + + /** 需要 Java 版本 */ + private String javaVersion; + + /** 游戏参数模板 */ + private String argsGame; + + /** JVM 参数模板 */ + private String argsJVM; + + /** 启动核心地址 */ + private String coreURL; + + /** 启动核心 SHA1 */ + private String coreSHA1; + + /** 核心大小 */ + private Long coreSize; + + /** 资源版本 */ + private String assetsVersion; + + /** 资源列表 */ + private List assetList; + + /** 依赖列表 */ + private List librarieList; + + /** 需下载的文件列表(解析结果,包括资源和依赖文件) */ + private List downloadList; + + /** + * 资源 + * + * @author 夜雨 + * @since 2022-11-21 11:04 + */ + @Data + public static class Assets { + + /** 哈希值 */ + private String hash; + + /** 下载 URL */ + private String url; + + /** 大小 */ + private Long size; + } + + /** + * 依赖 + * + * @author 夜雨 + * @since 2022-11-21 11:04 + */ + @Data + public static class Libraries { + + /** 哈希值 */ + private String sha1; + + /** 相对路径 */ + private String path; + + /** 下载 URL */ + private String url; + + /** 文件大小 */ + private Long size; + + /** true 为 JNA 依赖 */ + private boolean isNatives; + + /** @return true 为非 JNA 依赖 */ + public boolean isNotNatives() { + return !isNatives; + } + } + } + + /** + * 版本设置 + * + * @author 夜雨 + * @since 2022-12-09 20:31 + */ + @Data + public static class Option implements Serializable { + + /** + * 登录方式 + * + * @author 夜雨 + * @since 2022-12-05 23:05 + */ + @Getter + @AllArgsConstructor + public enum LoginType implements Serializable { + + /** 离线 */ + OFFLINE(TimiFXUI.MULTILINGUAL.text("offline"), TimiFXUI.MULTILINGUAL.textArgs("fmc.launcher.menu.account.type", TimiFXUI.MULTILINGUAL.text("offline"))), + + /** ForeverMC */ + FOREVER_MC("ForeverMC", TimiFXUI.MULTILINGUAL.textArgs("fmc.launcher.menu.account.type", TimiFXUI.MULTILINGUAL.text("fmc.launcher.menu.account.fmc"))), + + /** 官方正版验证(未支持) */ + MOJANG("Mojang", TimiFXUI.MULTILINGUAL.textArgs("fmc.launcher.menu.account.type", TimiFXUI.MULTILINGUAL.text("fmc.launcher.menu.account.mojang"))); + + /** 显示名称 */ + final String name; + + /** 提示 */ + final String tips; + } + + /** + * 可选规则 + * + * @author 夜雨 + * @since 2023-06-17 11:34 + */ + @Getter + @AllArgsConstructor + public enum Rules { + + /** 体验模式 */ + DEMO("is_demo_user"), + + /** 自定义尺寸 */ + CUSTOM_RESOLUTION("has_custom_resolution"), + + /** 快速游戏日志 */ + QUICK_PLAYS_SUPPORT("has_quick_plays_support"), + + /** 快速单人游戏 */ + QUICK_PLAY_SINGLEPLAYER("is_quick_play_singleplayer"), + + /** 快速多人游戏 */ + QUICK_PLAY_MULTIPLAYER("is_quick_play_multiplayer"), + + /** 快速领域游戏 */ + QUICK_PLAY_REALMS("is_quick_play_realms"); + + /** 名称 */ + final String name; + } + + /** 名称,从整合版版本包获取并储存 */ + private StringProperty name; + + /** 支持的登录方式 */ + private ObjectProperty loginType; + + /** 启动 Java */ + private StringProperty java; + + /** 服务器 */ + private StringProperty server; + + /** 是否自动连接 */ + private BooleanProperty autoConnect; + } +} diff --git a/src/main/java/cn/forevermc/launcher/bean/GameDownloadSource.java b/src/main/java/cn/forevermc/launcher/bean/GameDownloadSource.java new file mode 100644 index 0000000..2a65386 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/GameDownloadSource.java @@ -0,0 +1,25 @@ +package cn.forevermc.launcher.bean; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author 夜雨 + * @since 2023-06-20 15:21 + */ +@Getter +@AllArgsConstructor +public enum GameDownloadSource { + + /** 官方源 */ + MOJANG("https://libraries.minecraft.net/", "https://resources.download.minecraft.net/"), + + /** BMCLAPI */ + BMCLAPI("https://bmclapi2.bangbang93.com/maven/", "https://bmclapi2.bangbang93.com/assets/"); + + /** 依赖 */ + final String libraries; + + /** 资源 */ + final String resources; +} diff --git a/src/main/java/cn/forevermc/launcher/bean/LaunchGame.java b/src/main/java/cn/forevermc/launcher/bean/LaunchGame.java new file mode 100644 index 0000000..4ed0172 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/LaunchGame.java @@ -0,0 +1,167 @@ +package cn.forevermc.launcher.bean; + +import cn.forevermc.launcher.service.FMCLoginService; +import cn.forevermc.launcher.service.GameService; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.SimpleObjectProperty; +import com.imyeyu.inject.annotation.Bean; +import com.imyeyu.inject.annotation.Inject; +import com.imyeyu.inject.annotation.InvokeForInjected; + +/** + * 启动游戏对象 + * + * @author 夜雨 + * @since 2024-07-20 19:24 + */ +@Bean +public class LaunchGame extends SimpleObjectProperty { + + @Inject + private Config config; + + @Inject + private GameService gameService; + + @Inject + private FMCLoginService fmcLoginService; + + /** true 为使用新标题 */ + private final BooleanBinding newTitle; + + /** true 为使用新 UI */ + private final BooleanBinding newUI; + + /** true 为远古版本 */ + private final BooleanBinding legacy; + + /** true 为官方原版 */ + private final BooleanBinding original; + + /** true 为使用 Fabric */ + private final BooleanBinding fabric; + + /** true 为支持 ForeverMC 登录 */ + private final BooleanBinding supportFMCLogin; + + public LaunchGame() { + newTitle = Bindings.createBooleanBinding(() -> { + if (get() == null) { + return false; + } + Game.MetaData.RealVersion realVersion = gameService.getRealVersion(get()); + return 1 <= realVersion.getRoot() && 20 <= realVersion.getMain(); // 1.20 <= 使用新标题 + }, this); + newUI = Bindings.createBooleanBinding(() -> { + if (get() == null) { + return false; + } + Game.MetaData.RealVersion realVersion = gameService.getRealVersion(get()); + return 1 <= realVersion.getRoot() && 21 <= realVersion.getMain(); // 1.21 <= 使用新 UI + }, this); + legacy = Bindings.createBooleanBinding(() -> { + if (get() == null) { + return false; + } + return get().isLegacy(); + }, this); + original = Bindings.createBooleanBinding(() -> { + if (get() == null) { + return false; + } + return get().isOriginal(); + }, this); + fabric = Bindings.createBooleanBinding(() -> { + if (get() == null) { + return false; + } + return get().isFabric(); + }, this); + supportFMCLogin = Bindings.createBooleanBinding(() -> { + if (fmcLoginService == null) { + return false; + } + return fmcLoginService.isSupportFMCLogin(get()); + }, this, FMCLoginService.loginModMapProperty(), FMCLoginService.fabricAPIMapProperty()); + } + + @InvokeForInjected + private void injected() { + String defLaunch = config.getLauncher().getGame().get(); + config.getLauncher().getGame().bind(Bindings.createStringBinding(() -> { + if (get() == null) { + return defLaunch; + } + return get().getName(); + }, this)); + } + + public boolean isOffline() { + return get().getOption().getLoginType().get() == Game.Option.LoginType.OFFLINE; + } + + public boolean isOnline() { + return !isOffline(); + } + + public boolean isFMCLogin() { + return get().getOption().getLoginType().get() == Game.Option.LoginType.FOREVER_MC; + } + + public boolean isMojangLogin() { + return get().getOption().getLoginType().get() == Game.Option.LoginType.MOJANG; + } + + public boolean isNewTitle() { + return newTitle.get(); + } + + public BooleanBinding newTitleProperty() { + return newTitle; + } + + public boolean isNewUI() { + return newUI.get(); + } + + public BooleanBinding newUIProperty() { + return newUI; + } + + public boolean isLegacy() { + return legacy.get(); + } + + public BooleanBinding legacyProperty() { + return legacy; + } + + public boolean isOriginal() { + return original.get(); + } + + public BooleanBinding originalProperty() { + return original; + } + + public boolean isFabric() { + return fabric.get(); + } + + public BooleanBinding fabricProperty() { + return fabric; + } + + public boolean isSupportFMCLogin() { + return supportFMCLogin.get(); + } + + public boolean isNotSupportFMCLogin() { + return !supportFMCLogin.get(); + } + + public BooleanBinding supportFMCLoginProperty() { + return supportFMCLogin; + } +} diff --git a/src/main/java/cn/forevermc/launcher/bean/MCPopupTips.java b/src/main/java/cn/forevermc/launcher/bean/MCPopupTips.java new file mode 100644 index 0000000..799bfd6 --- /dev/null +++ b/src/main/java/cn/forevermc/launcher/bean/MCPopupTips.java @@ -0,0 +1,32 @@ +package cn.forevermc.launcher.bean; + +import javafx.geometry.Insets; +import javafx.scene.control.Label; +import javafx.scene.layout.Background; +import javafx.scene.layout.Border; +import com.imyeyu.fx.ui.components.popup.tips.AbstractPopupTips; +import com.imyeyu.fx.utils.BorderStroke; + +/** + * 弹出提示组件 + * + * @author 夜雨 + * @since 2023-06-08 17:12 + */ +public class MCPopupTips extends AbstractPopupTips