diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8886e69c..13b14830 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -30,17 +30,17 @@ jobs:
echo "Current ref: ${{ github.ref }}"
- name: Clone Repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup JavaJDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'liberica'
cache: 'gradle'
- name: Setup Gradle
- uses: gradle/gradle-build-action@v2
+ uses: gradle/gradle-build-action@v3
with:
gradle-version: 8.1.1
@@ -48,21 +48,21 @@ jobs:
run: gradle clean distAll
- name: Upload Exe
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: ${{ ! startsWith(github.ref, 'refs/tags/') }}
with:
name: ArkPets.exe
path: desktop/build/dist/*.exe
- name: Upload Zip
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: ${{ ! startsWith(github.ref, 'refs/tags/') }}
with:
name: ArkPets.zip
path: desktop/build/dist/*.zip
- name: Upload Jar
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: ${{ ! startsWith(github.ref, 'refs/tags/') }}
with:
name: ArkPets.jar
diff --git a/.gitignore b/.gitignore
index 13559cee..e59da0b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,5 +22,8 @@ test*/
*.jar
# Exclude runtime files
-/ArkPetsConfig.json
-/models_data.json
+ArkPetsConfig.json
+models_data.json
+models*/
+logs*/
+err**
diff --git a/.idea/Ark-Pets.iml b/.idea/Ark-Pets.iml
index eb0c48ed..76089bcf 100644
--- a/.idea/Ark-Pets.iml
+++ b/.idea/Ark-Pets.iml
@@ -7,6 +7,7 @@
+
\ No newline at end of file
diff --git a/.idea/GitCommitMessageStorage.xml b/.idea/GitCommitMessageStorage.xml
new file mode 100644
index 00000000..e4fd56aa
--- /dev/null
+++ b/.idea/GitCommitMessageStorage.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/cn/harryh/arkpets/concurrent/ProcessPool.java b/core/src/cn/harryh/arkpets/concurrent/ProcessPool.java
index 0c45efc1..5acb0de1 100644
--- a/core/src/cn/harryh/arkpets/concurrent/ProcessPool.java
+++ b/core/src/cn/harryh/arkpets/concurrent/ProcessPool.java
@@ -22,11 +22,14 @@ public final class ProcessPool implements Executor {
return thread;
});
- private static ProcessPool instance = null;
+ private static volatile ProcessPool instance = null;
- public static synchronized ProcessPool getInstance() {
+ public static ProcessPool getInstance() {
if (instance == null)
- instance = new ProcessPool();
+ synchronized (ProcessPool.class) {
+ if (instance == null)
+ instance = new ProcessPool();
+ }
return instance;
}
@@ -82,14 +85,20 @@ public boolean isSuccess() {
public static class UnexpectedExitCodeException extends Exception {
private final int exitCode;
+ private final long processId;
- public UnexpectedExitCodeException(int exitCode) {
+ public UnexpectedExitCodeException(int exitCode, long processId) {
this.exitCode = exitCode;
+ this.processId = processId;
}
@Override
public String getMessage() {
return "The process exited with a non-zero exit code: " + exitCode;
}
+
+ public long getProcessId() {
+ return processId;
+ }
}
}
diff --git a/core/src/cn/harryh/arkpets/concurrent/SocketServer.java b/core/src/cn/harryh/arkpets/concurrent/SocketServer.java
index 94630c8e..34159c62 100644
--- a/core/src/cn/harryh/arkpets/concurrent/SocketServer.java
+++ b/core/src/cn/harryh/arkpets/concurrent/SocketServer.java
@@ -15,6 +15,7 @@
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
import static cn.harryh.arkpets.Const.serverPorts;
@@ -24,12 +25,15 @@ public final class SocketServer {
private ServerSocket serverSocket = null;
private final Set sessionList = new CopyOnWriteArraySet<>();
private Thread listener;
+ private final AtomicBoolean running = new AtomicBoolean(false);
+ private static volatile SocketServer instance = null;
- private static SocketServer instance = null;
-
- public static synchronized SocketServer getInstance() {
+ public static SocketServer getInstance() {
if (instance == null)
- instance = new SocketServer();
+ synchronized (SocketServer.class) {
+ if (instance == null)
+ instance = new SocketServer();
+ }
return instance;
}
@@ -43,6 +47,8 @@ private SocketServer() {
*/
public synchronized void startServer(HostTray hostTray)
throws PortUtils.NoPortAvailableException, PortUtils.ServerCollisionException {
+ if (running.get())
+ return;
Logger.info("SocketServer", "Request to start server");
this.port = PortUtils.getAvailablePort(serverPorts);
listener = new Thread(() -> {
@@ -65,15 +71,19 @@ public synchronized void startServer(HostTray hostTray)
}
});
ProcessPool.getInstance().execute(listener);
+ running.set(true);
}
/** Stops the server and close all the sessions.
*/
public synchronized void stopServer() {
+ if (!running.get())
+ return;
Logger.info("SocketServer", "Request to stop server");
if (listener != null)
listener.interrupt();
sessionList.forEach(SocketSession::close);
+ running.set(false);
}
@Override
diff --git a/core/src/cn/harryh/arkpets/utils/Logger.java b/core/src/cn/harryh/arkpets/utils/Logger.java
index 1eaf6b51..5430410a 100644
--- a/core/src/cn/harryh/arkpets/utils/Logger.java
+++ b/core/src/cn/harryh/arkpets/utils/Logger.java
@@ -7,10 +7,12 @@
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.varia.LevelRangeFilter;
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
import static cn.harryh.arkpets.Const.charsetDefault;
@@ -95,6 +97,13 @@ public String getHeader() {
};
}
+ /** Get log file path
+ * @return log file path
+ */
+ public static String getLogFilePath() {
+ return logFilePath;
+ }
+
/** Sets a new log level.
* @param level The new level.
*/
diff --git a/desktop/src/cn/harryh/arkpets/controllers/RootModule.java b/desktop/src/cn/harryh/arkpets/controllers/RootModule.java
index f77a0a07..1351afe0 100644
--- a/desktop/src/cn/harryh/arkpets/controllers/RootModule.java
+++ b/desktop/src/cn/harryh/arkpets/controllers/RootModule.java
@@ -166,7 +166,7 @@ protected Boolean call() throws InterruptedException, ExecutionException {
if (!future.get().isSuccess()) {
int exitCode = future.get().exitValue();
Logger.warn("Launcher", "Detected an abnormal finalization of an ArkPets thread (exit code " + exitCode + "). Please check the log file for details.");
- lastLaunchFailed = new ProcessPool.UnexpectedExitCodeException(exitCode);
+ lastLaunchFailed = new ProcessPool.UnexpectedExitCodeException(exitCode, future.get().processId());
return false;
}
Logger.debug("Launcher", "Detected a successful finalization of an ArkPets thread.");
diff --git a/desktop/src/cn/harryh/arkpets/guitasks/ZipTask.java b/desktop/src/cn/harryh/arkpets/guitasks/ZipTask.java
index 81ab34ef..b246841d 100644
--- a/desktop/src/cn/harryh/arkpets/guitasks/ZipTask.java
+++ b/desktop/src/cn/harryh/arkpets/guitasks/ZipTask.java
@@ -10,7 +10,10 @@
import javafx.scene.layout.StackPane;
import java.io.File;
+import java.nio.file.Paths;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
public class ZipTask extends GuiTask {
@@ -23,6 +26,16 @@ public ZipTask(StackPane root, GuiTaskStyle style, String zipPath, Map contents) {
+ super(root, style);
+ this.zipPath = zipPath;
+ this.contents = contents.stream()
+ .collect(Collectors.toMap(
+ path -> path,
+ path -> Paths.get(path).getFileName().toString()
+ ));
+ }
+
@Override
protected String getHeader() {
return "正在创建压缩文件...";
diff --git a/desktop/src/cn/harryh/arkpets/utils/GuiPrefabs.java b/desktop/src/cn/harryh/arkpets/utils/GuiPrefabs.java
index 5e70a818..201af2f2 100644
--- a/desktop/src/cn/harryh/arkpets/utils/GuiPrefabs.java
+++ b/desktop/src/cn/harryh/arkpets/utils/GuiPrefabs.java
@@ -5,6 +5,8 @@
import cn.harryh.arkpets.Const;
import cn.harryh.arkpets.concurrent.ProcessPool;
+import cn.harryh.arkpets.guitasks.GuiTask;
+import cn.harryh.arkpets.guitasks.ZipTask;
import com.jfoenix.controls.*;
import javafx.animation.FadeTransition;
import javafx.animation.KeyFrame;
@@ -20,18 +22,20 @@
import javafx.scene.layout.VBox;
import javafx.scene.paint.Paint;
import javafx.scene.shape.SVGPath;
+import javafx.stage.FileChooser;
import javafx.stage.Window;
import javafx.util.Duration;
import javax.net.ssl.SSLException;
+import java.io.File;
import java.io.FileNotFoundException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
import java.util.zip.ZipException;
import static cn.harryh.arkpets.Const.durationNormal;
@@ -43,14 +47,14 @@ public class GuiPrefabs {
public static class Colors {
- public static final String COLOR_INFO = "#37B";
- public static final String COLOR_SUCCESS = "#5B5";
- public static final String COLOR_WARNING = "#E93";
- public static final String COLOR_DANGER = "#F54";
- public static final String COLOR_WHITE = "#FFF";
- public static final String COLOR_BLACK = "#000";
- public static final String COLOR_DARK_GRAY = "#222";
- public static final String COLOR_GRAY = "#444";
+ public static final String COLOR_INFO = "#37B";
+ public static final String COLOR_SUCCESS = "#5B5";
+ public static final String COLOR_WARNING = "#E93";
+ public static final String COLOR_DANGER = "#F54";
+ public static final String COLOR_WHITE = "#FFF";
+ public static final String COLOR_BLACK = "#000";
+ public static final String COLOR_DARK_GRAY = "#222";
+ public static final String COLOR_GRAY = "#444";
public static final String COLOR_LIGHT_GRAY = "#666";
private Colors() {
@@ -109,17 +113,17 @@ public static void replaceStyleClass(Node node, String from, String to) {
public static class Icons {
- public static final String ICON_INFO = "m12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-.001 5.75c.69 0 1.251.56 1.251 1.25s-.561 1.25-1.251 1.25-1.249-.56-1.249-1.25.559-1.25 1.249-1.25zm2.001 12.25h-4v-1c.484-.179 1-.201 1-.735v-4.467c0-.534-.516-.618-1-.797v-1h3v6.265c0 .535.517.558 1 .735v.999z";
- public static final String ICON_INFO_ALT = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-.001 5.75c.69 0 1.251.56 1.251 1.25s-.561 1.25-1.251 1.25-1.249-.56-1.249-1.25.559-1.25 1.249-1.25zm2.001 12.25h-4v-1c.484-.179 1-.201 1-.735v-4.467c0-.534-.516-.618-1-.797v-1h3v6.265c0 .535.517.558 1 .735v.999z";
- public static final String ICON_HELP = "m12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1.25 17c0 .69-.559 1.25-1.25 1.25-.689 0-1.25-.56-1.25-1.25s.561-1.25 1.25-1.25c.691 0 1.25.56 1.25 1.25zm1.393-9.998c-.608-.616-1.515-.955-2.551-.955-2.18 0-3.59 1.55-3.59 3.95h2.011c0-1.486.829-2.013 1.538-2.013.634 0 1.307.421 1.364 1.226.062.847-.39 1.277-.962 1.821-1.412 1.343-1.438 1.993-1.432 3.468h2.005c-.013-.664.03-1.203.935-2.178.677-.73 1.519-1.638 1.536-3.022.011-.924-.284-1.719-.854-2.297z";
- public static final String ICON_HELP_ALT = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm0 18.25c-.69 0-1.25-.56-1.25-1.25s.56-1.25 1.25-1.25c.691 0 1.25.56 1.25 1.25s-.559 1.25-1.25 1.25zm1.961-5.928c-.904.975-.947 1.514-.935 2.178h-2.005c-.007-1.475.02-2.125 1.431-3.468.573-.544 1.025-.975.962-1.821-.058-.805-.73-1.226-1.365-1.226-.709 0-1.538.527-1.538 2.013h-2.01c0-2.4 1.409-3.95 3.59-3.95 1.036 0 1.942.339 2.55.955.57.578.865 1.372.854 2.298-.016 1.383-.857 2.291-1.534 3.021z";
- public static final String ICON_SUCCESS = "m12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm4.393 7.5l-5.643 5.784-2.644-2.506-1.856 1.858 4.5 4.364 7.5-7.643-1.857-1.857z";
+ public static final String ICON_INFO = "m12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-.001 5.75c.69 0 1.251.56 1.251 1.25s-.561 1.25-1.251 1.25-1.249-.56-1.249-1.25.559-1.25 1.249-1.25zm2.001 12.25h-4v-1c.484-.179 1-.201 1-.735v-4.467c0-.534-.516-.618-1-.797v-1h3v6.265c0 .535.517.558 1 .735v.999z";
+ public static final String ICON_INFO_ALT = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-.001 5.75c.69 0 1.251.56 1.251 1.25s-.561 1.25-1.251 1.25-1.249-.56-1.249-1.25.559-1.25 1.249-1.25zm2.001 12.25h-4v-1c.484-.179 1-.201 1-.735v-4.467c0-.534-.516-.618-1-.797v-1h3v6.265c0 .535.517.558 1 .735v.999z";
+ public static final String ICON_HELP = "m12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1.25 17c0 .69-.559 1.25-1.25 1.25-.689 0-1.25-.56-1.25-1.25s.561-1.25 1.25-1.25c.691 0 1.25.56 1.25 1.25zm1.393-9.998c-.608-.616-1.515-.955-2.551-.955-2.18 0-3.59 1.55-3.59 3.95h2.011c0-1.486.829-2.013 1.538-2.013.634 0 1.307.421 1.364 1.226.062.847-.39 1.277-.962 1.821-1.412 1.343-1.438 1.993-1.432 3.468h2.005c-.013-.664.03-1.203.935-2.178.677-.73 1.519-1.638 1.536-3.022.011-.924-.284-1.719-.854-2.297z";
+ public static final String ICON_HELP_ALT = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm0 18.25c-.69 0-1.25-.56-1.25-1.25s.56-1.25 1.25-1.25c.691 0 1.25.56 1.25 1.25s-.559 1.25-1.25 1.25zm1.961-5.928c-.904.975-.947 1.514-.935 2.178h-2.005c-.007-1.475.02-2.125 1.431-3.468.573-.544 1.025-.975.962-1.821-.058-.805-.73-1.226-1.365-1.226-.709 0-1.538.527-1.538 2.013h-2.01c0-2.4 1.409-3.95 3.59-3.95 1.036 0 1.942.339 2.55.955.57.578.865 1.372.854 2.298-.016 1.383-.857 2.291-1.534 3.021z";
+ public static final String ICON_SUCCESS = "m12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm4.393 7.5l-5.643 5.784-2.644-2.506-1.856 1.858 4.5 4.364 7.5-7.643-1.857-1.857z";
public static final String ICON_SUCCESS_ALT = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.25 17.292l-4.5-4.364 1.857-1.858 2.643 2.506 5.643-5.784 1.857 1.857-7.5 7.643z";
- public static final String ICON_WARNING = "m12 5.177l8.631 15.823h-17.262l8.631-15.823zm0-4.177l-12 22h24l-12-22zm-1 9h2v6h-2v-6zm1 9.75c-.689 0-1.25-.56-1.25-1.25s.561-1.25 1.25-1.25 1.25.56 1.25 1.25-.561 1.25-1.25 1.25z";
+ public static final String ICON_WARNING = "m12 5.177l8.631 15.823h-17.262l8.631-15.823zm0-4.177l-12 22h24l-12-22zm-1 9h2v6h-2v-6zm1 9.75c-.689 0-1.25-.56-1.25-1.25s.561-1.25 1.25-1.25 1.25.56 1.25 1.25-.561 1.25-1.25 1.25z";
public static final String ICON_WARNING_ALT = "m12 1l-12 22h24l-12-22zm-1 8h2v7h-2v-7zm1 11.25c-.69 0-1.25-.56-1.25-1.25s.56-1.25 1.25-1.25 1.25.56 1.25 1.25-.56 1.25-1.25 1.25z";
- public static final String ICON_DANGER = "m16.142 2l5.858 5.858v8.284l-5.858 5.858h-8.284l-5.858-5.858v-8.284l5.858-5.858h8.284zm.829-2h-9.942l-7.029 7.029v9.941l7.029 7.03h9.941l7.03-7.029v-9.942l-7.029-7.029zm-8.482 16.992l3.518-3.568 3.554 3.521 1.431-1.43-3.566-3.523 3.535-3.568-1.431-1.432-3.539 3.583-3.581-3.457-1.418 1.418 3.585 3.473-3.507 3.566 1.419 1.417z";
- public static final String ICON_DANGER_ALT = "m16.971 0h-9.942l-7.029 7.029v9.941l7.029 7.03h9.941l7.03-7.029v-9.942l-7.029-7.029zm-1.402 16.945l-3.554-3.521-3.518 3.568-1.418-1.418 3.507-3.566-3.586-3.472 1.418-1.417 3.581 3.458 3.539-3.583 1.431 1.431-3.535 3.568 3.566 3.522-1.431 1.43z";
- public static final String ICON_UPDATE = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1 15.889v-2.223s-3.78-.114-7 3.333c1.513-6.587 7-7.778 7-7.778v-2.221l5 4.425-5 4.464z";
+ public static final String ICON_DANGER = "m16.142 2l5.858 5.858v8.284l-5.858 5.858h-8.284l-5.858-5.858v-8.284l5.858-5.858h8.284zm.829-2h-9.942l-7.029 7.029v9.941l7.029 7.03h9.941l7.03-7.029v-9.942l-7.029-7.029zm-8.482 16.992l3.518-3.568 3.554 3.521 1.431-1.43-3.566-3.523 3.535-3.568-1.431-1.432-3.539 3.583-3.581-3.457-1.418 1.418 3.585 3.473-3.507 3.566 1.419 1.417z";
+ public static final String ICON_DANGER_ALT = "m16.971 0h-9.942l-7.029 7.029v9.941l7.029 7.03h9.941l7.03-7.029v-9.942l-7.029-7.029zm-1.402 16.945l-3.554-3.521-3.518 3.568-1.418-1.418 3.507-3.566-3.586-3.472 1.418-1.417 3.581 3.458 3.539-3.583 1.431 1.431-3.535 3.568 3.566 3.522-1.431 1.43z";
+ public static final String ICON_UPDATE = "m12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1 15.889v-2.223s-3.78-.114-7 3.333c1.513-6.587 7-7.778 7-7.778v-2.221l5 4.425-5 4.464z";
/** Gets an SVGPath Node using the given path string and color.
* @param svg The SVG path string.
@@ -158,8 +162,8 @@ public static JFXDialog createCenteredDialog(StackPane root, boolean overlayClos
public static JFXDialog createCommonDialog(StackPane root, Node graphic, String title, String header, String content, String detail) {
JFXDialog dialog = DialogUtil.createCenteredDialog(root, false);
VBox body = new VBox();
- Label h2 = (Label)DialogUtil.getPrefabsH2(header);
- Label h3 = (Label)DialogUtil.getPrefabsH3(content);
+ Label h2 = (Label) DialogUtil.getPrefabsH2(header);
+ Label h3 = (Label) DialogUtil.getPrefabsH3(content);
body.setSpacing(5);
body.getChildren().add(h2);
body.getChildren().add(new Separator());
@@ -185,8 +189,8 @@ public static JFXDialog createCommonDialog(StackPane root, Node graphic, String
public static JFXDialog createConfirmDialog(StackPane root, Node graphic, String title, String header, String content, Runnable onConfirmed) {
JFXDialog dialog = DialogUtil.createCenteredDialog(root, true);
VBox body = new VBox();
- Label h2 = (Label)DialogUtil.getPrefabsH2(header);
- Label h3 = (Label)DialogUtil.getPrefabsH3(content);
+ Label h2 = (Label) DialogUtil.getPrefabsH2(header);
+ Label h3 = (Label) DialogUtil.getPrefabsH3(content);
body.setSpacing(5);
body.getChildren().add(h2);
body.getChildren().add(new Separator());
@@ -210,8 +214,8 @@ public static JFXDialog createErrorDialog(StackPane root, Throwable e) {
JFXDialog dialog = DialogUtil.createCenteredDialog(root, false);
VBox content = new VBox();
- Label h2 = (Label)DialogUtil.getPrefabsH2("啊哦~ ArkPets启动器抛出了一个异常。");
- Label h3 = (Label)DialogUtil.getPrefabsH3("请重试操作,或查看帮助文档与日志。如需联系开发者,请提供下述信息:");
+ Label h2 = (Label) DialogUtil.getPrefabsH2("啊哦~ ArkPets启动器抛出了一个异常。");
+ Label h3 = (Label) DialogUtil.getPrefabsH3("请重试操作,或查看帮助文档与日志。如需联系开发者,请提供下述信息:");
content.setSpacing(5);
content.getChildren().add(h2);
content.getChildren().add(new Separator());
@@ -231,7 +235,32 @@ public static JFXDialog createErrorDialog(StackPane root, Throwable e) {
JFXDialogLayout layout = new JFXDialogLayout();
layout.setHeading(DialogUtil.getHeading(Icons.getIcon(Icons.ICON_DANGER, Colors.COLOR_DANGER), "发生异常", Colors.COLOR_DANGER));
layout.setBody(content);
- layout.setActions(DialogUtil.getOkayButton(dialog, root));
+
+ JFXButton button = new JFXButton();
+ button.setText("导出错误报告");
+ button.setTextFill(Paint.valueOf(Colors.COLOR_WHITE));
+ button.setStyle("-fx-font-size:13px;-fx-text-fill:" + Colors.COLOR_WHITE + ";-fx-background-color:" + Colors.COLOR_DARK_GRAY);
+ button.setOnAction(event -> {
+ List logList = new ArrayList<>();
+ logList.add(Logger.getLogFilePath());
+ if (e instanceof ProcessPool.UnexpectedExitCodeException exception) {
+ logList.add(String.format("%s.%d.log", Const.LogConfig.logCorePath, exception.getProcessId()));
+ }
+ FileChooser fileChooser = new FileChooser();
+ fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Archives", "*.zip"));
+ fileChooser.setInitialDirectory(new File("."));
+ fileChooser.setInitialFileName(String.format("error_logs_%s_%d.zip",
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
+ System.currentTimeMillis()));
+ File zipFile = fileChooser.showSaveDialog(root.getScene().getWindow());
+ if (zipFile == null) {
+ return;
+ }
+ new ZipTask(root, GuiTask.GuiTaskStyle.STRICT, zipFile.toString(), logList).start();
+ disposeDialog(dialog, root);
+ });
+
+ layout.setActions(button, DialogUtil.getOkayButton(dialog, root));
dialog.setContent(layout);
if (e instanceof ProcessPool.UnexpectedExitCodeException) {
@@ -286,7 +315,7 @@ public static JFXDialog createErrorDialog(StackPane root, Throwable e) {
}
public static void attachAction(JFXDialog dialog, Node action, int index) {
- ObservableList actionList = ((JFXDialogLayout)dialog.getContent()).getActions();
+ ObservableList actionList = ((JFXDialogLayout) dialog.getContent()).getActions();
if (index < 0)
actionList.add(action);
else
@@ -400,7 +429,8 @@ public int getActivatedId() {
return activatedId;
}
- protected record PeerNodeData(Node[] nodes, EventHandler onActivating, EventHandler onSuppressing) {
+ protected record PeerNodeData(Node[] nodes, EventHandler onActivating,
+ EventHandler onSuppressing) {
public void handleActivating() {
for (Node node : nodes)
activateNode(node);