Crash and upgrade

This commit is contained in:
huangyuhui
2018-01-27 16:16:38 +08:00
parent 1ff36552e0
commit 2c7510fe5f
20 changed files with 293 additions and 58 deletions

View File

@@ -23,10 +23,14 @@ import javafx.application.Platform;
import javafx.stage.Stage;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.upgrade.IUpgrader;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
import org.jackhuang.hmcl.util.*;
import java.io.File;
import java.util.Arrays;
import java.util.ResourceBundle;
import java.util.logging.Level;
@@ -44,8 +48,17 @@ public final class Main extends Application {
}
public static void main(String[] args) {
NetworkUtils.setUserAgentSupplier(() -> "Hello Minecraft! Launcher");
Thread.setDefaultUncaughtExceptionHandler(new CrashReporter());
// NetworkUtils.setUserAgentSupplier(() -> "Hello Minecraft! Launcher");
Constants.UI_THREAD_SCHEDULER = Constants.JAVAFX_UI_THREAD_SCHEDULER;
IUpgrader.NOW_UPGRADER.parseArguments(VersionNumber.asVersion(VERSION), Arrays.asList(args));
Logging.LOG.info("*** " + TITLE + " ***");
UPDATE_CHECKER.process(false)
.then(Task.of(Controllers::showUpdate))
.start();
launch(args);
}
@@ -99,4 +112,8 @@ public final class Main extends Application {
public static final String TITLE = NAME + " " + VERSION;
public static final File APPDATA = getWorkingDirectory("hmcl");
public static final ResourceBundle RESOURCE_BUNDLE = Settings.INSTANCE.getLocale().getResourceBundle();
public static final UpdateChecker UPDATE_CHECKER = new UpdateChecker(VersionNumber.asVersion(VERSION), "hmcl");
public static final String CONTACT = "http://huangyuhui.duapp.com/hmcl.php";
public static final String PUBLISH = "http://www.mcbbs.net/thread-142335-1-1.html";
}

View File

