Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c15ec71be9 | ||
|
|
93273d555d | ||
|
|
793f81e287 | ||
|
|
d87b768fc0 | ||
|
|
c07d2dc6d3 | ||
|
|
95af0222f3 | ||
|
|
3f15eddb0c | ||
|
|
c39f1ad75f | ||
|
|
f27b60e031 | ||
|
|
5f1d0a5936 | ||
|
|
4fdadd5474 | ||
|
|
b2ea6d449e | ||
|
|
3afff687b2 | ||
|
|
37ddecf629 | ||
|
|
27e58edb1f | ||
|
|
3dd421a2bf | ||
|
|
4537f9e48f | ||
|
|
94b6cda86e | ||
|
|
9ae010a391 | ||
|
|
13c105472e | ||
|
|
88194e479e | ||
|
|
b36c194f67 | ||
|
|
7c7b6e0fd9 | ||
|
|
01b77f1f5f | ||
|
|
840a0ad840 | ||
|
|
ab1ca18488 | ||
|
|
75e0fa2def | ||
|
|
ca3ed47d21 |
No files matched your search
+10
-1
@@ -14,6 +14,15 @@
|
||||
<task-args/>
|
||||
<task-jvm-args/>
|
||||
</task>
|
||||
<task>
|
||||
<display-name>createApp</display-name>
|
||||
<non-blocking>no</non-blocking>
|
||||
<task-names>
|
||||
<name must-exist="yes">createApp</name>
|
||||
</task-names>
|
||||
<task-args/>
|
||||
<task-jvm-args/>
|
||||
</task>
|
||||
</common-tasks>
|
||||
<script-platform>
|
||||
<spec-name>j2se</spec-name>
|
||||
@@ -22,6 +31,6 @@
|
||||
<license-header>
|
||||
<name>GNU General Public License</name>
|
||||
<template>license-header.txt</template>
|
||||
<property name="organization">huangyuhui</property>
|
||||
<property name="organization">HMCLSoft</property>
|
||||
</license-header>
|
||||
</gradle-project-properties>
|
||||
+5
-3
@@ -11,15 +11,15 @@ before_deploy:
|
||||
- git push -q ${REPO} --tags
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: lfFEwKtij/s9Ao/SKL7oVdsWcfASshZuwT27gllMrTx1ZQqLCG2I5mGJOp5ukx7lb3y4Tu316nFasLjy9NI3eLXSx9f0w4q+wMf0K5Yj9iOwu/TIn7JkLyHDMQ20qRwGxZplS2WUb669gIRg+l6jUHeTBW+dlTxr0mMa6WHIl8UDpHwfFrGC3i6dL4y6WlDwGl2rYktvOoA/iqvtglBcHuXaL2sDfhp5MXRcYULTIw+b9zmiQXP665DQN+Su5I3gwB4y5X8RH72GAacZn13fEIo5i8UUoHM7UQxM8y8DKSO3avyFCfpUle9+9sErQVW7b6JV1c+AoLWuAhNJLMlUTKarZE7UMqfjvoQHxX5hp2B2WHLEON/UJiGf25HJWx6VhJitE0/odujqnG/umesqki2jMTs6gPcxbc9iBjzUg+ZmFztdtC+Emnni7lpqVVl+Y5hsJRn3Z6rIiNgwmaE0r2OQgAm1vRYFc7jvOdRfyFG+uCRZF6nS56BzJ7dLc0WW8dTgSft6YFll4ZYL6hiI9qiIaBAK948y5HV+6VBWuO3xf/G2CUFbE1Y9qUCjToh3ahxNDzZvXB+rXqvlvNQOi5l8n594oQ61n45qIHSKlMBn9Bxhw29oWT5mo1aYIaNXbpzKam2w4mK0T3VrgTszu/3282wRbNr+VAwdGMfwW1s=
|
||||
api_key: ${DEPLOY_REPO}
|
||||
file:
|
||||
- HMCL/build/libs/HMCL-${HMCL_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.jar
|
||||
- HMCL/build/libs/HMCL-${HMCL_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.exe
|
||||
- HMCL/build/libs/HMCL-${HMCL_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}-MacOSApp.zip
|
||||
- HMCSM/build/libs/HMCSM-${HMCSM_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.jar
|
||||
- HMCSM/build/libs/HMCSM-${HMCSM_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.exe
|
||||
- HMCSM/build/libs/HMCSM-${HMCSM_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}-MacOSApp.zip
|
||||
on:
|
||||
repo: huanghongxun/HMCL
|
||||
tags: false
|
||||
skip_cleanup: true
|
||||
install: echo "skip 'gradle assemble' step"
|
||||
@@ -30,3 +30,5 @@ cache:
|
||||
directories:
|
||||
- "$HOME/.gradle/caches/"
|
||||
- "$HOME/.gradle/wrapper/"
|
||||
git:
|
||||
depth: 1
|
||||
+56
-24
@@ -15,6 +15,26 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral();
|
||||
|
||||
maven {
|
||||
url "https://libraries.minecraft.net"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'net.sf.proguard:proguard-gradle:4.10'
|
||||
classpath 'edu.sc.seis.gradle:launch4j:1.0.6'
|
||||
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "edu.sc.seis.macAppBundle" version "2.1.6"
|
||||
}
|
||||
|
||||
import java.util.jar.JarOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
@@ -26,15 +46,31 @@ if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'org.jackhuang.hellominecraft.launcher.Main'
|
||||
}
|
||||
|
||||
def readBuildNumber() {
|
||||
def versionPropsFile = file('version.properties')
|
||||
|
||||
if (versionPropsFile.canRead()) {
|
||||
def Properties versionProps = new Properties()
|
||||
versionProps.load(new FileInputStream(versionPropsFile))
|
||||
|
||||
def code = versionProps['VERSION_CODE'].toInteger() + 1
|
||||
versionProps['VERSION_CODE'] = code.toString()
|
||||
versionProps.store(versionPropsFile.newWriter(), null)
|
||||
|
||||
return code.toString()
|
||||
}
|
||||
return "233"
|
||||
}
|
||||
|
||||
def buildnumber = System.getenv("TRAVIS_BUILD_NUMBER")
|
||||
if (buildnumber == null)
|
||||
buildnumber = System.getenv("BUILD_NUMBER")
|
||||
if (buildnumber == null)
|
||||
buildnumber = "233"
|
||||
|
||||
buildnumber = readBuildNumber()
|
||||
|
||||
def versionroot = System.getenv("VERSION_ROOT")
|
||||
if (versionroot == null)
|
||||
versionroot = "2.4.1"
|
||||
versionroot = "2.5.0"
|
||||
|
||||
String mavenGroupId = 'HMCL'
|
||||
String mavenVersion = versionroot + '.' + buildnumber
|
||||
@@ -56,6 +92,19 @@ task generateSources(type: Copy) {
|
||||
compileJava.setSource "$buildDir/generated-src"
|
||||
compileJava.dependsOn generateSources
|
||||
|
||||
task macAppCompressed(type: Zip, dependsOn: createApp) {
|
||||
archiveName "HMCL-$mavenVersion-MacOSApp.zip"
|
||||
include '**'
|
||||
destinationDir file("$buildDir/libs/")
|
||||
from "$buildDir/macApp"
|
||||
}
|
||||
|
||||
macAppBundle {
|
||||
mainClassName = mainClass
|
||||
icon = "src/main/icon.icns"
|
||||
javaProperties.put("apple.laf.useScreenMenuBar", "true")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
@@ -85,22 +134,6 @@ configurations {
|
||||
coreRuntime.extendsFrom runtime
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral();
|
||||
|
||||
maven {
|
||||
url "https://libraries.minecraft.net"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'net.sf.proguard:proguard-gradle:4.10'
|
||||
classpath 'edu.sc.seis.gradle:launch4j:1.0.6'
|
||||
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure(install.repositories.mavenInstaller) {
|
||||
pom.project {
|
||||
groupId = mavenGroupId
|
||||
@@ -123,22 +156,20 @@ jar {
|
||||
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||
|
||||
manifest {
|
||||
attributes 'Created-By' : 'Copyright(c) 2013-2016 huangyuhui.',
|
||||
attributes 'Created-By' : 'Copyright(c) 2013-2016 HMCLSoft.',
|
||||
'Main-Class' : mainClass
|
||||
}
|
||||
}
|
||||
|
||||
launch4j {
|
||||
launch4jCmd = 'D:\\Develop\\Java\\Launch4j\\launch4j.exe'
|
||||
//launch4jCmd = '/home/huangyuhui/softwares/launch4j/launch4j'
|
||||
supportUrl = 'http://www.mcbbs.net/thread-142335-1-1.html'
|
||||
supportUrl = 'http://www.hmclsoft.com'
|
||||
jreMinVersion = '1.6.0'
|
||||
|
||||
mainClassName = mainClass
|
||||
icon = new File(project.buildDir, '../icon.ico').absolutePath
|
||||
version = mavenVersion
|
||||
downloadUrl = 'http://java.com/download'
|
||||
copyright = "Copyright(c) 2013-2015 huangyuhui."
|
||||
copyright = "Copyright(c) 2013-2015 HMCLSoft."
|
||||
|
||||
jar = new File(project.buildDir, 'libs/' + mavenGroupId + '-' + mavenVersion + '.jar').absolutePath
|
||||
outfile = mavenGroupId + '-' + mavenVersion + '.exe'
|
||||
@@ -153,3 +184,4 @@ processResources {
|
||||
|
||||
build.dependsOn makeExecutable
|
||||
build.dependsOn makePackGZ
|
||||
build.dependsOn macAppCompressed
|
||||
+1
-1
@@ -98,7 +98,7 @@ public class AssetsMojangLoader extends IAssetsHandler {
|
||||
|
||||
@Override
|
||||
public Task getDownloadTask(IDownloadProvider sourceType) {
|
||||
return new AssetsTask(sourceType.getAssetsDownloadURL());
|
||||
return new AssetsTask(sourceType.getAssetsDownloadURL(), sourceType.getRetryAssetsDownloadURL());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+37
-12
@@ -34,6 +34,8 @@ import org.jackhuang.hellominecraft.util.code.DigestUtils;
|
||||
import org.jackhuang.hellominecraft.util.system.IOUtils;
|
||||
import org.jackhuang.hellominecraft.util.NetUtils;
|
||||
import org.jackhuang.hellominecraft.util.OverridableSwingWorker;
|
||||
import org.jackhuang.hellominecraft.util.StrUtils;
|
||||
import org.jackhuang.hellominecraft.util.func.Function;
|
||||
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
|
||||
|
||||
/**
|
||||
@@ -89,30 +91,37 @@ public abstract class IAssetsHandler {
|
||||
|
||||
protected class AssetsTask extends TaskInfo {
|
||||
|
||||
ArrayList<Task> al;
|
||||
String u;
|
||||
ArrayList<Task> tasks;
|
||||
String baseUrl;
|
||||
String retryBaseUrl;
|
||||
|
||||
public AssetsTask(String url) {
|
||||
public AssetsTask(String url, String retryUrl) {
|
||||
super(C.i18n("assets.download"));
|
||||
this.u = url;
|
||||
this.baseUrl = url;
|
||||
this.retryBaseUrl = retryUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeTask() {
|
||||
if (assetsDownloadURLs == null || assetsLocalNames == null || contents == null)
|
||||
throw new IllegalStateException(C.i18n("assets.not_refreshed"));
|
||||
|
||||
tasks = new ArrayList<>();
|
||||
int max = assetsDownloadURLs.size();
|
||||
al = new ArrayList<>();
|
||||
int hasDownloaded = 0;
|
||||
for (int i = 0; i < max; i++) {
|
||||
String mark = assetsDownloadURLs.get(i);
|
||||
String url = u + mark;
|
||||
String downloadUrl = baseUrl + mark;
|
||||
String downloadRetryUrl = StrUtils.isNotBlank(retryBaseUrl) ? retryBaseUrl + mark : "";
|
||||
File location = assetsLocalNames.get(i);
|
||||
|
||||
if (!location.getParentFile().exists() && !location.getParentFile().mkdirs())
|
||||
HMCLog.warn("Failed to make directories: " + location.getParent());
|
||||
|
||||
if (location.isDirectory())
|
||||
continue;
|
||||
boolean need = true;
|
||||
|
||||
boolean needDownload = true;
|
||||
try {
|
||||
if (location.exists()) {
|
||||
FileInputStream fis = new FileInputStream(location);
|
||||
@@ -121,23 +130,39 @@ public abstract class IAssetsHandler {
|
||||
if (contents.get(i).geteTag().equals(sha)) {
|
||||
++hasDownloaded;
|
||||
HMCLog.log("File " + assetsLocalNames.get(i) + " has been downloaded successfully, skipped downloading.");
|
||||
if (ppl != null)
|
||||
if (ppl != null) {
|
||||
ppl.setProgress(this, hasDownloaded, max);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
HMCLog.warn("Failed to get hash: " + location, e);
|
||||
need = !location.exists();
|
||||
needDownload = !location.exists();
|
||||
}
|
||||
if (need)
|
||||
al.add(new FileDownloadTask(url, location).setTag(mark));
|
||||
|
||||
if (needDownload) {
|
||||
FileDownloadTask fileDownloadTask = new FileDownloadTask(downloadUrl, location);
|
||||
fileDownloadTask.setTag(mark);
|
||||
|
||||
// retry
|
||||
if (StrUtils.isNotBlank(downloadRetryUrl)) {
|
||||
fileDownloadTask.setFailedCallbackReturnsNewURL(new Function<Integer, String>() {
|
||||
@Override
|
||||
public String apply(Integer t) {
|
||||
return downloadRetryUrl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tasks.add(fileDownloadTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getAfterTasks() {
|
||||
return al;
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -56,7 +56,8 @@ public class MinecraftAssetService extends IMinecraftAssetService {
|
||||
public Task downloadAssets(final MinecraftVersion mv) {
|
||||
if (mv == null)
|
||||
return null;
|
||||
return IAssetsHandler.ASSETS_HANDLER.getList(mv, service.asset()).after(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(service.getDownloadType().getProvider()));
|
||||
return IAssetsHandler.ASSETS_HANDLER.getList(mv, service.asset())
|
||||
.after(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(service.getDownloadType().getProvider()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -148,7 +148,7 @@ public class YggdrasilAuthentication {
|
||||
|
||||
if (StrUtils.isNotBlank(response.error)) {
|
||||
HMCLog.err("Failed to log in, the auth server returned an error: " + response.error + ", message: " + response.errorMessage + ", cause: " + response.cause);
|
||||
if (response.errorMessage.contains("Invalid token"))
|
||||
if (response.errorMessage != null && response.errorMessage.contains("Invalid token"))
|
||||
response.errorMessage = C.i18n("login.invalid_token");
|
||||
throw new AuthenticationException("Request error: " + response.errorMessage);
|
||||
}
|
||||
|
||||
+3
-1
@@ -29,10 +29,12 @@ public class DownloadLibraryJob {
|
||||
|
||||
public IMinecraftLibrary lib;
|
||||
public String url;
|
||||
public String retryUrl;
|
||||
public File path;
|
||||
|
||||
public DownloadLibraryJob(IMinecraftLibrary n, String u, File p) {
|
||||
public DownloadLibraryJob(IMinecraftLibrary n, String u, String retry, File p) {
|
||||
url = u;
|
||||
retryUrl = retry;
|
||||
lib = n;
|
||||
path = IOUtils.tryGetCanonicalFile(p);
|
||||
}
|
||||
|
||||
+3
-2
@@ -29,7 +29,8 @@ public enum DownloadType {
|
||||
Mojang("download.mojang", new MojangDownloadProvider()),
|
||||
BMCL("download.BMCL", new BMCLAPIDownloadProvider()),
|
||||
//RapidData("download.rapid_data", new RapidDataDownloadProvider()),
|
||||
Curse("Curse CDN", new CurseDownloadProvider());
|
||||
Curse("Curse CDN", new CurseDownloadProvider()),
|
||||
Dynamic("HMCLSoft", DynamicDownloadProvider.getInstance());
|
||||
|
||||
private final String name;
|
||||
private final IDownloadProvider provider;
|
||||
@@ -47,7 +48,7 @@ public enum DownloadType {
|
||||
return C.i18n(name);
|
||||
}
|
||||
|
||||
private static DownloadType suggestedDownloadType = Mojang;
|
||||
private static DownloadType suggestedDownloadType = Dynamic;
|
||||
|
||||
public static DownloadType getSuggestedDownloadType() {
|
||||
return suggestedDownloadType;
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2013 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.hellominecraft.launcher.core.download;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hellominecraft.util.C;
|
||||
import org.jackhuang.hellominecraft.util.NetUtils;
|
||||
import org.jackhuang.hellominecraft.util.StrUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author evilwk <evilwk@gmail.com>
|
||||
*/
|
||||
public class DynamicDownloadProvider extends MojangDownloadProvider {
|
||||
|
||||
private static final String PROVIDER_ADDR = "http://client.api.mcgogogo.com:81/provider.php";
|
||||
|
||||
private volatile static DynamicDownloadProvider instance;
|
||||
|
||||
private String versionManifestAddr = null;
|
||||
private String launcherMetaAddr = null;
|
||||
private String launcherAddr = null;
|
||||
|
||||
private String librariesAddr = null;
|
||||
private String assetsAddr = null;
|
||||
|
||||
public void setVersionManifestAddr(String versionManifestAddr) {
|
||||
this.versionManifestAddr = versionManifestAddr;
|
||||
}
|
||||
|
||||
public void setLauncherMetaAddr(String launcherMetaAddr) {
|
||||
this.launcherMetaAddr = launcherMetaAddr;
|
||||
}
|
||||
|
||||
public void setLauncherAddr(String launcherAddr) {
|
||||
this.launcherAddr = launcherAddr;
|
||||
}
|
||||
|
||||
public void setLibrariesAddr(String librariesAddr) {
|
||||
this.librariesAddr = librariesAddr;
|
||||
}
|
||||
|
||||
public void setAssetsAddr(String assetsAddr) {
|
||||
this.assetsAddr = assetsAddr;
|
||||
}
|
||||
|
||||
private DynamicDownloadProvider() {
|
||||
|
||||
}
|
||||
|
||||
public static DynamicDownloadProvider getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (DynamicDownloadProvider.class) {
|
||||
if (instance == null) {
|
||||
instance = new DynamicDownloadProvider();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRetryAssetsDownloadURL() {
|
||||
return super.getAssetsDownloadURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRetryLibraryDownloadURL() {
|
||||
return super.getLibraryDownloadURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssetsDownloadURL() {
|
||||
if (StrUtils.isNotBlank(assetsAddr)) {
|
||||
return assetsAddr;
|
||||
}
|
||||
return super.getAssetsDownloadURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLibraryDownloadURL() {
|
||||
if (StrUtils.isNotBlank(librariesAddr)) {
|
||||
return librariesAddr;
|
||||
}
|
||||
return super.getLibraryDownloadURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionsListDownloadURL() {
|
||||
if (StrUtils.isNotBlank(versionManifestAddr)) {
|
||||
return versionManifestAddr;
|
||||
}
|
||||
return super.getVersionsListDownloadURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParsedDownloadURL(String str) {
|
||||
if (StrUtils.isNotBlank(librariesAddr)) {
|
||||
str = str.replace("https://libraries.minecraft.net", librariesAddr);
|
||||
}
|
||||
if (StrUtils.isNotBlank(launcherMetaAddr)) {
|
||||
str = str.replace("https://launchermeta.mojang.com", launcherMetaAddr);
|
||||
}
|
||||
if (StrUtils.isNotBlank(launcherMetaAddr)) {
|
||||
str = str.replace("https://launcher.mojang.com", launcherAddr);
|
||||
}
|
||||
return super.getParsedDownloadURL(str);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
new Thread() {
|
||||
|
||||
private String getValue(Map<String, String> addrInfo, String key) {
|
||||
String value = null;
|
||||
do {
|
||||
if (!addrInfo.containsKey(key))
|
||||
continue;
|
||||
value = addrInfo.get(key);
|
||||
} while(false);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
String providerInfo = NetUtils.get(PROVIDER_ADDR);
|
||||
Map<String, String> addrInfo = null;
|
||||
addrInfo = C.GSON.fromJson(providerInfo, new TypeToken<Map<String, String>>() {
|
||||
}.getType());
|
||||
if (addrInfo != null) {
|
||||
setLibrariesAddr(getValue(addrInfo, "libraries"));
|
||||
setAssetsAddr(getValue(addrInfo, "assets"));
|
||||
setLauncherMetaAddr(getValue(addrInfo, "launcherMeta"));
|
||||
setLauncherAddr(getValue(addrInfo, "launcher"));
|
||||
setVersionManifestAddr(getValue(addrInfo, "versionManifest"));
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -38,7 +38,7 @@ public abstract class IDownloadProvider {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract InstallerVersionList getForgeInstaller();
|
||||
|
||||
public abstract InstallerVersionList getLiteLoaderInstaller();
|
||||
@@ -46,6 +46,10 @@ public abstract class IDownloadProvider {
|
||||
public abstract InstallerVersionList getOptiFineInstaller();
|
||||
|
||||
public abstract String getLibraryDownloadURL();
|
||||
|
||||
public String getRetryLibraryDownloadURL() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public abstract String getVersionsDownloadURL();
|
||||
|
||||
@@ -55,6 +59,10 @@ public abstract class IDownloadProvider {
|
||||
|
||||
public abstract String getAssetsDownloadURL();
|
||||
|
||||
public String getRetryAssetsDownloadURL() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* For example, minecraft.json/assetIndex/url or
|
||||
* minecraft.json/downloads/client/url
|
||||
|
||||
+16
-9
@@ -31,6 +31,7 @@ import org.jackhuang.hellominecraft.launcher.core.GameException;
|
||||
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
|
||||
import org.jackhuang.hellominecraft.launcher.core.version.GameDownloadInfo;
|
||||
import org.jackhuang.hellominecraft.launcher.core.version.IMinecraftLibrary;
|
||||
import org.jackhuang.hellominecraft.launcher.core.version.LibraryDownloadInfo;
|
||||
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
|
||||
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
|
||||
import org.jackhuang.hellominecraft.util.func.Function;
|
||||
@@ -53,14 +54,17 @@ public class MinecraftDownloadService extends IMinecraftDownloadService {
|
||||
ArrayList<DownloadLibraryJob> downloadLibraries = new ArrayList<>();
|
||||
if (mv == null)
|
||||
return downloadLibraries;
|
||||
|
||||
MinecraftVersion v = mv.resolve(service.version());
|
||||
for (IMinecraftLibrary l : v.getLibraries())
|
||||
if (l != null && l.allow() && l.getDownloadInfo() != null) {
|
||||
File ff = l.getFilePath(service.baseDirectory());
|
||||
for (IMinecraftLibrary libraryInfo : v.getLibraries())
|
||||
if (libraryInfo != null && libraryInfo.allow() && libraryInfo.getDownloadInfo() != null) {
|
||||
File ff = libraryInfo.getFilePath(service.baseDirectory());
|
||||
if (!ff.exists()) {
|
||||
String libURL = l.getDownloadInfo().getUrl(service.getDownloadType());
|
||||
if (libURL != null)
|
||||
downloadLibraries.add(new DownloadLibraryJob(l, libURL, ff));
|
||||
LibraryDownloadInfo downloadInfo = libraryInfo.getDownloadInfo();
|
||||
String downloadUrl = downloadInfo.getUrl(service.getDownloadType());
|
||||
String retryDownloadUrl = downloadInfo.getRetryUrl(service.getDownloadType());
|
||||
if (downloadUrl != null)
|
||||
downloadLibraries.add(new DownloadLibraryJob(libraryInfo, downloadUrl, retryDownloadUrl, ff));
|
||||
}
|
||||
}
|
||||
return downloadLibraries;
|
||||
@@ -114,10 +118,13 @@ public class MinecraftDownloadService extends IMinecraftDownloadService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(Integer t) {
|
||||
return DownloadType.values()[t / 2].getProvider().getVersionsDownloadURL() + suffix;
|
||||
public String apply(Integer repeat) {
|
||||
int index = repeat / 2;
|
||||
if (index > DownloadType.values().length) {
|
||||
index = 0;
|
||||
}
|
||||
return DownloadType.values()[index].getProvider().getVersionsDownloadURL() + suffix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-4
@@ -41,27 +41,32 @@ public class MojangDownloadProvider extends IDownloadProvider {
|
||||
public InstallerVersionList getOptiFineInstaller() {
|
||||
return org.jackhuang.hellominecraft.launcher.core.install.optifine.vanilla.OptiFineVersionList.getInstance();
|
||||
}
|
||||
|
||||
|
||||
// jars
|
||||
@Override
|
||||
public String getLibraryDownloadURL() {
|
||||
return "https://libraries.minecraft.net";
|
||||
}
|
||||
|
||||
// jars
|
||||
@Override
|
||||
public String getVersionsDownloadURL() {
|
||||
return "http://s3.amazonaws.com/Minecraft.Download/versions/";
|
||||
}
|
||||
|
||||
|
||||
// resource
|
||||
@Override
|
||||
public String getIndexesDownloadURL() {
|
||||
return "http://s3.amazonaws.com/Minecraft.Download/indexes/";
|
||||
}
|
||||
|
||||
|
||||
// game versions json
|
||||
@Override
|
||||
public String getVersionsListDownloadURL() {
|
||||
return "https://launchermeta.mojang.com/mc/game/version_manifest.json";
|
||||
}
|
||||
|
||||
|
||||
// resource
|
||||
@Override
|
||||
public String getAssetsDownloadURL() {
|
||||
return "https://resources.download.minecraft.net/";
|
||||
|
||||
+92
-73
@@ -30,91 +30,110 @@ import org.jackhuang.hellominecraft.util.tasks.Task;
|
||||
*/
|
||||
public abstract class InstallerVersionList {
|
||||
|
||||
/**
|
||||
* Refresh installer versions list from the downloaded content.
|
||||
*
|
||||
* @param versions Minecraft versions you need to refresh
|
||||
*
|
||||
* @throws java.lang.Exception including network exceptions, IO exceptions.
|
||||
*/
|
||||
public abstract Task refresh(String[] versions);
|
||||
/**
|
||||
* Refresh installer versions list from the downloaded content.
|
||||
*
|
||||
* @param versions Minecraft versions you need to refresh
|
||||
*
|
||||
* @throws java.lang.Exception including network exceptions, IO exceptions.
|
||||
*/
|
||||
public abstract Task refresh(String[] versions);
|
||||
|
||||
/**
|
||||
* Installer name.
|
||||
*
|
||||
* @return installer name.
|
||||
*/
|
||||
public abstract String getName();
|
||||
/**
|
||||
* Installer name.
|
||||
*
|
||||
* @return installer name.
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Get installers you want.
|
||||
*
|
||||
* @param mcVersion the installers to this Minecraft version.
|
||||
*
|
||||
* @return cached result.
|
||||
*/
|
||||
protected abstract List<InstallerVersion> getVersionsImpl(String mcVersion);
|
||||
/**
|
||||
* Get installers you want.
|
||||
*
|
||||
* @param mcVersion the installers to this Minecraft version.
|
||||
*
|
||||
* @return cached result.
|
||||
*/
|
||||
protected abstract List<InstallerVersion> getVersionsImpl(String mcVersion);
|
||||
|
||||
/**
|
||||
* Get installers you want, please cache this method's result to save time.
|
||||
*
|
||||
* @param mcVersion the installers to this Minecraft version.
|
||||
*
|
||||
* @return a copy of the cached data to prevent
|
||||
* ConcurrentModificationException.
|
||||
*/
|
||||
public List<InstallerVersion> getVersions(String mcVersion) {
|
||||
List<InstallerVersion> a = getVersionsImpl(mcVersion);
|
||||
if (a == null)
|
||||
return null;
|
||||
else
|
||||
return new ArrayList<>(a);
|
||||
}
|
||||
/**
|
||||
* Get installers you want, please cache this method's result to save time.
|
||||
*
|
||||
* @param mcVersion the installers to this Minecraft version.
|
||||
*
|
||||
* @return a copy of the cached data to prevent
|
||||
* ConcurrentModificationException.
|
||||
*/
|
||||
public List<InstallerVersion> getVersions(String mcVersion) {
|
||||
List<InstallerVersion> a = getVersionsImpl(mcVersion);
|
||||
if (a == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new ArrayList<>(a);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstallerVersion implements Comparable<InstallerVersion> {
|
||||
public static int compareVersion(String verOne, String verTwo) {
|
||||
String[] verInfoOne = verOne.split("\\.");
|
||||
String[] verInfoTwo = verTwo.split("\\.");
|
||||
int idx = 0;
|
||||
int minLength = Math.min(verInfoOne.length, verInfoTwo.length);
|
||||
int diff = 0;
|
||||
while (idx < minLength
|
||||
&& (diff = verInfoOne[idx].length() - verInfoTwo[idx].length()) == 0
|
||||
&& (diff = verInfoOne[idx].compareTo(verInfoTwo[idx])) == 0) {
|
||||
++idx;
|
||||
}
|
||||
diff = (diff != 0) ? diff : verInfoOne.length - verInfoTwo.length;
|
||||
return (diff == 0) ? 0 : (diff < 0 ? -1 : 1);
|
||||
}
|
||||
|
||||
public String selfVersion, mcVersion;
|
||||
public String installer, universal;
|
||||
public String changelog;
|
||||
public static class InstallerVersion implements Comparable<InstallerVersion> {
|
||||
|
||||
public InstallerVersion(String selfVersion, String mcVersion) {
|
||||
this.selfVersion = selfVersion;
|
||||
this.mcVersion = mcVersion;
|
||||
}
|
||||
public String selfVersion, mcVersion;
|
||||
public String installer, universal;
|
||||
public String changelog;
|
||||
|
||||
@Override
|
||||
public int compareTo(InstallerVersion o) {
|
||||
return selfVersion.compareTo(o.selfVersion);
|
||||
}
|
||||
public InstallerVersion(String selfVersion, String mcVersion) {
|
||||
this.selfVersion = selfVersion;
|
||||
this.mcVersion = mcVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return selfVersion.hashCode();
|
||||
}
|
||||
@Override
|
||||
public int compareTo(InstallerVersion o) {
|
||||
return compareVersion(selfVersion, o.selfVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final InstallerVersion other = (InstallerVersion) obj;
|
||||
return Objects.equals(this.selfVersion, other.selfVersion);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return selfVersion.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final InstallerVersion other = (InstallerVersion) obj;
|
||||
return Objects.equals(this.selfVersion, other.selfVersion);
|
||||
}
|
||||
|
||||
public static class InstallerVersionComparator implements Comparator<InstallerVersion>, Serializable {
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 3276198781795213723L;
|
||||
public static class InstallerVersionComparator implements Comparator<InstallerVersion>, Serializable {
|
||||
|
||||
public static final InstallerVersionComparator INSTANCE = new InstallerVersionComparator();
|
||||
private static final long serialVersionUID = 3276198781795213723L;
|
||||
|
||||
@Override
|
||||
public int compare(InstallerVersion o1, InstallerVersion o2) {
|
||||
return o2.compareTo(o1);
|
||||
}
|
||||
}
|
||||
public static final InstallerVersionComparator INSTANCE = new InstallerVersionComparator();
|
||||
|
||||
@Override
|
||||
public int compare(InstallerVersion o1, InstallerVersion o2) {
|
||||
return o2.compareTo(o1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-5
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hellominecraft.launcher.core.install.forge;
|
||||
|
||||
import org.jackhuang.hellominecraft.launcher.core.install.InstallProfile;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -32,6 +31,7 @@ import org.jackhuang.hellominecraft.util.system.FileUtils;
|
||||
import org.jackhuang.hellominecraft.util.NetUtils;
|
||||
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftLibrary;
|
||||
import org.jackhuang.hellominecraft.util.MessageBox;
|
||||
import org.jackhuang.hellominecraft.util.system.IOUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -79,10 +79,8 @@ public class ForgeInstaller extends Task {
|
||||
File file = new File(gameDir, "libraries/" + forge.getDownloadInfo().path);
|
||||
if (file.getParentFile().mkdirs())
|
||||
HMCLog.warn("Failed to make library directory " + file.getParent());
|
||||
try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos)) {
|
||||
int c;
|
||||
while ((c = is.read()) != -1)
|
||||
bos.write((byte) c);
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
IOUtils.copyStream(is, fos);
|
||||
}
|
||||
mp.version().refreshVersions();
|
||||
}
|
||||
|
||||
+5
-2
@@ -76,10 +76,13 @@ public class MinecraftForgeVersionList extends InstallerVersionList {
|
||||
|
||||
for (Map.Entry<String, int[]> arr : root.mcversion.entrySet()) {
|
||||
String mcver = StrUtils.formatVersion(arr.getKey());
|
||||
if (mcver == null) {
|
||||
mcver = arr.getKey();
|
||||
}
|
||||
ArrayList<InstallerVersion> al = new ArrayList<>();
|
||||
for (int num : arr.getValue()) {
|
||||
MinecraftForgeVersion v = root.number.get(num);
|
||||
InstallerVersion iv = new InstallerVersion(v.version, StrUtils.formatVersion(v.mcversion));
|
||||
InstallerVersion iv = new InstallerVersion(v.version, v.mcversion);
|
||||
for (String[] f : v.files) {
|
||||
|
||||
String ver = v.mcversion + "-" + v.version;
|
||||
@@ -108,7 +111,7 @@ public class MinecraftForgeVersionList extends InstallerVersionList {
|
||||
versions.add(iv);
|
||||
}
|
||||
|
||||
versionMap.put(StrUtils.formatVersion(mcver), al);
|
||||
versionMap.put(mcver, al);
|
||||
}
|
||||
|
||||
Collections.sort(versions, new InstallerVersionComparator());
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ public class GameLauncher {
|
||||
if (appdata != null) {
|
||||
writer.write("set appdata=" + appdata);
|
||||
writer.newLine();
|
||||
writer.write("cd %appdata%");
|
||||
writer.write("cd /D %appdata%");
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
+12
-2
@@ -21,6 +21,8 @@ import java.io.File;
|
||||
import java.net.URL;
|
||||
import org.jackhuang.hellominecraft.util.C;
|
||||
import org.jackhuang.hellominecraft.launcher.core.download.DownloadLibraryJob;
|
||||
import org.jackhuang.hellominecraft.util.StrUtils;
|
||||
import org.jackhuang.hellominecraft.util.func.Function;
|
||||
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
|
||||
|
||||
/**
|
||||
@@ -49,12 +51,20 @@ public class LibraryDownloadTask extends FileDownloadTask {
|
||||
if (s.length == 3 && s[2].length() > 3)
|
||||
job.url = "http://dl.liteloader.com/versions/com/mumfrey/liteloader/" + s[2].substring(0, s[2].length() - 3) + "/liteloader-" + s[2] + ".jar";
|
||||
}
|
||||
download(new URL(job.url), job.path);
|
||||
download(new URL(job.url), job.retryUrl, job.path);
|
||||
}
|
||||
|
||||
void download(URL url, File filePath) throws Throwable {
|
||||
void download(URL url, String retryUrl, File filePath) throws Throwable {
|
||||
this.url = url;
|
||||
this.filePath = filePath;
|
||||
if (StrUtils.isNotBlank(retryUrl)) {
|
||||
this.failedCallbackReturnsNewURL = new Function<Integer, String>() {
|
||||
@Override
|
||||
public String apply(Integer t) {
|
||||
return retryUrl;
|
||||
}
|
||||
};
|
||||
}
|
||||
super.executeTask();
|
||||
}
|
||||
|
||||
|
||||
+20
-2
@@ -19,6 +19,7 @@ package org.jackhuang.hellominecraft.launcher.core.launch;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hellominecraft.util.StrUtils;
|
||||
import org.jackhuang.hellominecraft.util.logging.HMCLog;
|
||||
@@ -44,9 +45,24 @@ public class MinecraftLoader extends AbstractMinecraftLoader {
|
||||
@Override
|
||||
protected void makeSelf(List<String> res) throws GameException {
|
||||
StringBuilder library = new StringBuilder("");
|
||||
ArrayList<MinecraftLibrary> opt = new ArrayList<>();
|
||||
for (MinecraftLibrary l : version.libraries)
|
||||
if (l.allow() && !l.isRequiredToUnzip())
|
||||
library.append(l.getFilePath(gameDir).getAbsolutePath()).append(File.pathSeparator);
|
||||
if (l.allow() && !l.isRequiredToUnzip()) {
|
||||
if (l.name.toLowerCase().contains("optifine")) {
|
||||
opt.add(l);
|
||||
continue;
|
||||
}
|
||||
File f = l.getFilePath(gameDir);
|
||||
if (f == null)
|
||||
continue;
|
||||
library.append(f.getAbsolutePath()).append(File.pathSeparator);
|
||||
}
|
||||
for (MinecraftLibrary l : opt) {
|
||||
File f = l.getFilePath(gameDir);
|
||||
if (f == null)
|
||||
continue;
|
||||
library.append(f.getAbsolutePath()).append(File.pathSeparator);
|
||||
}
|
||||
File f = version.getJar(service.baseDirectory());
|
||||
if (!f.exists())
|
||||
throw new GameException("Minecraft jar does not exists");
|
||||
@@ -55,6 +71,8 @@ public class MinecraftLoader extends AbstractMinecraftLoader {
|
||||
res.add(library.toString().substring(0, library.length() - File.pathSeparator.length()));
|
||||
res.add(version.mainClass);
|
||||
|
||||
if (version.minecraftArguments == null)
|
||||
throw new GameException(new NullPointerException("Minecraft Arguments can not be null."));
|
||||
String[] splitted = StrUtils.tokenize(version.minecraftArguments);
|
||||
|
||||
String game_assets = assetProvider.apply(version, !options.isNotCheckGame());
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
*/
|
||||
package org.jackhuang.hellominecraft.launcher.core.mod;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
@@ -60,6 +62,8 @@ public class ModInfo implements Comparable<ModInfo> {
|
||||
public String credits;
|
||||
@SerializedName("authorList")
|
||||
public String[] authorList;
|
||||
@SerializedName("authors")
|
||||
public String[] authors;
|
||||
|
||||
public boolean isActive() {
|
||||
return !location.getName().endsWith(".disabled");
|
||||
@@ -87,6 +91,8 @@ public class ModInfo implements Comparable<ModInfo> {
|
||||
public String getAuthor() {
|
||||
if (authorList != null && authorList.length > 0)
|
||||
return StrUtils.parseParams("", authorList, ", ");
|
||||
else if (authors != null && authors.length > 0)
|
||||
return StrUtils.parseParams("", authors, ", ");
|
||||
else if (StrUtils.isNotBlank(author))
|
||||
return author;
|
||||
else
|
||||
@@ -123,18 +129,30 @@ public class ModInfo implements Comparable<ModInfo> {
|
||||
return name.endsWith(".zip") || name.endsWith(".jar") || name.endsWith("litemod");
|
||||
}
|
||||
|
||||
private static final Type TYPE = new TypeToken<List<ModInfo>>() {
|
||||
}.getType();
|
||||
|
||||
private static ModInfo getForgeModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
|
||||
ModInfo i = new ModInfo();
|
||||
i.location = f;
|
||||
List<ModInfo> m = C.GSON.fromJson(new InputStreamReader(jar.getInputStream(entry), "UTF-8"), TYPE);
|
||||
if (m != null && m.size() > 0) {
|
||||
i = m.get(0);
|
||||
i.location = f;
|
||||
}
|
||||
return i;
|
||||
ModInfo i = new ModInfo();
|
||||
i.location = f;
|
||||
|
||||
InputStreamReader streamReader = new InputStreamReader(jar.getInputStream(entry), "UTF-8");
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonElement element = parser.parse(streamReader);
|
||||
List<ModInfo> m = null;
|
||||
if (element.isJsonArray()) {
|
||||
m = C.GSON.fromJson(element, new TypeToken<List<ModInfo>>(){}.getType());
|
||||
} else if (element.isJsonObject()) {
|
||||
JsonObject modInfo = element.getAsJsonObject();
|
||||
if (modInfo.has("modList") && modInfo.get("modList").isJsonArray()) {
|
||||
m = C.GSON.fromJson(modInfo.get("modList"), new TypeToken<List<ModInfo>>(){}.getType());
|
||||
}
|
||||
}
|
||||
|
||||
if (m != null && m.size() > 0) {
|
||||
i = m.get(0);
|
||||
i.location = f;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
private static ModInfo getLiteLoaderModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
|
||||
|
||||
+39
-9
@@ -19,6 +19,7 @@ package org.jackhuang.hellominecraft.launcher.core.version;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
|
||||
import org.jackhuang.hellominecraft.launcher.core.download.IDownloadProvider;
|
||||
import org.jackhuang.hellominecraft.util.StrUtils;
|
||||
import org.jackhuang.hellominecraft.util.system.IOUtils;
|
||||
|
||||
@@ -35,14 +36,43 @@ public class LibraryDownloadInfo extends GameDownloadInfo {
|
||||
|
||||
@Override
|
||||
public String getUrl(DownloadType dt, boolean allowSelf) {
|
||||
String myURL = (forgeURL == null ? dt.getProvider().getLibraryDownloadURL() : forgeURL);
|
||||
if (StrUtils.isNotBlank(url) && allowSelf)
|
||||
myURL = url;
|
||||
if (!myURL.endsWith(".jar"))
|
||||
if (path == null)
|
||||
return null;
|
||||
else
|
||||
myURL = IOUtils.addURLSeparator(myURL) + path.replace('\\', '/');
|
||||
return myURL;
|
||||
IDownloadProvider provider = dt.getProvider();
|
||||
String downloadUrl = (forgeURL == null ? provider.getLibraryDownloadURL() : forgeURL);
|
||||
if (StrUtils.isNotBlank(url) && allowSelf) {
|
||||
downloadUrl = url;
|
||||
} // forced replace: Let different download sources into force
|
||||
return provider.getParsedDownloadURL(getUrlWithBaseUrl(downloadUrl));
|
||||
}
|
||||
|
||||
public String getRetryUrl(DownloadType dt) {
|
||||
IDownloadProvider provider = dt.getProvider();
|
||||
String retryBaseUrl = provider.getRetryLibraryDownloadURL();
|
||||
|
||||
String downloadUrl = (forgeURL == null ? retryBaseUrl : forgeURL);
|
||||
if (StrUtils.isNotBlank(url) && provider.isAllowedToUseSelfURL()) {
|
||||
downloadUrl = url;
|
||||
}
|
||||
|
||||
if (StrUtils.isBlank(downloadUrl)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
downloadUrl = getUrlWithBaseUrl(downloadUrl);
|
||||
if (downloadUrl.contains("minecraftforge")) { // fix forge url
|
||||
downloadUrl = provider.getParsedDownloadURL(downloadUrl);
|
||||
}
|
||||
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
private String getUrlWithBaseUrl(String baseUrl) {
|
||||
if (!baseUrl.endsWith(".jar")) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
} else {
|
||||
baseUrl = IOUtils.addURLSeparator(baseUrl) + path.replace('\\', '/');
|
||||
}
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
}
|
||||
+37
-24
@@ -48,29 +48,25 @@ public class MinecraftLibrary extends IMinecraftLibrary {
|
||||
|
||||
public MinecraftLibrary(ArrayList<Rules> rules, String url, Natives natives, String name, Extract extract, LibraryDownloadInfo downloads) {
|
||||
super(name);
|
||||
this.rules = rules == null ? null : (ArrayList<Rules>) rules.clone();
|
||||
this.rules = (rules == null) ? null : (ArrayList<Rules>) rules.clone();
|
||||
this.url = url;
|
||||
this.natives = natives == null ? null : (Natives) natives.clone();
|
||||
this.extract = extract == null ? null : (Extract) extract.clone();
|
||||
this.natives = (natives == null) ? null : (Natives) natives.clone();
|
||||
this.extract = (extract == null) ? null : (Extract) extract.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* is the library allowed to load.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean allow() {
|
||||
if (rules != null) {
|
||||
boolean flag = false;
|
||||
for (Rules r : rules)
|
||||
for (Rules r : rules) {
|
||||
if ("disallow".equals(r.action()))
|
||||
return false;
|
||||
else if ("allow".equals(r.action()))
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String formatArch(String nati) {
|
||||
@@ -95,17 +91,25 @@ public class MinecraftLibrary extends IMinecraftLibrary {
|
||||
|
||||
public String formatName() {
|
||||
String[] s = name.split(":");
|
||||
if (s.length < 3)
|
||||
if (s.length < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(s[0].replace('.', '/')).append('/').append(s[1]).append('/').append(s[2]).append('/').append(s[1]).append('-').append(s[2]);
|
||||
if (natives != null)
|
||||
if (natives != null) {
|
||||
sb.append('-').append(getNative());
|
||||
}
|
||||
|
||||
return sb.append(".jar").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFilePath(File gameDir) {
|
||||
return new File(gameDir, "libraries/" + getDownloadInfo().path);
|
||||
LibraryDownloadInfo info = getDownloadInfo();
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
return new File(gameDir, "libraries/" + info.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,25 +118,34 @@ public class MinecraftLibrary extends IMinecraftLibrary {
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo getDownloadInfo() {
|
||||
if (downloads == null)
|
||||
if (downloads == null) {
|
||||
downloads = new LibrariesDownloadInfo();
|
||||
LibraryDownloadInfo info;
|
||||
}
|
||||
|
||||
LibraryDownloadInfo info = null;
|
||||
if (natives != null) {
|
||||
if (downloads.classifiers == null)
|
||||
if (downloads.classifiers == null) {
|
||||
downloads.classifiers = new HashMap<>();
|
||||
if (!downloads.classifiers.containsKey(getNative()))
|
||||
downloads.classifiers.put(getNative(), info = new LibraryDownloadInfo());
|
||||
else
|
||||
info = downloads.classifiers.get(getNative());
|
||||
} else if (downloads.artifact == null)
|
||||
} else {
|
||||
if (!downloads.classifiers.containsKey(getNative())) {
|
||||
downloads.classifiers.put(getNative(), info = new LibraryDownloadInfo());
|
||||
} else {
|
||||
info = downloads.classifiers.get(getNative());
|
||||
}
|
||||
}
|
||||
} else if (downloads.artifact == null) {
|
||||
downloads.artifact = info = new LibraryDownloadInfo();
|
||||
else
|
||||
} else {
|
||||
info = downloads.artifact;
|
||||
}
|
||||
|
||||
if (StrUtils.isBlank(info.path)) {
|
||||
info.path = formatName();
|
||||
if (info.path == null)
|
||||
if (info.path == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
info.forgeURL = this.url;
|
||||
return info;
|
||||
}
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ public class MinecraftVersion implements Cloneable, Comparable<MinecraftVersion>
|
||||
this.assets != null ? this.assets : parent.assets,
|
||||
this.jar != null ? this.jar : parent.jar,
|
||||
null, this.runDir, parent.minimumLauncherVersion,
|
||||
this.libraries != null ? ArrayUtils.merge(parent.libraries, this.libraries) : parent.libraries, this.hidden,
|
||||
this.libraries != null ? ArrayUtils.merge(this.libraries, parent.libraries) : parent.libraries, this.hidden,
|
||||
this.downloads != null ? this.downloads : parent.downloads,
|
||||
this.assetIndex != null ? this.assetIndex : parent.assetIndex);
|
||||
|
||||
|
||||
@@ -59,144 +59,158 @@ import org.jackhuang.hellominecraft.util.VersionNumber;
|
||||
*/
|
||||
public final class Main implements Runnable {
|
||||
|
||||
private static final X509TrustManager XTM = new X509TrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
private static final X509TrustManager XTM = new X509TrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
};
|
||||
private static final HostnameVerifier HNV = (hostname, session) -> true;
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
};
|
||||
private static final HostnameVerifier HNV = (hostname, session) -> true;
|
||||
|
||||
static {
|
||||
SSLContext sslContext = null;
|
||||
static {
|
||||
SSLContext sslContext = null;
|
||||
|
||||
try {
|
||||
sslContext = SSLContext.getInstance("TLS");
|
||||
X509TrustManager[] xtmArray = new X509TrustManager[] { XTM };
|
||||
sslContext.init(null, xtmArray, new java.security.SecureRandom());
|
||||
} catch (GeneralSecurityException gse) {
|
||||
}
|
||||
if (sslContext != null)
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
|
||||
try {
|
||||
sslContext = SSLContext.getInstance("TLS");
|
||||
X509TrustManager[] xtmArray = new X509TrustManager[]{XTM};
|
||||
sslContext.init(null, xtmArray, new java.security.SecureRandom());
|
||||
} catch (GeneralSecurityException gse) {
|
||||
}
|
||||
if (sslContext != null) {
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
|
||||
}
|
||||
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(HNV);
|
||||
}
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(HNV);
|
||||
}
|
||||
|
||||
public static final String LAUNCHER_NAME = "Hello Minecraft! Launcher";
|
||||
public static final String LAUNCHER_VERSION = "@HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING@";
|
||||
public static final int MINIMUM_LAUNCHER_VERSION = 16;
|
||||
public static final String LAUNCHER_NAME = "Hello Minecraft! Launcher";
|
||||
public static final String LAUNCHER_VERSION = "@HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING@";
|
||||
public static final int MINIMUM_LAUNCHER_VERSION = 16;
|
||||
|
||||
public static VersionNumber getVersionNumber() {
|
||||
return VersionNumber.check(LAUNCHER_VERSION);
|
||||
}
|
||||
public static VersionNumber getVersionNumber() {
|
||||
return VersionNumber.check(LAUNCHER_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the main window title.
|
||||
*
|
||||
* @return the MainWindow title.
|
||||
*/
|
||||
public static String makeTitle() {
|
||||
return LAUNCHER_NAME + ' ' + LAUNCHER_VERSION;
|
||||
}
|
||||
/**
|
||||
* Make the main window title.
|
||||
*
|
||||
* @return the MainWindow title.
|
||||
*/
|
||||
public static String makeTitle() {
|
||||
return LAUNCHER_NAME + ' ' + LAUNCHER_VERSION;
|
||||
}
|
||||
|
||||
public static String shortTitle() {
|
||||
return "HMCL" + ' ' + LAUNCHER_VERSION;
|
||||
}
|
||||
public static String shortTitle() {
|
||||
return "HMCL" + ' ' + LAUNCHER_VERSION;
|
||||
}
|
||||
|
||||
public static final Main INSTANCE = new Main();
|
||||
private static HelloMinecraftLookAndFeel LOOK_AND_FEEL;
|
||||
public static final Main INSTANCE = new Main();
|
||||
private static HelloMinecraftLookAndFeel LOOK_AND_FEEL;
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
|
||||
|
||||
@SuppressWarnings({ "CallToPrintStackTrace", "UseSpecificCatch" })
|
||||
public static void main(String[] args) throws IOException {
|
||||
{
|
||||
PluginManager.getPlugin(DefaultPlugin.class);
|
||||
if (IUpgrader.NOW_UPGRADER.parseArguments(getVersionNumber(), args))
|
||||
return;
|
||||
@SuppressWarnings({"CallToPrintStackTrace", "UseSpecificCatch"})
|
||||
public static void main(String[] args) throws IOException {
|
||||
PluginManager.getPlugin(DefaultPlugin.class);
|
||||
if (IUpgrader.NOW_UPGRADER.parseArguments(getVersionNumber(), args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||
System.setProperty("swing.aatext", "true");
|
||||
System.setProperty("sun.java2d.noddraw", "true");
|
||||
System.setProperty("sun.java2d.dpiaware", "false");
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashReporter(true));
|
||||
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||
System.setProperty("swing.aatext", "true");
|
||||
System.setProperty("sun.java2d.noddraw", "true");
|
||||
System.setProperty("sun.java2d.dpiaware", "false");
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashReporter(true));
|
||||
|
||||
try {
|
||||
File file = new File("hmcl.log");
|
||||
if (!file.exists() && !file.createNewFile())
|
||||
HMCLog.warn("Failed to create log file " + file);
|
||||
Configuration.DEFAULT.appenders.add(new ConsoleAppender("File", new DefaultLayout(), true, new FileOutputStream(file), true));
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to add log appender File because an error occurred while creating or opening hmcl.log", ex);
|
||||
}
|
||||
try {
|
||||
File file = new File("hmcl.log");
|
||||
if (!file.exists() && !file.createNewFile()) {
|
||||
HMCLog.warn("Failed to create log file " + file);
|
||||
}
|
||||
Configuration.DEFAULT.appenders.add(new ConsoleAppender("File", new DefaultLayout(), true, new FileOutputStream(file), true));
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to add log appender File because an error occurred while creating or opening hmcl.log", ex);
|
||||
}
|
||||
|
||||
HMCLog.log("*** " + Main.makeTitle() + " ***");
|
||||
HMCLog.log("*** " + Main.makeTitle() + " ***");
|
||||
|
||||
String s = Settings.getInstance().getLocalization();
|
||||
for (SupportedLocales sl : SupportedLocales.values())
|
||||
if (sl.name().equals(s)) {
|
||||
SupportedLocales.NOW_LOCALE = sl;
|
||||
Locale.setDefault(sl.self);
|
||||
}
|
||||
String s = Settings.getInstance().getLocalization();
|
||||
for (SupportedLocales sl : SupportedLocales.values()) {
|
||||
if (sl.name().equals(s)) {
|
||||
SupportedLocales.NOW_LOCALE = sl;
|
||||
Locale.setDefault(sl.self);
|
||||
}
|
||||
}
|
||||
|
||||
LogWindow.INSTANCE.clean();
|
||||
LogWindow.INSTANCE.setTerminateGame(GameLauncher.PROCESS_MANAGER::stopAllProcesses);
|
||||
LogWindow.INSTANCE.clean();
|
||||
LogWindow.INSTANCE.setTerminateGame(GameLauncher.PROCESS_MANAGER::stopAllProcesses);
|
||||
|
||||
try {
|
||||
LOOK_AND_FEEL = new HelloMinecraftLookAndFeel(Settings.getInstance().getTheme().settings);
|
||||
UIManager.setLookAndFeel(LOOK_AND_FEEL);
|
||||
} catch (ParseException | UnsupportedLookAndFeelException ex) {
|
||||
HMCLog.warn("Failed to set look and feel...", ex);
|
||||
}
|
||||
try {
|
||||
LOOK_AND_FEEL = new HelloMinecraftLookAndFeel(Settings.getInstance().getTheme().settings);
|
||||
UIManager.setLookAndFeel(LOOK_AND_FEEL);
|
||||
} catch (ParseException | UnsupportedLookAndFeelException ex) {
|
||||
HMCLog.warn("Failed to set look and feel...", ex);
|
||||
}
|
||||
|
||||
Settings.UPDATE_CHECKER.outdated.register(IUpgrader.NOW_UPGRADER);
|
||||
Settings.UPDATE_CHECKER.process(false).reg(t -> Main.invokeUpdate()).execute();
|
||||
Settings.UPDATE_CHECKER.outdated.register(IUpgrader.NOW_UPGRADER);
|
||||
Settings.UPDATE_CHECKER.process(false)
|
||||
.reg(t -> Main.invokeUpdate())
|
||||
.regDone(() -> { Settings.UPDATE_CHECKER.checkOutdate(); })
|
||||
.execute();
|
||||
|
||||
if (StrUtils.isNotBlank(Settings.getInstance().getProxyHost()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPort()) && MathUtils.canParseInt(Settings.getInstance().getProxyPort())) {
|
||||
HMCLog.log("Initializing customized proxy");
|
||||
System.setProperty("http.proxyHost", Settings.getInstance().getProxyHost());
|
||||
System.setProperty("http.proxyPort", Settings.getInstance().getProxyPort());
|
||||
if (StrUtils.isNotBlank(Settings.getInstance().getProxyUserName()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPassword()))
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(Settings.getInstance().getProxyUserName(), Settings.getInstance().getProxyPassword().toCharArray());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (StrUtils.isNotBlank(Settings.getInstance().getProxyHost()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPort()) && MathUtils.canParseInt(Settings.getInstance().getProxyPort())) {
|
||||
HMCLog.log("Initializing customized proxy");
|
||||
System.setProperty("http.proxyHost", Settings.getInstance().getProxyHost());
|
||||
System.setProperty("http.proxyPort", Settings.getInstance().getProxyPort());
|
||||
if (StrUtils.isNotBlank(Settings.getInstance().getProxyUserName()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPassword())) {
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(Settings.getInstance().getProxyUserName(), Settings.getInstance().getProxyPassword().toCharArray());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
PluginManager.plugin().showUI();
|
||||
} catch (Throwable t) {
|
||||
new CrashReporter(false).uncaughtException(Thread.currentThread(), t);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
PluginManager.plugin().showUI();
|
||||
} catch (Throwable t) {
|
||||
new CrashReporter(false).uncaughtException(Thread.currentThread(), t);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
GameLauncher.PROCESS_MANAGER.stopAllProcesses();
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
GameLauncher.PROCESS_MANAGER.stopAllProcesses();
|
||||
}
|
||||
|
||||
public static void invokeUpdate() {
|
||||
MainFrame.INSTANCE.invokeUpdate();
|
||||
}
|
||||
public static void invokeUpdate() {
|
||||
if (Settings.UPDATE_CHECKER.isForceUpdate())
|
||||
return;
|
||||
|
||||
if (Settings.getInstance().ignoreUpdate(
|
||||
Settings.UPDATE_CHECKER.getNewVersion() )) {
|
||||
return;
|
||||
}
|
||||
|
||||
MainFrame.INSTANCE.invokeUpdate();
|
||||
}
|
||||
|
||||
public static ImageIcon getIcon(String path) {
|
||||
try {
|
||||
return new ImageIcon(Main.class.getResource("/org/jackhuang/hellominecraft/launcher/" + path));
|
||||
} catch (Exception e) {
|
||||
HMCLog.err("Failed to load icon", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static ImageIcon getIcon(String path) {
|
||||
try {
|
||||
return new ImageIcon(Main.class.getResource("/org/jackhuang/hellominecraft/launcher/" + path));
|
||||
} catch (Exception e) {
|
||||
HMCLog.err("Failed to load icon", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import java.util.UUID;
|
||||
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
|
||||
import org.jackhuang.hellominecraft.lookandfeel.Theme;
|
||||
import org.jackhuang.hellominecraft.util.EventHandler;
|
||||
import org.jackhuang.hellominecraft.util.StrUtils;
|
||||
import org.jackhuang.hellominecraft.util.VersionNumber;
|
||||
import org.jackhuang.hellominecraft.util.system.JdkVersion;
|
||||
import org.jackhuang.hellominecraft.util.system.OS;
|
||||
|
||||
@@ -72,10 +74,35 @@ public final class Config implements Cloneable {
|
||||
@SerializedName("auth")
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private Map<String, Map> auth;
|
||||
|
||||
@SerializedName("ignoreUpdateVersion")
|
||||
private String ignoreUpdateVersion;
|
||||
|
||||
public List<JdkVersion> getJava() {
|
||||
return java == null ? java = new ArrayList<>() : java;
|
||||
}
|
||||
|
||||
public boolean ignoreUpdate(VersionNumber versionNumber) {
|
||||
boolean ignore = false;
|
||||
do
|
||||
{
|
||||
if (StrUtils.isBlank(ignoreUpdateVersion))
|
||||
continue;
|
||||
|
||||
VersionNumber ignoreVersion = VersionNumber.check(ignoreUpdateVersion);
|
||||
if (ignoreVersion == null)
|
||||
continue;
|
||||
|
||||
if (versionNumber.compareTo(ignoreVersion) == 0)
|
||||
ignore = true;
|
||||
|
||||
} while(false);
|
||||
return ignore;
|
||||
}
|
||||
|
||||
public void setIgnoreUpdate(VersionNumber versionNumber) {
|
||||
ignoreUpdateVersion = versionNumber.toString();
|
||||
Settings.save();
|
||||
}
|
||||
|
||||
public transient final EventHandler<Theme> themeChangedEvent = new EventHandler<>(this);
|
||||
public transient final EventHandler<DownloadType> downloadTypeChangedEvent = new EventHandler<>(this);
|
||||
@@ -193,7 +220,8 @@ public final class Config implements Cloneable {
|
||||
|
||||
public Config() {
|
||||
clientToken = UUID.randomUUID().toString();
|
||||
logintype = downloadtype = 0;
|
||||
logintype = 0;
|
||||
downloadtype = DownloadType.Dynamic.ordinal();
|
||||
enableShadow = false;
|
||||
enableAnimation = true;
|
||||
theme = 4;
|
||||
@@ -203,7 +231,7 @@ public final class Config implements Cloneable {
|
||||
|
||||
public DownloadType getDownloadSource() {
|
||||
if (downloadtype >= DownloadType.values().length || downloadtype < 0) {
|
||||
downloadtype = 0;
|
||||
downloadtype = DownloadType.Dynamic.ordinal();
|
||||
Settings.save();
|
||||
}
|
||||
return DownloadType.values()[downloadtype];
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.jackhuang.hellominecraft.util.C;
|
||||
import org.jackhuang.hellominecraft.util.logging.HMCLog;
|
||||
import org.jackhuang.hellominecraft.launcher.Main;
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
*/
|
||||
package org.jackhuang.hellominecraft.launcher.ui;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import javax.swing.RowSorter;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
import org.jackhuang.hellominecraft.util.C;
|
||||
import org.jackhuang.hellominecraft.launcher.setting.Settings;
|
||||
import org.jackhuang.hellominecraft.launcher.core.install.InstallerType;
|
||||
@@ -36,29 +40,45 @@ import org.jackhuang.hellominecraft.util.ui.SwingUtils;
|
||||
*/
|
||||
public class InstallerPanel extends AnimatedPanel {
|
||||
|
||||
GameSettingsPanel gsp;
|
||||
GameSettingsPanel gsp;
|
||||
|
||||
/**
|
||||
* Creates new form InstallerPanel
|
||||
*
|
||||
* @param gsp To get the minecraft version
|
||||
* @param installerType load which installer
|
||||
*/
|
||||
public InstallerPanel(GameSettingsPanel gsp, InstallerType installerType) {
|
||||
initComponents();
|
||||
private static class VerComparator implements Comparator<String> {
|
||||
|
||||
setOpaque(false);
|
||||
this.gsp = gsp;
|
||||
id = installerType;
|
||||
list = Settings.getInstance().getDownloadSource().getProvider().getInstallerByType(id);
|
||||
}
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return InstallerVersionList.compareVersion(o1, o2);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
/**
|
||||
* Creates new form InstallerPanel
|
||||
*
|
||||
* @param gsp To get the minecraft version
|
||||
* @param installerType load which installer
|
||||
*/
|
||||
public InstallerPanel(GameSettingsPanel gsp, InstallerType installerType) {
|
||||
initComponents();
|
||||
|
||||
//表格排序
|
||||
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(lstInstallers.getModel());
|
||||
VerComparator verComparator = new VerComparator();
|
||||
for (int i = 0; i < lstInstallers.getColumnCount(); i++) {
|
||||
sorter.setComparator(i, verComparator);
|
||||
}
|
||||
lstInstallers.setRowSorter(sorter);
|
||||
|
||||
setOpaque(false);
|
||||
this.gsp = gsp;
|
||||
id = installerType;
|
||||
list = Settings.getInstance().getDownloadSource().getProvider().getInstallerByType(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
@@ -109,60 +129,64 @@ public class InstallerPanel extends AnimatedPanel {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void btnInstallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnInstallActionPerformed
|
||||
downloadSelectedRow();
|
||||
downloadSelectedRow();
|
||||
}//GEN-LAST:event_btnInstallActionPerformed
|
||||
|
||||
private void btnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshActionPerformed
|
||||
refreshVersions();
|
||||
refreshVersions();
|
||||
}//GEN-LAST:event_btnRefreshActionPerformed
|
||||
|
||||
transient List<InstallerVersionList.InstallerVersion> versions;
|
||||
transient InstallerVersionList list;
|
||||
InstallerType id;
|
||||
transient List<InstallerVersionList.InstallerVersion> versions;
|
||||
transient InstallerVersionList list;
|
||||
InstallerType id;
|
||||
|
||||
void refreshVersions() {
|
||||
if (TaskWindow.execute(list.refresh(new String[] { gsp.getMinecraftVersionFormatted() })))
|
||||
loadVersions();
|
||||
}
|
||||
void refreshVersions() {
|
||||
if (TaskWindow.execute(list.refresh(new String[]{gsp.getMinecraftVersionFormatted()}))) {
|
||||
loadVersions();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized InstallerVersionList.InstallerVersion getVersion(int idx) {
|
||||
return versions.get(idx);
|
||||
}
|
||||
public synchronized InstallerVersionList.InstallerVersion getVersion(int idx) {
|
||||
return versions.get(idx);
|
||||
}
|
||||
|
||||
synchronized void downloadSelectedRow() {
|
||||
int idx = lstInstallers.getSelectedRow();
|
||||
if (versions == null || idx < 0 || idx >= versions.size()) {
|
||||
MessageBox.Show(C.i18n("install.not_refreshed"));
|
||||
return;
|
||||
}
|
||||
TaskWindow.execute(Settings.getLastProfile().service().install().download(Settings.getLastProfile().getSelectedVersion(), getVersion(idx), id),
|
||||
new TaskRunnable(this::refreshVersions));
|
||||
}
|
||||
synchronized void downloadSelectedRow() {
|
||||
int idx = lstInstallers.getSelectedRow();
|
||||
if (versions == null || idx < 0 || idx >= versions.size()) {
|
||||
MessageBox.Show(C.i18n("install.not_refreshed"));
|
||||
return;
|
||||
}
|
||||
TaskWindow.execute(Settings.getLastProfile().service().install().download(Settings.getLastProfile().getSelectedVersion(), getVersion(idx), id),
|
||||
new TaskRunnable(this::refreshVersions));
|
||||
}
|
||||
|
||||
public void loadVersions() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
synchronized (InstallerPanel.this) {
|
||||
DefaultTableModel model = (DefaultTableModel) lstInstallers.getModel();
|
||||
String mcver = StrUtils.formatVersion(gsp.getMinecraftVersionFormatted());
|
||||
versions = list.getVersions(mcver);
|
||||
SwingUtils.clearDefaultTable(lstInstallers);
|
||||
if (versions != null)
|
||||
for (InstallerVersionList.InstallerVersion v : versions)
|
||||
if (v != null)
|
||||
model.addRow(new Object[] { v.selfVersion == null ? "null" : v.selfVersion, v.mcVersion == null ? "null" : v.mcVersion });
|
||||
}
|
||||
});
|
||||
}
|
||||
public void loadVersions() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
synchronized (InstallerPanel.this) {
|
||||
DefaultTableModel model = (DefaultTableModel) lstInstallers.getModel();
|
||||
String mcver = StrUtils.formatVersion(gsp.getMinecraftVersionFormatted());
|
||||
versions = list.getVersions(mcver);
|
||||
SwingUtils.clearDefaultTable(lstInstallers);
|
||||
if (versions != null) {
|
||||
for (InstallerVersionList.InstallerVersion v : versions) {
|
||||
if (v != null) {
|
||||
model.addRow(new Object[]{v.selfVersion == null ? "null" : v.selfVersion, v.mcVersion == null ? "null" : v.mcVersion});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
boolean refreshed = false;
|
||||
boolean refreshed = false;
|
||||
|
||||
@Override
|
||||
public void onSelect() {
|
||||
if (!refreshed) {
|
||||
refreshVersions();
|
||||
refreshed = true;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onSelect() {
|
||||
if (!refreshed) {
|
||||
refreshVersions();
|
||||
refreshed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton btnInstall;
|
||||
|
||||
+14
-5
@@ -26,6 +26,8 @@
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="btnCheckUpdate" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnMCBBS" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="chkDecorated" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@@ -125,10 +127,11 @@
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="btnCheckUpdate" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
|
||||
<Component id="chkDecorated" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="btnMCBBS" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lblRestart" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="65" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="116" max="32767" attributes="0"/>
|
||||
<Component id="lblModpack" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lblAbout" min="-2" max="-2" attributes="0"/>
|
||||
@@ -154,12 +157,9 @@
|
||||
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.about" replaceFormat="C.i18n("{key}")"/>
|
||||
</Property>
|
||||
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
|
||||
<Color id="手型光标"/>
|
||||
<Color id="默认光标"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="lblAboutMouseClicked"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="btnSelBackgroundPath">
|
||||
<Properties>
|
||||
@@ -345,5 +345,14 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="btnMCBBS">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="MCBBS"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnMCBBSActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
+23
-14
@@ -116,6 +116,7 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
cboLang = new javax.swing.JComboBox();
|
||||
lblLang = new javax.swing.JLabel();
|
||||
lblRestart = new javax.swing.JLabel();
|
||||
btnMCBBS = new javax.swing.JButton();
|
||||
|
||||
cboDownloadSource.addItemListener(new java.awt.event.ItemListener() {
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||
@@ -124,12 +125,7 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
});
|
||||
|
||||
lblAbout.setText(C.i18n("launcher.about")); // NOI18N
|
||||
lblAbout.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
|
||||
lblAbout.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
public void mouseClicked(java.awt.event.MouseEvent evt) {
|
||||
lblAboutMouseClicked(evt);
|
||||
}
|
||||
});
|
||||
lblAbout.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
|
||||
|
||||
btnSelBackgroundPath.setText(C.i18n("ui.button.explore")); // NOI18N
|
||||
btnSelBackgroundPath.addActionListener(new java.awt.event.ActionListener() {
|
||||
@@ -240,6 +236,14 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
|
||||
lblRestart.setText(C.i18n("launcher.restart")); // NOI18N
|
||||
|
||||
btnMCBBS.setText("MCBBS");
|
||||
btnMCBBS.setToolTipText("");
|
||||
btnMCBBS.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnMCBBSActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
@@ -253,6 +257,8 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
.addComponent(chkEnableAnimation))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(btnCheckUpdate)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnMCBBS)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(chkDecorated))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
@@ -334,10 +340,11 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(btnCheckUpdate, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(chkDecorated))
|
||||
.addComponent(chkDecorated)
|
||||
.addComponent(btnMCBBS))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lblRestart)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 116, Short.MAX_VALUE)
|
||||
.addComponent(lblModpack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lblAbout, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
@@ -377,8 +384,9 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
}//GEN-LAST:event_txtBackgroundPathFocusLost
|
||||
|
||||
private void btnCheckUpdateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheckUpdateActionPerformed
|
||||
Settings.UPDATE_CHECKER.process(true);
|
||||
Settings.UPDATE_CHECKER.checkOutdate();
|
||||
Settings.UPDATE_CHECKER.process(true)
|
||||
.regDone(() -> { Settings.UPDATE_CHECKER.checkOutdate(); })
|
||||
.execute();
|
||||
}//GEN-LAST:event_btnCheckUpdateActionPerformed
|
||||
|
||||
private void cboThemeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboThemeItemStateChanged
|
||||
@@ -386,7 +394,7 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
}//GEN-LAST:event_cboThemeItemStateChanged
|
||||
|
||||
private void lblModpackMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblModpackMouseClicked
|
||||
SwingUtils.openLink("http://huangyuhui.duapp.com/link.php?type=modpack");
|
||||
SwingUtils.openLink("http://client.api.mcgogogo.com:81/link.php?type=modpack");
|
||||
}//GEN-LAST:event_lblModpackMouseClicked
|
||||
|
||||
private void cboLangItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboLangItemStateChanged
|
||||
@@ -421,12 +429,13 @@ public class LauncherSettingsPanel extends AnimatedPanel {
|
||||
Settings.getInstance().setProxyPassword(txtProxyPassword.getText());
|
||||
}//GEN-LAST:event_txtProxyPasswordFocusLost
|
||||
|
||||
private void lblAboutMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblAboutMouseClicked
|
||||
SwingUtils.openLink("http://huangyuhui.duapp.com/link.php?type=sponsor");
|
||||
}//GEN-LAST:event_lblAboutMouseClicked
|
||||
private void btnMCBBSActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnMCBBSActionPerformed
|
||||
SwingUtils.openLink(C.URL_PUBLISH);
|
||||
}//GEN-LAST:event_btnMCBBSActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton btnCheckUpdate;
|
||||
private javax.swing.JButton btnMCBBS;
|
||||
private javax.swing.JButton btnSelBackgroundPath;
|
||||
private javax.swing.JComboBox cboDownloadSource;
|
||||
private javax.swing.JComboBox cboLang;
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.jackhuang.hellominecraft.util.logging.HMCLog;
|
||||
import org.jackhuang.hellominecraft.launcher.Main;
|
||||
import org.jackhuang.hellominecraft.launcher.setting.Settings;
|
||||
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
|
||||
import org.jackhuang.hellominecraft.launcher.core.download.DynamicDownloadProvider;
|
||||
import org.jackhuang.hellominecraft.util.ui.GraphicsUtils;
|
||||
import org.jackhuang.hellominecraft.lookandfeel.Theme;
|
||||
import org.jackhuang.hellominecraft.util.MessageBox;
|
||||
@@ -85,23 +86,27 @@ public final class MainFrame extends DraggableFrame {
|
||||
setUndecorated(!Settings.getInstance().isDecorated());
|
||||
defaultTitle = isUndecorated() ? Main.makeTitle() : "";
|
||||
enableShadow = Settings.getInstance().isEnableShadow() && isUndecorated();
|
||||
if (enableShadow)
|
||||
setContentSize(834, 542);
|
||||
else
|
||||
if (enableShadow) {
|
||||
setContentSize(834, 542);
|
||||
} else {
|
||||
setContentSize(802, 511);
|
||||
setDefaultCloseOperation(3);
|
||||
}
|
||||
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
setTitle(Main.makeTitle());
|
||||
initComponents();
|
||||
loadBackground();
|
||||
|
||||
DynamicDownloadProvider.getInstance().init();
|
||||
|
||||
setLocationRelativeTo(null);
|
||||
if (MainFrame.this.isUndecorated())
|
||||
if (MainFrame.this.isUndecorated()) {
|
||||
setResizable(false);
|
||||
}
|
||||
|
||||
this.addWindowListener(new WindowListener() {
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {
|
||||
}
|
||||
public void windowOpened(WindowEvent e) { }
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
@@ -109,16 +114,13 @@ public final class MainFrame extends DraggableFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
}
|
||||
public void windowClosed(WindowEvent e) { }
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) {
|
||||
}
|
||||
public void windowIconified(WindowEvent e) { }
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {
|
||||
}
|
||||
public void windowDeiconified(WindowEvent e) { }
|
||||
|
||||
@Override
|
||||
public void windowActivated(WindowEvent e) {
|
||||
@@ -131,11 +133,10 @@ public final class MainFrame extends DraggableFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent e) {
|
||||
}
|
||||
public void windowDeactivated(WindowEvent e) { }
|
||||
});
|
||||
|
||||
if (enableShadow)
|
||||
if (enableShadow) {
|
||||
try {
|
||||
setBackground(new Color(0, 0, 0, 0));
|
||||
getRootPane().setBorder(border = new DropShadowBorder(borderColor, 4));
|
||||
@@ -144,6 +145,8 @@ public final class MainFrame extends DraggableFrame {
|
||||
Settings.getInstance().setEnableShadow(false);
|
||||
setSize(802, 511);
|
||||
}
|
||||
}
|
||||
|
||||
((JPanel) getContentPane()).setOpaque(true);
|
||||
|
||||
Settings.getInstance().themeChangedEvent.register(this::reloadColor);
|
||||
|
||||
@@ -277,5 +277,16 @@
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="contentPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
|
||||
<AbsoluteConstraints x="220" y="40" width="540" height="320"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
|
||||
<Property name="useNullLayout" type="boolean" value="true"/>
|
||||
</Layout>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -61,7 +61,7 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
|
||||
void initGui() {
|
||||
initComponents();
|
||||
|
||||
|
||||
pnlButtons = new javax.swing.JPanel();
|
||||
pnlButtons.setLayout(null);
|
||||
|
||||
@@ -84,6 +84,9 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
pnlMore.setBounds(0, 0, pnlMore.getWidth(), DEFAULT_HEIGHT);
|
||||
pnlMore.setBackground(GraphicsUtils.getWebColorWithAlpha("FFFFFF7F"));
|
||||
pnlMore.setOpaque(true);
|
||||
|
||||
recommendPanel = new RecommendPanel();
|
||||
contentPanel.add(recommendPanel);
|
||||
|
||||
Settings.getInstance().authChangedEvent.register(onAuthChanged);
|
||||
Settings.profileLoadingEvent.register(onLoadingProfiles);
|
||||
@@ -122,6 +125,7 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
btnLogout = new javax.swing.JButton();
|
||||
btnImportModpack = new javax.swing.JButton();
|
||||
btnExportModpack = new javax.swing.JButton();
|
||||
contentPanel = new javax.swing.JPanel();
|
||||
|
||||
setLayout(null);
|
||||
|
||||
@@ -262,7 +266,7 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
.addComponent(lblVersion, javax.swing.GroupLayout.Alignment.TRAILING))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(cboProfiles, 0, 128, Short.MAX_VALUE)
|
||||
.addComponent(cboProfiles, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(cboVersions, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
|
||||
.addGroup(pnlMoreLayout.createSequentialGroup()
|
||||
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@@ -306,6 +310,10 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
|
||||
add(pnlMore);
|
||||
pnlMore.setBounds(0, 0, 190, 480);
|
||||
|
||||
contentPanel.setLayout(null);
|
||||
add(contentPanel);
|
||||
contentPanel.setBounds(220, 40, 540, 320);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void txtPlayerNameFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPlayerNameFocusGained
|
||||
@@ -426,6 +434,8 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
super.onCreate();
|
||||
Settings.onProfileLoading();
|
||||
}
|
||||
|
||||
private RecommendPanel recommendPanel;
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton btnExportModpack;
|
||||
@@ -434,6 +444,7 @@ public class MainPagePanel extends AnimatedPanel {
|
||||
private javax.swing.JComboBox cboLoginMode;
|
||||
private javax.swing.JComboBox cboProfiles;
|
||||
private javax.swing.JComboBox cboVersions;
|
||||
private javax.swing.JPanel contentPanel;
|
||||
private javax.swing.JLabel jLabel10;
|
||||
private javax.swing.JLabel jLabel7;
|
||||
private javax.swing.JLabel jLabel9;
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2016 evilwk <evilwk@gmail.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.hellominecraft.launcher.ui;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jackhuang.hellominecraft.util.C;
|
||||
import org.jackhuang.hellominecraft.util.NetUtils;
|
||||
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author evilwk <evilwk@gmail.com>
|
||||
*/
|
||||
public class RecommendPanel extends JPanel {
|
||||
|
||||
private static final int SWITCH_INTERVAL = 10;
|
||||
|
||||
private Image currImage;
|
||||
private String imageKey = null;
|
||||
private List<RecommendInfo> recommends;
|
||||
public ScheduledExecutorService scheduledexec = Executors.newScheduledThreadPool(1);
|
||||
|
||||
public RecommendPanel() {
|
||||
recommends = new ArrayList<RecommendInfo>();
|
||||
new LoadImages().execute();
|
||||
setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
MouseClicked(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void MouseClicked(MouseEvent evt) {
|
||||
if (imageKey == null) {
|
||||
return;
|
||||
}
|
||||
RecommendInfo info = recommends.get(getCurrentImageIndex());
|
||||
if (info.link != null && !info.link.equals("")) {
|
||||
SwingUtils.openLink(info.link);
|
||||
}
|
||||
}
|
||||
|
||||
public void showImages() {
|
||||
if (recommends.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (RecommendInfo info : recommends) {
|
||||
try {
|
||||
File tempFile = File.createTempFile("hmcl", "png");
|
||||
String tempPath = tempFile.getCanonicalPath();
|
||||
if (NetUtils.download(info.url, tempPath)) {
|
||||
info.image = ImageIO.read(tempFile);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
if (getImagesSize() == 0 || showIfOnly()) {
|
||||
return;
|
||||
}
|
||||
scheduledexec.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int showIndex = getNextImageIndex();
|
||||
RecommendInfo info = recommends.get(showIndex);
|
||||
RecommendPanel.this.setImage(info.url, info.image);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 0, SWITCH_INTERVAL, TimeUnit.SECONDS);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public int getImagesSize() {
|
||||
int imageCount = 0;
|
||||
for (RecommendInfo recommend : recommends) {
|
||||
if (recommend.image != null) {
|
||||
imageCount++;
|
||||
}
|
||||
}
|
||||
return imageCount;
|
||||
}
|
||||
|
||||
public boolean showIfOnly() {
|
||||
if (getImagesSize() != 1) {
|
||||
return false;
|
||||
}
|
||||
for (RecommendInfo recommend : recommends) {
|
||||
if (recommend.image != null) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
RecommendPanel.this.setImage(recommend.url, recommend.image);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getNextImageIndex(int showIndex) {
|
||||
if (showIndex >= recommends.size()) {
|
||||
showIndex = 0;
|
||||
}
|
||||
RecommendInfo info = recommends.get(showIndex);
|
||||
if (info.image == null) {
|
||||
showIndex = getNextImageIndex(++showIndex);
|
||||
}
|
||||
return showIndex;
|
||||
}
|
||||
|
||||
public int getNextImageIndex() {
|
||||
int showIndex = 0;
|
||||
if (imageKey != null) {
|
||||
showIndex = getCurrentImageIndex();
|
||||
showIndex++;
|
||||
}
|
||||
if (showIndex >= recommends.size()) {
|
||||
showIndex = 0;
|
||||
}
|
||||
showIndex = getNextImageIndex(showIndex);
|
||||
return showIndex >= recommends.size() ? 0 : showIndex;
|
||||
}
|
||||
|
||||
public int getCurrentImageIndex() {
|
||||
int currIndex = 0;
|
||||
for (int i = 0; i < recommends.size(); i++) {
|
||||
RecommendInfo info = recommends.get(i);
|
||||
if (imageKey != null && info.url.equals(imageKey)) {
|
||||
currIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return currIndex;
|
||||
}
|
||||
|
||||
public void setImage(String key, Image image) {
|
||||
this.imageKey = key;
|
||||
this.currImage = image;
|
||||
//setToolTipText(C.i18n("ui.message.recommend_tip"));
|
||||
setSize(image.getWidth(this), image.getHeight(this));
|
||||
SwingUtilities.updateComponentTreeUI(this.getRootPane());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
if (null == currImage) {
|
||||
return;
|
||||
}
|
||||
g.drawImage(currImage, 0, 0, currImage.getWidth(this), currImage.getHeight(this), this);
|
||||
}
|
||||
|
||||
static class RecommendInfo {
|
||||
String url;
|
||||
String link;
|
||||
Image image;
|
||||
}
|
||||
|
||||
class LoadImages extends SwingWorker<List<Map<String, String>>, Void> {
|
||||
|
||||
private static final String RECOMMEND_URL = "http://client.api.mcgogogo.com:81/recommend.php";
|
||||
|
||||
@Override
|
||||
protected List<Map<String, String>> doInBackground() throws Exception {
|
||||
List<Map<String, String>> infos = null;
|
||||
do {
|
||||
String content = NetUtils.get(RECOMMEND_URL);
|
||||
if (content == null || content.equals("")) {
|
||||
break;
|
||||
}
|
||||
|
||||
Map<String, Object> data = new Gson().fromJson(content,
|
||||
new TypeToken<Map<String, Object>>() {
|
||||
}.getType());
|
||||
if (data == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
infos = (List<Map<String, String>>) data.get("data");
|
||||
} while (false);
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
List<Map<String, String>> infos = this.get();
|
||||
if (infos == null) {
|
||||
return;
|
||||
}
|
||||
for (Map<String, String> info : infos) {
|
||||
RecommendInfo recommend = new RecommendInfo();
|
||||
recommend.url = info.get("url");
|
||||
recommend.link = info.get("link");
|
||||
recommend.image = null;
|
||||
recommends.add(recommend);
|
||||
}
|
||||
RecommendPanel.this.showImages();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+67
-35
@@ -36,9 +36,11 @@ import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Pack200;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import javax.swing.JCheckBox;
|
||||
import org.jackhuang.hellominecraft.util.C;
|
||||
import org.jackhuang.hellominecraft.util.logging.HMCLog;
|
||||
import org.jackhuang.hellominecraft.launcher.core.MCUtils;
|
||||
import org.jackhuang.hellominecraft.launcher.setting.Settings;
|
||||
import org.jackhuang.hellominecraft.util.tasks.Task;
|
||||
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
|
||||
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
|
||||
@@ -47,9 +49,11 @@ import org.jackhuang.hellominecraft.util.MessageBox;
|
||||
import org.jackhuang.hellominecraft.util.UpdateChecker;
|
||||
import org.jackhuang.hellominecraft.util.Utils;
|
||||
import org.jackhuang.hellominecraft.util.VersionNumber;
|
||||
import org.jackhuang.hellominecraft.util.func.Consumer;
|
||||
import org.jackhuang.hellominecraft.util.system.FileUtils;
|
||||
import org.jackhuang.hellominecraft.util.system.IOUtils;
|
||||
import org.jackhuang.hellominecraft.util.system.OS;
|
||||
import org.jackhuang.hellominecraft.util.tasks.TaskList;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -97,43 +101,71 @@ public class AppDataUpgrader extends IUpgrader {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public boolean askUpdateVersion(VersionNumber versionNumber) {
|
||||
if (!Settings.UPDATE_CHECKER.isManualUpdate() &&
|
||||
Settings.getInstance().ignoreUpdate(versionNumber))
|
||||
return false;
|
||||
|
||||
String content = C.i18n("update.newest_version") +
|
||||
versionNumber.firstVer + "." + versionNumber.secondVer + "." +
|
||||
versionNumber.thirdVer + "\n" +
|
||||
C.i18n("update.should_open_link");
|
||||
JCheckBox checkbox = new JCheckBox(C.i18n("update.ignore"));
|
||||
int ret = MessageBox.Show(new Object[]{content, checkbox}, MessageBox.YES_NO_OPTION);
|
||||
if (ret == MessageBox.NO_OPTION) {
|
||||
Settings.getInstance().setIgnoreUpdate(versionNumber);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean call(Object sender, final VersionNumber number) {
|
||||
((UpdateChecker) sender).requestDownloadLink().reg(map -> {
|
||||
if (MessageBox.Show(C.i18n("update.newest_version") + number.firstVer + "." + number.secondVer + "." + number.thirdVer + "\n"
|
||||
+ C.i18n("update.should_open_link"),
|
||||
MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
|
||||
if (map != null && map.containsKey("pack"))
|
||||
try {
|
||||
String hash = null;
|
||||
if (map.containsKey("packsha1"))
|
||||
hash = map.get("packsha1");
|
||||
if (TaskWindow.factory().append(new AppDataUpgraderTask(map.get("pack"), number.version, hash)).create()) {
|
||||
new ProcessBuilder(new String[] { IOUtils.getJavaDir(), "-jar", AppDataUpgraderTask.getSelf(number.version).getAbsolutePath() }).directory(new File(".")).start();
|
||||
System.exit(0);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
HMCLog.err("Failed to create upgrader", ex);
|
||||
}
|
||||
else {
|
||||
String url = C.URL_PUBLISH;
|
||||
if (map != null)
|
||||
if (map.containsKey(OS.os().checked_name))
|
||||
url = map.get(OS.os().checked_name);
|
||||
else if (map.containsKey(OS.UNKOWN.checked_name))
|
||||
url = map.get(OS.UNKOWN.checked_name);
|
||||
if (url == null)
|
||||
url = C.URL_PUBLISH;
|
||||
try {
|
||||
java.awt.Desktop.getDesktop().browse(new URI(url));
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
HMCLog.warn("Failed to browse uri: " + url, e);
|
||||
Utils.setClipborad(url);
|
||||
MessageBox.Show(C.i18n("update.no_browser"));
|
||||
}
|
||||
}
|
||||
}).execute();
|
||||
((UpdateChecker) sender).requestDownloadLink().reg(new Consumer<Map<String, String>>() {
|
||||
@Override
|
||||
public void accept(Map<String, String> map) {
|
||||
boolean isForceUpdate = Settings.UPDATE_CHECKER.isForceUpdate();
|
||||
if (isForceUpdate || askUpdateVersion(number))
|
||||
if (map != null && map.containsKey("pack"))
|
||||
try {
|
||||
String hash = null;
|
||||
if (map.containsKey("packsha1")) {
|
||||
hash = map.get("packsha1");
|
||||
}
|
||||
AppDataUpgraderTask upgraderTask = new AppDataUpgraderTask(map.get("pack"), number.version, hash);
|
||||
if (isForceUpdate) {
|
||||
TaskList tasks = new TaskList();
|
||||
tasks.addTask(upgraderTask);
|
||||
tasks.start();
|
||||
} else {
|
||||
if (TaskWindow.factory().append(upgraderTask).create()) {
|
||||
new ProcessBuilder(new String[] { IOUtils.getJavaDir(), "-jar", AppDataUpgraderTask.getSelf(number.version).getAbsolutePath() }).directory(new File(".")).start();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
HMCLog.err("Failed to create upgrader", ex);
|
||||
}
|
||||
else {
|
||||
String url = C.URL_PUBLISH;
|
||||
if (map != null)
|
||||
if (map.containsKey(OS.os().checked_name))
|
||||
url = map.get(OS.os().checked_name);
|
||||
else if (map.containsKey(OS.UNKOWN.checked_name))
|
||||
url = map.get(OS.UNKOWN.checked_name);
|
||||
if (url == null)
|
||||
url = C.URL_PUBLISH;
|
||||
try {
|
||||
java.awt.Desktop.getDesktop().browse(new URI(url));
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
HMCLog.warn("Failed to browse uri: " + url, e);
|
||||
Utils.setClipborad(url);
|
||||
MessageBox.Show(C.i18n("update.no_browser"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}).execute();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#Thu Jul 07 14:30:49 CST 2016
|
||||
VERSION_CODE=92
|
||||
+27
-8
@@ -15,6 +15,21 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral();
|
||||
dependencies {
|
||||
classpath 'edu.sc.seis.gradle:launch4j:1.0.6'
|
||||
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "edu.sc.seis.macAppBundle" version "2.1.6"
|
||||
}
|
||||
|
||||
apply plugin: 'launch4j'
|
||||
apply plugin: 'me.tatarka.retrolambda'
|
||||
|
||||
@@ -41,14 +56,17 @@ version = mavenVersion
|
||||
|
||||
String mavenArtifactId = name
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral();
|
||||
dependencies {
|
||||
classpath 'edu.sc.seis.gradle:launch4j:1.0.6'
|
||||
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
|
||||
}
|
||||
}
|
||||
task macAppCompressed(type: Zip, dependsOn: createApp) {
|
||||
archiveName "HMCSM-$mavenVersion-MacOSApp.zip"
|
||||
include '**'
|
||||
destinationDir file("$buildDir/libs/")
|
||||
from "$buildDir/macApp"
|
||||
}
|
||||
|
||||
macAppBundle {
|
||||
mainClassName = mainClass
|
||||
icon = "src/main/icon.icns"
|
||||
javaProperties.put("apple.laf.useScreenMenuBar", "true")
|
||||
}
|
||||
|
||||
configure(install.repositories.mavenInstaller) {
|
||||
@@ -87,3 +105,4 @@ processResources {
|
||||
}
|
||||
|
||||
build.dependsOn makeExecutable
|
||||
build.dependsOn macAppCompressed
|
||||
Executable
BIN
Binary file not shown.
@@ -32,7 +32,7 @@ public final class C {
|
||||
//http://repo1.maven.org/maven2
|
||||
public static final String URL_PUBLISH = "http://www.mcbbs.net/thread-142335-1-1.html";
|
||||
public static final String URL_TIEBA = "http://tieba.baidu.com/f?kw=hellominecraftlauncher";
|
||||
public static final String URL_GITHUB = "https://github.com/huanghongxun/HMCL/issues";
|
||||
public static final String URL_GITHUB = "https://github.com/mclauncher/HMCL/issues";
|
||||
public static final String URL_MINECRAFTFORUM = "http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-tools/1265720-hello-minecraft-launcher-1-9-3-mc-1-7-4-auto";
|
||||
|
||||
public static final String FILE_MINECRAFT_VERSIONS = "versions";
|
||||
|
||||
@@ -51,21 +51,21 @@ public class DoubleOutputStream extends OutputStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(byte[] paramArrayOfByte) throws IOException {
|
||||
public final void write(byte[] arr) throws IOException {
|
||||
if (this.a != null)
|
||||
this.a.write(paramArrayOfByte);
|
||||
this.a.write(arr);
|
||||
if (this.b != null)
|
||||
this.b.write(paramArrayOfByte);
|
||||
this.b.write(arr);
|
||||
if (this.c)
|
||||
flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(int paramInt) throws IOException {
|
||||
public final void write(int i) throws IOException {
|
||||
if (this.a != null)
|
||||
this.a.write(paramInt);
|
||||
this.a.write(i);
|
||||
if (this.b != null)
|
||||
this.b.write(paramInt);
|
||||
this.b.write(i);
|
||||
if (this.c)
|
||||
flush();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ public interface IUpdateChecker {
|
||||
*
|
||||
*/
|
||||
void checkOutdate();
|
||||
|
||||
boolean isForceUpdate();
|
||||
|
||||
boolean isManualUpdate();
|
||||
|
||||
/**
|
||||
* Get the <b>cached</b> newest version number, use "process" method to
|
||||
|
||||
@@ -86,23 +86,23 @@ public class MessageBox {
|
||||
/**
|
||||
* Show MsgBox with title and options
|
||||
*
|
||||
* @param Msg The Message
|
||||
* @param Title The title of MsgBox.
|
||||
* @param Option The type of MsgBox.
|
||||
* @param msg The Message
|
||||
* @param title The title of MsgBox.
|
||||
* @param optionType The type of MsgBox.
|
||||
*
|
||||
* @return user operation.
|
||||
*/
|
||||
public static int Show(String Msg, String Title, int Option) {
|
||||
switch (Option) {
|
||||
public static int Show(Object msg, String title, int optionType) {
|
||||
switch (optionType) {
|
||||
case YES_NO_OPTION:
|
||||
case YES_NO_CANCEL_OPTION:
|
||||
case OK_CANCEL_OPTION:
|
||||
return SwingUtils.invokeAndWait(() -> JOptionPane.showConfirmDialog(null, Msg, Title, Option - 10));
|
||||
return SwingUtils.invokeAndWait(() -> JOptionPane.showConfirmDialog(null, msg, title, optionType - 10));
|
||||
default:
|
||||
SwingUtils.invokeAndWait(() -> JOptionPane.showMessageDialog(null, Msg, Title, Option));
|
||||
SwingUtils.invokeAndWait(() -> JOptionPane.showMessageDialog(null, msg, title, optionType));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show MsgBox with options
|
||||
@@ -112,8 +112,8 @@ public class MessageBox {
|
||||
*
|
||||
* @return User Operation
|
||||
*/
|
||||
public static int Show(String Msg, int Option) {
|
||||
return Show(Msg, TITLE, Option);
|
||||
public static int Show(Object msg, int optionType) {
|
||||
return Show(msg, TITLE, optionType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,8 +123,8 @@ public class MessageBox {
|
||||
*
|
||||
* @return User Operation
|
||||
*/
|
||||
public static int Show(String Msg) {
|
||||
return Show(Msg, TITLE, INFORMATION_MESSAGE);
|
||||
public static int Show(Object msg) {
|
||||
return Show(msg, TITLE, INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
public static int ShowLocalized(String msg) {
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.jackhuang.hellominecraft.util;
|
||||
|
||||
import org.jackhuang.hellominecraft.util.logging.HMCLog;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -37,13 +39,10 @@ import org.jackhuang.hellominecraft.util.system.IOUtils;
|
||||
public final class NetUtils {
|
||||
|
||||
public static byte[] getBytesFromStream(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
|
||||
byte[] arrayOfByte1 = new byte[1024];
|
||||
int i;
|
||||
while ((i = is.read(arrayOfByte1)) >= 0)
|
||||
localByteArrayOutputStream.write(arrayOfByte1, 0, i);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
IOUtils.copyStream(is, out);
|
||||
is.close();
|
||||
return localByteArrayOutputStream.toByteArray();
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public static String getStreamContent(InputStream is) throws IOException {
|
||||
@@ -83,12 +82,8 @@ public final class NetUtils {
|
||||
public static String post(URL u, Map<String, String> params) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (params != null) {
|
||||
for (Map.Entry<String, String> e : params.entrySet()) {
|
||||
sb.append(e.getKey());
|
||||
sb.append("=");
|
||||
sb.append(e.getValue());
|
||||
sb.append("&");
|
||||
}
|
||||
for (Map.Entry<String, String> e : params.entrySet())
|
||||
sb.append(e.getKey()).append("=").append(e.getValue()).append("&");
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
return post(u, sb.toString());
|
||||
@@ -136,6 +131,23 @@ public final class NetUtils {
|
||||
con.disconnect();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean download(String url, String saveFile) {
|
||||
try {
|
||||
int readCount = 0;
|
||||
byte[] buffer = new byte[1204];
|
||||
InputStream inputStream = new URL(url).openConnection().getInputStream();
|
||||
FileOutputStream fs = new FileOutputStream(saveFile);
|
||||
while ((readCount = inputStream.read(buffer)) != -1) {
|
||||
fs.write(buffer, 0, readCount);
|
||||
}
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DEFAULT_CHARSET = "UTF-8";
|
||||
|
||||
@@ -150,9 +162,9 @@ public final class NetUtils {
|
||||
|
||||
public static URL concatenateURL(URL url, String query) {
|
||||
try {
|
||||
if ((url.getQuery() != null) && (url.getQuery().length() > 0))
|
||||
return new URL(url.getProtocol(), url.getHost(), url.getPort(), new StringBuilder().append(url.getFile()).append("&").append(query).toString());
|
||||
return new URL(url.getProtocol(), url.getHost(), url.getPort(), new StringBuilder().append(url.getFile()).append("?").append(query).toString());
|
||||
if (url.getQuery() != null && url.getQuery().length() > 0)
|
||||
return new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + "&" + query);
|
||||
return new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + "?" + query);
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new IllegalArgumentException("Could not concatenate given URL with GET arguments!", ex);
|
||||
}
|
||||
|
||||
@@ -25,10 +25,18 @@ import java.util.Map;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class UpdateChecker implements IUpdateChecker {
|
||||
|
||||
|
||||
public static final String VERSION_URL = "http://client.api.mcgogogo.com:81/version.php?type=";
|
||||
public static final String UPDATE_LINK_URL = "http://client.api.mcgogogo.com:81/update_link.php?type=";
|
||||
|
||||
public boolean OUT_DATED = false;
|
||||
|
||||
public String versionString;
|
||||
public VersionNumber base;
|
||||
public String versionString;
|
||||
private VersionNumber value;
|
||||
private boolean isforceUpdate = false;
|
||||
private boolean isManualUpdate = false;
|
||||
|
||||
public String type;
|
||||
private Map<String, String> download_link = null;
|
||||
|
||||
@@ -37,26 +45,34 @@ public final class UpdateChecker implements IUpdateChecker {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
VersionNumber value;
|
||||
|
||||
@Override
|
||||
public OverridableSwingWorker<VersionNumber> process(final boolean showMessage) {
|
||||
return new OverridableSwingWorker() {
|
||||
@Override
|
||||
protected void work() throws Exception {
|
||||
isManualUpdate = showMessage;
|
||||
|
||||
if (value == null) {
|
||||
versionString = NetUtils.get("http://huangyuhui.duapp.com/info.php?type=" + type);
|
||||
value = VersionNumber.check(versionString);
|
||||
versionString = NetUtils.get(VERSION_URL + type + "&ver=" + base.toString());
|
||||
Map<String, Object> versionInfo = C.GSON.fromJson(versionString, Map.class);
|
||||
if (versionInfo.containsKey("version"))
|
||||
value = VersionNumber.check((String)versionInfo.get("version"));
|
||||
if (versionInfo.containsKey("force"))
|
||||
isforceUpdate = (boolean)versionInfo.get("force");
|
||||
}
|
||||
|
||||
|
||||
if (value == null) {
|
||||
HMCLog.warn("Failed to check update...");
|
||||
if (showMessage)
|
||||
if (showMessage) {
|
||||
MessageBox.Show(C.i18n("update.failed"));
|
||||
} else if (VersionNumber.isOlder(base, value))
|
||||
}
|
||||
} else if (VersionNumber.isOlder(base, value)) {
|
||||
OUT_DATED = true;
|
||||
if (OUT_DATED)
|
||||
}
|
||||
|
||||
if (OUT_DATED) {
|
||||
publish(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -66,6 +82,16 @@ public final class UpdateChecker implements IUpdateChecker {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceUpdate() {
|
||||
return isforceUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isManualUpdate() {
|
||||
return isManualUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OverridableSwingWorker<Map<String, String>> requestDownloadLink() {
|
||||
return new OverridableSwingWorker() {
|
||||
@@ -73,7 +99,7 @@ public final class UpdateChecker implements IUpdateChecker {
|
||||
protected void work() throws Exception {
|
||||
if (download_link == null)
|
||||
try {
|
||||
download_link = C.GSON.fromJson(NetUtils.get("http://huangyuhui.duapp.com/update_link.php?type=" + type), Map.class);
|
||||
download_link = C.GSON.fromJson(NetUtils.get(UPDATE_LINK_URL + type), Map.class);
|
||||
} catch (Exception e) {
|
||||
HMCLog.warn("Failed to get update link.", e);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,6 @@ public class Compressor {
|
||||
}
|
||||
String pathName;//存相对路径(相对于待压缩的根目录)
|
||||
byte[] buf = new byte[1024];
|
||||
int length;
|
||||
for (File file : files)
|
||||
if (file.isDirectory()) {
|
||||
pathName = file.getPath().substring(basePath.length() + 1)
|
||||
@@ -129,8 +128,7 @@ public class Compressor {
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
zos.putNextEntry(new ZipEntry(pathName));
|
||||
while ((length = bis.read(buf)) > 0)
|
||||
zos.write(buf, 0, length);
|
||||
IOUtils.copyStream(bis, zos, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,6 +152,7 @@ public class Compressor {
|
||||
* @throws java.io.IOException 解压失败或无法写入
|
||||
*/
|
||||
public static void unzip(File zipFileName, File extPlace, Predicate<String> callback, boolean ignoreExistsFile) throws IOException {
|
||||
byte[] buf = new byte[1024];
|
||||
extPlace.mkdirs();
|
||||
try (ZipInputStream zipFile = new ZipInputStream(new FileInputStream(zipFileName))) {
|
||||
if (zipFileName.exists()) {
|
||||
@@ -184,10 +183,8 @@ public class Compressor {
|
||||
}
|
||||
if (ignoreExistsFile && new File(strtemp).exists())
|
||||
continue;
|
||||
try (FileOutputStream fos = new FileOutputStream(strtemp); BufferedOutputStream bos = new BufferedOutputStream(fos)) {
|
||||
int c;
|
||||
while ((c = zipFile.read()) != -1)
|
||||
bos.write((byte) c);
|
||||
try (FileOutputStream fos = new FileOutputStream(strtemp)) {
|
||||
IOUtils.copyStream(zipFile, fos, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,4 +288,14 @@ public class IOUtils {
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
public static void copyStream(InputStream input, OutputStream output) throws IOException {
|
||||
copyStream(input, output, new byte[1024]);
|
||||
}
|
||||
|
||||
public static void copyStream(InputStream input, OutputStream output, byte[] buf) throws IOException {
|
||||
int length;
|
||||
while ((length = input.read(buf)) != -1)
|
||||
output.write(buf, 0, length);
|
||||
}
|
||||
}
|
||||
@@ -121,11 +121,9 @@ public class ZipEngine {
|
||||
}
|
||||
|
||||
public void putStream(InputStream is, String pathName) throws IOException {
|
||||
int length;
|
||||
try (BufferedInputStream bis = new BufferedInputStream(is)) {
|
||||
put(new ZipEntry(pathName));
|
||||
while ((length = bis.read(buf)) > 0)
|
||||
zos.write(buf, 0, length);
|
||||
IOUtils.copyStream(bis, zos, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -118,7 +118,7 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
||||
this.url = IOUtils.parseURL(p.getResult());
|
||||
|
||||
for (int repeat = 0; repeat < 6; repeat++) {
|
||||
if (repeat > 0)
|
||||
if (repeat > 0) {
|
||||
if (failedCallbackReturnsNewURL != null) {
|
||||
URL tmp = IOUtils.parseURL(failedCallbackReturnsNewURL.apply(repeat));
|
||||
if (tmp != null) {
|
||||
@@ -126,6 +126,8 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
||||
HMCLog.warn("Switch to: " + url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HMCLog.log("Downloading: " + url + ", to: " + filePath);
|
||||
if (!shouldContinue)
|
||||
break;
|
||||
@@ -260,4 +262,8 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
|
||||
al.add(pr);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setFailedCallbackReturnsNewURL() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -62,12 +62,12 @@ public class HTTPGetTask extends TaskInfo implements PreviousResult<String> {
|
||||
URLConnection conn = new URL(url).openConnection();
|
||||
InputStream is = conn.getInputStream();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int i;
|
||||
int size = conn.getContentLength(), read = 0;
|
||||
byte[] buf = new byte[1024];
|
||||
int size = conn.getContentLength(), read = 0, len;
|
||||
long lastTime = System.currentTimeMillis();
|
||||
while ((i = is.read()) != -1) {
|
||||
baos.write(i);
|
||||
++read;
|
||||
while ((len = is.read(buf)) != -1) {
|
||||
baos.write(buf, 0, len);
|
||||
read += len;
|
||||
long now = System.currentTimeMillis();
|
||||
if (ppl != null && (now - lastTime) >= 1000) {
|
||||
ppl.setProgress(this, read, size);
|
||||
|
||||
+10
-9
@@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hellominecraft.util.ui;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.Timer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jackhuang.hellominecraft.util.logging.Level;
|
||||
@@ -35,23 +36,23 @@ public class LogWindowOutputStream extends OutputStream {
|
||||
|
||||
public LogWindowOutputStream(LogWindow logWindow, Level l) {
|
||||
txt = logWindow;
|
||||
this.sas = l;
|
||||
sas = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(byte[] paramArrayOfByte) {
|
||||
write(paramArrayOfByte, 0, paramArrayOfByte.length);
|
||||
public final void write(byte[] arr) {
|
||||
write(arr, 0, arr.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(byte[] paramArrayOfByte, int off, int len) {
|
||||
append(new String(paramArrayOfByte, off, len));
|
||||
public final void write(byte[] arr, int off, int len) {
|
||||
append(new String(arr, off, len));
|
||||
}
|
||||
|
||||
private void append(final String newString) {
|
||||
private void append(final String str) {
|
||||
try {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
txt.log(newString, Level.guessLevel(newString, sas));
|
||||
txt.log(str, Level.guessLevel(str, sas));
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@@ -59,8 +60,8 @@ public class LogWindowOutputStream extends OutputStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(int paramInt) {
|
||||
append(new String(new byte[] { (byte) paramInt }));
|
||||
public final void write(int i) {
|
||||
append(new String(new byte[] { (byte) i }));
|
||||
}
|
||||
|
||||
public static void dispose() {
|
||||
|
||||
@@ -168,6 +168,7 @@ ui.message.launching=启动中
|
||||
ui.message.making=生成中
|
||||
ui.message.sure_remove=真的要删除配置%s吗?
|
||||
ui.message.update_java=请更新您的Java
|
||||
ui.message.recommend_tip=点击打开链接
|
||||
|
||||
ui.label.settings=选项
|
||||
ui.label.crashing=<html>Hello Minecraft!遇到了无法处理的错误,请复制下列内容并通过mcbbs、贴吧、Github或Minecraft Forum反馈bug。</html>
|
||||
@@ -175,7 +176,7 @@ ui.label.crashing_out_dated=<html>Hello Minecraft! Launcher遇到了无法处理
|
||||
ui.label.failed_set=设置失败:
|
||||
|
||||
download=下载
|
||||
download.mojang=官方
|
||||
download.mojang=Mojang官方
|
||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||
download.rapid_data=RapidData (锐网云计算, https://www.rapiddata.org/)
|
||||
download.not_200=下载失败,回复码
|
||||
@@ -298,7 +299,7 @@ mainwindow.enter_script_name=输入要生成脚本的文件名
|
||||
mainwindow.make_launch_succeed=启动脚本已生成完毕:
|
||||
mainwindow.no_version=未找到任何版本,是否进入游戏下载?
|
||||
|
||||
launcher.about=<html>默认背景图感谢gamerteam提供。<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">如果您希望本软件继续发展,请赞助</a><br/>关于作者:<br/>百度ID:huanghongxun20<br/>mcbbs:huanghongxun<br/>邮箱:huanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>欢迎提交Bug哦<br/>Copyright (c) 2013-2016 huangyuhui.<br/>免责声明:Minecraft软件版权归Mojang AB所有,使用本软件产生的版权问题本软件制作方概不负责。<br/>本启动器在GPLv3协议下开源:https://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者<br/>本软件使用了基于Apache License 2.0的Gson项目,感谢贡献者。</html>
|
||||
launcher.about=<html>默认背景图感谢gamerteam提供。<br/>关于作者:<br/>主页:http://www.hmclsoft.com<br/>邮箱:contact@hmclsoft.com<br/>欢迎提交Bug哦<br/>Copyright (c) 2013-2016 HMCLSoft.<br/>免责声明:Minecraft软件版权归Mojang AB所有,使用本软件产生的版权问题本软件制作方概不负责。<br/>本启动器在GPLv3协议下开源:https://github.com/mclauncher/HMCL,感谢issues和pull requests贡献者<br/>本软件使用了基于Apache License 2.0的Gson项目,感谢贡献者。</html>
|
||||
launcher.download_source=下载源
|
||||
launcher.background_location=背景地址
|
||||
launcher.exit_failed=强制退出失败,可能是Forge 1.7.10及更高版本导致的,无法解决。
|
||||
@@ -312,7 +313,7 @@ launcher.enable_shadow=启用窗口阴影
|
||||
launcher.theme=主题
|
||||
launcher.proxy=代理
|
||||
launcher.decorated=启用窗口边框(Linux下可解决程序界面全灰问题)
|
||||
launcher.modpack=<html><a href="http://huangyuhui.duapp.com/link.php?type=modpack">整合包作者帮助</a></html>
|
||||
launcher.modpack=<html><a href="http://client.api.mcgogogo.com:81/link.php?type=modpack">整合包作者帮助</a></html>
|
||||
launcher.enable_animation=启用动态效果
|
||||
launcher.lang=语言
|
||||
launcher.restart=本界面选项需要重启本启动器生效
|
||||
@@ -369,6 +370,7 @@ update.should_open_link=是否更新?
|
||||
update.newest_version=最新版本为:
|
||||
update.failed=检查更新失败
|
||||
update.found=(发现更新!)
|
||||
update.ignore=不再提醒此版本更新
|
||||
|
||||
logwindow.terminate_game=结束游戏进程
|
||||
logwindow.tieba=贴吧
|
||||
|
||||
@@ -168,6 +168,7 @@ ui.message.launching=\u542f\u52a8\u4e2d
|
||||
ui.message.making=\u751f\u6210\u4e2d
|
||||
ui.message.sure_remove=\u771f\u7684\u8981\u5220\u9664\u914d\u7f6e%s\u5417\uff1f
|
||||
ui.message.update_java=\u8bf7\u66f4\u65b0\u60a8\u7684Java
|
||||
ui.message.recommend_tip=\u70b9\u51fb\u6253\u5f00\u94fe\u63a5
|
||||
|
||||
ui.label.settings=\u9009\u9879
|
||||
ui.label.crashing=<html>Hello Minecraft!\u9047\u5230\u4e86\u65e0\u6cd5\u5904\u7406\u7684\u9519\u8bef\uff0c\u8bf7\u590d\u5236\u4e0b\u5217\u5185\u5bb9\u5e76\u901a\u8fc7mcbbs\u3001\u8d34\u5427\u3001Github\u6216Minecraft Forum\u53cd\u9988bug\u3002</html>
|
||||
@@ -175,7 +176,7 @@ ui.label.crashing_out_dated=<html>Hello Minecraft! Launcher\u9047\u5230\u4e86\u6
|
||||
ui.label.failed_set=\u8bbe\u7f6e\u5931\u8d25\uff1a
|
||||
|
||||
download=\u4e0b\u8f7d
|
||||
download.mojang=\u5b98\u65b9
|
||||
download.mojang=Mojang\u5b98\u65b9
|
||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||
download.rapid_data=RapidData (\u9510\u7f51\u4e91\u8ba1\u7b97, https://www.rapiddata.org/)
|
||||
download.not_200=\u4e0b\u8f7d\u5931\u8d25\uff0c\u56de\u590d\u7801
|
||||
@@ -298,7 +299,7 @@ mainwindow.enter_script_name=\u8f93\u5165\u8981\u751f\u6210\u811a\u672c\u7684\u6
|
||||
mainwindow.make_launch_succeed=\u542f\u52a8\u811a\u672c\u5df2\u751f\u6210\u5b8c\u6bd5:
|
||||
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u8fdb\u5165\u6e38\u620f\u4e0b\u8f7d\uff1f
|
||||
|
||||
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u611f\u8c22gamerteam\u63d0\u4f9b\u3002<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">\u5982\u679c\u60a8\u5e0c\u671b\u672c\u8f6f\u4ef6\u7ee7\u7eed\u53d1\u5c55\uff0c\u8bf7\u8d5e\u52a9</a><br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\u767e\u5ea6ID\uff1ahuanghongxun20<br/>mcbbs\uff1ahuanghongxun<br/>\u90ae\u7bb1\uff1ahuanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u4f7f\u7528\u672c\u8f6f\u4ef6\u4ea7\u751f\u7684\u7248\u6743\u95ee\u9898\u672c\u8f6f\u4ef6\u5236\u4f5c\u65b9\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/ ,\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684Gson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
|
||||
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u611f\u8c22gamerteam\u63d0\u4f9b\u3002<br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\u4e3b\u9875\uff1ahttp://www.hmclsoft.com<br/>\u90ae\u7bb1\uff1acontact@hmclsoft.com<br/>\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 HMCLSoft.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u4f7f\u7528\u672c\u8f6f\u4ef6\u4ea7\u751f\u7684\u7248\u6743\u95ee\u9898\u672c\u8f6f\u4ef6\u5236\u4f5c\u65b9\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90\uff1ahttps://github.com/mclauncher/HMCL\uff0c\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684Gson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
|
||||
launcher.download_source=\u4e0b\u8f7d\u6e90
|
||||
launcher.background_location=\u80cc\u666f\u5730\u5740
|
||||
launcher.exit_failed=\u5f3a\u5236\u9000\u51fa\u5931\u8d25\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5bfc\u81f4\u7684\uff0c\u65e0\u6cd5\u89e3\u51b3\u3002
|
||||
@@ -312,7 +313,7 @@ launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71
|
||||
launcher.theme=\u4e3b\u9898
|
||||
launcher.proxy=\u4ee3\u7406
|
||||
launcher.decorated=\u542f\u7528\u7a97\u53e3\u8fb9\u6846(Linux\u4e0b\u53ef\u89e3\u51b3\u7a0b\u5e8f\u754c\u9762\u5168\u7070\u95ee\u9898)
|
||||
launcher.modpack=<html><a href="http://huangyuhui.duapp.com/link.php?type=modpack">\u6574\u5408\u5305\u4f5c\u8005\u5e2e\u52a9</a></html>
|
||||
launcher.modpack=<html><a href="http://client.api.mcgogogo.com:81/link.php?type=modpack">\u6574\u5408\u5305\u4f5c\u8005\u5e2e\u52a9</a></html>
|
||||
launcher.enable_animation=\u542f\u7528\u52a8\u6001\u6548\u679c
|
||||
launcher.lang=\u8bed\u8a00
|
||||
launcher.restart=\u672c\u754c\u9762\u9009\u9879\u9700\u8981\u91cd\u542f\u672c\u542f\u52a8\u5668\u751f\u6548
|
||||
@@ -369,6 +370,7 @@ update.should_open_link=\u662f\u5426\u66f4\u65b0\uff1f
|
||||
update.newest_version=\u6700\u65b0\u7248\u672c\u4e3a\uff1a
|
||||
update.failed=\u68c0\u67e5\u66f4\u65b0\u5931\u8d25
|
||||
update.found=(\u53d1\u73b0\u66f4\u65b0!)
|
||||
update.ignore=\u4e0d\u518d\u63d0\u9192\u6b64\u7248\u672c\u66f4\u65b0
|
||||
|
||||
logwindow.terminate_game=\u7ed3\u675f\u6e38\u620f\u8fdb\u7a0b
|
||||
logwindow.tieba=\u8d34\u5427
|
||||
|
||||
@@ -168,6 +168,7 @@ ui.message.launching=Launching...
|
||||
ui.message.making=Generating...
|
||||
ui.message.sure_remove=Sure to remove profile %s?
|
||||
ui.message.update_java=Please upgrade your Java.
|
||||
ui.message.recommend_tip=Click to open link
|
||||
|
||||
ui.label.settings=Settings
|
||||
ui.label.crashing=<html>Hello Minecraft! Launcher has crashed!</html>
|
||||
@@ -298,7 +299,7 @@ mainwindow.enter_script_name=Enter the script name.
|
||||
mainwindow.make_launch_succeed=Finished script creation.
|
||||
mainwindow.no_version=No version found. Switch to Game Downloads Tab?
|
||||
|
||||
launcher.about=<html>About Author<br/>Email:huanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>Copyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
|
||||
launcher.about=<html>About Author<br/>Homepage: http://www.hmclsoft.com<br/>Email: contact@hmclsoft.com<br/>Copyright (c) 2013 HMCLSoft.<br/>Opened source under GPL v3 license: http://github.com/mclauncher/HMCL<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
|
||||
launcher.download_source=Download Source
|
||||
launcher.background_location=Background Location
|
||||
launcher.exit_failed=Failed to shutdown.
|
||||
@@ -312,7 +313,7 @@ launcher.enable_shadow=Enable Window Shadow
|
||||
launcher.theme=Theme
|
||||
launcher.proxy=Proxy
|
||||
launcher.decorated=Enable system window border(in order to fix the problem that the ui become all gray in Linux OS)
|
||||
launcher.modpack=<html><a href="http://blog.163.com/huanghongxun2008@126/blog/static/7738046920160323812771/">Documentations for modpacks.</a></html>
|
||||
launcher.modpack=<html><a href="http://client.api.mcgogogo.com:81/link.php?type=modpack">Documentations for modpacks.</a></html>
|
||||
launcher.enable_animation=Enable Animation
|
||||
launcher.lang=Language
|
||||
launcher.restart=Options will be in operations only if restart this app.
|
||||
@@ -369,6 +370,7 @@ update.should_open_link=Are you willing to upgrade this app?
|
||||
update.newest_version=Newest version:
|
||||
update.failed=Failed to check for updates.
|
||||
update.found=(Found Update!)
|
||||
update.ignore=Do not remind this version update.
|
||||
|
||||
logwindow.terminate_game=Terminate Game
|
||||
logwindow.tieba=Baidu Tieba
|
||||
|
||||
@@ -168,6 +168,7 @@ ui.message.launching=Launching...
|
||||
ui.message.making=Generating...
|
||||
ui.message.sure_remove=Sure to remove profile %s?
|
||||
ui.message.update_java=Please upgrade your Java.
|
||||
ui.message.recommend_tip=Click to open link
|
||||
|
||||
ui.label.settings=Settings
|
||||
ui.label.crashing=<html>Hello Minecraft! Launcher has crashed!</html>
|
||||
@@ -298,7 +299,7 @@ mainwindow.enter_script_name=Enter the script name.
|
||||
mainwindow.make_launch_succeed=Finished script creation.
|
||||
mainwindow.no_version=No version found. Switch to Game Downloads Tab?
|
||||
|
||||
launcher.about=<html>About Author<br/>Email\uff1ahuanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>Copyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
|
||||
launcher.about=<html>About Author<br/>Homepage: http://www.hmclsoft.com<br/>Email: contact@hmclsoft.com<br/>Copyright (c) 2013 HMCLSoft.<br/>Opened source under GPL v3 license: http://github.com/mclauncher/HMCL<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
|
||||
launcher.download_source=Download Source
|
||||
launcher.background_location=Background Location
|
||||
launcher.exit_failed=Failed to shutdown.
|
||||
@@ -312,7 +313,7 @@ launcher.enable_shadow=Enable Window Shadow
|
||||
launcher.theme=Theme
|
||||
launcher.proxy=Proxy
|
||||
launcher.decorated=Enable system window border(in order to fix the problem that the ui become all gray in Linux OS)
|
||||
launcher.modpack=<html><a href="http://blog.163.com/huanghongxun2008@126/blog/static/7738046920160323812771/">Documentations for modpacks.</a></html>
|
||||
launcher.modpack=<html><a href="http://client.api.mcgogogo.com:81/link.php?type=modpack">Documentations for modpacks.</a></html>
|
||||
launcher.enable_animation=Enable Animation
|
||||
launcher.lang=Language
|
||||
launcher.restart=Options will be in operations only if restart this app.
|
||||
@@ -369,6 +370,7 @@ update.should_open_link=Are you willing to upgrade this app?
|
||||
update.newest_version=Newest version:
|
||||
update.failed=Failed to check for updates.
|
||||
update.found=(Found Update!)
|
||||
update.ignore=Do not remind this version update.
|
||||
|
||||
logwindow.terminate_game=Terminate Game
|
||||
logwindow.tieba=Baidu Tieba
|
||||
|
||||
@@ -168,6 +168,7 @@ ui.message.launching=啟動中
|
||||
ui.message.making=生成中
|
||||
ui.message.sure_remove=真的要删除配置%s吗?
|
||||
ui.message.update_java=请更新您的Java
|
||||
ui.message.recommend_tip=點擊打開連接
|
||||
|
||||
ui.label.settings=選項
|
||||
ui.label.crashing=<html>Hello Minecraft! Launcher遇到了無法處理的錯誤,請複制下列內容並通過mcbbs、貼吧或Minecraft Forum反饋bug。 </html>
|
||||
@@ -175,7 +176,7 @@ ui.label.crashing_out_dated=<html>Hello Minecraft! Launcher遇到了無法處理
|
||||
ui.label.failed_set=設定失敗:
|
||||
|
||||
download=下載
|
||||
download.mojang=官方
|
||||
download.mojang=Mojang官方
|
||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||
download.rapid_data=RapidData (銳網雲計算, https://www.rapiddata.org/)
|
||||
download.not_200=下載失敗,回复码
|
||||
@@ -298,7 +299,7 @@ mainwindow.enter_script_name=輸入要生成腳本的資料名
|
||||
mainwindow.make_launch_succeed=啟動腳本已生成完畢:
|
||||
mainwindow.no_version=未找到任何版本,是否進入遊戲下載?
|
||||
|
||||
launcher.about=<html>默認背景圖感謝gamerteam提供。<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">如果您希望本軟件繼續發展,請贊助</a><br>關於作者:<br>百度ID:huanghongxun20<br>mcbbs:huanghongxun<br>郵箱:huanghongxun2008@126.com<br>Minecraft Forum ID: klkl6523<br>歡迎提交Bug哦<br/>Copyright (c) 2013-2016 huangyuhui.<br>免責聲明:Minecraft軟體版權歸Mojang AB所有,遊戲由於誤操作本啟動器而丟失數據的概不負責。<br>本啟動器在GPLv3協議下開源:http://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者<br>本軟體使用了基於Apache License 2.0的Gson項目,感謝貢獻者。</html>
|
||||
launcher.about=<html>默認背景圖感謝gamerteam提供。<br/>關於作者:<br/>主頁:http://www.hmclsoft.com<br/>郵箱:contact@hmclsoft.com<br/>歡迎提交Bug哦<br/>Copyright (c) 2013-2016 HMCLSoft.<br/>免責聲明:Minecraft軟體版權歸Mojang AB所有,遊戲由於誤操作本啟動器而丟失數據的概不負責。<br/>本啟動器在GPLv3協議下開源:http://github.com/mclauncher/HMCL,感谢issues和pull requests贡献者<br/>本軟體使用了基於Apache License 2.0的Gson項目,感謝貢獻者。</html>
|
||||
launcher.download_source=下載源
|
||||
launcher.background_location=背景地址
|
||||
launcher.exit_failed=強制退出失敗,可能是Forge 1.7.10及更高版本導致的,無法解決。
|
||||
@@ -312,7 +313,7 @@ launcher.enable_shadow=启用窗口阴影
|
||||
launcher.theme=主题
|
||||
launcher.proxy=代理
|
||||
launcher.decorated=啟用窗口邊框(Linux下可解決程序界面全灰問題)
|
||||
launcher.modpack=<html><a href="http://huangyuhui.duapp.com/link.php?type=modpack">整合包作者帮助</a></html>
|
||||
launcher.modpack=<html><a href="http://client.api.mcgogogo.com:81/link.php?type=modpack">整合包作者帮助</a></html>
|
||||
launcher.enable_animation=啟用動態效果
|
||||
launcher.lang=語言
|
||||
launcher.restart=本界面選項需要重啟本啟動器生效
|
||||
@@ -369,6 +370,7 @@ update.should_open_link=是否更新?
|
||||
update.newest_version=最新版本為:
|
||||
update.failed=檢查更新失敗
|
||||
update.found=(發現更新!)
|
||||
update.ignore=不再提醒此版本更新
|
||||
|
||||
logwindow.terminate_game=結束遊戲進程
|
||||
logwindow.tieba=貼吧
|
||||
|
||||
@@ -168,6 +168,7 @@ ui.message.launching=\u555f\u52d5\u4e2d
|
||||
ui.message.making=\u751f\u6210\u4e2d
|
||||
ui.message.sure_remove=\u771f\u7684\u8981\u5220\u9664\u914d\u7f6e%s\u5417\uff1f
|
||||
ui.message.update_java=\u8bf7\u66f4\u65b0\u60a8\u7684Java
|
||||
ui.message.recommend_tip=\u9ede\u64ca\u6253\u958b\u9023\u63a5
|
||||
|
||||
ui.label.settings=\u9078\u9805
|
||||
ui.label.crashing=<html>Hello Minecraft! Launcher\u9047\u5230\u4e86\u7121\u6cd5\u8655\u7406\u7684\u932f\u8aa4\uff0c\u8acb\u8907\u5236\u4e0b\u5217\u5167\u5bb9\u4e26\u901a\u904emcbbs\u3001\u8cbc\u5427\u6216Minecraft Forum\u53cd\u994bbug\u3002 </html>
|
||||
@@ -175,7 +176,7 @@ ui.label.crashing_out_dated=<html>Hello Minecraft! Launcher\u9047\u5230\u4e86\u7
|
||||
ui.label.failed_set=\u8a2d\u5b9a\u5931\u6557\uff1a
|
||||
|
||||
download=\u4e0b\u8f09
|
||||
download.mojang=\u5b98\u65b9
|
||||
download.mojang=Mojang\u5b98\u65b9
|
||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||
download.rapid_data=RapidData (\u92b3\u7db2\u96f2\u8a08\u7b97, https://www.rapiddata.org/)
|
||||
download.not_200=\u4e0b\u8f09\u5931\u6557\uff0c\u56de\u590d\u7801
|
||||
@@ -298,7 +299,7 @@ mainwindow.enter_script_name=\u8f38\u5165\u8981\u751f\u6210\u8173\u672c\u7684\u8
|
||||
mainwindow.make_launch_succeed=\u555f\u52d5\u8173\u672c\u5df2\u751f\u6210\u5b8c\u7562:
|
||||
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u9032\u5165\u904a\u6232\u4e0b\u8f09\uff1f
|
||||
|
||||
launcher.about=<html>\u9ed8\u8a8d\u80cc\u666f\u5716\u611f\u8b1dgamerteam\u63d0\u4f9b\u3002<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">\u5982\u679c\u60a8\u5e0c\u671b\u672c\u8edf\u4ef6\u7e7c\u7e8c\u767c\u5c55\uff0c\u8acb\u8d0a\u52a9</a><br>\u95dc\u65bc\u4f5c\u8005\uff1a<br>\u767e\u5ea6ID\uff1ahuanghongxun20<br>mcbbs\uff1ahuanghongxun<br>\u90f5\u7bb1\uff1ahuanghongxun2008@126.com<br>Minecraft Forum ID: klkl6523<br>\u6b61\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 huangyuhui.<br>\u514d\u8cac\u8072\u660e\uff1aMinecraft\u8edf\u9ad4\u7248\u6b0a\u6b78Mojang AB\u6240\u6709\uff0c\u904a\u6232\u7531\u65bc\u8aa4\u64cd\u4f5c\u672c\u555f\u52d5\u5668\u800c\u4e1f\u5931\u6578\u64da\u7684\u6982\u4e0d\u8ca0\u8cac\u3002<br>\u672c\u555f\u52d5\u5668\u5728GPLv3\u5354\u8b70\u4e0b\u958b\u6e90:http://github.com/huanghongxun/HMCL/ ,\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br>\u672c\u8edf\u9ad4\u4f7f\u7528\u4e86\u57fa\u65bcApache License 2.0\u7684Gson\u9805\u76ee\uff0c\u611f\u8b1d\u8ca2\u737b\u8005\u3002</html>
|
||||
launcher.about=<html>\u9ed8\u8a8d\u80cc\u666f\u5716\u611f\u8b1dgamerteam\u63d0\u4f9b\u3002<br/>\u95dc\u65bc\u4f5c\u8005\uff1a<br/>\u4e3b\u9801\uff1ahttp://www.hmclsoft.com<br/>\u90f5\u7bb1\uff1acontact@hmclsoft.com<br/>\u6b61\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 HMCLSoft.<br/>\u514d\u8cac\u8072\u660e\uff1aMinecraft\u8edf\u9ad4\u7248\u6b0a\u6b78Mojang AB\u6240\u6709\uff0c\u904a\u6232\u7531\u65bc\u8aa4\u64cd\u4f5c\u672c\u555f\u52d5\u5668\u800c\u4e1f\u5931\u6578\u64da\u7684\u6982\u4e0d\u8ca0\u8cac\u3002<br/>\u672c\u555f\u52d5\u5668\u5728GPLv3\u5354\u8b70\u4e0b\u958b\u6e90\uff1ahttp://github.com/mclauncher/HMCL\uff0c\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br>\u672c\u8edf\u9ad4\u4f7f\u7528\u4e86\u57fa\u65bcApache License 2.0\u7684Gson\u9805\u76ee\uff0c\u611f\u8b1d\u8ca2\u737b\u8005\u3002</html>
|
||||
launcher.download_source=\u4e0b\u8f09\u6e90
|
||||
launcher.background_location=\u80cc\u666f\u5730\u5740
|
||||
launcher.exit_failed=\u5f37\u5236\u9000\u51fa\u5931\u6557\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5c0e\u81f4\u7684\uff0c\u7121\u6cd5\u89e3\u6c7a\u3002
|
||||
@@ -312,7 +313,7 @@ launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71
|
||||
launcher.theme=\u4e3b\u9898
|
||||
launcher.proxy=\u4ee3\u7406
|
||||
launcher.decorated=\u555f\u7528\u7a97\u53e3\u908a\u6846(Linux\u4e0b\u53ef\u89e3\u6c7a\u7a0b\u5e8f\u754c\u9762\u5168\u7070\u554f\u984c)
|
||||
launcher.modpack=<html><a href="http://huangyuhui.duapp.com/link.php?type=modpack">\u6574\u5408\u5305\u4f5c\u8005\u5e2e\u52a9</a></html>
|
||||
launcher.modpack=<html><a href="http://client.api.mcgogogo.com:81/link.php?type=modpack">\u6574\u5408\u5305\u4f5c\u8005\u5e2e\u52a9</a></html>
|
||||
launcher.enable_animation=\u555f\u7528\u52d5\u614b\u6548\u679c
|
||||
launcher.lang=\u8a9e\u8a00
|
||||
launcher.restart=\u672c\u754c\u9762\u9078\u9805\u9700\u8981\u91cd\u555f\u672c\u555f\u52d5\u5668\u751f\u6548
|
||||
@@ -369,6 +370,7 @@ update.should_open_link=\u662f\u5426\u66f4\u65b0\uff1f
|
||||
update.newest_version=\u6700\u65b0\u7248\u672c\u70ba\uff1a
|
||||
update.failed=\u6aa2\u67e5\u66f4\u65b0\u5931\u6557
|
||||
update.found=(\u767c\u73fe\u66f4\u65b0!)
|
||||
update.ignore=\u4e0d\u518d\u63d0\u9192\u6b64\u7248\u672c\u66f4\u65b0
|
||||
|
||||
logwindow.terminate_game=\u7d50\u675f\u904a\u6232\u9032\u7a0b
|
||||
logwindow.tieba=\u8cbc\u5427
|
||||
|
||||
@@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
Hello Minecraft! Launcher, a Minecraft Launcher which is easy to use.
|
||||
Copyright (C) 2014 huangyuhui
|
||||
Copyright (C) 2016 HMCLSoft.
|
||||
|
||||
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
|
||||
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
Hello Minecraft! Launcher Copyright (C) 2014 huangyuhui
|
||||
Hello Minecraft! Launcher Copyright (C) 2016 HMCLSoft.
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
# Hello Minecraft! Launcher [](https://travis-ci.org/huanghongxun/HMCL)
|
||||
License is GPL v3, see http://www.gnu.org/licenses/gpl.html
|
||||
# Hello Minecraft! Launcher [](https://travis-ci.org/mclauncher/HMCL)
|
||||
开源协议为GPL v3, 详情参见http://www.gnu.org/licenses/gpl.html
|
||||
|
||||
## Introduction
|
||||
## 介绍
|
||||
|
||||
This application is a Minecraft launcher that supports mod management, game modification, auto-installing Minecraft/Forge/LiteLoader/OptiFine, modpack manufacture, UI theme customization, and so on.
|
||||
HMCL是一个Minecraft启动器,支持Mod管理,游戏定制,自动安装,整合包制作,界面主题定制等功能。
|
||||
但是本项目的代码不够完善,希望有更多的人能加入HMCL的开发。
|
||||
|
||||
This application has more than 100,000 users and would be opened more than 500,000 times per day.
|
||||
## 贡献
|
||||
如果你很想为本项目贡献代码,这里有一些要求:
|
||||
* 开发环境为Netbeans 8.1
|
||||
* 编译器为Java 1.8,通过retrolambda兼容Java 1.7,所以请不要使用Java 8的新API(如Stream)
|
||||
* 请不要修改`gradle`文件
|
||||
|
||||
But the code of this app is not strong, I hope someone could join the development of this app and make this app stronger.
|
||||
## 代码
|
||||
* 包 `org.jackhuang.hellominecraft.util` 为HMCL和HMCSM的共用工具代码
|
||||
* 包 `org.jackhuang.hellominecraft.launcher` 包含了HMCL的界面以及逻辑代码
|
||||
* 包 `org.jackhuang.hellominecraft.launcher.core` 为HMCL的启动核心
|
||||
* 包 `org.jackhuang.hellominecraft.launcher.api` 是HMCL为了便于定制提供的API,暂不支持加载插件
|
||||
* 包 `org.jackhuang.hellominecraft.svrmgr` 为HMCSM的所有代码
|
||||
* 文件夹 `HMCUtils/src/main/resources/org/jackhuang/hellominecraft/lang` 包含了HMCL和HMCSM使用的语言文件
|
||||
|
||||
由于包树已经相当清晰,因此不再赘述各包各类的用途。
|
||||
|
||||
## Contribution
|
||||
If you really want to join the development, here's some requests.
|
||||
* The Development Environment is Netbeans 8.0.2 with plugin: Gradle Support.
|
||||
* The project is built on Java 1.8 using the retrolambda backporting to Java 1.7. So DO NOT use the libraries of Java 8 like Stream APIs.
|
||||
* DO NOT modify any file whose suffix is `gradle`.
|
||||
|
||||
## Code tree
|
||||
* Package `hmc.util` contains all the utilities that HMCL and HMCSM depend on.
|
||||
* Package `hmc.launcher` contains HMCL ui, a few utility codes.
|
||||
* Package `hmc.launcher.core` contains all the Minecraft Launcher logic that the HMCL supports.
|
||||
* Package `hmc.svrmgr` contains all HMCSM logic.
|
||||
* Folder `HMCLAPI/src/main/resources/org/jackhuang/hellominecraft/lang` contains all the localization files that HMCL and HMCSM used. If you are good at translation, you could join the localization plan by opening a pull request.
|
||||
## 注意事项
|
||||
* 包 `org.jackhuang.hellominecraft.util.logging` 包含了经过精简的Apache License 2.0的Log4j项目的代码
|
||||
* 包 `com.google.gson` 为Google Gson项目Apache License 2.0的代码
|
||||
* 包 `org.jackhuang.hellominecraft.lookandfeel.ui` 包含了Sun Microsystems的NimbusLookAndFeel项目的部分LGPL代码
|
||||
* 所有Pull Request提交的代码均会被重写
|
||||
* 本项目的开源协议是GPL v3,因此包含LGPL和Apache License 2.0的代码是没有法律问题的
|
||||
+1
-1
@@ -102,4 +102,4 @@ task makePackGZ(dependsOn: jar) << {
|
||||
def fileEx = new File(project.buildDir, "libs/" + makeExecutableoutjar.getName().substring(0, makeExecutableoutjar.getName().length()-4)+".pack.gz.sha1")
|
||||
if (!fileEx.exists()) fileEx.createNewFile()
|
||||
fileEx.append sha1Hex
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
|
||||
* Copyright (C) 2016 HMCLSoft.
|
||||
*
|
||||
* 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
|
||||
|
||||
Reference in new issue
Block a user