Skip to content

Commit dfa65d7

Browse files
committed
feat(GUI): 初步实现下载GUI
1 parent 2eddc62 commit dfa65d7

9 files changed

Lines changed: 210 additions & 6 deletions

File tree

build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ tasks.test {
6363
}
6464

6565
tasks.processResources {
66-
filesMatching("**") {
66+
filesMatching("**/*.json") {
67+
expand(
68+
"version" to project.version,
69+
)
70+
}
71+
filesMatching("**/*.mod.json") {
6772
expand(
6873
"version" to project.version,
6974
)

src/main/java/i18nupdatemod/I18nUpdateMod.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import i18nupdatemod.core.ResourcePack;
88
import i18nupdatemod.core.ResourcePackConverter;
99
import i18nupdatemod.entity.GameAssetDetail;
10+
import i18nupdatemod.core.LoadDetailUI;
11+
import i18nupdatemod.entity.LoadStage;
1012
import i18nupdatemod.util.FileUtil;
1113
import i18nupdatemod.util.Log;
1214

@@ -24,10 +26,13 @@
2426
public class I18nUpdateMod {
2527
public static final String MOD_ID = "i18nupdatemod";
2628
public static String MOD_VERSION;
27-
29+
public static volatile boolean shouldShutdown = false;
2830
public static final Gson GSON = new Gson();
2931

3032
public static void init(Path minecraftPath, String minecraftVersion, String loader) {
33+
LoadDetailUI.show();
34+
LoadDetailUI.setStage(LoadStage.INIT);
35+
3136
try (InputStream is = I18nUpdateMod.class.getResourceAsStream("/i18nMetaData.json")) {
3237
MOD_VERSION = GSON.fromJson(new InputStreamReader(is), JsonObject.class).get("version").getAsString();
3338
} catch (Exception e) {
@@ -47,6 +52,11 @@ public static void init(Path minecraftPath, String minecraftVersion, String load
4752
Log.warning("I18nUpdateMod会从互联网获取内容不可控的资源包。");
4853
Log.warning("这一行为违背了网易我的世界「开发者内容审核制度」:禁止上传与提审内容不一致的游戏内容。");
4954
Log.warning("为了遵循这一制度,I18nUpdateMod不会下载任何内容。");
55+
56+
LoadDetailUI.appendLog("I18nUpdateMod会从互联网获取内容不可控的资源包。");
57+
LoadDetailUI.appendLog("这一行为违背了网易我的世界「开发者内容审核制度」:禁止上传与提审内容不一致的游戏内容。");
58+
LoadDetailUI.appendLog("为了遵循这一制度,I18nUpdateMod不会下载任何内容。");
59+
LoadDetailUI.appendLog("请您手动关闭此窗口");
5060
return;
5161
} catch (ClassNotFoundException ignored) {
5262
}
@@ -57,36 +67,60 @@ public static void init(Path minecraftPath, String minecraftVersion, String load
5767

5868
try {
5969
//Get asset
70+
if (shouldShutdown) {
71+
return;
72+
}
6073
GameAssetDetail assets = I18nConfig.getAssetDetail(minecraftVersion, loader);
6174

6275
//Update resource pack
76+
LoadDetailUI.setStage(LoadStage.DOWNLOAD_ASSET);
77+
if (shouldShutdown) {
78+
return;
79+
}
6380
List<ResourcePack> languagePacks = new ArrayList<>();
6481
boolean convertNotNeed = assets.downloads.size() == 1 && assets.downloads.get(0).targetVersion.equals(minecraftVersion);
6582
String applyFileName = assets.downloads.get(0).fileName;
6683
for (GameAssetDetail.AssetDownloadDetail it : assets.downloads) {
84+
if (shouldShutdown) {
85+
return;
86+
}
6787
FileUtil.setTemporaryDirPath(Paths.get(localStorage, "." + MOD_ID, it.targetVersion));
6888
ResourcePack languagePack = new ResourcePack(it.fileName, convertNotNeed);
6989
languagePack.checkUpdate(it.fileUrl, it.md5Url);
7090
languagePacks.add(languagePack);
7191
}
7292

7393
//Convert resourcepack
94+
LoadDetailUI.setStage(LoadStage.CONVERT_RESOURCE_PACK);
95+
if (shouldShutdown){
96+
return;
97+
}
7498
if (!convertNotNeed) {
7599
FileUtil.setTemporaryDirPath(Paths.get(localStorage, "." + MOD_ID, minecraftVersion));
76100
applyFileName = assets.covertFileName;
77101
ResourcePackConverter converter = new ResourcePackConverter(languagePacks, applyFileName);
78102
converter.convert(assets.covertPackFormat, getResourcePackDescription(assets.downloads));
79103
}
104+
LoadDetailUI.appendLog("资源包已转换完成。");
80105

81106
//Apply resource pack
107+
LoadDetailUI.setStage(LoadStage.APPLY_RESOURCE_PACK);
108+
if (shouldShutdown){
109+
return;
110+
}
82111
GameConfig config = new GameConfig(minecraftPath.resolve("options.txt"));
83112
config.addResourcePack("Minecraft-Mod-Language-Modpack",
84113
(minecraftMajorVersion <= 12 ? "" : "file/") + applyFileName);
85114
config.writeToFile();
115+
LoadDetailUI.appendLog("资源包已应用。");
116+
LoadDetailUI.setStage(LoadStage.FINISH);
86117
} catch (Exception e) {
87118
Log.warning(String.format("Failed to update resource pack: %s", e));
119+
LoadDetailUI.appendLog(String.format("I18n Update Mod 运行失败: %s", e));
120+
LoadDetailUI.appendLog("请您手动关闭此窗口");
88121
// e.printStackTrace();
89122
}
123+
LoadDetailUI.hide();
90124
}
91125

92126
private static String getResourcePackDescription(List<GameAssetDetail.AssetDownloadDetail> downloads) {

src/main/java/i18nupdatemod/core/I18nConfig.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package i18nupdatemod.core;
22

33
import com.google.gson.Gson;
4-
import i18nupdatemod.entity.AssetMetaData;
5-
import i18nupdatemod.entity.GameAssetDetail;
6-
import i18nupdatemod.entity.GameMetaData;
7-
import i18nupdatemod.entity.I18nMetaData;
4+
import i18nupdatemod.entity.*;
85
import i18nupdatemod.util.Log;
96
import i18nupdatemod.util.Version;
107
import i18nupdatemod.util.VersionRange;
@@ -62,8 +59,10 @@ public static GameAssetDetail getAssetDetail(String minecraftVersion, String loa
6259
GameMetaData convert = getGameMetaData(minecraftVersion);
6360
GameAssetDetail ret = new GameAssetDetail();
6461

62+
LoadDetailUI.appendLog("正在获取最快的镜像源...");
6563
String assetRoot = getFastestUrl();
6664
Log.debug("Using asset root: " + assetRoot);
65+
LoadDetailUI.appendLog("即将从"+assetRoot+"下载资源包");
6766

6867
if (assetRoot.equals("https://raw.githubusercontent.com/")) {
6968
ret.downloads = createDownloadDetailsFromGit(convert, loader);
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package i18nupdatemod.core;
2+
3+
import i18nupdatemod.I18nUpdateMod;
4+
import i18nupdatemod.entity.LoadStage;
5+
6+
import javax.swing.*;
7+
import java.awt.*;
8+
import java.awt.event.ActionEvent;
9+
import java.awt.event.WindowAdapter;
10+
import java.awt.event.WindowEvent;
11+
import java.net.URL;
12+
13+
public class LoadDetailUI {
14+
private static volatile LoadDetailUI instance;
15+
private final JFrame frame;
16+
private final JProgressBar statusBar;
17+
private final JTextArea logArea;
18+
private final boolean useGUI;
19+
20+
private LoadDetailUI() {
21+
useGUI = Boolean.parseBoolean(System.getProperty("java.awt.headless"));
22+
23+
frame = new JFrame();
24+
frame.setTitle("I18nUpdateMod-资源包下载进度");
25+
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
26+
frame.setSize(854, 480);
27+
frame.setLocationRelativeTo(null);
28+
frame.setLayout(new BorderLayout());
29+
frame.addWindowListener(new WindowAdapter() {
30+
@Override
31+
public void windowClosing(WindowEvent e) {
32+
shutdown();
33+
}
34+
});
35+
36+
37+
URL iconURL = getClass().getResource("/icons/CFPA.png");
38+
if (iconURL != null) {
39+
Image icon = Toolkit.getDefaultToolkit().getImage(iconURL);
40+
frame.setIconImage(icon);
41+
}
42+
43+
// 主面板
44+
JPanel panel = new JPanel();
45+
panel.setBackground(new Color(220, 220, 220));
46+
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
47+
panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
48+
49+
// 状态栏
50+
statusBar = new JProgressBar();
51+
statusBar.setString("正在合并资源包");
52+
statusBar.setStringPainted(true);
53+
statusBar.setMaximum(LoadStage.values().length - 1);
54+
statusBar.setValue(100);
55+
statusBar.setForeground(new Color(102, 255, 102));
56+
panel.add(statusBar);
57+
panel.add(Box.createVerticalStrut(10));
58+
59+
// 日志输出区
60+
logArea = new JTextArea(6, 30);
61+
logArea.setEditable(false);
62+
logArea.setFont(new Font("Monospaced", Font.PLAIN, 13));
63+
JScrollPane scrollPane = new JScrollPane(logArea);
64+
scrollPane.setBorder(BorderFactory.createLineBorder(Color.GRAY));
65+
panel.add(scrollPane);
66+
panel.add(Box.createVerticalStrut(10));
67+
68+
// 提示文字
69+
JLabel tip = new JLabel("如遇到进度卡住,可以点击下方按钮/关闭此窗口停止此次下载。");
70+
tip.setAlignmentX(Component.CENTER_ALIGNMENT);
71+
panel.add(tip);
72+
panel.add(Box.createVerticalStrut(10));
73+
74+
// 停止按钮
75+
JButton stopButton = new JButton("停止此次下载");
76+
stopButton.setFocusPainted(false);
77+
stopButton.setBackground(Color.WHITE);
78+
stopButton.setAlignmentX(Component.CENTER_ALIGNMENT);
79+
stopButton.addActionListener((ActionEvent e) -> shutdown());
80+
panel.add(stopButton);
81+
82+
frame.add(panel, BorderLayout.CENTER);
83+
}
84+
85+
public static LoadDetailUI getInstance() {
86+
if (instance == null) {
87+
synchronized (LoadDetailUI.class) {
88+
if (instance == null) {
89+
instance = new LoadDetailUI();
90+
}
91+
}
92+
}
93+
return instance;
94+
}
95+
96+
public static void show() {
97+
getInstance().frame.setVisible(true);
98+
}
99+
100+
public static void hide() {
101+
getInstance().frame.setVisible(false);
102+
}
103+
104+
private void shutdown(){
105+
hide();
106+
I18nUpdateMod.shouldShutdown = true;
107+
}
108+
109+
public static void setStage(LoadStage stage) {
110+
SwingUtilities.invokeLater(() -> {
111+
LoadDetailUI gui = getInstance();
112+
gui.statusBar.setString(LoadStage.getDescription(stage));
113+
gui.statusBar.setValue(stage.getValue());
114+
gui.logArea.append("当前阶段: " + LoadStage.getDescription(stage) + "\n");
115+
gui.logArea.setCaretPosition(gui.logArea.getDocument().getLength());
116+
});
117+
}
118+
119+
public static void appendLog(String log) {
120+
SwingUtilities.invokeLater(() -> {
121+
LoadDetailUI gui = getInstance();
122+
gui.logArea.append(log + "\n");
123+
gui.logArea.setCaretPosition(gui.logArea.getDocument().getLength());
124+
});
125+
}
126+
}

src/main/java/i18nupdatemod/core/ResourcePack.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ public ResourcePack(String filename, boolean saveToGame) {
4141

4242
public void checkUpdate(String fileUrl, String md5Url) throws IOException, URISyntaxException, NoSuchAlgorithmException {
4343
if (isUpToDate(md5Url)) {
44+
LoadDetailUI.appendLog(filename + "无需更新");
4445
Log.debug("Already up to date.");
4546
return;
4647
}
4748
//In this time, we can only download full file
49+
LoadDetailUI.appendLog("正在下载" + filename);
4850
downloadFull(fileUrl, md5Url);
51+
LoadDetailUI.appendLog(filename + "下载完成");
4952
//In the future, we will download patch file and merge local file
5053
}
5154

src/main/java/i18nupdatemod/core/ResourcePackConverter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public void convert(int packFormat, String description) throws Exception {
4040
// zos.setMethod(ZipOutputStream.STORED);
4141
for (Path p : sourcePath) {
4242
Log.info("Converting: " + p);
43+
LoadDetailUI.appendLog("正在转换" + p);
4344
try (ZipFile zf = new ZipFile(p.toFile(), StandardCharsets.UTF_8)) {
4445
for (Enumeration<? extends ZipEntry> e = zf.entries(); e.hasMoreElements(); ) {
4546
ZipEntry ze = e.nextElement();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package i18nupdatemod.entity;
2+
3+
public enum LoadStage{
4+
INIT(0),
5+
DOWNLOAD_ASSET(1),
6+
CONVERT_RESOURCE_PACK(2),
7+
APPLY_RESOURCE_PACK(3),
8+
FINISH(4);
9+
10+
private final int value;
11+
12+
LoadStage(int value) {
13+
this.value = value;
14+
}
15+
16+
public int getValue() {
17+
return value;
18+
}
19+
20+
public static String getDescription(LoadStage stage) {
21+
switch (stage){
22+
case INIT:
23+
return "初始化";
24+
case DOWNLOAD_ASSET:
25+
return "更新资源包";
26+
case CONVERT_RESOURCE_PACK:
27+
return "转换资源包";
28+
case APPLY_RESOURCE_PACK:
29+
return "应用资源包";
30+
case FINISH:
31+
return "完成";
32+
default:
33+
return "未知";
34+
}
35+
}
36+
}

src/main/resources/icons/CFPA.png

10.5 KB
Loading
2.09 KB
Loading

0 commit comments

Comments
 (0)