diff --git a/.idea/.gitignore b/.idea/.gitignore index 5f337ac..e873147 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -2,3 +2,4 @@ /shelf/ /workspace.xml /developer-tools.xml +/CopilotChatHistory.xml diff --git a/src/main/java/cn/forevermc/launcher/bean/APISetting.java b/src/main/java/cn/forevermc/launcher/bean/APISetting.java index 55f6383..0ef1d3a 100644 --- a/src/main/java/cn/forevermc/launcher/bean/APISetting.java +++ b/src/main/java/cn/forevermc/launcher/bean/APISetting.java @@ -29,17 +29,16 @@ public class APISetting { private DynamicList splashes; /** - * * @author 夜雨 - * @since 2022-12-01 15:59 + * @since 2022-12-01 15:59 */ @Data public static class DynamicList { - /** 激活的标语 */ - private String active; + /** 常驻的资源 */ + private String permanent; - /** 标语列表 */ + /** 资源列表 */ private List list; } } diff --git a/src/main/java/cn/forevermc/launcher/service/APISettingService.java b/src/main/java/cn/forevermc/launcher/service/APISettingService.java index 7e1ad6b..dc7f72e 100644 --- a/src/main/java/cn/forevermc/launcher/service/APISettingService.java +++ b/src/main/java/cn/forevermc/launcher/service/APISettingService.java @@ -15,6 +15,7 @@ import javafx.beans.property.SimpleObjectProperty; import lombok.extern.slf4j.Slf4j; import org.apache.hc.client5.http.fluent.Request; import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.util.Timeout; import java.util.HashMap; import java.util.Map; @@ -49,7 +50,8 @@ public class APISettingService { for (APISetting.Key key : APISetting.Key.values()) { reqArgs.put(key, null); } - Map data = TimiRequest.wrap(Request.post(API).bodyString(gson.toJson(reqArgs), ContentType.APPLICATION_JSON)).resultAs(new TypeToken<>() {}); + Request request = Request.post(API).connectTimeout(Timeout.ofSeconds(8)).bodyString(gson.toJson(reqArgs), ContentType.APPLICATION_JSON); + Map data = TimiRequest.wrap(request).resultAs(new TypeToken<>() {}); setting.setBg(gson.fromJson(data.get(APISetting.Key.FMC_BG), APISetting.DynamicList.class)); setting.setBgm(gson.fromJson(data.get(APISetting.Key.FMC_BGM), APISetting.DynamicList.class)); setting.setSplashes(gson.fromJson(data.get(APISetting.Key.FMC_SPLASHES), APISetting.DynamicList.class)); diff --git a/src/main/java/cn/forevermc/launcher/service/BGMService.java b/src/main/java/cn/forevermc/launcher/service/BGMService.java index e90ccff..8a00ffb 100644 --- a/src/main/java/cn/forevermc/launcher/service/BGMService.java +++ b/src/main/java/cn/forevermc/launcher/service/BGMService.java @@ -108,7 +108,7 @@ public class BGMService implements OS.FileSystem { return; } try { - String active = setting.getBgm().getActive(); + String active = setting.getBgm().getPermanent(); if (TimiJava.isNotEmpty(active)) { if (cacheList.containsKey(active)) { map.put(active, new Media(cacheList.get(active).toURI().toURL().toExternalForm())); diff --git a/src/main/java/cn/forevermc/launcher/service/BGService.java b/src/main/java/cn/forevermc/launcher/service/BGService.java index 4852db9..50484cd 100644 --- a/src/main/java/cn/forevermc/launcher/service/BGService.java +++ b/src/main/java/cn/forevermc/launcher/service/BGService.java @@ -1,15 +1,17 @@ package cn.forevermc.launcher.service; +import cn.forevermc.launcher.bean.APISetting; import cn.forevermc.launcher.util.Resources; import com.google.gson.Gson; -import com.imyeyu.fx.task.RunAsync; +import com.imyeyu.fx.listener.NewValueListener; +import com.imyeyu.fx.task.RunAsyncDaemon; import com.imyeyu.fx.utils.BgImage; import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.InvokeForInjected; import com.imyeyu.inject.annotation.Service; import com.imyeyu.io.IO; import com.imyeyu.java.TimiJava; -import com.imyeyu.java.bean.CallbackArg; +import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.network.FileRequest; import com.imyeyu.utils.OS; import javafx.beans.property.ObjectProperty; @@ -18,15 +20,13 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.scene.image.Image; import javafx.scene.layout.Background; import lombok.extern.slf4j.Slf4j; -import org.apache.hc.client5.http.fluent.Request; +import javax.naming.NoPermissionException; import java.io.File; +import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * 动态背景地址获取服务 @@ -47,82 +47,85 @@ public class BGService implements OS.FileSystem { private Gson gson; private final ObjectProperty value; - private final Map cacheList = new HashMap<>(); public BGService() { value = new SimpleObjectProperty<>(); - setValue(IO.resourceToInputStream(getClass(), "assets/img/bg.png")); } @InvokeForInjected private void injected() { - try { - { - File[] files = IO.dir(CACHE_PATH).listFiles(); - if (files != null) { - for (int i = 0; i < files.length; i++) { - cacheList.put(files[i].getName(), files[i]); - } - } - } - if (TimiJava.isNotEmpty(cacheList)) { - List files = new ArrayList<>(cacheList.values()); - Collections.shuffle(files); - setValue(IO.getInputStream(files.get(0))); - } - } catch (Exception e) { - e.printStackTrace(); - } + new RunAsyncDaemon(3000) { - // 从缓存随机抽取 - apiSettingService.valueProperty().addListener((obs, o, setting) -> { - if (setting == null) { - return; - } - try { - String active = setting.getBg().getActive(); - if (TimiJava.isNotEmpty(active)) { - if (cacheList.containsKey(active)) { - setValue(IO.getInputStream(cacheList.get(active))); - } else { - fetch(active, active, this::setValue); - } - } else { - List list = setting.getBg().getList(); - if (TimiJava.isNotEmpty(list)){ - Collections.shuffle(list); - String shuffleMongoId = list.get(0); - if (cacheList.containsKey(shuffleMongoId)) { - setValue(IO.getInputStream(cacheList.get(shuffleMongoId))); - } else { - fetch(shuffleMongoId, shuffleMongoId, this::setValue); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - }); - } + private final Object lock = new Object(); - private void setValue(InputStream stream) { - value.set(new BgImage(new Image(stream, -1, -1, false, false)).cover().build()); - } - - private void fetch(String mongoId, String fileName, CallbackArg callback) { - new RunAsync() { + private APISetting.DynamicList bgList = null; @Override protected InputStream call() throws Exception { - File file = IO.file(CACHE_PATH + SEP + fileName); - FileRequest.get(Resources.TIMI_SERVER_API + "/attachment/read/" + mongoId).toFile(file); - cacheList.put(mongoId, file); - return IO.getInputStream(file); + if (apiSettingService.getValue() == null) { + apiSettingService.valueProperty().addListener((NewValueListener) apiSetting -> { + bgList = apiSetting.getBg(); + synchronized (lock) { + lock.notifyAll(); + } + }); + // 等待配置 + log.info("waiting apiSetting"); + synchronized (lock) { + lock.wait(2000); + } + TimiException.required(bgList, "not found bgList"); + } else { + bgList = apiSettingService.getValue().getBg(); + } + List fileList = IO.listFile(IO.dir(CACHE_PATH)); + for (File file : fileList) { + if (!bgList.getList().contains(file.getName())) { + // 删除过时的背景 + log.info("delete bg {}", file.getName()); + IO.destroy(file); + } + } + for (String item : bgList.getList()) { + IO.file(IO.fitPath(CACHE_PATH) + item, newFile -> { + // 下载新的背景 + try { + log.info("download new bg {}", item); + FileRequest.get(Resources.TIMI_SERVER_API + "/attachment/download/" + item).toFile(newFile); + } catch (IOException | NoPermissionException e) { + throw new RuntimeException(e); + } + }); + } + String result = bgList.getPermanent(); // 常驻背景 + if (TimiJava.isEmpty(result)) { + // 随机背景 + Collections.shuffle(bgList.getList()); + result = bgList.getList().getFirst(); + } + return IO.getInputStream(IO.fitPath(CACHE_PATH) + result); } @Override protected void onFinish(InputStream stream) { - callback.handler(stream); + if (!isTimeout) { + setValue(stream); + } + } + + @Override + protected void onException(Throwable e) { + log.error("BGService", e); + } + + @Override + protected void onTimeout() { + // 内置背景 + setValue(IO.resourceToInputStream(getClass(), "assets/img/bg.png")); + } + + private void setValue(InputStream stream) { + value.set(new BgImage(new Image(stream, -1, -1, false, false)).cover().build()); } }.start(); } diff --git a/src/main/java/cn/forevermc/launcher/service/SplashService.java b/src/main/java/cn/forevermc/launcher/service/SplashService.java index 1f1b617..d9f5193 100644 --- a/src/main/java/cn/forevermc/launcher/service/SplashService.java +++ b/src/main/java/cn/forevermc/launcher/service/SplashService.java @@ -1,14 +1,14 @@ package cn.forevermc.launcher.service; import cn.forevermc.launcher.bean.APISetting; -import javafx.beans.property.ReadOnlyStringProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import lombok.extern.slf4j.Slf4j; import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.InvokeForInjected; import com.imyeyu.inject.annotation.Service; import com.imyeyu.java.TimiJava; +import javafx.beans.property.ReadOnlyStringProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import lombok.extern.slf4j.Slf4j; import java.util.Collections; @@ -39,12 +39,12 @@ public class SplashService { return; } APISetting.DynamicList splashes = setting.getSplashes(); - if (TimiJava.isNotEmpty(splashes.getActive())) { - value.set(splashes.getActive()); + if (TimiJava.isNotEmpty(splashes.getPermanent())) { + value.set(splashes.getPermanent()); return; } Collections.shuffle(splashes.getList()); - value.set(splashes.getList().get(0)); + value.set(splashes.getList().getFirst()); }); } diff --git a/src/main/java/cn/forevermc/launcher/view/components/RootLayout.java b/src/main/java/cn/forevermc/launcher/view/components/RootLayout.java index cc9ad5c..73a553f 100644 --- a/src/main/java/cn/forevermc/launcher/view/components/RootLayout.java +++ b/src/main/java/cn/forevermc/launcher/view/components/RootLayout.java @@ -5,6 +5,10 @@ import cn.forevermc.launcher.bean.Page; import cn.forevermc.launcher.service.BGService; import cn.forevermc.launcher.service.PageService; import cn.forevermc.launcher.util.Resources; +import com.imyeyu.fx.utils.BgImage; +import com.imyeyu.inject.annotation.Component; +import com.imyeyu.inject.annotation.Inject; +import com.imyeyu.inject.annotation.InvokeForInjected; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.event.EventHandler; @@ -13,10 +17,6 @@ import javafx.scene.input.MouseEvent; import javafx.scene.layout.Background; import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; -import com.imyeyu.fx.utils.BgImage; -import com.imyeyu.inject.annotation.Component; -import com.imyeyu.inject.annotation.Inject; -import com.imyeyu.inject.annotation.InvokeForInjected; /** * 根布局 @@ -92,7 +92,7 @@ public class RootLayout extends StackPane { return bgService.getValue(); } return legacyBG; - }, launchGame.newUIProperty(), pageService.activatedPageProperty())); + }, launchGame.newUIProperty(), pageService.activatedPageProperty(), bgService.valueProperty())); BooleanBinding withOutBlur = pageService.activatedPageProperty().isEqualTo(Page.MENU).or(launchGame.newUIProperty().not()); bg.effectProperty().bind(Bindings.when(withOutBlur).then((GaussianBlur) null).otherwise(new GaussianBlur(16))); } diff --git a/src/main/java/cn/forevermc/launcher/view/pages/MenuPane.java b/src/main/java/cn/forevermc/launcher/view/pages/MenuPane.java index 2790535..7e5eb5b 100644 --- a/src/main/java/cn/forevermc/launcher/view/pages/MenuPane.java +++ b/src/main/java/cn/forevermc/launcher/view/pages/MenuPane.java @@ -3,6 +3,7 @@ package cn.forevermc.launcher.view.pages; import cn.forevermc.launcher.ForeverMC; import cn.forevermc.launcher.bean.ComponentSize; import cn.forevermc.launcher.bean.Game; +import cn.forevermc.launcher.service.BGService; import cn.forevermc.launcher.util.Resources; import cn.forevermc.launcher.view.components.AbstractPane; import cn.forevermc.launcher.view.components.LoginTypeSelector; @@ -10,6 +11,11 @@ import cn.forevermc.launcher.view.components.control.MCButton; import cn.forevermc.launcher.view.components.control.MCLabel; import cn.forevermc.launcher.view.components.control.MCPasswordField; import cn.forevermc.launcher.view.components.control.MCTextField; +import com.imyeyu.fx.icon.TimiFXIcon; +import com.imyeyu.fx.ui.TimiFXUI; +import com.imyeyu.fx.utils.BgFill; +import com.imyeyu.fx.utils.Row; +import com.imyeyu.inject.annotation.Inject; import javafx.animation.FadeTransition; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleDoubleProperty; @@ -17,18 +23,12 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.geometry.VPos; import javafx.scene.canvas.Canvas; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.StackPane; -import javafx.scene.text.Text; import javafx.util.Duration; -import com.imyeyu.fx.icon.TimiFXIcon; -import com.imyeyu.fx.ui.TimiFXUI; -import com.imyeyu.fx.utils.BgFill; -import com.imyeyu.fx.utils.Row; /** * 菜单面板 @@ -38,6 +38,9 @@ import com.imyeyu.fx.utils.Row; */ public abstract class MenuPane extends AbstractPane { + @Inject + private BGService bgService; + protected final Canvas splashCanvas; protected final MCLabel launchGameLabel; protected final MCButton fmcAccount, fmcServer, launchGameSelect, launch, option, exit, langSelect, about; @@ -181,12 +184,12 @@ public abstract class MenuPane extends AbstractPane { welcomeFT.setNode(transitionPane); welcomeFT.setFromValue(1); welcomeFT.setToValue(0); - welcomeFT.setDelay(Duration.millis(2000)); + welcomeFT.setDelay(Duration.millis(1000)); welcomeFT.setOnFinished(e -> { root.getChildren().remove(transitionPane); isFirstShow = false; }); - welcomeFT.play(); + bgService.valueProperty().addListener((obs, o, n) -> welcomeFT.play()); } } }