@@ -61,6 +61,7 @@ public final class Locales {
}
public static SupportedLocale getLocaleByName(String name) {
if (name == null) return DEFAULT;
switch (name.toLowerCase()) {
case "en": return EN;
case "zh": return ZH;

View File

@@ -68,6 +68,7 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
FXUtils.setValidateWhileTextChanged(txtUsername);
FXUtils.setValidateWhileTextChanged(txtPassword);
cboType.getItems().setAll(Main.i18n("account.methods.offline"), Main.i18n("account.methods.yggdrasil"));
cboType.getSelectionModel().selectedIndexProperty().addListener((a, b, newValue) -> {
txtPassword.setVisible(newValue.intValue() != 0);
});

View File

@@ -139,4 +139,8 @@ public final class Controllers {
public static void navigate(Node node) {
decorator.showPage(node);
}
public static void showUpdate() {
}
}

View File

@@ -0,0 +1,72 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.ui;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.jackhuang.hmcl.Main;
/**
* @author huangyuhui
*/
public class CrashWindow extends Stage {
private Label lblCrash = new Label();
private Button btnContact = new Button();
private TextArea textArea = new TextArea();
public CrashWindow(String text) {
if (Main.UPDATE_CHECKER.isOutOfDate())
lblCrash.setText(Main.i18n("launcher.crash_out_dated"));
else
lblCrash.setText(Main.i18n("launcher.crash"));
lblCrash.setWrapText(true);
textArea.setText(text);
textArea.setEditable(false);
btnContact.setText(Main.i18n("launcher.contact"));
btnContact.setOnMouseClicked(event -> FXUtils.openLink(Main.CONTACT));
HBox box = new HBox();
box.setStyle("-fx-padding: 8px;");
box.getChildren().add(btnContact);
box.setAlignment(Pos.CENTER_RIGHT);
BorderPane pane = new BorderPane();
StackPane stackPane = new StackPane();
stackPane.setStyle("-fx-padding: 8px;");
stackPane.getChildren().add(lblCrash);
pane.setTop(stackPane);
pane.setCenter(textArea);
pane.setBottom(box);
Scene scene = new Scene(pane, 800, 480);
setScene(scene);
getIcons().add(new Image("/assets/img/icon.png"));
setTitle(Main.i18n("message.error"));
}
}

View File

@@ -118,6 +118,8 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
private JFXButton btnMax;
@FXML
private JFXButton btnClose;
@FXML
private HBox updatePane;
public Decorator(Stage primaryStage, Node mainPage, String title) {
this(primaryStage, mainPage, title, true, true);
@@ -131,6 +133,9 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
FXUtils.loadFXML(this, "/assets/fxml/decorator.fxml");
updatePane.setCursor(Cursor.HAND);
updatePane.setOnMouseClicked(event -> Main.UPDATE_CHECKER.checkOutdate());
primaryStage.initStyle(StageStyle.UNDECORATED);
btnClose.setGraphic(close);
btnMin.setGraphic(minus);
@@ -374,6 +379,10 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
}
}
public void showUpdate() {
updatePane.setVisible(true);
}
private void setContent(Node content, AnimationProducer animation) {
animationHandler.setContent(content, animation);

View File

@@ -48,6 +48,7 @@ import org.jackhuang.hmcl.util.OperatingSystem;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -203,6 +204,27 @@ public final class FXUtils {
}
}
/**
* Open URL by java.awt.Desktop
*
* @param link null is allowed but will be ignored
*/
public static void openLink(String link) {
if (link == null)
return;
try {
java.awt.Desktop.getDesktop().browse(new URI(link));
} catch (Throwable e) {
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX)
try {
Runtime.getRuntime().exec(new String[] { "/usr/bin/open", link });
} catch (IOException ex) {
Logging.LOG.log(Level.WARNING, "Unable to open link: " + link, ex);
}
Logging.LOG.log(Level.WARNING, "Failed to open link: " + link, e);
}
}
public static void bindInt(JFXTextField textField, Property<?> property) {
textField.textProperty().unbind();
textField.textProperty().bindBidirectional((Property<Integer>) property, SafeIntStringConverter.INSTANCE);

View File

@@ -40,7 +40,7 @@ import java.util.Objects;
public final class LeftPaneController {
private final AdvancedListBox leftPane;
private final VBox profilePane = new VBox();
private final VersionListItem accountItem = new VersionListItem("No Account", "unknown");
private final VersionListItem accountItem = new VersionListItem("", "");
public LeftPaneController(AdvancedListBox leftPane) {
this.leftPane = leftPane;
@@ -67,8 +67,8 @@ public final class LeftPaneController {
FXUtils.onChangeAndOperate(Settings.INSTANCE.selectedAccountProperty(), it -> {
if (it == null) {
accountItem.setVersionName("mojang@mojang.com");
accountItem.setGameVersion("Yggdrasil");
accountItem.setVersionName(Main.i18n("account.missing"));
accountItem.setGameVersion(Main.i18n("message.unknown"));
} else {
accountItem.setVersionName(it.getUsername());
accountItem.setGameVersion(AccountsPage.accountType(it));

View File

@@ -48,7 +48,6 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.task.TaskExecutor;
import org.jackhuang.hmcl.ui.construct.MessageBox;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
import org.jackhuang.hmcl.ui.download.DownloadWizardProvider;
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
@@ -104,13 +103,13 @@ public final class MainPage extends StackPane implements DecoratorPage {
item.setVersionName(version);
item.setOnLaunchButtonClicked(e -> {
if (Settings.INSTANCE.getSelectedAccount() == null)
Controllers.dialog(Main.i18n("login.no_Player007"));
Controllers.dialog(Main.i18n("login.empty_username"));
else
LauncherHelper.INSTANCE.launch(version, null);
});
item.setOnScriptButtonClicked(e -> {
if (Settings.INSTANCE.getSelectedAccount() == null)
Controllers.dialog(Main.i18n("login.no_Player007"));
Controllers.dialog(Main.i18n("login.empty_username"));
else {
FileChooser chooser = new FileChooser();
chooser.setInitialDirectory(profile.getRepository().getRunDirectory(version));

View File

@@ -106,7 +106,7 @@ public class AppDataUpgrader extends IUpgrader {
String hash = null;
if (map.containsKey("jarsha1"))
hash = map.get("jarsha1");
Controllers.dialog(Main.i18n("ui.message.downloading"));
Controllers.dialog(Main.i18n("message.downloading"));
if (new AppDataUpgraderJarTask(NetworkUtils.toURL(map.get("jar")), version.toString(), hash).test()) {
new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderJarTask.getSelf(version.toString()).getAbsolutePath())
.directory(new File("").getAbsoluteFile()).start();
@@ -121,7 +121,7 @@ public class AppDataUpgrader extends IUpgrader {
String hash = null;
if (map.containsKey("packsha1"))
hash = map.get("packsha1");
Controllers.dialog(Main.i18n("ui.message.downloading"));
Controllers.dialog(Main.i18n("message.downloading"));
if (new AppDataUpgraderPackGzTask(NetworkUtils.toURL(map.get("pack")), version.toString(), hash).test()) {
new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderPackGzTask.getSelf(version.toString()).getAbsolutePath())
.directory(new File("").getAbsoluteFile()).start();
@@ -132,14 +132,14 @@ public class AppDataUpgrader extends IUpgrader {
Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex);
}
else {
String url = URL_PUBLISH;
String url = Main.PUBLISH;
if (map != null)
if (map.containsKey(OperatingSystem.CURRENT_OS.getCheckedName()))
url = map.get(OperatingSystem.CURRENT_OS.getCheckedName());
else if (map.containsKey(OperatingSystem.UNKNOWN.getCheckedName()))
url = map.get(OperatingSystem.UNKNOWN.getCheckedName());
if (url == null)
url = URL_PUBLISH;
url = Main.PUBLISH;
try {
java.awt.Desktop.getDesktop().browse(new URI(url));
} catch (URISyntaxException | IOException e) {
@@ -240,7 +240,4 @@ public class AppDataUpgrader extends IUpgrader {
}
}
public static final String URL_PUBLISH = "http://www.mcbbs.net/thread-142335-1-1.html";
public static final String URL_CONTACT = "http://huangyuhui.duapp.com/hmcl.php";
}

View File

@@ -51,7 +51,7 @@ public class NewFileUpgrader extends IUpgrader {
URL url = requestDownloadLink();
if (url == null) return;
File newf = new File(url.getFile());
Controllers.dialog(Main.i18n("ui.message.downloading"));
Controllers.dialog(Main.i18n("message.downloading"));
if (new FileDownloadTask(url, newf).test()) {
try {
new ProcessBuilder(newf.getCanonicalPath(), "--removeOldLauncher", getRealPath())

View File

@@ -75,7 +75,7 @@ public final class UpdateChecker {
}
if (value == null) {
Logging.LOG.warning("Failed to check update...");
Logging.LOG.warning("Unable to check update...");
if (showMessage)
MessageBox.show(Main.i18n("update.failed"));
} else if (base.compareTo(value) < 0)

View File

@@ -0,0 +1,121 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.util;
import javafx.application.Platform;
import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.ui.CrashWindow;
import org.jackhuang.hmcl.ui.construct.MessageBox;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;
/**
* @author huangyuhui
*/
public class CrashReporter implements Thread.UncaughtExceptionHandler {
private static final HashMap<String, String> SOURCE = new HashMap<String, String>() {
{
put("UnsatisfiedLinkError", Main.i18n("crash.user_fault"));
put("java.lang.NoClassDefFoundError", Main.i18n("crash.NoClassDefFound"));
put("java.lang.VerifyError", Main.i18n("crash.NoClassDefFound"));
put("java.lang.NoSuchMethodError", Main.i18n("crash.NoClassDefFound"));
put("java.lang.IncompatibleClassChangeError", Main.i18n("crash.NoClassDefFound"));
put("java.lang.ClassFormatError", Main.i18n("crash.NoClassDefFound"));
put("java.lang.OutOfMemoryError", "FUCKING MEMORY LIMIT!");
put("Trampoline", Main.i18n("launcher.update_java"));
put("NoSuchAlgorithmException", "Has your operating system been installed completely or is a ghost system?");
}
};
private boolean checkThrowable(Throwable e) {
String s = StringUtils.getStackTrace(e);
for (HashMap.Entry<String, String> entry : SOURCE.entrySet())
if (s.contains(entry.getKey())) {
if (StringUtils.isNotBlank(entry.getValue())) {
String info = entry.getValue();
Logging.LOG.severe(info);
try {
MessageBox.show(info);
} catch (Throwable t) {
Logging.LOG.log(Level.SEVERE, "Unable to show message", t);
}
}
return false;
}
return true;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
String s = StringUtils.getStackTrace(e);
if (!s.contains("org.jackhuang"))
return;
try {
StringBuilder builder = new StringBuilder();
builder.append("---- Hello Minecraft! Crash Report ----\n");
builder.append(" Version: " + Main.VERSION + "\n");
builder.append(" Time: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n");
builder.append(" Thread: ").append(t.toString()).append("\n");
builder.append("\n Content: \n ");
builder.append(s).append("\n\n");
builder.append("-- System Details --\n");
builder.append(" Operating System: ").append(OperatingSystem.SYSTEM_VERSION).append("\n");
builder.append(" Java Version: ").append(System.getProperty("java.version")).append(", ").append(System.getProperty("java.vendor")).append("\n");
builder.append(" Java VM Version: ").append(System.getProperty("java.vm.name")).append(" (").append(System.getProperty("java.vm.info")).append("), ").append(System.getProperty("java.vm.vendor")).append("\n");
String text = builder.toString();
Logging.LOG.log(Level.SEVERE, text);
if (checkThrowable(e) && !System.getProperty("java.vm.name").contains("OpenJDK")) {
Platform.runLater(() -> new CrashWindow(text).show());
if (!Main.UPDATE_CHECKER.isOutOfDate())
reportToServer(text, s);
}
} catch (Throwable ex) {
Logging.LOG.log(Level.SEVERE, "Unable to caught exception", ex);
Logging.LOG.log(Level.SEVERE, "There is the original exception", e);
}
}
private static final HashSet<String> THROWABLE_SET = new HashSet<>();
private void reportToServer(final String text, String stacktrace) {
if (THROWABLE_SET.contains(stacktrace) || stacktrace.contains("Font") || stacktrace.contains("InternalError"))
return;
THROWABLE_SET.add(stacktrace);
Thread t = new Thread(() -> {
HashMap<String, String> map = new HashMap<>();
map.put("crash_report", text);
map.put("version", Main.VERSION);
try {
NetworkUtils.doPost(NetworkUtils.toURL("http://huangyuhui.duapp.com/hmcl/crash.php"), map);
} catch (IOException ex) {
Logging.LOG.log(Level.SEVERE, "Unable to post HMCL server.", ex);
}
});
t.setDaemon(true);
t.start();
}
}

View File

@@ -26,7 +26,7 @@
<StackPane>
<JFXDialogLayout>
<heading>
<Label>Create a new account</Label>
<Label text="%account.create" />
</heading>
<body>
<GridPane vgap="15" hgap="15" style="-fx-padding: 15 0 0 0;">
@@ -34,24 +34,17 @@
<ColumnConstraints maxWidth="100" />
<ColumnConstraints />
</columnConstraints>
<Label text="Type" GridPane.halignment="RIGHT" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label text="%account.methods" GridPane.halignment="RIGHT" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<JFXComboBox fx:id="cboType" GridPane.columnIndex="1" GridPane.rowIndex="0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Offline Account"/>
<String fx:value="Online Account" />
</FXCollections>
</items>
</JFXComboBox>
<JFXComboBox fx:id="cboType" GridPane.columnIndex="1" GridPane.rowIndex="0" />
<JFXTextField fx:id="txtUsername" promptText="Username" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="1" GridPane.columnSpan="2">
<JFXTextField fx:id="txtUsername" promptText="%account.username" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="1" GridPane.columnSpan="2">
<validators>
<RequiredFieldValidator message="%input.not_empty">
</RequiredFieldValidator>
</validators>
</JFXTextField>
<JFXPasswordField fx:id="txtPassword" promptText="%login.password" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="2" GridPane.columnSpan="2">
<JFXPasswordField fx:id="txtPassword" promptText="%account.password" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="2" GridPane.columnSpan="2">
<validators>
<RequiredFieldValidator message="%input.not_empty">
</RequiredFieldValidator>

View File

@@ -29,6 +29,11 @@
</center>
<bottom>
<BorderPane fx:id="menuBottomBar">
<left>
<HBox fx:id="updatePane" visible="false" style="-fx-background-color: red;" alignment="CENTER_LEFT">
<Label text="%update.found" style="-fx-text-fill: white; -fx-font-size: 16px;" />
</HBox>
</left>
<right>
<JFXButton fx:id="addMenuButton" styleClass="toggle-icon4">
<graphic>

View File

@@ -103,7 +103,7 @@
<BorderPane>
<left>
<Label text="%mainwindow.show_log"/>
<Label text="%settings.show_log"/>
</left>
<right>
<JFXToggleButton fx:id="chkShowLogs" size="7"/>

View File

@@ -15,7 +15,7 @@
<body>
<VBox spacing="15" style="-fx-padding: 15 0 0 0;">
<Label fx:id="lblUsername" />
<JFXPasswordField fx:id="txtPassword" promptText="%login.password" labelFloat="true">
<JFXPasswordField fx:id="txtPassword" promptText="%account.password" labelFloat="true">
<validators>
<RequiredFieldValidator message="Input Required!">
</RequiredFieldValidator>

View File

@@ -50,7 +50,7 @@ crash.minecraft=Minecraft has crashed!
login.choose_charactor=Please choose the character you want
account.failed.no_charactor=No character in this account.
login.failed=Failed to login
login.no_Player007=You have not set a username!
login.empty_username=You have not set a username!
account.failed.wrong_password=Incorrect password or username
login.invalid_username=Invalid username
login.invalid_uuid_and_username=Invalid UUID and username
@@ -58,9 +58,9 @@ account.failed.invalid_password=Invalid password
account.failed.invalid_access_token=Invalid Access Token
login.changed_client_token=The server response has changed the client token.
input.email=The username must be an e-mail.
account.methods=Login
account.methods=Login Type
account.username=Name
login.account=Email
account.email=Email
account.failed.invalid_token=Please log out and re-input your password to log in.
login.no_valid_character=No valid character, please visit skinme.cc and create your own character.
@@ -101,9 +101,6 @@ crash.headless=If your OS is Linux, please use Oracle JDK instead of OpenJDK, or
crash.NoClassDefFound=Please check "HMCL" software is complete.
crash.error=Minecraft has crashed.
crash.main_class_not_found=Main Class is not found, may be your mc has been broken.
crash.class_path_wrong=Maybe the launch script is malformed.
profile.new_name=New Profile Name:
profile.copy_from=Copy From:
profile.new=New Config
@@ -130,12 +127,12 @@ button.ok=OK
button.yes=Yes
button.no=No
login.password=Password
account.password=Password
profile=Profile
login.enter_username=Please enter your name.
login.enter_password=Please enter your password.
ui.message.downloading=Downloading...
message.downloading=Downloading...
profile.remove=Sure to remove profile %s?
launcher.update_java=Please upgrade your Java.
launcher.open_jdk=We have found that you started this application using OpenJDK, which will cause so many troubles drawing the UI. We suggest you using Oracle JDK instead.
@@ -263,13 +260,11 @@ advancedsettings.precall_command=Precalling command(will be executed before game
advancedsettings.server_ip=Server Host
advancedsettings.dont_check_game_completeness=Don't check game completeness
mainwindow.show_log=Show Logs
settings.show_log=Show Logs
version.launch_script=Make Launching Script.
version.launch_script.failed=Failed to make script.
version.launch_script.save=Save the launch script
version.launch_script.success=Finished script creation, %s.
mainwindow.no_version=No version found. Switch to Game Downloads Tab?
launcher.about=About Author\nMinecraft Forum ID: klkl6523\nCopyright (c) 2013 huangyuhui\nOpened source under GPL v3 license:http://github.com/huanghongxun/HMCL/\nThis software used project Gson which is under Apache License 2.0, thanks contributors.
launcher_settings.download_source=Download Source
launcher.background_location=Background Location
@@ -285,7 +280,6 @@ launcher.background_tooltip=The laucher uses a default background.\nIf you use c
launcher.update_launcher=Check for update
launcher_settings.theme=Theme
launcher_settings.proxy=Proxy
launcher_settings.decorated=Enable system window border(in order to fix the problem that the ui become all gray in Linux OS)
launcher.modpack=Documentations for modpacks.
launcher_settings.language=Language
launcher.restart=Options will be in operations only if restart this app.
@@ -337,11 +331,11 @@ update.no_browser=Cannot open any browser. The link has been copied to the clipb
update.should_open_link=Are you willing to update the launcher?
update.newest_version=Newest version:
update.failed=Failed to check for updates.
update.found=(Found Update!)
update.found=Found Update!
logwindow.terminate_game=Terminate Game
logwindow.title=Log
logwindow.contact=Contact Us
launcher.contact=Contact Us
logwindow.show_lines=Show Lines
logwindow.search=Search
@@ -373,7 +367,7 @@ wizard.steps=Steps
lang=English
lang.default=Belong to OS language.
account.create=
account.create=Create a new account
input.not_empty=Input Requrired!
account=Accounts
install.new_game=Install a New Game
@@ -412,3 +406,5 @@ modpack.invalid=Invalid modpack file.
modpack.update=Upgrading game
message.confirm=Confirm
version.forbidden_name=Forbidden name, do not use this.
account.missing=Missing account
message.unknown=Unknown

View File

@@ -15,6 +15,7 @@
# along with this program. If not, see {http://www.gnu.org/licenses/}.
#
#author: huangyuhui
message.downloading=正在下载...
launch.failed=启动失败
launch.failed_creating_process=启动失败在创建新进程时发生错误可能是Java路径错误。
launch.failed.sh_permission=为启动文件添加权限时发生错误
@@ -50,7 +51,7 @@ crash.minecraft=Minecraft崩溃了请认真阅读建议。
login.choose_charactor=请选择您要使用的角色
account.failed.no_charactor=该帐号没有角色
login.failed=登录失败:
login.no_Player007=你还未设置用户名!
login.empty_username=你还未设置用户名!
account.failed.wrong_password=可能是您的用户名或密码错误
login.invalid_username=无效的用户名
login.invalid_uuid_and_username=无效的UUID和用户名
@@ -58,9 +59,9 @@ account.failed.invalid_password=无效的密码
account.failed.invalid_access_token=无效的访问令牌
login.changed_client_token=服务器回应已经修改客户端令牌
input.email=用户名必须是邮箱
account.methods=登录
account.methods=登录方式
account.username=用户名
login.account=邮箱
account.email=邮箱
account.failed.invalid_token=请尝试登出并重新输入密码登录
login.no_valid_character=无有效的角色自行到skinme.cc登陆并创建角色
@@ -101,9 +102,6 @@ crash.headless=如果您的操作系统是Linux请注意不要使用OpenJDK
crash.NoClassDefFound=请确认HMCL本体是否完整
crash.error=您的Minecraft崩溃了。
crash.main_class_not_found=找不到主类可能是您的JSON文件填写错误。无法启动游戏。可以通过下载整合包解决问题。
crash.class_path_wrong=解析Class Path时出现错误此错误本不应该发生。可能是启动脚本错误请仔细检查启动脚本。
profile.new_name=新配置名:
profile.copy_from=复制配置:
profile.new=新建配置
@@ -130,7 +128,7 @@ button.ok=确定
button.yes=
button.no=
login.password=密码
account.password=密码
profile=配置
login.enter_username=请输入您的账号
@@ -263,13 +261,11 @@ advancedsettings.precall_command=启动前执行命令(不必填写,将在游
advancedsettings.server_ip=直入服务器ip地址(不必填写,启动游戏后直接进入对应服务器)
advancedsettings.dont_check_game_completeness=不检查游戏完整性
mainwindow.show_log=查看日志
settings.show_log=查看日志
version.launch_script=生成启动脚本
version.launch_script.failed=生成启动脚本失败
version.launch_script.save=保存启动脚本
version.launch_script.success=启动脚本已生成完毕: %s.
mainwindow.no_version=未找到任何版本,是否进入游戏下载?
launcher.about=默认背景图感谢gamerteam提供。\n关于作者\n百度IDhuanghongxun20\nmcbbshuanghongxun\nMinecraft Forum ID: klkl6523\n欢迎提交Bug哦\nCopyright (c) 2013-2017 huangyuhui.\n免责声明Minecraft软件版权归Mojang AB所有使用本软件产生的版权问题本软件制作方概不负责。\n本启动器在GPLv3协议下开源:https://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者\n本软件使用了基于Apache License 2.0的Gson项目感谢贡献者。
launcher_settings.download_source=下载源
launcher.background_location=背景地址
@@ -285,7 +281,6 @@ launcher.background_tooltip=启动器默认使用自带的背景\n如果当前
launcher.update_launcher=检查更新
launcher_settings.theme=主题
launcher_settings.proxy=代理
launcher_settings.decorated=启用窗口边框(Linux下可解决程序界面全灰问题)
launcher.modpack=整合包作者帮助
launcher_settings.language=语言
launcher.restart=本界面选项需要重启本启动器生效
@@ -337,11 +332,11 @@ update.no_browser=无法打开浏览器,网址已经复制到剪贴板了,
update.should_open_link=是否更新?
update.newest_version=最新版本为:
update.failed=检查更新失败
update.found=(发现更新!)
update.found=发现更新
logwindow.terminate_game=结束游戏进程
logwindow.title=日志
logwindow.contact=联系我们
launcher.contact=联系我们
logwindow.show_lines=显示行数
logwindow.search=查找
@@ -412,3 +407,5 @@ modpack.invalid=无效的整合包升级文件,可能是下载时出现问题
modpack.update=正在升级整合包
message.confirm=提示
version.forbidden_name=此版本名称不受支持,请换一个名字
account.missing=没有账户
message.unknown=未知

View File

@@ -283,6 +283,7 @@ public final class Lang {
public static Integer toIntOrNull(Object string) {
try {
if (string == null) return null;
return Integer.parseInt(string.toString());
} catch (NumberFormatException e) {
return null;