diff --git a/core/build.gradle b/core/build.gradle index e01b97c..ee57ad3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -7,4 +7,6 @@ dependencies { annotationProcessor 'org.projectlombok:lombok:1.18.20' implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" + implementation group: 'com.kotcrab.vis', name: 'vis-ui', version: '1.5.1' + } \ No newline at end of file diff --git a/core/src/main/java/io/github/creeper12356/MyGame.java b/core/src/main/java/io/github/creeper12356/MyGame.java index 46af12a..912ee69 100644 --- a/core/src/main/java/io/github/creeper12356/MyGame.java +++ b/core/src/main/java/io/github/creeper12356/MyGame.java @@ -3,6 +3,7 @@ import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; +import com.kotcrab.vis.ui.VisUI; import io.github.creeper12356.screen.BasicMenuScreen; import io.github.creeper12356.screen.BoardScreen; @@ -10,6 +11,7 @@ import io.github.creeper12356.screen.RoundMenuScreen; import io.github.creeper12356.screen.StoryMenuScreen; import io.github.creeper12356.utils.Resource; +import io.github.creeper12356.utils.UpdateChecker; public class MyGame extends Game { public static final int SCREEN_MAIN_MENU = 0; @@ -20,6 +22,9 @@ public class MyGame extends Game { private BasicMenuScreen[] screens = new BasicMenuScreen[4]; private int lastScreen = -1; private int currentScreen = -1; + + private UpdateChecker updateChecker = new UpdateChecker(); + /** * @brief 切换屏幕 * @details 在外部调用此方法切换屏幕 @@ -43,10 +48,14 @@ public void navigateBack() { @Override public void create() { + VisUI.load(); screens[0] = new MainMenuScreen(this); screens[1] = new StoryMenuScreen(this); screens[2] = new RoundMenuScreen(this); screens[3] = new BoardScreen(this); + + updateChecker.checkUpdate(); + setScreen(SCREEN_MAIN_MENU); } @@ -54,9 +63,10 @@ public void create() { public void dispose() { Resource.dispose(); - for(Screen screen: screens) { + for (Screen screen : screens) { screen.dispose(); } + VisUI.dispose(); System.out.println("Game disposed"); super.dispose(); } diff --git a/core/src/main/java/io/github/creeper12356/utils/Resource.java b/core/src/main/java/io/github/creeper12356/utils/Resource.java index 7df0d87..e08b325 100644 --- a/core/src/main/java/io/github/creeper12356/utils/Resource.java +++ b/core/src/main/java/io/github/creeper12356/utils/Resource.java @@ -118,7 +118,7 @@ public class Resource { public static float aniDelayDuration; public static int pointMgr; - + public static String version; public static String language; // public static Animation aniTalkButton; @@ -753,7 +753,8 @@ public static byte[] loadData(String filename) { aniDelayDuration = 0.1f; // pointMgr = new PointMgr(); // aniTalkButton = new Animation(); - + + version = "v1.0.0"; language = "en"; // 启动游戏时加载 diff --git a/core/src/main/java/io/github/creeper12356/utils/UpdateChecker.java b/core/src/main/java/io/github/creeper12356/utils/UpdateChecker.java new file mode 100644 index 0000000..09e7efa --- /dev/null +++ b/core/src/main/java/io/github/creeper12356/utils/UpdateChecker.java @@ -0,0 +1,169 @@ +package io.github.creeper12356.utils; + +import java.io.BufferedInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.io.File; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Net.HttpMethods; +import com.badlogic.gdx.Net.HttpRequest; +import com.badlogic.gdx.Net.HttpResponseListener; +import com.badlogic.gdx.utils.JsonReader; +import com.badlogic.gdx.utils.JsonValue; + +import io.github.creeper12356.MyGame; + +public class UpdateChecker { + private String latestVersion; + private String downloadUrl; + + public void checkUpdate() { + String url = "https://api.github.com/repos/creeper12356/ChineseCheckerPorted/releases/latest"; + HttpRequest httpGet = new HttpRequest(HttpMethods.GET); + httpGet.setUrl(url); + + Gdx.net.sendHttpRequest(httpGet, new HttpResponseListener() { + @Override + public void handleHttpResponse(com.badlogic.gdx.Net.HttpResponse httpResponse) { + JsonReader json = new JsonReader(); + JsonValue latestRelease = json.parse(httpResponse.getResultAsString()); + + latestVersion = latestRelease.getString("tag_name"); + + if (latestVersion.equals(Resource.version)) { + System.out.println("No updates available."); + return; + } + + JsonValue assets = latestRelease.get("assets"); + for (JsonValue asset : assets) { + String assetName = asset.getString("name"); + if (assetName.endsWith(Resource.language + ".jar")) { + downloadUrl = asset.getString("browser_download_url"); + break; + } + } + + if (downloadUrl == null) { + System.out.println("No download URL found."); + return; + } + + System.out.println("Latest version: " + latestVersion); + System.out.println("Download URL: " + downloadUrl); + + // 下载并替换jar包 + setProxy(); + downloadFile(downloadUrl, System.getProperty("user.dir")); + unsetProxy(); + } + + @Override + public void failed(Throwable t) { + t.printStackTrace(); + System.out.println("Failed to check for updates."); + } + + @Override + public void cancelled() { + System.out.println("Cancelled checking for updates."); + } + }); + } + + public void downloadFile(String fileURL, String savePath) { + try { + URL url = new URL(fileURL); + HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); + int responseCode = httpConn.getResponseCode(); + + // 检查HTTP响应代码 + if (responseCode == HttpURLConnection.HTTP_OK) { + String disposition = httpConn.getHeaderField("Content-Disposition"); + int contentLength = httpConn.getContentLength(); + + // 打印文件信息 + System.out.println("Content-Type = " + httpConn.getContentType()); + System.out.println("Content-Disposition = " + disposition); + System.out.println("Content-Length = " + contentLength); + + // 打开输入流和输出流 + InputStream inputStream = httpConn.getInputStream(); + String oldJarPath = getCurrentJarPath(); + String saveFilePath = oldJarPath + ".new"; + + try (FileOutputStream outputStream = new FileOutputStream(saveFilePath); + BufferedInputStream in = new BufferedInputStream(inputStream)) { + + byte[] buffer = new byte[4096]; + int bytesRead = -1; + long totalBytesRead = 0; + int percentCompleted = 0; + long fileSize = contentLength; + + while ((bytesRead = in.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + totalBytesRead += bytesRead; + int percent = (int) (totalBytesRead * 100 / fileSize); + if (percent > percentCompleted) { + percentCompleted = percent; + System.out.print("下载进度: " + percentCompleted + "%\r"); + } + } + System.out.println("\n文件下载完成,保存到: " + saveFilePath); + + ProcessBuilder processBuilder; + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + processBuilder = new ProcessBuilder("cmd", "/c", + "move " + saveFilePath + " " + oldJarPath + " && java -jar " + oldJarPath); + } else { + processBuilder = new ProcessBuilder("sh", "-c", + "mv " + saveFilePath + " " + oldJarPath + " && chmod +x " + oldJarPath + + " && java -jar " + oldJarPath); + } + processBuilder.start(); + + System.exit(0); + } + } else { + System.out.println("服务器返回非预期响应代码: " + responseCode); + } + httpConn.disconnect(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void setProxy() { + System.setProperty("http.proxyHost", "127.0.0.1"); + System.setProperty("http.proxyPort", "7890"); + System.setProperty("https.proxyHost", "127.0.0.1"); + System.setProperty("https.proxyPort", "7890"); + } + + private void unsetProxy() { + System.clearProperty("http.proxyHost"); + System.clearProperty("http.proxyPort"); + System.clearProperty("https.proxyHost"); + System.clearProperty("https.proxyPort"); + } + + /** + * @brief 获取当前jar包路径 + * @return + */ + private String getCurrentJarPath() { + String path = null; + try { + path = new File(MyGame.class.getProtectionDomain().getCodeSource().getLocation() + .toURI()).getPath(); + System.out.println(path); + } catch (Exception e) { + e.printStackTrace(); + } + return path; + } +}