Turn to java
This commit is contained in:
40
HMCLCore/src/main/java/org/jackhuang/hmcl/auth/Account.java
Normal file
40
HMCLCore/src/main/java/org/jackhuang/hmcl/auth/Account.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public abstract class Account {
|
||||
|
||||
public abstract String getUsername();
|
||||
|
||||
public AuthInfo logIn() throws AuthenticationException {
|
||||
return logIn(Proxy.NO_PROXY);
|
||||
}
|
||||
|
||||
public abstract AuthInfo logIn(Proxy proxy) throws AuthenticationException;
|
||||
|
||||
public abstract void logOut();
|
||||
|
||||
public abstract Map<Object, Object> toStorage();
|
||||
}
|
||||
@@ -15,17 +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/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.task
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The tasks that provides a way to execute tasks parallelly.
|
||||
* Fails when some of [tasks] failed.
|
||||
*
|
||||
* @param tasks the tasks that can be executed parallelly.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
class ParallelTask(vararg tasks: Task): Task() {
|
||||
override val hidden: Boolean = true
|
||||
override val dependents: Collection<Task> = listOf(*tasks)
|
||||
public abstract class AccountFactory<T extends Account> {
|
||||
|
||||
override fun execute() {}
|
||||
}
|
||||
public final T fromUsername(String username) {
|
||||
return fromUsername(username, "");
|
||||
}
|
||||
|
||||
public abstract T fromUsername(String username, String password);
|
||||
|
||||
public abstract T fromStorage(Map<Object, Object> storage);
|
||||
}
|
||||
96
HMCLCore/src/main/java/org/jackhuang/hmcl/auth/AuthInfo.java
Normal file
96
HMCLCore/src/main/java/org/jackhuang/hmcl/auth/AuthInfo.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class AuthInfo {
|
||||
|
||||
private final String username;
|
||||
private final String userId;
|
||||
private final String authToken;
|
||||
private final UserType userType;
|
||||
private final String userProperties;
|
||||
private final String userPropertyMap;
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken) {
|
||||
this(username, userId, authToken, UserType.LEGACY);
|
||||
}
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken, UserType userType) {
|
||||
this(username, userId, authToken, userType, "{}");
|
||||
}
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken, UserType userType, String userProperties) {
|
||||
this(username, userId, authToken, userType, userProperties, "{}");
|
||||
}
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken, UserType userType, String userProperties, String userPropertyMap) {
|
||||
this.username = username;
|
||||
this.userId = userId;
|
||||
this.authToken = authToken;
|
||||
this.userType = userType;
|
||||
this.userProperties = userProperties;
|
||||
this.userPropertyMap = userPropertyMap;
|
||||
}
|
||||
|
||||
public AuthInfo(GameProfile profile, String authToken, UserType userType, String userProperties) {
|
||||
this(profile.getName(), UUIDTypeAdapter.fromUUID(profile.getId()), authToken, userType, userProperties);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
public UserType getUserType() {
|
||||
return userType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties of this user.
|
||||
* Don't know the difference between user properties and user property map.
|
||||
*
|
||||
* @return the user property map in JSON.
|
||||
*/
|
||||
public String getUserProperties() {
|
||||
return userProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties of this user.
|
||||
* Don't know the difference between user properties and user property map.
|
||||
*
|
||||
* @return the user property map in JSON.
|
||||
*/
|
||||
public String getUserPropertyMap() {
|
||||
return userPropertyMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class AuthenticationException extends Exception {
|
||||
|
||||
public AuthenticationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public AuthenticationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AuthenticationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public class OfflineAccount extends Account {
|
||||
|
||||
private final String username;
|
||||
private final String uuid;
|
||||
|
||||
OfflineAccount(String username, String uuid) {
|
||||
Objects.requireNonNull(username);
|
||||
Objects.requireNonNull(uuid);
|
||||
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
|
||||
if (StringUtils.isBlank(username))
|
||||
throw new IllegalArgumentException("Username cannot be blank");
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo logIn(Proxy proxy) throws AuthenticationException {
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(uuid))
|
||||
throw new AuthenticationException("Username cannot be empty");
|
||||
|
||||
return new AuthInfo(username, uuid, uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logOut() {
|
||||
// Offline account need not log out.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> toStorage() {
|
||||
return Lang.mapOf(
|
||||
new Pair<>("uuid", uuid),
|
||||
new Pair<>("username", username)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OfflineAccount[username=" + username + ", uuid=" + uuid + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class OfflineAccountFactory extends AccountFactory<OfflineAccount> {
|
||||
public static final OfflineAccountFactory INSTANCE = new OfflineAccountFactory();
|
||||
|
||||
private OfflineAccountFactory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfflineAccount fromUsername(String username, String password) {
|
||||
return new OfflineAccount(username, getUUIDFromUserName(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfflineAccount fromStorage(Map<Object, Object> storage) {
|
||||
Object username = storage.get("username");
|
||||
if (username == null || !(username instanceof String))
|
||||
throw new IllegalStateException("Offline account configuration malformed.");
|
||||
|
||||
Object uuid = storage.get("uuid");
|
||||
if (uuid == null || !(uuid instanceof String))
|
||||
uuid = getUUIDFromUserName((String) username);
|
||||
|
||||
return new OfflineAccount((String) username, (String) uuid);
|
||||
}
|
||||
|
||||
private static String getUUIDFromUserName(String username) {
|
||||
return DigestUtils.md5Hex(username);
|
||||
}
|
||||
|
||||
}
|
||||
49
HMCLCore/src/main/java/org/jackhuang/hmcl/auth/UserType.java
Normal file
49
HMCLCore/src/main/java/org/jackhuang/hmcl/auth/UserType.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public enum UserType {
|
||||
LEGACY,
|
||||
MOJANG;
|
||||
|
||||
public static UserType fromName(String name) {
|
||||
return BY_NAME.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
public static UserType fromLegacy(boolean isLegacy) {
|
||||
return isLegacy ? LEGACY : MOJANG;
|
||||
}
|
||||
|
||||
static {
|
||||
HashMap<String, UserType> byName = new HashMap<>();
|
||||
for (UserType type : values())
|
||||
byName.put(type.name().toLowerCase(), type);
|
||||
BY_NAME = Collections.unmodifiableMap(byName);
|
||||
}
|
||||
|
||||
public static final Map<String, UserType> BY_NAME;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class AuthenticationRequest {
|
||||
|
||||
/**
|
||||
* The user name of Minecraft account.
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* The password of Minecraft account.
|
||||
*/
|
||||
private final String password;
|
||||
|
||||
/**
|
||||
* The client token of this game.
|
||||
*/
|
||||
private final String clientToken;
|
||||
|
||||
private final Map<String, Object> agent = Lang.mapOf(
|
||||
new Pair("name", "minecraft"),
|
||||
new Pair("version", 1));
|
||||
|
||||
private final boolean requestUser = true;
|
||||
|
||||
public AuthenticationRequest(String username, String password, String clientToken) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.clientToken = clientToken;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAgent() {
|
||||
return agent;
|
||||
}
|
||||
|
||||
public boolean isRequestUser() {
|
||||
return requestUser;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public final class GameProfile {
|
||||
|
||||
private final UUID id;
|
||||
private final String name;
|
||||
private final PropertyMap properties;
|
||||
private final boolean legacy;
|
||||
|
||||
public GameProfile() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public GameProfile(UUID id, String name) {
|
||||
this(id, name, new PropertyMap(), false);
|
||||
}
|
||||
|
||||
public GameProfile(UUID id, String name, PropertyMap properties, boolean legacy) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
this.legacy = legacy;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PropertyMap getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public boolean isLegacy() {
|
||||
return legacy;
|
||||
}
|
||||
|
||||
public static class Serializer implements JsonSerializer<GameProfile>, JsonDeserializer<GameProfile> {
|
||||
|
||||
public static final Serializer INSTANCE = new Serializer();
|
||||
|
||||
private Serializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(GameProfile src, Type type, JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
if (src.getId() != null)
|
||||
result.add("id", context.serialize(src.getId()));
|
||||
if (src.getName() != null)
|
||||
result.addProperty("name", src.getName());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile deserialize(JsonElement je, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (!(je instanceof JsonObject))
|
||||
throw new JsonParseException("The json element is not a JsonObject.");
|
||||
|
||||
JsonObject json = (JsonObject) je;
|
||||
|
||||
UUID id = json.has("id") ? context.deserialize(json.get("id"), UUID.class) : null;
|
||||
String name = json.has("name") ? json.getAsJsonPrimitive("name").getAsString() : null;
|
||||
return new GameProfile(id, name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class InvalidCredentialsException extends AuthenticationException {
|
||||
|
||||
private final YggdrasilAccount account;
|
||||
|
||||
public InvalidCredentialsException(YggdrasilAccount account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public YggdrasilAccount getAccount() {
|
||||
return account;
|
||||
}
|
||||
}
|
||||
@@ -15,20 +15,24 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
enum class UserType() {
|
||||
LEGACY,
|
||||
MOJANG;
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
|
||||
companion object {
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class InvalidTokenException extends AuthenticationException {
|
||||
|
||||
fun fromName(name: String) = BY_NAME[name.toLowerCase()]
|
||||
fun fromLegacy(isLegacy: Boolean) = if (isLegacy) LEGACY else MOJANG
|
||||
private YggdrasilAccount account;
|
||||
|
||||
private val BY_NAME = HashMap<String, UserType>().apply {
|
||||
for (type in values())
|
||||
this[type.name.toLowerCase()] = type
|
||||
}
|
||||
public InvalidTokenException(YggdrasilAccount account) {
|
||||
super();
|
||||
this.account = account;
|
||||
}
|
||||
}
|
||||
|
||||
public YggdrasilAccount getAccount() {
|
||||
return account;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -15,12 +15,23 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.task
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap
|
||||
public class Property {
|
||||
|
||||
internal class SimpleTask @JvmOverloads constructor(private val runnable: (AutoTypingMap<String>) -> Unit, override val scheduler: Scheduler = Scheduler.DEFAULT) : Task() {
|
||||
override fun execute() {
|
||||
runnable(variables!!)
|
||||
private final String name;
|
||||
private final String value;
|
||||
|
||||
public Property(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
public final class PropertyMap extends HashMap<String, Property> {
|
||||
|
||||
public List<Map<String, String>> toList() {
|
||||
List<Map<String, String>> properties = new ArrayList<>();
|
||||
for (Property profileProperty : values()) {
|
||||
Map<String, String> property = new HashMap<>();
|
||||
property.put("name", profileProperty.getName());
|
||||
property.put("value", profileProperty.getValue());
|
||||
properties.add(property);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void fromList(List<?> list) {
|
||||
for (Object propertyMap : list) {
|
||||
if (!(propertyMap instanceof Map<?, ?>))
|
||||
continue;
|
||||
Optional<String> name = Lang.get((Map<?, ?>) propertyMap, "name", String.class);
|
||||
Optional<String> value = Lang.get((Map<?, ?>) propertyMap, "value", String.class);
|
||||
if (name.isPresent() && value.isPresent())
|
||||
put(name.get(), new Property(name.get(), value.get()));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Serializer implements JsonSerializer<PropertyMap>, JsonDeserializer<PropertyMap> {
|
||||
|
||||
public static final Serializer INSTANCE = new Serializer();
|
||||
|
||||
private Serializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
PropertyMap result = new PropertyMap();
|
||||
if (json instanceof JsonObject) {
|
||||
for (Map.Entry<String, JsonElement> entry : ((JsonObject) json).entrySet())
|
||||
if (entry.getValue() instanceof JsonArray)
|
||||
for (JsonElement element : (JsonArray) entry.getValue())
|
||||
result.put(entry.getKey(), new Property(entry.getKey(), element.getAsString()));
|
||||
} else if ((json instanceof JsonArray))
|
||||
for (JsonElement element : (JsonArray) json)
|
||||
if ((element instanceof JsonObject)) {
|
||||
JsonObject object = (JsonObject) element;
|
||||
String name = object.getAsJsonPrimitive("name").getAsString();
|
||||
String value = object.getAsJsonPrimitive("value").getAsString();
|
||||
result.put(name, new Property(name, value));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonArray result = new JsonArray();
|
||||
for (Property property : src.values()) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("name", property.getName());
|
||||
object.addProperty("value", property.getValue());
|
||||
result.add(object);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LegacySerializer
|
||||
implements JsonSerializer<PropertyMap> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
for (PropertyMap.Entry<String, Property> entry : src.entrySet()) {
|
||||
JsonArray values = new JsonArray();
|
||||
values.add(new JsonPrimitive(entry.getValue().getValue()));
|
||||
result.add(entry.getKey(), values);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public final class RefreshRequest {
|
||||
|
||||
private final String accessToken;
|
||||
private final String clientToken;
|
||||
private final GameProfile selectedProfile;
|
||||
private final boolean requestUser;
|
||||
|
||||
public RefreshRequest(String accessToken, String clientToken) {
|
||||
this(accessToken, clientToken, null);
|
||||
}
|
||||
|
||||
public RefreshRequest(String accessToken, String clientToken, GameProfile selectedProfile) {
|
||||
this(accessToken, clientToken, selectedProfile, true);
|
||||
}
|
||||
|
||||
public RefreshRequest(String accessToken, String clientToken, GameProfile selectedProfile, boolean requestUser) {
|
||||
this.accessToken = accessToken;
|
||||
this.clientToken = clientToken;
|
||||
this.selectedProfile = selectedProfile;
|
||||
this.requestUser = requestUser;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
public GameProfile getSelectedProfile() {
|
||||
return selectedProfile;
|
||||
}
|
||||
|
||||
public boolean isRequestUser() {
|
||||
return requestUser;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class Response {
|
||||
|
||||
private final String accessToken;
|
||||
private final String clientToken;
|
||||
private final GameProfile selectedProfile;
|
||||
private final GameProfile[] availableProfiles;
|
||||
private final User user;
|
||||
private final String error;
|
||||
private final String errorMessage;
|
||||
private final String cause;
|
||||
|
||||
public Response() {
|
||||
this(null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public Response(String accessToken, String clientToken, GameProfile selectedProfile, GameProfile[] availableProfiles, User user, String error, String errorMessage, String cause) {
|
||||
this.accessToken = accessToken;
|
||||
this.clientToken = clientToken;
|
||||
this.selectedProfile = selectedProfile;
|
||||
this.availableProfiles = availableProfiles;
|
||||
this.user = user;
|
||||
this.error = error;
|
||||
this.errorMessage = errorMessage;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
public GameProfile getSelectedProfile() {
|
||||
return selectedProfile;
|
||||
}
|
||||
|
||||
public GameProfile[] getAvailableProfiles() {
|
||||
return availableProfiles;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public String getCause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public final class User implements Validation {
|
||||
|
||||
private final String id;
|
||||
private final PropertyMap properties;
|
||||
|
||||
public User(String id) {
|
||||
this(id, null);
|
||||
}
|
||||
|
||||
public User(String id, PropertyMap properties) {
|
||||
this.id = id;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public PropertyMap getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (StringUtils.isBlank(id))
|
||||
throw new JsonParseException("User id cannot be empty.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,19 +15,28 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.task
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap
|
||||
import java.util.concurrent.Callable
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class ValidateRequest {
|
||||
|
||||
internal class TaskCallable<V>(override val id: String, private val callable: Callable<V>) : TaskResult<V>() {
|
||||
override fun execute() {
|
||||
result = callable.call()
|
||||
private final String accessToken;
|
||||
private final String clientToken;
|
||||
|
||||
public ValidateRequest(String accessToken, String clientToken) {
|
||||
this.accessToken = accessToken;
|
||||
this.clientToken = clientToken;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class TaskCallable2<V>(override val id: String, private val callable: (AutoTypingMap<String>) -> V) : TaskResult<V>() {
|
||||
override fun execute() {
|
||||
result = callable(variables!!)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
import java.io.IOException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
import org.jackhuang.hmcl.auth.UserType;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public final class YggdrasilAccount extends Account {
|
||||
|
||||
private final String username;
|
||||
private String password;
|
||||
private String userId;
|
||||
private String accessToken = null;
|
||||
private String clientToken = randomToken();
|
||||
private boolean isOnline = false;
|
||||
private PropertyMap userProperties = new PropertyMap();
|
||||
private GameProfile selectedProfile = null;
|
||||
private GameProfile[] profiles;
|
||||
private UserType userType = UserType.LEGACY;
|
||||
|
||||
public YggdrasilAccount(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
void setClientToken(String clientToken) {
|
||||
this.clientToken = clientToken;
|
||||
}
|
||||
|
||||
PropertyMap getUserProperties() {
|
||||
return userProperties;
|
||||
}
|
||||
|
||||
public GameProfile getSelectedProfile() {
|
||||
return selectedProfile;
|
||||
}
|
||||
|
||||
void setSelectedProfile(GameProfile selectedProfile) {
|
||||
this.selectedProfile = selectedProfile;
|
||||
}
|
||||
|
||||
public boolean isLoggedIn() {
|
||||
return StringUtils.isNotBlank(accessToken);
|
||||
}
|
||||
|
||||
public boolean canPlayOnline() {
|
||||
return isLoggedIn() && selectedProfile != null && isOnline;
|
||||
}
|
||||
|
||||
public boolean canLogIn() {
|
||||
return !canPlayOnline() && StringUtils.isNotBlank(username)
|
||||
&& (StringUtils.isNotBlank(password) || StringUtils.isNotBlank(accessToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo logIn(Proxy proxy) throws AuthenticationException {
|
||||
if (canPlayOnline())
|
||||
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
|
||||
else {
|
||||
logIn0(proxy);
|
||||
if (!isLoggedIn())
|
||||
throw new AuthenticationException("Wrong password for account " + username);
|
||||
|
||||
if (selectedProfile == null)
|
||||
// TODO: multi-available-profiles support
|
||||
throw new UnsupportedOperationException("Do not support multi-available-profiles account yet.");
|
||||
else
|
||||
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
|
||||
}
|
||||
}
|
||||
|
||||
private void logIn0(Proxy proxy) throws AuthenticationException {
|
||||
if (StringUtils.isNotBlank(accessToken)) {
|
||||
if (StringUtils.isBlank(userId))
|
||||
if (StringUtils.isNotBlank(username))
|
||||
userId = username;
|
||||
else
|
||||
throw new AuthenticationException("Invalid uuid and username");
|
||||
if (checkTokenValidity(proxy)) {
|
||||
isOnline = true;
|
||||
return;
|
||||
}
|
||||
logIn1(ROUTE_REFRESH, new RefreshRequest(accessToken, clientToken), proxy);
|
||||
} else if (StringUtils.isNotBlank(password))
|
||||
logIn1(ROUTE_AUTHENTICATE, new AuthenticationRequest(username, password, clientToken), proxy);
|
||||
else
|
||||
throw new AuthenticationException("Password cannot be blank");
|
||||
}
|
||||
|
||||
private void logIn1(URL url, Object input, Proxy proxy) throws AuthenticationException {
|
||||
Response response = makeRequest(url, input, proxy);
|
||||
if (response == null || !clientToken.equals(response.getClientToken()))
|
||||
throw new AuthenticationException("Client token changed");
|
||||
|
||||
if (response.getSelectedProfile() != null)
|
||||
userType = UserType.fromLegacy(response.getSelectedProfile().isLegacy());
|
||||
else if (response.getAvailableProfiles() != null && response.getAvailableProfiles().length > 0)
|
||||
userType = UserType.fromLegacy(response.getAvailableProfiles()[0].isLegacy());
|
||||
|
||||
User user = response.getUser();
|
||||
if (user == null || user.getId() == null)
|
||||
userId = null;
|
||||
else
|
||||
userId = user.getId();
|
||||
|
||||
isOnline = true;
|
||||
profiles = response.getAvailableProfiles();
|
||||
selectedProfile = response.getSelectedProfile();
|
||||
userProperties.clear();
|
||||
accessToken = response.getAccessToken();
|
||||
|
||||
if (user != null && user.getProperties() != null)
|
||||
userProperties.putAll(user.getProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logOut() {
|
||||
password = null;
|
||||
userId = null;
|
||||
accessToken = null;
|
||||
isOnline = false;
|
||||
userProperties.clear();
|
||||
profiles = null;
|
||||
selectedProfile = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> toStorage() {
|
||||
HashMap<Object, Object> result = new HashMap<>();
|
||||
|
||||
result.put(STORAGE_KEY_USER_NAME, getUsername());
|
||||
result.put(STORAGE_KEY_CLIENT_TOKEN, getClientToken());
|
||||
if (getUserId() != null)
|
||||
result.put(STORAGE_KEY_USER_ID, getUserId());
|
||||
if (!userProperties.isEmpty())
|
||||
result.put(STORAGE_KEY_USER_PROPERTIES, userProperties.toList());
|
||||
GameProfile profile = selectedProfile;
|
||||
if (profile != null && profile.getName() != null && profile.getId() != null) {
|
||||
result.put(STORAGE_KEY_PROFILE_NAME, profile.getName());
|
||||
result.put(STORAGE_KEY_PROFILE_ID, profile.getId());
|
||||
|
||||
if (!profile.getProperties().isEmpty())
|
||||
result.put(STORAGE_KEY_PROFILE_PROPERTIES, profile.getProperties().toList());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(accessToken))
|
||||
result.put(STORAGE_KEY_ACCESS_TOKEN, accessToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Response makeRequest(URL url, Object input, Proxy proxy) throws AuthenticationException {
|
||||
try {
|
||||
String jsonResult = input == null ? NetworkUtils.doGet(url, proxy) : NetworkUtils.doPost(url, GSON.toJson(input), "application/json", proxy);
|
||||
Response response = GSON.fromJson(jsonResult, Response.class);
|
||||
if (response == null)
|
||||
return null;
|
||||
if (!StringUtils.isBlank(response.getError())) {
|
||||
if (response.getErrorMessage() != null)
|
||||
if (response.getErrorMessage().contains("Invalid credentials"))
|
||||
throw new InvalidCredentialsException(this);
|
||||
else if (response.getErrorMessage().contains("Invalid token"))
|
||||
throw new InvalidTokenException(this);
|
||||
throw new AuthenticationException(response.getError() + ": " + response.getErrorMessage());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
throw new AuthenticationException("Unable to connect to authentication server", e);
|
||||
} catch (JsonParseException e) {
|
||||
throw new AuthenticationException("Unable to parse server response", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkTokenValidity(Proxy proxy) {
|
||||
if (accessToken == null)
|
||||
return false;
|
||||
|
||||
try {
|
||||
makeRequest(ROUTE_VALIDATE, new ValidateRequest(accessToken, clientToken), proxy);
|
||||
return true;
|
||||
} catch (AuthenticationException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "YggdrasilAccount[username=" + getUsername() + "]";
|
||||
}
|
||||
|
||||
private static final String BASE_URL = "https://authserver.mojang.com/";
|
||||
private static final URL ROUTE_AUTHENTICATE = NetworkUtils.toURL(BASE_URL + "authenticate");
|
||||
private static final URL ROUTE_REFRESH = NetworkUtils.toURL(BASE_URL + "refresh");
|
||||
private static final URL ROUTE_VALIDATE = NetworkUtils.toURL(BASE_URL + "validate");
|
||||
|
||||
static final String STORAGE_KEY_ACCESS_TOKEN = "accessToken";
|
||||
static final String STORAGE_KEY_PROFILE_NAME = "displayName";
|
||||
static final String STORAGE_KEY_PROFILE_ID = "uuid";
|
||||
static final String STORAGE_KEY_PROFILE_PROPERTIES = "profileProperties";
|
||||
static final String STORAGE_KEY_USER_NAME = "username";
|
||||
static final String STORAGE_KEY_USER_ID = "userid";
|
||||
static final String STORAGE_KEY_USER_PROPERTIES = "userProperties";
|
||||
static final String STORAGE_KEY_CLIENT_TOKEN = "clientToken";
|
||||
|
||||
public static String randomToken() {
|
||||
return UUIDTypeAdapter.fromUUID(UUID.randomUUID());
|
||||
}
|
||||
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapter(GameProfile.class, GameProfile.Serializer.INSTANCE)
|
||||
.registerTypeAdapter(PropertyMap.class, PropertyMap.Serializer.INSTANCE)
|
||||
.registerTypeAdapter(UUID.class, UUIDTypeAdapter.INSTANCE)
|
||||
.create();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import static org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount.*;
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccount> {
|
||||
public static final YggdrasilAccountFactory INSTANCE = new YggdrasilAccountFactory();
|
||||
|
||||
private YggdrasilAccountFactory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public YggdrasilAccount fromUsername(String username, String password) {
|
||||
YggdrasilAccount account = new YggdrasilAccount(username);
|
||||
account.setPassword(password);
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YggdrasilAccount fromStorage(Map<Object, Object> storage) {
|
||||
String username = Lang.get(storage, STORAGE_KEY_USER_NAME, String.class)
|
||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_USER_NAME));
|
||||
|
||||
YggdrasilAccount account = new YggdrasilAccount(username);
|
||||
account.setUserId(Lang.get(storage, STORAGE_KEY_USER_ID, String.class, username));
|
||||
account.setAccessToken(Lang.get(storage, STORAGE_KEY_ACCESS_TOKEN, String.class, null));
|
||||
account.setClientToken(Lang.get(storage, STORAGE_KEY_CLIENT_TOKEN, String.class)
|
||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_CLIENT_TOKEN)));
|
||||
|
||||
Lang.get(storage, STORAGE_KEY_USER_PROPERTIES, List.class)
|
||||
.ifPresent(account.getUserProperties()::fromList);
|
||||
Optional<String> profileId = Lang.get(storage, STORAGE_KEY_PROFILE_ID, String.class);
|
||||
Optional<String> profileName = Lang.get(storage, STORAGE_KEY_PROFILE_NAME, String.class);
|
||||
GameProfile profile = null;
|
||||
if (profileId.isPresent() && profileName.isPresent()) {
|
||||
profile = new GameProfile(UUIDTypeAdapter.fromString(profileId.get()), profileName.get());
|
||||
Lang.get(storage, STORAGE_KEY_PROFILE_PROPERTIES, List.class)
|
||||
.ifPresent(profile.getProperties()::fromList);
|
||||
}
|
||||
account.setSelectedProfile(profile);
|
||||
return account;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,14 +15,18 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
abstract class AbstractDependencyManager
|
||||
: DependencyManager {
|
||||
abstract val downloadProvider: DownloadProvider
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public abstract class AbstractDependencyManager implements DependencyManager {
|
||||
|
||||
override fun getVersionList(id: String): VersionList<*> {
|
||||
return downloadProvider.getVersionListById(id)
|
||||
public abstract DownloadProvider getDownloadProvider();
|
||||
|
||||
@Override
|
||||
public VersionList<?> getVersionList(String id) {
|
||||
return getDownloadProvider().getVersionListById(id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.download.forge.ForgeVersionList;
|
||||
import org.jackhuang.hmcl.download.game.GameVersionList;
|
||||
import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList;
|
||||
import org.jackhuang.hmcl.download.optifine.OptiFineBMCLVersionList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public class BMCLAPIDownloadProvider implements DownloadProvider {
|
||||
|
||||
public static final BMCLAPIDownloadProvider INSTANCE = new BMCLAPIDownloadProvider();
|
||||
|
||||
private BMCLAPIDownloadProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLibraryBaseURL() {
|
||||
return "http://bmclapi2.bangbang93.com/libraries/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionListURL() {
|
||||
return "http://bmclapi2.bangbang93.com/mc/game/version_manifest.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionBaseURL() {
|
||||
return "http://bmclapi2.bangbang93.com/versions/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssetIndexBaseURL() {
|
||||
return "http://bmclapi2.bangbang93.com/indexes/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssetBaseURL() {
|
||||
return "http://bmclapi2.bangbang93.com/assets/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionList<?> getVersionListById(String id) {
|
||||
switch (id) {
|
||||
case "game":
|
||||
return GameVersionList.INSTANCE;
|
||||
case "forge":
|
||||
return ForgeVersionList.INSTANCE;
|
||||
case "liteloader":
|
||||
return LiteLoaderVersionList.INSTANCE;
|
||||
case "optifine":
|
||||
return OptiFineBMCLVersionList.INSTANCE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized version list id: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String injectURL(String baseURL) {
|
||||
return baseURL
|
||||
.replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com")
|
||||
.replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com")
|
||||
.replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
|
||||
.replace("http://files.minecraftforge.net/maven", "https://bmclapi2.bangbang93.com/maven")
|
||||
.replace("http://dl.liteloader.com/versions/versions.json", "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json")
|
||||
.replace("http://dl.liteloader.com/versions", "https://bmclapi2.bangbang93.com/maven");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import java.net.Proxy;
|
||||
import org.jackhuang.hmcl.download.forge.ForgeInstallTask;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.download.game.GameLoggingDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
|
||||
import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
|
||||
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.ParallelTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
|
||||
/**
|
||||
* Note: This class has no state.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class DefaultDependencyManager extends AbstractDependencyManager {
|
||||
|
||||
private final DefaultGameRepository repository;
|
||||
private final DownloadProvider downloadProvider;
|
||||
private final Proxy proxy;
|
||||
|
||||
public DefaultDependencyManager(DefaultGameRepository repository, DownloadProvider downloadProvider) {
|
||||
this(repository, downloadProvider, Proxy.NO_PROXY);
|
||||
}
|
||||
|
||||
public DefaultDependencyManager(DefaultGameRepository repository, DownloadProvider downloadProvider, Proxy proxy) {
|
||||
this.repository = repository;
|
||||
this.downloadProvider = downloadProvider;
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultGameRepository getGameRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadProvider getDownloadProvider() {
|
||||
return downloadProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Proxy getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameBuilder gameBuilder() {
|
||||
return new DefaultGameBuilder(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task checkGameCompletionAsync(Version version) {
|
||||
return new ParallelTask(
|
||||
new GameAssetDownloadTask(this, version),
|
||||
new GameLoggingDownloadTask(this, version),
|
||||
new GameLibrariesTask(this, version)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) {
|
||||
switch (libraryId) {
|
||||
case "forge":
|
||||
return new ForgeInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then(variables -> new VersionJsonSaveTask(repository, variables.get("version")));
|
||||
case "liteloader":
|
||||
return new LiteLoaderInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then(variables -> new VersionJsonSaveTask(repository, variables.get("version")));
|
||||
case "optifine":
|
||||
return new OptiFineInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then(variables -> new VersionJsonSaveTask(repository, variables.get("version")));
|
||||
default:
|
||||
throw new IllegalArgumentException("Library id " + libraryId + " is unrecognized.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import java.util.function.Function;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.download.game.GameLoggingDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.VersionJsonDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.ParallelTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class DefaultGameBuilder extends GameBuilder {
|
||||
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final DownloadProvider downloadProvider;
|
||||
|
||||
public DefaultGameBuilder(DefaultDependencyManager dependencyManager) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.downloadProvider = dependencyManager.getDownloadProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task buildAsync() {
|
||||
return new VersionJsonDownloadTask(gameVersion, dependencyManager).then(variables -> {
|
||||
Version version = Constants.GSON.fromJson(variables.<String>get(VersionJsonDownloadTask.ID), Version.class);
|
||||
variables.set("version", version);
|
||||
version = version.setId(name).setJar(null);
|
||||
Task result = new ParallelTask(
|
||||
new GameAssetDownloadTask(dependencyManager, version),
|
||||
new GameLoggingDownloadTask(dependencyManager, version),
|
||||
new GameDownloadTask(dependencyManager, version),
|
||||
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
||||
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
||||
|
||||
if (toolVersions.containsKey("forge"))
|
||||
result = result.then(libraryTaskHelper(gameVersion, "forge"));
|
||||
if (toolVersions.containsKey("liteloader"))
|
||||
result = result.then(libraryTaskHelper(gameVersion, "liteloader"));
|
||||
if (toolVersions.containsKey("optifine"))
|
||||
result = result.then(libraryTaskHelper(gameVersion, "optifine"));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
private Function<AutoTypingMap<String>, Task> libraryTaskHelper(String gameVersion, String libraryId) {
|
||||
return variables -> dependencyManager.installLibraryAsync(gameVersion, variables.get("version"), libraryId, toolVersions.get(libraryId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,27 +15,30 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.game.GameRepository
|
||||
import org.jackhuang.hmcl.game.Version
|
||||
import org.jackhuang.hmcl.task.Task
|
||||
import java.net.Proxy
|
||||
import java.net.Proxy;
|
||||
import org.jackhuang.hmcl.game.GameRepository;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
|
||||
/**
|
||||
* Do everything that will connect to Internet.
|
||||
* Downloading Minecraft files.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
interface DependencyManager {
|
||||
public interface DependencyManager {
|
||||
|
||||
/**
|
||||
* The relied game repository.
|
||||
*/
|
||||
val repository: GameRepository
|
||||
GameRepository getGameRepository();
|
||||
|
||||
/**
|
||||
* The proxy that all network operations should go through.
|
||||
*/
|
||||
val proxy: Proxy
|
||||
Proxy getProxy();
|
||||
|
||||
/**
|
||||
* Check if the game is complete.
|
||||
@@ -43,12 +46,12 @@ interface DependencyManager {
|
||||
*
|
||||
* @return the task to check game completion.
|
||||
*/
|
||||
fun checkGameCompletionAsync(version: Version): Task
|
||||
Task checkGameCompletionAsync(Version version);
|
||||
|
||||
/**
|
||||
* The builder to build a brand new game then libraries such as Forge, LiteLoader and OptiFine.
|
||||
*/
|
||||
fun gameBuilder(): GameBuilder
|
||||
GameBuilder gameBuilder();
|
||||
|
||||
/**
|
||||
* Install a library to a version.
|
||||
@@ -60,7 +63,7 @@ interface DependencyManager {
|
||||
* @param libraryVersion the version of being installed library.
|
||||
* @return the task to install the specific library.
|
||||
*/
|
||||
fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task
|
||||
Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion);
|
||||
|
||||
/**
|
||||
* Get registered version list.
|
||||
@@ -68,5 +71,5 @@ interface DependencyManager {
|
||||
* @param id the id of version list. i.e. game, forge, liteloader, optifine
|
||||
* @throws IllegalArgumentException if the version list of specific id is not found.
|
||||
*/
|
||||
fun getVersionList(id: String): VersionList<*>
|
||||
}
|
||||
VersionList<?> getVersionList(String id);
|
||||
}
|
||||
@@ -15,17 +15,24 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
/**
|
||||
* The service provider that provides Minecraft online file downloads.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
interface DownloadProvider {
|
||||
val libraryBaseURL: String
|
||||
val versionListURL: String
|
||||
val versionBaseURL: String
|
||||
val assetIndexBaseURL: String
|
||||
val assetBaseURL: String
|
||||
public interface DownloadProvider {
|
||||
|
||||
String getLibraryBaseURL();
|
||||
|
||||
String getVersionListURL();
|
||||
|
||||
String getVersionBaseURL();
|
||||
|
||||
String getAssetIndexBaseURL();
|
||||
|
||||
String getAssetBaseURL();
|
||||
|
||||
/**
|
||||
* Inject into original URL provided by Mojang and Forge.
|
||||
@@ -36,12 +43,13 @@ interface DownloadProvider {
|
||||
* @param baseURL original URL provided by Mojang and Forge.
|
||||
* @return the URL that is equivalent to [baseURL], but belongs to your own service provider.
|
||||
*/
|
||||
fun injectURL(baseURL: String): String
|
||||
String injectURL(String baseURL);
|
||||
|
||||
/**
|
||||
* the specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine"
|
||||
*
|
||||
* @param id the id of specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine"
|
||||
* @return the version list
|
||||
*/
|
||||
fun getVersionListById(id: String): VersionList<*>
|
||||
}
|
||||
VersionList<?> getVersionListById(String id);
|
||||
}
|
||||
@@ -15,45 +15,57 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.task.Task
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
|
||||
/**
|
||||
* The builder which provide a task to build Minecraft environment.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
abstract class GameBuilder {
|
||||
var name: String = ""
|
||||
protected var gameVersion: String = ""
|
||||
protected var toolVersions = HashMap<String, String>()
|
||||
public abstract class GameBuilder {
|
||||
|
||||
protected String name = "";
|
||||
protected String gameVersion = "";
|
||||
protected Map<String, String> toolVersions = new HashMap<>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The new game version name, for .minecraft/<version name>.
|
||||
*
|
||||
* @param name the name of new game version.
|
||||
*/
|
||||
fun name(name: String): GameBuilder {
|
||||
this.name = name
|
||||
return this
|
||||
public GameBuilder name(String name) {
|
||||
this.name = Objects.requireNonNull(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
fun gameVersion(version: String): GameBuilder {
|
||||
gameVersion = version
|
||||
return this
|
||||
public GameBuilder gameVersion(String version) {
|
||||
this.gameVersion = Objects.requireNonNull(version);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the core library id. i.e. "forge", "liteloader", "optifine"
|
||||
* @param version the version of the core library. For documents, you can first try [VersionList.versions]
|
||||
*/
|
||||
fun version(id: String, version: String): GameBuilder {
|
||||
toolVersions[id] = version
|
||||
return this
|
||||
public GameBuilder version(String id, String version) {
|
||||
if ("game".equals(id))
|
||||
gameVersion(version);
|
||||
else
|
||||
toolVersions.put(id, version);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the task that can build thw whole Minecraft environment
|
||||
*/
|
||||
abstract fun buildAsync(): Task
|
||||
}
|
||||
public abstract Task buildAsync();
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.download.forge.ForgeVersionList;
|
||||
import org.jackhuang.hmcl.download.game.GameVersionList;
|
||||
import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList;
|
||||
import org.jackhuang.hmcl.download.optifine.OptiFineVersionList;
|
||||
|
||||
/**
|
||||
* @see {@link http://wiki.vg}
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class MojangDownloadProvider implements DownloadProvider {
|
||||
|
||||
public static final MojangDownloadProvider INSTANCE = new MojangDownloadProvider();
|
||||
|
||||
private MojangDownloadProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLibraryBaseURL() {
|
||||
return "https://libraries.minecraft.net/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionListURL() {
|
||||
return "https://launchermeta.mojang.com/mc/game/version_manifest.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionBaseURL() {
|
||||
return "http://s3.amazonaws.com/Minecraft.Download/versions/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssetIndexBaseURL() {
|
||||
return "http://s3.amazonaws.com/Minecraft.Download/indexes/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssetBaseURL() {
|
||||
return "http://resources.download.minecraft.net/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionList<?> getVersionListById(String id) {
|
||||
switch (id) {
|
||||
case "game":
|
||||
return GameVersionList.INSTANCE;
|
||||
case "forge":
|
||||
return ForgeVersionList.INSTANCE;
|
||||
case "liteloader":
|
||||
return LiteLoaderVersionList.INSTANCE;
|
||||
case "optifine":
|
||||
return OptiFineVersionList.INSTANCE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized version list id: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String injectURL(String baseURL) {
|
||||
if (baseURL.contains("net/minecraftforge/forge"))
|
||||
return baseURL;
|
||||
else
|
||||
return baseURL.replace("http://files.minecraftforge.net/maven", "http://ftb.cursecdn.com/FTB2/maven");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import org.jackhuang.hmcl.util.VersionNumber;
|
||||
|
||||
/**
|
||||
* The remote version.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class RemoteVersion<T> implements Comparable<RemoteVersion<T>> {
|
||||
|
||||
private final String gameVersion;
|
||||
private final String selfVersion;
|
||||
private final String url;
|
||||
private final T tag;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param gameVersion the Minecraft version that this remote version suits.
|
||||
* @param selfVersion the version string of the remote version.
|
||||
* @param url the installer or universal jar URL.
|
||||
* @param tag some necessary information for Installer Task.
|
||||
*/
|
||||
public RemoteVersion(String gameVersion, String selfVersion, String url, T tag) {
|
||||
this.gameVersion = Objects.requireNonNull(gameVersion);
|
||||
this.selfVersion = Objects.requireNonNull(selfVersion);
|
||||
this.url = Objects.requireNonNull(url);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public String getGameVersion() {
|
||||
return gameVersion;
|
||||
}
|
||||
|
||||
public String getSelfVersion() {
|
||||
return selfVersion;
|
||||
}
|
||||
|
||||
public T getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof RemoteVersion && Objects.equals(selfVersion, ((RemoteVersion) obj).selfVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return selfVersion.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(RemoteVersion<T> o) {
|
||||
// newer versions are smaller than older versions
|
||||
return -selfVersion.compareTo(o.selfVersion);
|
||||
}
|
||||
|
||||
public static class RemoteVersionComparator implements Comparator<RemoteVersion<?>> {
|
||||
|
||||
public static final RemoteVersionComparator INSTANCE = new RemoteVersionComparator();
|
||||
|
||||
private RemoteVersionComparator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(RemoteVersion<?> o1, RemoteVersion<?> o2) {
|
||||
return -VersionNumber.asVersion(o1.selfVersion).compareTo(VersionNumber.asVersion(o2.selfVersion));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,39 +15,48 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.task.Task
|
||||
import org.jackhuang.hmcl.util.SimpleMultimap
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeSet;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.SimpleMultimap;
|
||||
|
||||
/**
|
||||
* The remote version list.
|
||||
* @param T The type of RemoteVersion<T>, the type of tags.
|
||||
*
|
||||
* @param T The type of {@code RemoteVersion<T>}, the type of tags.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
abstract class VersionList<T> {
|
||||
public abstract class VersionList<T> {
|
||||
|
||||
/**
|
||||
* the remote version list.
|
||||
* key: game version.
|
||||
* values: corresponding remote versions.
|
||||
*/
|
||||
protected val versions = SimpleMultimap<String, RemoteVersion<T>>(::HashMap, ::TreeSet)
|
||||
protected final SimpleMultimap<String, RemoteVersion<T>> versions = new SimpleMultimap<String, RemoteVersion<T>>(HashMap::new, TreeSet::new);
|
||||
|
||||
/**
|
||||
* True if the version list has been loaded.
|
||||
*/
|
||||
val loaded = versions.isNotEmpty
|
||||
public boolean isLoaded() {
|
||||
return !versions.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param downloadProvider DownloadProvider
|
||||
* @return the task to reload the remote version list.
|
||||
*/
|
||||
abstract fun refreshAsync(downloadProvider: DownloadProvider): Task
|
||||
public abstract Task refreshAsync(DownloadProvider downloadProvider);
|
||||
|
||||
private fun getVersionsImpl(gameVersion: String): Collection<RemoteVersion<T>> {
|
||||
val ans = versions[gameVersion]
|
||||
return if (ans.isEmpty()) versions.values else ans
|
||||
private Collection<RemoteVersion<T>> getVersionsImpl(String gameVersion) {
|
||||
Collection<RemoteVersion<T>> ans = versions.get(gameVersion);
|
||||
return ans.isEmpty() ? versions.values() : ans;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,8 +65,8 @@ abstract class VersionList<T> {
|
||||
* @param gameVersion the Minecraft version that remote versions belong to
|
||||
* @return the collection of specific remote versions
|
||||
*/
|
||||
fun getVersions(gameVersion: String): Collection<RemoteVersion<T>> {
|
||||
return Collections.unmodifiableCollection(getVersionsImpl(gameVersion))
|
||||
public final Collection<RemoteVersion<T>> getVersions(String gameVersion) {
|
||||
return Collections.unmodifiableCollection(getVersionsImpl(gameVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,13 +76,11 @@ abstract class VersionList<T> {
|
||||
* @param remoteVersion the version of the remote version.
|
||||
* @return the specific remote version, null if it is not found.
|
||||
*/
|
||||
fun getVersion(gameVersion: String, remoteVersion: String): RemoteVersion<T>? {
|
||||
var result : RemoteVersion<T>? = null
|
||||
versions[gameVersion].forEach {
|
||||
if (it.selfVersion == remoteVersion)
|
||||
result = it
|
||||
}
|
||||
return result
|
||||
public final Optional<RemoteVersion<T>> getVersion(String gameVersion, String remoteVersion) {
|
||||
RemoteVersion<T> result = null;
|
||||
for (RemoteVersion<T> it : versions.get(gameVersion))
|
||||
if (remoteVersion.equals(it.getSelfVersion()))
|
||||
result = it;
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.SimpleVersionProvider;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.IOUtils;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class ForgeInstallTask extends TaskResult<Version> {
|
||||
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final String gameVersion;
|
||||
private final Version version;
|
||||
private final String remoteVersion;
|
||||
private final VersionList<?> forgeVersionList;
|
||||
private final File installer = new File("forge-installer.jar").getAbsoluteFile();
|
||||
private RemoteVersion<?> remote;
|
||||
private final List<Task> dependents = new LinkedList<>();
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
private Task downloadFileTask() {
|
||||
remote = forgeVersionList.getVersion(gameVersion, remoteVersion)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Remote forge version " + gameVersion + ", " + remoteVersion + " not found"));
|
||||
return new FileDownloadTask(NetworkUtils.toURL(remote.getUrl()), installer);
|
||||
}
|
||||
|
||||
public ForgeInstallTask(DefaultDependencyManager dependencyManager, String gameVersion, Version version, String remoteVersion) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.gameVersion = gameVersion;
|
||||
this.version = version;
|
||||
this.remoteVersion = remoteVersion;
|
||||
|
||||
forgeVersionList = dependencyManager.getVersionList("forge");
|
||||
|
||||
if (!forgeVersionList.isLoaded())
|
||||
dependents.add(forgeVersionList.refreshAsync(dependencyManager.getDownloadProvider())
|
||||
.then(s -> downloadFileTask()));
|
||||
else
|
||||
dependents.add(downloadFileTask());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "version";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelyingOnDependencies() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
try (ZipFile zipFile = new ZipFile(installer)) {
|
||||
InputStream stream = zipFile.getInputStream(zipFile.getEntry("install_profile.json"));
|
||||
if (stream == null)
|
||||
throw new IOException("Malformed forge installer file, install_profile.json does not exist.");
|
||||
String json = IOUtils.readFullyAsString(stream);
|
||||
InstallProfile installProfile = Constants.GSON.fromJson(json, InstallProfile.class);
|
||||
if (installProfile == null)
|
||||
throw new IOException("Malformed forge installer file, install_profile.json does not exist.");
|
||||
|
||||
// unpack the universal jar in the installer file.
|
||||
Library forgeLibrary = Library.fromName(installProfile.getInstall().getPath());
|
||||
File forgeFile = dependencyManager.getGameRepository().getLibraryFile(version, forgeLibrary);
|
||||
if (!FileUtils.makeFile(forgeFile))
|
||||
throw new IOException("Cannot make directory " + forgeFile.getParent());
|
||||
|
||||
ZipEntry forgeEntry = zipFile.getEntry(installProfile.getInstall().getFilePath());
|
||||
try (InputStream is = zipFile.getInputStream(forgeEntry); OutputStream os = new FileOutputStream(forgeFile)) {
|
||||
IOUtils.copyTo(is, os);
|
||||
}
|
||||
|
||||
// resolve the version
|
||||
SimpleVersionProvider provider = new SimpleVersionProvider();
|
||||
provider.addVersion(version);
|
||||
|
||||
setResult(installProfile.getVersionInfo()
|
||||
.setInheritsFrom(version.getId())
|
||||
.resolve(provider)
|
||||
.setId(version.getId()).setLogging(Collections.EMPTY_MAP));
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, installProfile.getVersionInfo()));
|
||||
}
|
||||
|
||||
if (!installer.delete())
|
||||
throw new IOException("Unable to delete installer file" + installer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class ForgeVersion implements Validation {
|
||||
|
||||
private final String branch;
|
||||
private final String mcversion;
|
||||
private final String jobver;
|
||||
private final String version;
|
||||
private final int build;
|
||||
private final double modified;
|
||||
private final String[][] files;
|
||||
|
||||
public ForgeVersion() {
|
||||
this(null, null, null, null, 0, 0, null);
|
||||
}
|
||||
|
||||
public ForgeVersion(String branch, String mcversion, String jobver, String version, int build, double modified, String[][] files) {
|
||||
this.branch = branch;
|
||||
this.mcversion = mcversion;
|
||||
this.jobver = jobver;
|
||||
this.version = version;
|
||||
this.build = build;
|
||||
this.modified = modified;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public String getBranch() {
|
||||
return branch;
|
||||
}
|
||||
|
||||
public String getGameVersion() {
|
||||
return mcversion;
|
||||
}
|
||||
|
||||
public String getJobver() {
|
||||
return jobver;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public int getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
public double getModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public String[][] getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (files == null)
|
||||
throw new JsonParseException("ForgeVersion files cannot be null");
|
||||
if (version == null)
|
||||
throw new JsonParseException("ForgeVersion version cannot be null");
|
||||
if (mcversion == null)
|
||||
throw new JsonParseException("ForgeVersion mcversion cannot be null");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.VersionNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class ForgeVersionList extends VersionList<Void> {
|
||||
|
||||
public static final ForgeVersionList INSTANCE = new ForgeVersionList();
|
||||
|
||||
private ForgeVersionList() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task refreshAsync(DownloadProvider downloadProvider) {
|
||||
final GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(FORGE_LIST)));
|
||||
final List<Task> dependents = Collections.singletonList(task);
|
||||
return new Task() {
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
ForgeVersionRoot root = Constants.GSON.fromJson(task.getResult(), ForgeVersionRoot.class);
|
||||
if (root == null)
|
||||
return;
|
||||
versions.clear();
|
||||
|
||||
for (Map.Entry<String, int[]> entry : root.getGameVersions().entrySet()) {
|
||||
String gameVersion = VersionNumber.parseVersion(entry.getKey());
|
||||
if (gameVersion == null)
|
||||
continue;
|
||||
for (int v : entry.getValue()) {
|
||||
ForgeVersion version = root.getNumber().get(v);
|
||||
if (version == null)
|
||||
continue;
|
||||
String jar = null;
|
||||
for (String[] file : version.getFiles())
|
||||
if (file.length > 1 && "installer".equals(file[1])) {
|
||||
String classifier = version.getGameVersion() + "-" + version.getVersion()
|
||||
+ (StringUtils.isNotBlank(version.getBranch()) ? "-" + version.getBranch() : "");
|
||||
String fileName = root.getArtifact() + "-" + classifier + "-" + file[1] + "." + file[0];
|
||||
jar = downloadProvider.injectURL(root.getWebPath() + classifier + "/" + fileName);
|
||||
}
|
||||
|
||||
if (jar == null)
|
||||
continue;
|
||||
versions.put(gameVersion, new RemoteVersion<>(
|
||||
version.getGameVersion(), version.getVersion(), jar, null
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static final String FORGE_LIST = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json";
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class ForgeVersionRoot implements Validation {
|
||||
|
||||
private final String artifact;
|
||||
private final String webpath;
|
||||
private final String adfly;
|
||||
private final String homepage;
|
||||
private final String name;
|
||||
private final Map<String, int[]> branches;
|
||||
private final Map<String, int[]> mcversion;
|
||||
private final Map<String, Integer> promos;
|
||||
private final Map<Integer, ForgeVersion> number;
|
||||
|
||||
public ForgeVersionRoot() {
|
||||
this(null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public ForgeVersionRoot(String artifact, String webpath, String adfly, String homepage, String name, Map<String, int[]> branches, Map<String, int[]> mcversion, Map<String, Integer> promos, Map<Integer, ForgeVersion> number) {
|
||||
this.artifact = artifact;
|
||||
this.webpath = webpath;
|
||||
this.adfly = adfly;
|
||||
this.homepage = homepage;
|
||||
this.name = name;
|
||||
this.branches = branches;
|
||||
this.mcversion = mcversion;
|
||||
this.promos = promos;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getArtifact() {
|
||||
return artifact;
|
||||
}
|
||||
|
||||
public String getWebPath() {
|
||||
return webpath;
|
||||
}
|
||||
|
||||
public String getAdfly() {
|
||||
return adfly;
|
||||
}
|
||||
|
||||
public String getHomePage() {
|
||||
return homepage;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map<String, int[]> getBranches() {
|
||||
return branches;
|
||||
}
|
||||
|
||||
public Map<String, int[]> getGameVersions() {
|
||||
return mcversion;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getPromos() {
|
||||
return promos;
|
||||
}
|
||||
|
||||
public Map<Integer, ForgeVersion> getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (number == null)
|
||||
throw new JsonParseException("ForgeVersionRoot number cannot be null");
|
||||
if (mcversion == null)
|
||||
throw new JsonParseException("ForgeVersionRoot mcversion cannot be null");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class Install {
|
||||
|
||||
private final String profileName;
|
||||
private final String target;
|
||||
private final String path;
|
||||
private final String version;
|
||||
private final String filePath;
|
||||
private final String welcome;
|
||||
private final String minecraft;
|
||||
private final String mirrorList;
|
||||
private final String logo;
|
||||
|
||||
public Install() {
|
||||
this(null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public Install(String profileName, String target, String path, String version, String filePath, String welcome, String minecraft, String mirrorList, String logo) {
|
||||
this.profileName = profileName;
|
||||
this.target = target;
|
||||
this.path = path;
|
||||
this.version = version;
|
||||
this.filePath = filePath;
|
||||
this.welcome = welcome;
|
||||
this.minecraft = minecraft;
|
||||
this.mirrorList = mirrorList;
|
||||
this.logo = logo;
|
||||
}
|
||||
|
||||
public String getProfileName() {
|
||||
return profileName;
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public String getWelcome() {
|
||||
return welcome;
|
||||
}
|
||||
|
||||
public String getMinecraft() {
|
||||
return minecraft;
|
||||
}
|
||||
|
||||
public String getMirrorList() {
|
||||
return mirrorList;
|
||||
}
|
||||
|
||||
public String getLogo() {
|
||||
return logo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class InstallProfile implements Validation {
|
||||
|
||||
@SerializedName("install")
|
||||
private final Install install;
|
||||
|
||||
@SerializedName("versionInfo")
|
||||
private final Version versionInfo;
|
||||
|
||||
public InstallProfile(Install install, Version versionInfo) {
|
||||
this.install = install;
|
||||
this.versionInfo = versionInfo;
|
||||
}
|
||||
|
||||
public Install getInstall() {
|
||||
return install;
|
||||
}
|
||||
|
||||
public Version getVersionInfo() {
|
||||
return versionInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (install == null)
|
||||
throw new JsonParseException("InstallProfile install cannot be null");
|
||||
|
||||
if (versionInfo == null)
|
||||
throw new JsonParseException("InstallProfile versionInfo cannot be null");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
||||
import org.jackhuang.hmcl.game.AssetIndexInfo;
|
||||
import org.jackhuang.hmcl.game.AssetObject;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameAssetDownloadTask extends Task {
|
||||
|
||||
private final AbstractDependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final GameAssetRefreshTask refreshTask;
|
||||
private final List<Task> dependents = new LinkedList<>();
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides proxy settings and {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
*/
|
||||
public GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
this.refreshTask = new GameAssetRefreshTask(dependencyManager, version);
|
||||
this.dependents.add(refreshTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
int size = refreshTask.getResult().size();
|
||||
for (Map.Entry<File, AssetObject> entry : refreshTask.getResult()) {
|
||||
File file = entry.getKey();
|
||||
AssetObject assetObject = entry.getValue();
|
||||
String url = dependencyManager.getDownloadProvider().getAssetBaseURL() + assetObject.getLocation();
|
||||
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile())) {
|
||||
Logging.LOG.log(Level.SEVERE, "Unable to create new file {0}, because parent directory cannot be created", file);
|
||||
continue;
|
||||
}
|
||||
if (file.isDirectory())
|
||||
continue;
|
||||
boolean flag = true;
|
||||
int downloaded = 0;
|
||||
try {
|
||||
// check the checksum of file to ensure that the file is not need to re-download.
|
||||
if (file.exists()) {
|
||||
String sha1 = DigestUtils.sha1Hex(FileUtils.readBytes(file));
|
||||
if (sha1.equals(assetObject.getHash())) {
|
||||
++downloaded;
|
||||
Logging.LOG.finest("File $file has been downloaded successfully, skipped downloading");
|
||||
updateProgress(downloaded, size);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logging.LOG.log(Level.WARNING, "Unable to get hash code of file " + file, e);
|
||||
flag = !file.exists();
|
||||
}
|
||||
if (flag) {
|
||||
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(url), file, dependencyManager.getProxy(), assetObject.getHash());
|
||||
task.setName(assetObject.getHash());
|
||||
dependencies.add(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
||||
import org.jackhuang.hmcl.game.AssetIndexInfo;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
* This task is to download asset index file provided in minecraft.json.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameAssetIndexDownloadTask extends Task {
|
||||
|
||||
private final AbstractDependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides proxy settings and {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
*/
|
||||
public GameAssetIndexDownloadTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
AssetIndexInfo assetIndexInfo = version.getAssetIndex();
|
||||
File assetDir = dependencyManager.getGameRepository().getAssetDirectory(version.getId(), assetIndexInfo.getId());
|
||||
if (FileUtils.makeDirectory(assetDir))
|
||||
throw new IOException("Cannot create directory: " + assetDir);
|
||||
File assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
|
||||
dependencies.add(new FileDownloadTask(
|
||||
NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(assetIndexInfo.getUrl())),
|
||||
assetIndexFile, dependencyManager.getProxy()
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
||||
import org.jackhuang.hmcl.game.AssetIndex;
|
||||
import org.jackhuang.hmcl.game.AssetIndexInfo;
|
||||
import org.jackhuang.hmcl.game.AssetObject;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
|
||||
/**
|
||||
* This task is to extract all asset objects described in asset index json.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameAssetRefreshTask extends TaskResult<Collection<Pair<File, AssetObject>>> {
|
||||
|
||||
private final AbstractDependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final AssetIndexInfo assetIndexInfo;
|
||||
private final File assetIndexFile;
|
||||
private final List<Task> dependents = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides proxy settings and {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
*/
|
||||
public GameAssetRefreshTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
this.assetIndexInfo = version.getAssetIndex();
|
||||
this.assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
|
||||
|
||||
if (!assetIndexFile.exists())
|
||||
dependents.add(new GameAssetIndexDownloadTask(dependencyManager, version));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
AssetIndex index = Constants.GSON.fromJson(FileUtils.readText(assetIndexFile), AssetIndex.class);
|
||||
List<Pair<File, AssetObject>> res = new LinkedList<>();
|
||||
int progress = 0;
|
||||
if (index != null)
|
||||
for (AssetObject assetObject : index.getObjects().values()) {
|
||||
res.add(new Pair<>(dependencyManager.getGameRepository().getAssetObject(version.getId(), assetIndexInfo.getId(), assetObject), assetObject));
|
||||
updateProgress(++progress, index.getObjects().size());
|
||||
}
|
||||
setResult(res);
|
||||
}
|
||||
|
||||
public static final String ID = "game_asset_refresh_task";
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameDownloadTask extends Task {
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
public GameDownloadTask(DefaultDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
File jar = dependencyManager.getGameRepository().getVersionJar(version);
|
||||
|
||||
dependencies.add(new FileDownloadTask(
|
||||
NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(version.getDownloadInfo().getUrl())),
|
||||
jar,
|
||||
dependencyManager.getProxy(),
|
||||
version.getDownloadInfo().getSha1()
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
* This task is to download game libraries.
|
||||
* This task should be executed last(especially after game downloading, Forge, LiteLoader and OptiFine install task).
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameLibrariesTask extends Task {
|
||||
|
||||
private final AbstractDependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides proxy settings and {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
*/
|
||||
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
for (Library library : version.getLibraries())
|
||||
if (library.appliesToCurrentEnvironment()) {
|
||||
File file = dependencyManager.getGameRepository().getLibraryFile(version, library);
|
||||
if (!file.exists())
|
||||
dependencies.add(new FileDownloadTask(
|
||||
NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(library.getDownload().getUrl())),
|
||||
file, dependencyManager.getProxy(), library.getDownload().getSha1()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.DependencyManager;
|
||||
import org.jackhuang.hmcl.game.DownloadType;
|
||||
import org.jackhuang.hmcl.game.LoggingInfo;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
* This task is to download log4j configuration file provided in minecraft.json.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameLoggingDownloadTask extends Task {
|
||||
|
||||
private final DependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides proxy settings and {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
*/
|
||||
public GameLoggingDownloadTask(DependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
if (version.getLogging() == null || !version.getLogging().containsKey(DownloadType.CLIENT))
|
||||
return;
|
||||
|
||||
LoggingInfo logging = version.getLogging().get(DownloadType.CLIENT);
|
||||
File file = dependencyManager.getGameRepository().getLoggingObject(version.getId(), version.getAssetIndex().getId(), logging);
|
||||
if (!file.exists())
|
||||
dependencies.add(new FileDownloadTask(NetworkUtils.toURL(logging.getFile().getUrl()), file, dependencyManager.getProxy()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class GameRemoteLatestVersions {
|
||||
|
||||
@SerializedName("snapshot")
|
||||
private final String snapshot;
|
||||
|
||||
@SerializedName("release")
|
||||
private final String release;
|
||||
|
||||
public GameRemoteLatestVersions() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public GameRemoteLatestVersions(String snapshot, String release) {
|
||||
this.snapshot = snapshot;
|
||||
this.release = release;
|
||||
}
|
||||
|
||||
public String getRelease() {
|
||||
return release;
|
||||
}
|
||||
|
||||
public String getSnapshot() {
|
||||
return snapshot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Date;
|
||||
import org.jackhuang.hmcl.game.ReleaseType;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameRemoteVersion implements Validation {
|
||||
|
||||
@SerializedName("id")
|
||||
private final String gameVersion;
|
||||
|
||||
@SerializedName("time")
|
||||
private final Date time;
|
||||
|
||||
@SerializedName("releaseTime")
|
||||
private final Date releaseTime;
|
||||
|
||||
@SerializedName("type")
|
||||
private final ReleaseType type;
|
||||
|
||||
@SerializedName("url")
|
||||
private final String url;
|
||||
|
||||
public GameRemoteVersion() {
|
||||
this("", new Date(), new Date(), ReleaseType.UNKNOWN);
|
||||
}
|
||||
|
||||
public GameRemoteVersion(String gameVersion, Date time, Date releaseTime, ReleaseType type) {
|
||||
this(gameVersion, time, releaseTime, type, Constants.DEFAULT_LIBRARY_URL + gameVersion + "/" + gameVersion + ".json");
|
||||
}
|
||||
|
||||
public GameRemoteVersion(String gameVersion, Date time, Date releaseTime, ReleaseType type, String url) {
|
||||
this.gameVersion = gameVersion;
|
||||
this.time = time;
|
||||
this.releaseTime = releaseTime;
|
||||
this.type = type;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getGameVersion() {
|
||||
return gameVersion;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public Date getReleaseTime() {
|
||||
return releaseTime;
|
||||
}
|
||||
|
||||
public ReleaseType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (StringUtils.isBlank(gameVersion))
|
||||
throw new JsonParseException("GameRemoteVersion id cannot be blank");
|
||||
if (StringUtils.isBlank(url))
|
||||
throw new JsonParseException("GameRemoteVersion url cannot be blank");
|
||||
}
|
||||
}
|
||||
@@ -15,27 +15,36 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import org.jackhuang.hmcl.util.Immutable
|
||||
import org.jackhuang.hmcl.util.Validation
|
||||
import java.util.Date;
|
||||
import org.jackhuang.hmcl.game.ReleaseType;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
class LoggingInfo @JvmOverloads constructor(
|
||||
@SerializedName("file")
|
||||
val file: IdDownloadInfo = IdDownloadInfo(),
|
||||
public final class GameRemoteVersionTag {
|
||||
|
||||
@SerializedName("argument")
|
||||
val argument: String = "",
|
||||
private final ReleaseType type;
|
||||
private final Date time;
|
||||
|
||||
@SerializedName("type")
|
||||
val type: String = ""
|
||||
): Validation {
|
||||
|
||||
override fun validate() {
|
||||
file.validate()
|
||||
require(argument.isNotBlank(), { "LoggingInfo" })
|
||||
require(type.isNotBlank())
|
||||
public GameRemoteVersionTag() {
|
||||
this(ReleaseType.UNKNOWN, new Date());
|
||||
}
|
||||
}
|
||||
|
||||
public GameRemoteVersionTag(ReleaseType type, Date time) {
|
||||
this.type = type;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public ReleaseType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class GameRemoteVersions {
|
||||
|
||||
@SerializedName("versions")
|
||||
private final List<GameRemoteVersion> versions;
|
||||
|
||||
@SerializedName("latest")
|
||||
private final GameRemoteLatestVersions latest;
|
||||
|
||||
public GameRemoteVersions() {
|
||||
this(Collections.EMPTY_LIST, null);
|
||||
}
|
||||
|
||||
public GameRemoteVersions(List<GameRemoteVersion> versions, GameRemoteLatestVersions latest) {
|
||||
this.versions = versions;
|
||||
this.latest = latest;
|
||||
}
|
||||
|
||||
public GameRemoteLatestVersions getLatest() {
|
||||
return latest;
|
||||
}
|
||||
|
||||
public List<GameRemoteVersion> getVersions() {
|
||||
return versions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.VersionNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameVersionList extends VersionList<GameRemoteVersionTag> {
|
||||
|
||||
public static final GameVersionList INSTANCE = new GameVersionList();
|
||||
|
||||
private GameVersionList() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task refreshAsync(DownloadProvider downloadProvider) {
|
||||
GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.getVersionListURL()));
|
||||
return new Task() {
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return Collections.singleton(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
versions.clear();
|
||||
|
||||
GameRemoteVersions root = Constants.GSON.fromJson(task.getResult(), GameRemoteVersions.class);
|
||||
for (GameRemoteVersion remoteVersion : root.getVersions()) {
|
||||
String gameVersion = VersionNumber.parseVersion(remoteVersion.getGameVersion());
|
||||
if (gameVersion == null)
|
||||
continue;
|
||||
versions.put(gameVersion, new RemoteVersion<>(
|
||||
remoteVersion.getGameVersion(),
|
||||
remoteVersion.getGameVersion(),
|
||||
remoteVersion.getUrl(),
|
||||
new GameRemoteVersionTag(remoteVersion.getType(), remoteVersion.getReleaseTime()))
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class VersionJsonDownloadTask extends Task {
|
||||
private final String gameVersion;
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final List<Task> dependents = new LinkedList<>();
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
private final VersionList<?> gameVersionList;
|
||||
|
||||
public VersionJsonDownloadTask(String gameVersion, DefaultDependencyManager dependencyManager) {
|
||||
this.gameVersion = gameVersion;
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.gameVersionList = dependencyManager.getVersionList("game");
|
||||
|
||||
if (!gameVersionList.isLoaded())
|
||||
dependents.add(gameVersionList.refreshAsync(dependencyManager.getDownloadProvider()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
RemoteVersion<?> remoteVersion = gameVersionList.getVersions(gameVersion).stream().findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot find specific version "+gameVersion+" in remote repository"));
|
||||
String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl());
|
||||
dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL), Proxy.NO_PROXY, ID));
|
||||
}
|
||||
|
||||
public static final String ID = "raw_version_json";
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
|
||||
/**
|
||||
* This task is to save the version json.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class VersionJsonSaveTask extends Task {
|
||||
|
||||
private final DefaultGameRepository repository;
|
||||
private final Version version;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param repository the game repository
|
||||
* @param version the **resolved** version
|
||||
*/
|
||||
public VersionJsonSaveTask(DefaultGameRepository repository, Version version) {
|
||||
this.repository = repository;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
File json = repository.getVersionJson(version.getId()).getAbsoluteFile();
|
||||
if (!FileUtils.makeFile(json))
|
||||
throw new IOException("Cannot create file " + json);
|
||||
FileUtils.writeText(json, Constants.GSON.toJson(version));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LiteLoaderBranch {
|
||||
|
||||
@SerializedName("libraries")
|
||||
private final Collection<Library> libraries;
|
||||
|
||||
@SerializedName("com.mumfrey:liteloader")
|
||||
private final Map<String, LiteLoaderVersion> liteLoader;
|
||||
|
||||
public LiteLoaderBranch() {
|
||||
this(Collections.EMPTY_SET, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
public LiteLoaderBranch(Collection<Library> libraries, Map<String, LiteLoaderVersion> liteLoader) {
|
||||
this.libraries = libraries;
|
||||
this.liteLoader = liteLoader;
|
||||
}
|
||||
|
||||
public Collection<Library> getLibraries() {
|
||||
return Collections.unmodifiableCollection(libraries);
|
||||
}
|
||||
|
||||
public Map<String, LiteLoaderVersion> getLiteLoader() {
|
||||
return Collections.unmodifiableMap(liteLoader);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LiteLoaderGameVersions {
|
||||
|
||||
@SerializedName("repo")
|
||||
private final LiteLoaderRepository repoitory;
|
||||
|
||||
@SerializedName("artefacts")
|
||||
private final LiteLoaderBranch artifacts;
|
||||
|
||||
@SerializedName("snapshots")
|
||||
private final LiteLoaderBranch snapshots;
|
||||
|
||||
public LiteLoaderGameVersions() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
public LiteLoaderGameVersions(LiteLoaderRepository repoitory, LiteLoaderBranch artifacts, LiteLoaderBranch snapshots) {
|
||||
this.repoitory = repoitory;
|
||||
this.artifacts = artifacts;
|
||||
this.snapshots = snapshots;
|
||||
}
|
||||
|
||||
public LiteLoaderRepository getRepoitory() {
|
||||
return repoitory;
|
||||
}
|
||||
|
||||
public LiteLoaderBranch getArtifacts() {
|
||||
return artifacts;
|
||||
}
|
||||
|
||||
public LiteLoaderBranch getSnapshots() {
|
||||
return snapshots;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.Arguments;
|
||||
import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.LibraryDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
/**
|
||||
* Note: LiteLoader must be installed after Forge.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class LiteLoaderInstallTask extends TaskResult<Version> {
|
||||
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final String gameVersion;
|
||||
private final Version version;
|
||||
private final String remoteVersion;
|
||||
private final LiteLoaderVersionList liteLoaderVersionList;
|
||||
private RemoteVersion<LiteLoaderRemoteVersionTag> remote;
|
||||
private final List<Task> dependents = new LinkedList<>();
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
private void doRemote() {
|
||||
remote = liteLoaderVersionList.getVersion(gameVersion, remoteVersion)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Remote LiteLoader version " + gameVersion + ", " + remoteVersion + " not found"));
|
||||
}
|
||||
|
||||
public LiteLoaderInstallTask(DefaultDependencyManager dependencyManager, String gameVersion, Version version, String remoteVersion) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.gameVersion = gameVersion;
|
||||
this.version = version;
|
||||
this.remoteVersion = remoteVersion;
|
||||
|
||||
liteLoaderVersionList = (LiteLoaderVersionList) dependencyManager.getVersionList("liteloader");
|
||||
|
||||
if (!liteLoaderVersionList.isLoaded())
|
||||
dependents.add(liteLoaderVersionList.refreshAsync(dependencyManager.getDownloadProvider())
|
||||
.then(s -> {
|
||||
doRemote();
|
||||
return null;
|
||||
}));
|
||||
else
|
||||
doRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "version";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Library library = new Library(
|
||||
"com.mumfrey", "liteloader", remote.getSelfVersion(), null,
|
||||
"http://dl.liteloader.com/versions/",
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo(null, remote.getUrl()))
|
||||
);
|
||||
|
||||
Version tempVersion = version.setLibraries(Lang.merge(remote.getTag().getLibraries(), Arrays.asList(library)));
|
||||
setResult(version
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
.setLibraries(Lang.merge(tempVersion.getLibraries(), version.getLibraries()))
|
||||
.setLogging(Collections.EMPTY_MAP)
|
||||
.setMinecraftArguments(version.getMinecraftArguments().orElse("") + " --tweakClass " + remote.getTag().getTweakClass())
|
||||
//.setArguments(Arguments.addGameArguments(Lang.get(version.getArguments()), "--tweakClass", remote.getTag().getTweakClass()))
|
||||
);
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, tempVersion));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class LiteLoaderRemoteVersionTag {
|
||||
private final String tweakClass;
|
||||
private final Collection<Library> libraries;
|
||||
|
||||
public LiteLoaderRemoteVersionTag() {
|
||||
this("", Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
public LiteLoaderRemoteVersionTag(String tweakClass, Collection<Library> libraries) {
|
||||
this.tweakClass = tweakClass;
|
||||
this.libraries = libraries;
|
||||
}
|
||||
|
||||
public Collection<Library> getLibraries() {
|
||||
return libraries;
|
||||
}
|
||||
|
||||
public String getTweakClass() {
|
||||
return tweakClass;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LiteLoaderRepository {
|
||||
|
||||
@SerializedName("stream")
|
||||
private final String stream;
|
||||
|
||||
@SerializedName("type")
|
||||
private final String type;
|
||||
|
||||
@SerializedName("url")
|
||||
private final String url;
|
||||
|
||||
@SerializedName("classifier")
|
||||
private final String classifier;
|
||||
|
||||
public LiteLoaderRepository() {
|
||||
this("", "", "", "");
|
||||
}
|
||||
|
||||
public LiteLoaderRepository(String stream, String type, String url, String classifier) {
|
||||
this.stream = stream;
|
||||
this.type = type;
|
||||
this.url = url;
|
||||
this.classifier = classifier;
|
||||
}
|
||||
|
||||
public String getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getClassifier() {
|
||||
return classifier;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LiteLoaderVersion {
|
||||
private final String tweakClass;
|
||||
private final String file;
|
||||
private final String version;
|
||||
private final String md5;
|
||||
private final String timestamp;
|
||||
private final int lastSuccessfulBuild;
|
||||
private final Collection<Library> libraries;
|
||||
|
||||
public LiteLoaderVersion() {
|
||||
this("", "", "", "", "", 0, Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
public LiteLoaderVersion(String tweakClass, String file, String version, String md5, String timestamp, int lastSuccessfulBuild, Collection<Library> libraries) {
|
||||
this.tweakClass = tweakClass;
|
||||
this.file = file;
|
||||
this.version = version;
|
||||
this.md5 = md5;
|
||||
this.timestamp = timestamp;
|
||||
this.lastSuccessfulBuild = lastSuccessfulBuild;
|
||||
this.libraries = libraries;
|
||||
}
|
||||
|
||||
public String getTweakClass() {
|
||||
return tweakClass;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getMd5() {
|
||||
return md5;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public int getLastSuccessfulBuild() {
|
||||
return lastSuccessfulBuild;
|
||||
}
|
||||
|
||||
public Collection<Library> getLibraries() {
|
||||
return Collections.unmodifiableCollection(libraries);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.VersionNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class LiteLoaderVersionList extends VersionList<LiteLoaderRemoteVersionTag> {
|
||||
|
||||
public static final LiteLoaderVersionList INSTANCE = new LiteLoaderVersionList();
|
||||
|
||||
private LiteLoaderVersionList() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task refreshAsync(DownloadProvider downloadProvider) {
|
||||
GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(LITELOADER_LIST)));
|
||||
return new Task() {
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return Collections.singleton(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
LiteLoaderVersionsRoot root = Constants.GSON.fromJson(task.getResult(), LiteLoaderVersionsRoot.class);
|
||||
versions.clear();
|
||||
|
||||
for (Map.Entry<String, LiteLoaderGameVersions> entry : root.getVersions().entrySet()) {
|
||||
String gameVersion = entry.getKey();
|
||||
LiteLoaderGameVersions liteLoader = entry.getValue();
|
||||
String gg = VersionNumber.parseVersion(gameVersion);
|
||||
if (gg == null)
|
||||
continue;
|
||||
doBranch(gg, gameVersion, liteLoader.getRepoitory(), liteLoader.getArtifacts(), false);
|
||||
doBranch(gg, gameVersion, liteLoader.getRepoitory(), liteLoader.getSnapshots(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private void doBranch(String key, String gameVersion, LiteLoaderRepository repository, LiteLoaderBranch branch, boolean snapshot) {
|
||||
if (branch == null || repository == null)
|
||||
return;
|
||||
|
||||
for (Map.Entry<String, LiteLoaderVersion> entry : branch.getLiteLoader().entrySet()) {
|
||||
String branchName = entry.getKey();
|
||||
LiteLoaderVersion v = entry.getValue();
|
||||
if ("latest".equals(branchName))
|
||||
continue;
|
||||
|
||||
versions.put(key, new RemoteVersion<>(gameVersion,
|
||||
v.getVersion().replace("SNAPSHOT", "SNAPSHOT-" + v.getLastSuccessfulBuild()),
|
||||
snapshot
|
||||
? "http://jenkins.liteloader.com/LiteLoader " + gameVersion + "/lastSuccessfulBuild/artifact/build/libs/liteloader-" + v.getVersion() + "-release.jar"
|
||||
: downloadProvider.injectURL(repository.getUrl() + "com/mumfrey/liteloader/" + gameVersion + "/" + v.getFile()),
|
||||
new LiteLoaderRemoteVersionTag(v.getTweakClass(), v.getLibraries())
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final String LITELOADER_LIST = "http://dl.liteloader.com/versions/versions.json";
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LiteLoaderVersionsMeta {
|
||||
|
||||
@SerializedName("description")
|
||||
private final String description;
|
||||
|
||||
@SerializedName("authors")
|
||||
private final String authors;
|
||||
|
||||
@SerializedName("url")
|
||||
private final String url;
|
||||
|
||||
public LiteLoaderVersionsMeta() {
|
||||
this("", "", "");
|
||||
}
|
||||
|
||||
public LiteLoaderVersionsMeta(String description, String authors, String url) {
|
||||
this.description = description;
|
||||
this.authors = authors;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getAuthors() {
|
||||
return authors;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LiteLoaderVersionsRoot {
|
||||
|
||||
@SerializedName("versions")
|
||||
private final Map<String, LiteLoaderGameVersions> versions;
|
||||
|
||||
@SerializedName("meta")
|
||||
private final LiteLoaderVersionsMeta meta;
|
||||
|
||||
public LiteLoaderVersionsRoot() {
|
||||
this(Collections.EMPTY_MAP, null);
|
||||
}
|
||||
|
||||
public LiteLoaderVersionsRoot(Map<String, LiteLoaderGameVersions> versions, LiteLoaderVersionsMeta meta) {
|
||||
this.versions = versions;
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
public Map<String, LiteLoaderGameVersions> getVersions() {
|
||||
return Collections.unmodifiableMap(versions);
|
||||
}
|
||||
|
||||
public LiteLoaderVersionsMeta getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.optifine;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.VersionNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class OptiFineBMCLVersionList extends VersionList<Void> {
|
||||
|
||||
public static final OptiFineBMCLVersionList INSTANCE = new OptiFineBMCLVersionList();
|
||||
|
||||
private OptiFineBMCLVersionList() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task refreshAsync(DownloadProvider downloadProvider) {
|
||||
GetTask task = new GetTask(NetworkUtils.toURL("http://bmclapi.bangbang93.com/optifine/versionlist"));
|
||||
return new Task() {
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return Collections.singleton(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
versions.clear();
|
||||
Set<String> duplicates = new HashSet<>();
|
||||
List<OptiFineVersion> root = Constants.GSON.fromJson(task.getResult(), new TypeToken<List<OptiFineVersion>>() {
|
||||
}.getType());
|
||||
for (OptiFineVersion element : root) {
|
||||
String version = element.getType();
|
||||
if (version == null)
|
||||
continue;
|
||||
String mirror = "http://bmclapi2.bangbang93.com/optifine/" + element.getGameVersion() + "/" + element.getType() + "/" + element.getPatch();
|
||||
if (!duplicates.add(mirror))
|
||||
continue;
|
||||
|
||||
if (StringUtils.isBlank(element.getGameVersion()))
|
||||
continue;
|
||||
String gameVersion = VersionNumber.parseVersion(element.getGameVersion());
|
||||
versions.put(gameVersion, new RemoteVersion<>(gameVersion, version, mirror, null));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.optifine;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class OptiFineDownloadFormatter extends TaskResult<String> {
|
||||
|
||||
private final String url;
|
||||
|
||||
public OptiFineDownloadFormatter(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
String result = null;
|
||||
String content = NetworkUtils.doGet(NetworkUtils.toURL(url));
|
||||
Matcher m = PATTERN.matcher(content);
|
||||
while (m.find())
|
||||
result = m.group(1);
|
||||
if (result == null)
|
||||
throw new IllegalStateException("Cannot find version in " + content);
|
||||
setResult("http://optifine.net/downloadx?f=OptiFine" + result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public static final String ID = "optifine_formatter";
|
||||
private static final Pattern PATTERN = Pattern.compile("\"downloadx\\?f=OptiFine(.*)\"");
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.optifine;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.Argument;
|
||||
import org.jackhuang.hmcl.game.Arguments;
|
||||
import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.LibraryDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.StringArgument;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
/**
|
||||
* <b>Note</b>: OptiFine should be installed in the end.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class OptiFineInstallTask extends TaskResult<Version> {
|
||||
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final String gameVersion;
|
||||
private final Version version;
|
||||
private final String remoteVersion;
|
||||
private final VersionList<?> optiFineVersionList;
|
||||
private RemoteVersion<?> remote;
|
||||
private final List<Task> dependents = new LinkedList<>();
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
|
||||
private void doRemote() {
|
||||
remote = optiFineVersionList.getVersion(gameVersion, remoteVersion)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Remote OptiFine version " + gameVersion + ", " + remoteVersion + " not found"));
|
||||
}
|
||||
|
||||
public OptiFineInstallTask(DefaultDependencyManager dependencyManager, String gameVersion, Version version, String remoteVersion) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.gameVersion = gameVersion;
|
||||
this.version = version;
|
||||
this.remoteVersion = remoteVersion;
|
||||
|
||||
optiFineVersionList = dependencyManager.getVersionList("optifine");
|
||||
|
||||
if (!optiFineVersionList.isLoaded())
|
||||
dependents.add(optiFineVersionList.refreshAsync(dependencyManager.getDownloadProvider())
|
||||
.then(s -> {
|
||||
doRemote();
|
||||
return null;
|
||||
}));
|
||||
else
|
||||
doRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "version";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelyingOnDependencies() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Library library = new Library(
|
||||
"net.optifine", "optifine", remoteVersion, null, null,
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo(
|
||||
"net/optifine/optifine/" + remoteVersion + "/optifine-" + remoteVersion + ".jar",
|
||||
remote.getUrl())), true
|
||||
);
|
||||
|
||||
List<Library> libraries = new LinkedList<>();
|
||||
libraries.add(library);
|
||||
|
||||
boolean hasFMLTweaker = false;
|
||||
if (version.getMinecraftArguments().isPresent() && version.getMinecraftArguments().get().contains("FMLTweaker"))
|
||||
hasFMLTweaker = true;
|
||||
if (version.getArguments().isPresent()) {
|
||||
List<Argument> game = version.getArguments().get().getGame();
|
||||
if (game.stream().anyMatch(arg -> arg.toString(Collections.EMPTY_MAP, Collections.EMPTY_MAP).contains("FMLTweaker")))
|
||||
hasFMLTweaker = true;
|
||||
}
|
||||
|
||||
/*Arguments arguments = Lang.get(version.getArguments());
|
||||
|
||||
if (!hasFMLTweaker)
|
||||
arguments = Arguments.addGameArguments(arguments, "--tweakClass", "optifine.OptiFineTweaker");
|
||||
*/
|
||||
String minecraftArguments = version.getMinecraftArguments().orElse("");
|
||||
if (!hasFMLTweaker)
|
||||
minecraftArguments = minecraftArguments + " --tweakClass optifine.OptiFineTweaker";
|
||||
|
||||
if (version.getMainClass() == null || !version.getMainClass().startsWith("net.minecraft.launchwrapper."))
|
||||
libraries.add(0, new Library("net.minecraft", "launchwrapper", "1.12"));
|
||||
|
||||
setResult(version
|
||||
.setLibraries(Lang.merge(version.getLibraries(), libraries))
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
.setMinecraftArguments(minecraftArguments)
|
||||
//.setArguments(arguments)
|
||||
);
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, version.setLibraries(libraries)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.optifine;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class OptiFineVersion {
|
||||
|
||||
@SerializedName("dl")
|
||||
private final String downloadLink;
|
||||
|
||||
@SerializedName("ver")
|
||||
private final String version;
|
||||
|
||||
@SerializedName("date")
|
||||
private final String date;
|
||||
|
||||
@SerializedName("type")
|
||||
private final String type;
|
||||
|
||||
@SerializedName("patch")
|
||||
private final String patch;
|
||||
|
||||
@SerializedName("mirror")
|
||||
private final String mirror;
|
||||
|
||||
@SerializedName("mcversion")
|
||||
private final String gameVersion;
|
||||
|
||||
public OptiFineVersion() {
|
||||
this(null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public OptiFineVersion(String downloadLink, String version, String date, String type, String patch, String mirror, String gameVersion) {
|
||||
this.downloadLink = downloadLink;
|
||||
this.version = version;
|
||||
this.date = date;
|
||||
this.type = type;
|
||||
this.patch = patch;
|
||||
this.mirror = mirror;
|
||||
this.gameVersion = gameVersion;
|
||||
}
|
||||
|
||||
public String getDownloadLink() {
|
||||
return downloadLink;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getPatch() {
|
||||
return patch;
|
||||
}
|
||||
|
||||
public String getMirror() {
|
||||
return mirror;
|
||||
}
|
||||
|
||||
public String getGameVersion() {
|
||||
return gameVersion;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.optifine;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class OptiFineVersionList extends VersionList<Void> {
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("OptiFine (.*?) ");
|
||||
public static final OptiFineVersionList INSTANCE = new OptiFineVersionList();
|
||||
|
||||
private OptiFineVersionList() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task refreshAsync(DownloadProvider downloadProvider) {
|
||||
GetTask task = new GetTask(NetworkUtils.toURL("http://optifine.net/downloads"));
|
||||
return new Task() {
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return Collections.singleton(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
versions.clear();
|
||||
|
||||
String html = task.getResult().replace(" ", " ").replace(">", ">").replace("<", "<").replace("<br>", "<br />");
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
Document doc = db.parse(new ByteArrayInputStream(html.getBytes("UTF-8")));
|
||||
Element r = doc.getDocumentElement();
|
||||
NodeList tables = r.getElementsByTagName("table");
|
||||
for (int i = 0; i < tables.getLength(); i++) {
|
||||
Element e = (Element) tables.item(i);
|
||||
if ("downloadTable".equals(e.getAttribute("class"))) {
|
||||
NodeList tr = e.getElementsByTagName("tr");
|
||||
for (int k = 0; k < tr.getLength(); k++) {
|
||||
NodeList downloadLine = ((Element) tr.item(k)).getElementsByTagName("td");
|
||||
String url = null, version = null, gameVersion = null;
|
||||
for (int j = 0; j < downloadLine.getLength(); j++) {
|
||||
Element td = (Element) downloadLine.item(j);
|
||||
if (td.getAttribute("class") != null && td.getAttribute("class").startsWith("downloadLineMirror"))
|
||||
url = ((Element) td.getElementsByTagName("a").item(0)).getAttribute("href");
|
||||
if (td.getAttribute("class") != null && td.getAttribute("class").startsWith("downloadLineFile"))
|
||||
version = td.getTextContent();
|
||||
}
|
||||
Matcher matcher = PATTERN.matcher(version);
|
||||
while (matcher.find())
|
||||
gameVersion = matcher.group(1);
|
||||
if (gameVersion == null || version == null || url == null)
|
||||
continue;
|
||||
versions.put(gameVersion, new RemoteVersion<>(gameVersion, version, url, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
85
HMCLCore/src/main/java/org/jackhuang/hmcl/event/Event.java
Normal file
85
HMCLCore/src/main/java/org/jackhuang/hmcl/event/Event.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class Event extends EventObject {
|
||||
|
||||
public Event(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
private boolean canceled;
|
||||
|
||||
/**
|
||||
* true if this event is canceled.
|
||||
*
|
||||
* @throws UnsupportedOperationException if trying to cancel a non-cancelable event.
|
||||
*/
|
||||
public final boolean isCanceled() {
|
||||
return canceled;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param canceled new value
|
||||
* @throws UnsupportedOperationException if trying to cancel a non-cancelable event.
|
||||
*/
|
||||
public final void setCanceled(boolean canceled) {
|
||||
if (!isCancelable())
|
||||
throw new UnsupportedOperationException("Attempted to cancel a non-cancelable event: " + getClass());
|
||||
this.canceled = canceled;
|
||||
}
|
||||
|
||||
/**
|
||||
* true if this Event this cancelable.
|
||||
*/
|
||||
public boolean isCancelable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasResult() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Result result;
|
||||
|
||||
/**
|
||||
* Retutns the value set as the result of this event
|
||||
*/
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Result result) {
|
||||
if (!hasResult())
|
||||
throw new UnsupportedOperationException("Attempted to set result on a no result event: " + this.getClass() + " of type.");
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public enum Result {
|
||||
DENY,
|
||||
DEFAULT,
|
||||
ALLOW
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
import java.util.HashMap;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class EventBus {
|
||||
|
||||
private final HashMap<Class<?>, EventManager<?>> events = new HashMap<>();
|
||||
|
||||
public <T extends EventObject> EventManager<T> channel(Class<T> clazz) {
|
||||
if (!events.containsKey(clazz))
|
||||
events.put(clazz, new EventManager<>(Schedulers.computation()));
|
||||
return (EventManager<T>) events.get(clazz);
|
||||
}
|
||||
|
||||
public void fireEvent(EventObject obj) {
|
||||
channel((Class<EventObject>) obj.getClass()).fireEvent(obj);
|
||||
}
|
||||
|
||||
public static final EventBus EVENT_BUS = new EventBus();
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashSet;
|
||||
import java.util.function.Consumer;
|
||||
import org.jackhuang.hmcl.task.Scheduler;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.util.SimpleMultimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class EventManager<T extends EventObject> {
|
||||
|
||||
private final Scheduler scheduler;
|
||||
private final SimpleMultimap<EventPriority, Consumer<T>> handlers
|
||||
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new);
|
||||
private final SimpleMultimap<EventPriority, Runnable> handlers2
|
||||
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new);
|
||||
|
||||
public EventManager() {
|
||||
this(Schedulers.immediate());
|
||||
}
|
||||
|
||||
public EventManager(Scheduler scheduler) {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public void register(Consumer<T> consumer) {
|
||||
register(consumer, EventPriority.NORMAL);
|
||||
}
|
||||
|
||||
public void register(Consumer<T> consumer, EventPriority priority) {
|
||||
if (!handlers.get(priority).contains(consumer))
|
||||
handlers.put(priority, consumer);
|
||||
}
|
||||
|
||||
public void register(Runnable runnable) {
|
||||
register(runnable, EventPriority.NORMAL);
|
||||
}
|
||||
|
||||
public void register(Runnable runnable, EventPriority priority) {
|
||||
if (!handlers2.get(priority).contains(runnable))
|
||||
handlers2.put(priority, runnable);
|
||||
}
|
||||
|
||||
public void unregister(Consumer<T> consumer) {
|
||||
handlers.removeValue(consumer);
|
||||
}
|
||||
|
||||
public void unregister(Runnable runnable) {
|
||||
handlers2.removeValue(runnable);
|
||||
}
|
||||
|
||||
public void fireEvent(T event) {
|
||||
scheduler.schedule(() -> {
|
||||
for (EventPriority priority : EventPriority.values()) {
|
||||
for (Consumer<T> handler : handlers.get(priority))
|
||||
handler.accept(event);
|
||||
for (Runnable runnable : handlers2.get(priority))
|
||||
runnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,12 +15,16 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
enum class EventPriority {
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public enum EventPriority {
|
||||
HIGHEST,
|
||||
HIGH,
|
||||
NORMAL,
|
||||
LOW,
|
||||
LOWEST
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public class FailedEvent<T> extends EventObject {
|
||||
|
||||
private final int failedTime;
|
||||
private T newResult;
|
||||
|
||||
public FailedEvent(Object source, int failedTime, T newResult) {
|
||||
super(source);
|
||||
this.failedTime = failedTime;
|
||||
this.newResult = newResult;
|
||||
}
|
||||
|
||||
public int getFailedTime() {
|
||||
return failedTime;
|
||||
}
|
||||
|
||||
public T getNewResult() {
|
||||
return newResult;
|
||||
}
|
||||
|
||||
public void setNewResult(T newResult) {
|
||||
this.newResult = newResult;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,27 +15,30 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import org.jackhuang.hmcl.task.Scheduler
|
||||
import java.util.*
|
||||
import java.util.EventObject;
|
||||
import org.jackhuang.hmcl.util.ManagedProcess;
|
||||
|
||||
class EventBus {
|
||||
private val events = HashMap<Class<*>, EventManager<*>>()
|
||||
/**
|
||||
* This event gets fired when we launch the JVM and it got crashed.
|
||||
* <br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
*
|
||||
* @param source [org.jackhuang.hmcl.launch.ExitWaiter]
|
||||
* @param value the crashed process.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class JVMLaunchFailedEvent extends EventObject {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : EventObject> channel(classOfT: Class<T>): EventManager<T> {
|
||||
if (!events.containsKey(classOfT))
|
||||
events.put(classOfT, EventManager<T>(Scheduler.COMPUTATION))
|
||||
return events[classOfT] as EventManager<T>
|
||||
private final ManagedProcess process;
|
||||
|
||||
public JVMLaunchFailedEvent(Object source, ManagedProcess process) {
|
||||
super(source);
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
inline fun <reified T: EventObject> channel() = channel(T::class.java)
|
||||
|
||||
fun fireEvent(obj: EventObject) {
|
||||
channel(obj.javaClass).fireEvent(obj)
|
||||
public ManagedProcess getProcess() {
|
||||
return process;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val EVENT_BUS = EventBus()
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* This event gets fired when a minecraft version has been loaded.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the version id.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class LoadedOneVersionEvent extends EventObject {
|
||||
|
||||
private final String version;
|
||||
|
||||
public LoadedOneVersionEvent(Object source, String version) {
|
||||
super(source);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
import org.jackhuang.hmcl.util.ManagedProcess;
|
||||
|
||||
/**
|
||||
* This event gets fired when a JavaProcess exited abnormally and the exit code is not zero.
|
||||
* <br></br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param value The process that exited abnormally.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class ProcessExitedAbnormallyEvent extends EventObject {
|
||||
|
||||
private final ManagedProcess process;
|
||||
|
||||
public ProcessExitedAbnormallyEvent(Object source, ManagedProcess process) {
|
||||
super(source);
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
public ManagedProcess getProcess() {
|
||||
return process;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
import org.jackhuang.hmcl.util.ManagedProcess;
|
||||
|
||||
/**
|
||||
* This event gets fired when minecraft process exited successfully and the exit code is 0.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param value minecraft process
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class ProcessStoppedEvent extends EventObject {
|
||||
|
||||
private final ManagedProcess process;
|
||||
|
||||
public ProcessStoppedEvent(Object source, ManagedProcess process) {
|
||||
super(source);
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
public ManagedProcess getProcess() {
|
||||
return process;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* This event gets fired when all the versions in .minecraft folder are loaded.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.api.HMCLApi#EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository]
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class RefreshedVersionsEvent extends EventObject {
|
||||
|
||||
public RefreshedVersionsEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* This event gets fired when loading versions in a .minecraft folder.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class RefreshingVersionsEvent extends EventObject {
|
||||
|
||||
public RefreshingVersionsEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
74
HMCLCore/src/main/java/org/jackhuang/hmcl/game/Argument.java
Normal file
74
HMCLCore/src/main/java/org/jackhuang/hmcl/game/Argument.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public interface Argument extends Cloneable {
|
||||
|
||||
/**
|
||||
* Parse this argument in form: ${key name} or simply a string.
|
||||
*
|
||||
* @param keys the parse map
|
||||
* @param features the map that contains some features such as 'is_demo_user', 'has_custom_resolution'
|
||||
* @return parsed argument element, empty if this argument is ignored and will not be added.
|
||||
*/
|
||||
List<String> toString(Map<String, String> keys, Map<String, Boolean> features);
|
||||
|
||||
public static class Serializer implements JsonDeserializer<Argument>, JsonSerializer<Argument> {
|
||||
|
||||
public static final Serializer INSTANCE = new Serializer();
|
||||
|
||||
private Serializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Argument deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (json.isJsonPrimitive())
|
||||
return new StringArgument(json.getAsString());
|
||||
else
|
||||
return context.deserialize(json, RuledArgument.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Argument src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
if (src instanceof StringArgument)
|
||||
return new JsonPrimitive(((StringArgument) src).getArgument());
|
||||
else if (src instanceof RuledArgument)
|
||||
return context.serialize(src, RuledArgument.class);
|
||||
else
|
||||
throw new AssertionError("Unrecognized argument type: " + src);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
112
HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java
Normal file
112
HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.OperatingSystem;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class Arguments {
|
||||
|
||||
@SerializedName("game")
|
||||
private final List<Argument> game;
|
||||
@SerializedName("jvm")
|
||||
private final List<Argument> jvm;
|
||||
|
||||
public Arguments() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public Arguments(List<Argument> game, List<Argument> jvm) {
|
||||
this.game = game;
|
||||
this.jvm = jvm;
|
||||
}
|
||||
|
||||
public List<Argument> getGame() {
|
||||
return game == null ? Collections.EMPTY_LIST : Collections.unmodifiableList(game);
|
||||
}
|
||||
|
||||
public List<Argument> getJvm() {
|
||||
return jvm == null ? Collections.EMPTY_LIST : Collections.unmodifiableList(jvm);
|
||||
}
|
||||
|
||||
public static Arguments addGameArguments(Arguments arguments, String... gameArguments) {
|
||||
return addGameArguments(arguments, Arrays.asList(gameArguments));
|
||||
}
|
||||
|
||||
public static Arguments addGameArguments(Arguments arguments, List<String> gameArguments) {
|
||||
List<Argument> list = gameArguments.stream().map(StringArgument::new).collect(Collectors.toList());
|
||||
if (arguments == null)
|
||||
return new Arguments(list, null);
|
||||
else
|
||||
return new Arguments(Lang.merge(arguments.getGame(), list), arguments.getJvm());
|
||||
}
|
||||
|
||||
public static Arguments merge(Arguments a, Arguments b) {
|
||||
if (a == null)
|
||||
return b;
|
||||
else if (b == null)
|
||||
return a;
|
||||
else
|
||||
return new Arguments(Lang.merge(a.game, b.game), Lang.merge(a.jvm, b.jvm));
|
||||
}
|
||||
|
||||
public static List<String> parseStringArguments(List<String> arguments, Map<String, String> keys) {
|
||||
return arguments.stream().map(str -> keys.getOrDefault(str, str)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> parseArguments(List<Argument> arguments, Map<String, String> keys) {
|
||||
return parseArguments(arguments, keys, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
public static List<String> parseArguments(List<Argument> arguments, Map<String, String> keys, Map<String, Boolean> features) {
|
||||
return arguments.stream().flatMap(arg -> arg.toString(keys, features).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static final List<Argument> DEFAULT_JVM_ARGUMENTS;
|
||||
public static final List<Argument> DEFAULT_GAME_ARGUMENTS;
|
||||
|
||||
static {
|
||||
List<Argument> jvm = new LinkedList<>();
|
||||
jvm.add(new RuledArgument(Collections.singletonList(new CompatibilityRule(CompatibilityRule.Action.ALLOW, new OSRestriction(OperatingSystem.OSX))), Collections.singletonList("-XstartOnFirstThread")));
|
||||
jvm.add(new RuledArgument(Collections.singletonList(new CompatibilityRule(CompatibilityRule.Action.ALLOW, new OSRestriction(OperatingSystem.WINDOWS))), Collections.singletonList("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump")));
|
||||
jvm.add(new RuledArgument(Collections.singletonList(new CompatibilityRule(CompatibilityRule.Action.ALLOW, new OSRestriction(OperatingSystem.WINDOWS, "^10\\."))), Arrays.asList("-Dos.name=Windows 10", "-Dos.version=10.0")));
|
||||
jvm.add(new StringArgument("-Djava.library.path=${natives_directory}"));
|
||||
jvm.add(new StringArgument("-Dminecraft.launcher.brand=${launcher_name}"));
|
||||
jvm.add(new StringArgument("-Dminecraft.launcher.version=${launcher_version}"));
|
||||
jvm.add(new StringArgument("-cp"));
|
||||
jvm.add(new StringArgument("${classpath}"));
|
||||
DEFAULT_JVM_ARGUMENTS = Collections.unmodifiableList(jvm);
|
||||
|
||||
List<Argument> game = new LinkedList<>();
|
||||
game.add(new RuledArgument(Collections.singletonList(new CompatibilityRule(CompatibilityRule.Action.ALLOW, null, Collections.singletonMap("has_custom_resolution", true))), Arrays.asList("--width", "${resolution_width}", "--height", "${resolution_height}")));
|
||||
DEFAULT_GAME_ARGUMENTS = Collections.unmodifiableList(game);
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,40 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.util.*
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class AssetIndex @JvmOverloads constructor(
|
||||
@SerializedName("virtual")
|
||||
val virtual: Boolean = false,
|
||||
objects: Map<String, AssetObject> = emptyMap()
|
||||
) {
|
||||
val objects: Map<String, AssetObject>
|
||||
get() = Collections.unmodifiableMap(objectsImpl)
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class AssetIndex {
|
||||
|
||||
@SerializedName("virtual")
|
||||
private final boolean virtual;
|
||||
|
||||
@SerializedName("objects")
|
||||
private val objectsImpl: MutableMap<String, AssetObject> = HashMap(objects)
|
||||
}
|
||||
private final Map<String, AssetObject> objects;
|
||||
|
||||
public AssetIndex() {
|
||||
this(false, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
public AssetIndex(boolean virtual, Map<String, AssetObject> objects) {
|
||||
this.virtual = virtual;
|
||||
this.objects = new HashMap<>(objects);
|
||||
}
|
||||
|
||||
public boolean isVirtual() {
|
||||
return virtual;
|
||||
}
|
||||
|
||||
public Map<String, AssetObject> getObjects() {
|
||||
return Collections.unmodifiableMap(objects);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public class AssetIndexInfo extends IdDownloadInfo {
|
||||
|
||||
private final long totalSize;
|
||||
|
||||
public AssetIndexInfo() {
|
||||
this("", "");
|
||||
}
|
||||
|
||||
public AssetIndexInfo(String id, String url) {
|
||||
this(id, url, null);
|
||||
}
|
||||
|
||||
public AssetIndexInfo(String id, String url, String sha1) {
|
||||
this(id, url, sha1, 0);
|
||||
}
|
||||
|
||||
public AssetIndexInfo(String id, String url, String sha1, int size) {
|
||||
this(id, url, sha1, size, 0);
|
||||
}
|
||||
|
||||
public AssetIndexInfo(String id, String url, String sha1, int size, long totalSize) {
|
||||
super(id, url, sha1, size);
|
||||
this.totalSize = totalSize;
|
||||
}
|
||||
|
||||
public long getTotalSize() {
|
||||
return totalSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class AssetObject implements Validation {
|
||||
|
||||
private final String hash;
|
||||
private final long size;
|
||||
|
||||
public AssetObject() {
|
||||
this("", 0);
|
||||
}
|
||||
|
||||
public AssetObject(String hash, long size) {
|
||||
this.hash = hash;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return hash.substring(0, 2) + "/" + hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (StringUtils.isBlank(hash))
|
||||
throw new IllegalStateException("AssetObject hash cannot be blank.");
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,24 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
/**
|
||||
* What's circle dependency?
|
||||
* When C inherits from B, and B inherits from something else, and finally inherits from C again.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
class CircleDependencyException : GameException {
|
||||
constructor() : super() {}
|
||||
constructor(message: String) : super(message) {}
|
||||
constructor(message: String, cause: Throwable) : super(message, cause) {}
|
||||
}
|
||||
public final class CircleDependencyException extends GameException {
|
||||
|
||||
public CircleDependencyException() {
|
||||
}
|
||||
|
||||
public CircleDependencyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CircleDependencyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.mod
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
object ModpackManager {
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public class ClassicLibrary {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* The Minecraft version for 1.5.x and earlier.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class ClassicVersion extends Version {
|
||||
|
||||
public ClassicVersion() {
|
||||
super("Classic", "${auth_player_name} ${auth_session} --workDir ${game_directory}",
|
||||
null, "net.minecraft.client.Minecraft", null, null, null, null,
|
||||
Arrays.asList(new ClassicLibrary("lwjgl"), new ClassicLibrary("jinput"), new ClassicLibrary("lwjgl_util")),
|
||||
null, null, null, ReleaseType.UNKNOWN, new Date(), new Date(), 0);
|
||||
}
|
||||
|
||||
private static class ClassicLibrary extends Library {
|
||||
|
||||
public ClassicLibrary(String name) {
|
||||
super("", "", "", null, null,
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo("bin/" + name + ".jar"), null),
|
||||
false, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasClassicVersion(File baseDirectory) {
|
||||
File bin = new File(baseDirectory, "bin");
|
||||
return bin.exists()
|
||||
&& new File(bin, "lwjgl.jar").exists()
|
||||
&& new File(bin, "jinput.jar").exists()
|
||||
&& new File(bin, "lwjgl_util.jar").exists();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class CompatibilityRule {
|
||||
|
||||
private final Action action;
|
||||
private final OSRestriction os;
|
||||
private final Map<String, Boolean> features;
|
||||
|
||||
public CompatibilityRule() {
|
||||
this(Action.ALLOW, null);
|
||||
}
|
||||
|
||||
public CompatibilityRule(Action action, OSRestriction os) {
|
||||
this(action, os, null);
|
||||
}
|
||||
|
||||
public CompatibilityRule(Action action, OSRestriction os, Map<String, Boolean> features) {
|
||||
this.action = action;
|
||||
this.os = os;
|
||||
this.features = features;
|
||||
}
|
||||
|
||||
public Action getAppliedAction(Map<String, Boolean> supportedFeatures) {
|
||||
if (os != null && !os.allow())
|
||||
return null;
|
||||
|
||||
if (features != null)
|
||||
for (Map.Entry<String, Boolean> entry : features.entrySet())
|
||||
if (!Objects.equals(supportedFeatures.get(entry.getKey()), entry.getValue()))
|
||||
return null;
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
public static boolean appliesToCurrentEnvironment(Collection<CompatibilityRule> rules) {
|
||||
return appliesToCurrentEnvironment(rules, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
public static boolean appliesToCurrentEnvironment(Collection<CompatibilityRule> rules, Map<String, Boolean> features) {
|
||||
if (rules == null)
|
||||
return true;
|
||||
|
||||
Action action = Action.DISALLOW;
|
||||
for (CompatibilityRule rule : rules) {
|
||||
Action thisAction = rule.getAppliedAction(features);
|
||||
if (thisAction != null)
|
||||
action = thisAction;
|
||||
}
|
||||
|
||||
return action == Action.ALLOW;
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
ALLOW,
|
||||
DISALLOW
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import org.jackhuang.hmcl.event.EventBus;
|
||||
import org.jackhuang.hmcl.event.LoadedOneVersionEvent;
|
||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||
import org.jackhuang.hmcl.event.RefreshingVersionsEvent;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
|
||||
/**
|
||||
* An implementation of classic Minecraft game repository.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
private File baseDirectory;
|
||||
protected final Map<String, Version> versions = new TreeMap<>();
|
||||
protected boolean loaded = false;
|
||||
|
||||
public DefaultGameRepository(File baseDirectory) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
public File getBaseDirectory() {
|
||||
return baseDirectory;
|
||||
}
|
||||
|
||||
public void setBaseDirectory(File baseDirectory) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVersion(String id) {
|
||||
return versions.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getVersion(String id) {
|
||||
if (!hasVersion(id))
|
||||
throw new VersionNotFoundException("Version '" + id + "' does not exist.");
|
||||
return versions.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersionCount() {
|
||||
return versions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Version> getVersions() {
|
||||
return versions.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLibraryFile(Version version, Library lib) {
|
||||
return new File(getBaseDirectory(), "libraries/" + lib.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRunDirectory(String id) {
|
||||
return getBaseDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getVersionJar(Version version) {
|
||||
Version v = version.resolve(this);
|
||||
String id = Lang.nonNull(v.getJar(), v.getId());
|
||||
return new File(getVersionRoot(id), id + ".jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getNativeDirectory(String id) {
|
||||
return new File(getVersionRoot(id), id + "-natives");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getVersionRoot(String id) {
|
||||
return new File(getBaseDirectory(), "versions/" + id);
|
||||
}
|
||||
|
||||
public File getVersionJson(String id) {
|
||||
return new File(getVersionRoot(id), id + ".json");
|
||||
}
|
||||
|
||||
public Version readVersionJson(String id) throws IOException, JsonSyntaxException {
|
||||
return readVersionJson(getVersionJson(id));
|
||||
}
|
||||
|
||||
public Version readVersionJson(File file) throws IOException, JsonSyntaxException {
|
||||
return Constants.GSON.fromJson(FileUtils.readText(file), Version.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renameVersion(String from, String to) {
|
||||
try {
|
||||
Version fromVersion = getVersion(from);
|
||||
File fromDir = getVersionRoot(from);
|
||||
File toDir = getVersionRoot(to);
|
||||
if (!fromDir.renameTo(toDir))
|
||||
return false;
|
||||
|
||||
File toJson = new File(toDir, to + ".json");
|
||||
File toJar = new File(toDir, to + ".jar");
|
||||
|
||||
if (!new File(toDir, from + ".json").renameTo(toJson)
|
||||
|| !new File(toDir, from + ".jar").renameTo(toJar)) {
|
||||
// recovery
|
||||
toJson.renameTo(new File(toDir, from + ".json"));
|
||||
toJar.renameTo(new File(toDir, from + ".jar"));
|
||||
toDir.renameTo(fromDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
FileUtils.writeText(toJson, Constants.GSON.toJson(fromVersion.setId(to)));
|
||||
return true;
|
||||
} catch (IOException | JsonSyntaxException | VersionNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeVersionFromDisk(String id) {
|
||||
File file = getVersionRoot(id);
|
||||
if (!file.exists())
|
||||
return true;
|
||||
versions.remove(id);
|
||||
return FileUtils.deleteDirectoryQuietly(file);
|
||||
}
|
||||
|
||||
protected void refreshVersionsImpl() {
|
||||
versions.clear();
|
||||
|
||||
if (ClassicVersion.hasClassicVersion(getBaseDirectory())) {
|
||||
Version version = new ClassicVersion();
|
||||
versions.put(version.getId(), version);
|
||||
}
|
||||
|
||||
File[] files = new File(getBaseDirectory(), "versions").listFiles();
|
||||
if (files != null)
|
||||
for (File dir : files)
|
||||
if (dir.isDirectory()) {
|
||||
String id = dir.getName();
|
||||
File json = new File(dir, id + ".json");
|
||||
|
||||
// If user renamed the json file by mistake or created the json file in a wrong name,
|
||||
// we will find the only json and rename it to correct name.
|
||||
if (!json.exists()) {
|
||||
List<File> jsons = FileUtils.listFilesByExtension(dir, "json");
|
||||
if (jsons.size() == 1)
|
||||
jsons.get(0).renameTo(json);
|
||||
}
|
||||
|
||||
Version version;
|
||||
try {
|
||||
version = Objects.requireNonNull(readVersionJson(json));
|
||||
} catch (Exception e) {
|
||||
// JsonSyntaxException or IOException or NullPointerException(!!)
|
||||
// TODO: auto making up for the missing json
|
||||
// TODO: and even asking for removing the redundant version folder.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!id.equals(version.getId())) {
|
||||
version = version.setId(id);
|
||||
try {
|
||||
FileUtils.writeText(json, Constants.GSON.toJson(version));
|
||||
} catch (Exception e) {
|
||||
Logging.LOG.log(Level.WARNING, "Ignoring version {0} because wrong id {1} is set and cannot correct it.", new Object[] { id, version.getId() });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
versions.put(id, version);
|
||||
EventBus.EVENT_BUS.fireEvent(new LoadedOneVersionEvent(this, id));
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void refreshVersions() {
|
||||
EventBus.EVENT_BUS.fireEvent(new RefreshingVersionsEvent(this));
|
||||
refreshVersionsImpl();
|
||||
EventBus.EVENT_BUS.fireEvent(new RefreshedVersionsEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetIndex getAssetIndex(String version, String assetId) throws IOException {
|
||||
try {
|
||||
return Objects.requireNonNull(Constants.GSON.fromJson(FileUtils.readText(getIndexFile(version, assetId)), AssetIndex.class));
|
||||
} catch (JsonParseException | NullPointerException e) {
|
||||
throw new IOException("Asset index file malformed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getActualAssetDirectory(String version, String assetId) {
|
||||
try {
|
||||
return reconstructAssets(version, assetId);
|
||||
} catch (IOException | JsonParseException e) {
|
||||
Logging.LOG.log(Level.SEVERE, "Unable to reconstruct asset directory", e);
|
||||
return getAssetDirectory(version, assetId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getAssetDirectory(String version, String assetId) {
|
||||
return new File(getBaseDirectory(), "assets");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getAssetObject(String version, String assetId, String name) throws IOException {
|
||||
try {
|
||||
return getAssetObject(version, assetId, getAssetIndex(version, assetId).getObjects().get(name));
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Unrecognized asset object " + name + " in asset " + assetId + " of version " + version, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getAssetObject(String version, String assetId, AssetObject obj) {
|
||||
return getAssetObject(version, getAssetDirectory(version, assetId), obj);
|
||||
}
|
||||
|
||||
public File getAssetObject(String version, File assetDir, AssetObject obj) {
|
||||
return new File(assetDir, "objects/" + obj.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getIndexFile(String version, String assetId) {
|
||||
return new File(getAssetDirectory(version, assetId), "indexes/" + assetId + ".json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLoggingObject(String version, String assetId, LoggingInfo loggingInfo) {
|
||||
return new File(getAssetDirectory(version, assetId), "log_configs/" + loggingInfo.getFile().getId());
|
||||
}
|
||||
|
||||
protected File reconstructAssets(String version, String assetId) throws IOException, JsonParseException {
|
||||
File assetsDir = getAssetDirectory(version, assetId);
|
||||
File indexFile = getIndexFile(version, assetId);
|
||||
File virtualRoot = new File(new File(assetsDir, "virtual"), assetId);
|
||||
|
||||
if (!indexFile.isFile())
|
||||
return assetsDir;
|
||||
|
||||
String assetIndexContent = FileUtils.readText(indexFile);
|
||||
AssetIndex index = (AssetIndex) Constants.GSON.fromJson(assetIndexContent, AssetIndex.class);
|
||||
|
||||
if (index == null)
|
||||
return assetsDir;
|
||||
|
||||
if (index.isVirtual()) {
|
||||
int cnt = 0;
|
||||
int tot = index.getObjects().entrySet().size();
|
||||
for (Map.Entry<String, AssetObject> entry : index.getObjects().entrySet()) {
|
||||
File target = new File(virtualRoot, entry.getKey());
|
||||
File original = getAssetObject(version, assetsDir, entry.getValue());
|
||||
if (original.exists()) {
|
||||
cnt++;
|
||||
if (!target.isFile())
|
||||
FileUtils.copyFile(original, target);
|
||||
}
|
||||
}
|
||||
|
||||
// If the scale new format existent file is lower then 0.1, use the old format.
|
||||
if (cnt * 10 < tot)
|
||||
return assetsDir;
|
||||
else
|
||||
return virtualRoot;
|
||||
}
|
||||
|
||||
return assetsDir;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public class DownloadInfo implements Validation {
|
||||
|
||||
@SerializedName("url")
|
||||
private final String url;
|
||||
@SerializedName("sha1")
|
||||
private final String sha1;
|
||||
@SerializedName("size")
|
||||
private final int size;
|
||||
|
||||
public DownloadInfo() {
|
||||
this("");
|
||||
}
|
||||
|
||||
public DownloadInfo(String url) {
|
||||
this(url, null);
|
||||
}
|
||||
|
||||
public DownloadInfo(String url, String sha1) {
|
||||
this(url, sha1, 0);
|
||||
}
|
||||
|
||||
public DownloadInfo(String url, String sha1, int size) {
|
||||
this.url = url;
|
||||
this.sha1 = sha1;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getSha1() {
|
||||
return sha1;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (StringUtils.isBlank(url))
|
||||
throw new JsonParseException("DownloadInfo url can not be null");
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,14 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
data class Property(val name: String, val value: String)
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public enum DownloadType {
|
||||
CLIENT,
|
||||
SERVER,
|
||||
WINDOWS_SERVER
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class ExtractRules {
|
||||
|
||||
public static final ExtractRules EMPTY = new ExtractRules();
|
||||
|
||||
private final List<String> exclude;
|
||||
|
||||
public ExtractRules() {
|
||||
this.exclude = Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
public ExtractRules(List<String> exclude) {
|
||||
this.exclude = new LinkedList<>(exclude);
|
||||
}
|
||||
|
||||
public List<String> getExclude() {
|
||||
return Collections.unmodifiableList(exclude);
|
||||
}
|
||||
|
||||
public boolean shouldExtract(String path) {
|
||||
return exclude.stream().noneMatch(it -> path.startsWith(it));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class GameException extends Exception {
|
||||
|
||||
public GameException() {
|
||||
}
|
||||
|
||||
public GameException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public GameException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public GameException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -15,42 +15,50 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Supports operations on versioning.
|
||||
*
|
||||
* Note that game repository will not do any tasks that connect to Internet, if do, see [org.jackhuang.hmcl.download.DependencyManager]
|
||||
* Note that game repository will not do any tasks that connect to Internet, if do, see {@link org.jackhuang.hmcl.download.DependencyManager}
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
interface GameRepository : VersionProvider {
|
||||
public interface GameRepository extends VersionProvider {
|
||||
|
||||
/**
|
||||
* Does the version of id exist?
|
||||
*
|
||||
* @param id the id of version
|
||||
* @return true if the version exists
|
||||
*/
|
||||
override fun hasVersion(id: String): Boolean
|
||||
@Override
|
||||
boolean hasVersion(String id);
|
||||
|
||||
/**
|
||||
* Get the version
|
||||
*
|
||||
* @param id the id of version
|
||||
* @return the version you want
|
||||
*/
|
||||
override fun getVersion(id: String): Version
|
||||
@Override
|
||||
Version getVersion(String id);
|
||||
|
||||
/**
|
||||
* How many version are there?
|
||||
*/
|
||||
fun getVersionCount(): Int
|
||||
int getVersionCount();
|
||||
|
||||
/**
|
||||
* Gets the collection of versions
|
||||
*
|
||||
* @return the collection of versions
|
||||
*/
|
||||
fun getVersions(): Collection<Version>
|
||||
Collection<Version> getVersions();
|
||||
|
||||
/**
|
||||
* Load version list.
|
||||
@@ -59,20 +67,21 @@ interface GameRepository : VersionProvider {
|
||||
* A time-costly operation.
|
||||
* You'd better execute this method in a new thread.
|
||||
*/
|
||||
fun refreshVersions()
|
||||
void refreshVersions();
|
||||
|
||||
/**
|
||||
* Gets the root folder of specific version.
|
||||
* The root folders the versions must be unique.
|
||||
* For example, .minecraft/versions/<version name>/.
|
||||
*/
|
||||
fun getVersionRoot(id: String): File
|
||||
File getVersionRoot(String id);
|
||||
|
||||
/**
|
||||
* Gets the current running directory of the given version for game.
|
||||
*
|
||||
* @param id the version id
|
||||
*/
|
||||
fun getRunDirectory(id: String): File
|
||||
File getRunDirectory(String id);
|
||||
|
||||
/**
|
||||
* Get the library file in disk.
|
||||
@@ -82,7 +91,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param lib the library, [Version.libraries]
|
||||
* @return the library file
|
||||
*/
|
||||
fun getLibraryFile(version: Version, lib: Library): File
|
||||
File getLibraryFile(Version version, Library lib);
|
||||
|
||||
/**
|
||||
* Get the directory that native libraries will be unzipped to.
|
||||
@@ -94,7 +103,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param id version id
|
||||
* @return the native directory
|
||||
*/
|
||||
fun getNativeDirectory(id: String): File
|
||||
File getNativeDirectory(String id);
|
||||
|
||||
/**
|
||||
* Get minecraft jar
|
||||
@@ -102,7 +111,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param version resolvedVersion
|
||||
* @return the minecraft jar
|
||||
*/
|
||||
fun getVersionJar(version: Version): File
|
||||
File getVersionJar(Version version);
|
||||
|
||||
/**
|
||||
* Get minecraft jar
|
||||
@@ -110,7 +119,9 @@ interface GameRepository : VersionProvider {
|
||||
* @param version version id
|
||||
* @return the minecraft jar
|
||||
*/
|
||||
fun getVersionJar(version: String): File = getVersionJar(getVersion(version).resolve(this))
|
||||
default File getVersionJar(String version) {
|
||||
return getVersionJar(getVersion(version).resolve(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename given version to new name.
|
||||
@@ -121,7 +132,7 @@ interface GameRepository : VersionProvider {
|
||||
* @throws java.io.IOException if I/O operation fails.
|
||||
* @return true if the operation is done successfully.
|
||||
*/
|
||||
fun renameVersion(from: String, to: String): Boolean
|
||||
boolean renameVersion(String from, String to);
|
||||
|
||||
/**
|
||||
* Get actual asset directory.
|
||||
@@ -133,7 +144,7 @@ interface GameRepository : VersionProvider {
|
||||
* @throws java.io.IOException if I/O operation fails.
|
||||
* @return the actual asset directory
|
||||
*/
|
||||
fun getActualAssetDirectory(version: String, assetId: String): File
|
||||
File getActualAssetDirectory(String version, String assetId);
|
||||
|
||||
/**
|
||||
* Get the asset directory according to the asset id.
|
||||
@@ -142,7 +153,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id]
|
||||
* @return the asset directory
|
||||
*/
|
||||
fun getAssetDirectory(version: String, assetId: String): File
|
||||
File getAssetDirectory(String version, String assetId);
|
||||
|
||||
/**
|
||||
* Get the file that given asset object refers to
|
||||
@@ -153,8 +164,7 @@ interface GameRepository : VersionProvider {
|
||||
* @throws java.io.IOException if I/O operation fails.
|
||||
* @return the file that given asset object refers to
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun getAssetObject(version: String, assetId: String, name: String): File
|
||||
File getAssetObject(String version, String assetId, String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the file that given asset object refers to
|
||||
@@ -164,7 +174,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param obj the asset object, you can find it in [AssetIndex.objects]
|
||||
* @return the file that given asset object refers to
|
||||
*/
|
||||
fun getAssetObject(version: String, assetId: String, obj: AssetObject): File
|
||||
File getAssetObject(String version, String assetId, AssetObject obj);
|
||||
|
||||
/**
|
||||
* Get asset index that assetId represents
|
||||
@@ -173,7 +183,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id]
|
||||
* @return the asset index
|
||||
*/
|
||||
fun getAssetIndex(version: String, assetId: String): AssetIndex
|
||||
AssetIndex getAssetIndex(String version, String assetId) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the asset_index.json which includes asset objects information.
|
||||
@@ -181,7 +191,7 @@ interface GameRepository : VersionProvider {
|
||||
* @param version the id of specific version that is relevant to [assetId]
|
||||
* @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id]
|
||||
*/
|
||||
fun getIndexFile(version: String, assetId: String): File
|
||||
File getIndexFile(String version, String assetId);
|
||||
|
||||
/**
|
||||
* Get logging object
|
||||
@@ -191,6 +201,6 @@ interface GameRepository : VersionProvider {
|
||||
* @param loggingInfo the logging info
|
||||
* @return the file that loggingInfo refers to
|
||||
*/
|
||||
fun getLoggingObject(version: String, assetId: String, loggingInfo: LoggingInfo): File
|
||||
File getLoggingObject(String version, String assetId, LoggingInfo loggingInfo);
|
||||
|
||||
}
|
||||
}
|
||||
129
HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java
Normal file
129
HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.jackhuang.hmcl.util.Charsets;
|
||||
import org.jackhuang.hmcl.util.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class GameVersion {
|
||||
private static int lessThan32(byte[] b, int x) {
|
||||
for (; x < b.length; x++)
|
||||
if (b[x] < 32)
|
||||
return x;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int matchArray(byte[] a, byte[] b) {
|
||||
for (int i = 0; i < a.length - b.length; i++) {
|
||||
int j = 1;
|
||||
for (int k = 0; k < b.length; k++) {
|
||||
if (b[k] == a[(i + k)])
|
||||
continue;
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
if (j != 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static String getVersionOfOldMinecraft(ZipFile file, ZipArchiveEntry entry) throws IOException {
|
||||
byte[] tmp = IOUtils.readFullyAsByteArray(file.getInputStream(entry));
|
||||
|
||||
byte[] bytes = "Minecraft Minecraft ".getBytes(Charsets.US_ASCII);
|
||||
int j = matchArray(tmp, bytes);
|
||||
if (j < 0)
|
||||
return null;
|
||||
int i = j + bytes.length;
|
||||
|
||||
if ((j = lessThan32(tmp, i)) < 0)
|
||||
return null;
|
||||
|
||||
return new String(tmp, i, j - i, Charsets.US_ASCII);
|
||||
}
|
||||
|
||||
private static String getVersionOfNewMinecraft(ZipFile file, ZipArchiveEntry entry) throws IOException {
|
||||
byte[] tmp = IOUtils.readFullyAsByteArray(file.getInputStream(entry));
|
||||
|
||||
byte[] str = "-server.txt".getBytes(Charsets.US_ASCII);
|
||||
int j = matchArray(tmp, str);
|
||||
if (j < 0) return null;
|
||||
int i = j + str.length;
|
||||
i += 11;
|
||||
j = lessThan32(tmp, i);
|
||||
if (j < 0) return null;
|
||||
String result = new String(tmp, i, j - i, Charsets.US_ASCII);
|
||||
|
||||
char ch = result.charAt(0);
|
||||
// 1.8.1+
|
||||
if (ch < '0' || ch > '9') {
|
||||
str = "Can't keep up! Did the system time change, or is the server overloaded?".getBytes(Charsets.US_ASCII);
|
||||
j = matchArray(tmp, str);
|
||||
if (j < 0) return null;
|
||||
i = -1;
|
||||
while (j > 0) {
|
||||
if (tmp[j] >= 48 && tmp[j] <= 57) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
j--;
|
||||
}
|
||||
if (i == -1) return null;
|
||||
int k = i;
|
||||
if (tmp[i + 1] >= (int) 'a' && tmp[i + 1] <= (int) 'z')
|
||||
i++;
|
||||
while (tmp[k] >= 48 && tmp[k] <= 57 || tmp[k] == (int) '-' || tmp[k] == (int) '.' || tmp[k] >= 97 && tmp[k] <= (int) 'z')
|
||||
k--;
|
||||
k++;
|
||||
return new String(tmp, k, i - k + 1, Charsets.US_ASCII);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String minecraftVersion(File file) {
|
||||
if (file == null || !file.exists() || !file.isFile() || !file.canRead())
|
||||
return null;
|
||||
|
||||
ZipFile f = null;
|
||||
try {
|
||||
f = new ZipFile(file);
|
||||
ZipArchiveEntry minecraft = f
|
||||
.getEntry("net/minecraft/client/Minecraft.class");
|
||||
if (minecraft != null)
|
||||
return getVersionOfOldMinecraft(f, minecraft);
|
||||
ZipArchiveEntry main = f.getEntry("net/minecraft/client/main/Main.class");
|
||||
ZipArchiveEntry minecraftserver = f.getEntry("net/minecraft/server/MinecraftServer.class");
|
||||
if ((main != null) && (minecraftserver != null))
|
||||
return getVersionOfNewMinecraft(f, minecraftserver);
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public class IdDownloadInfo extends DownloadInfo {
|
||||
|
||||
@SerializedName("id")
|
||||
private final String id;
|
||||
|
||||
public IdDownloadInfo() {
|
||||
this("", "");
|
||||
}
|
||||
|
||||
public IdDownloadInfo(String id, String url) {
|
||||
this(id, url, null);
|
||||
}
|
||||
|
||||
public IdDownloadInfo(String id, String url, String sha1) {
|
||||
this(id, url, sha1, 0);
|
||||
}
|
||||
|
||||
public IdDownloadInfo(String id, String url, String sha1, int size) {
|
||||
super(url, sha1, size);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
super.validate();
|
||||
|
||||
if (StringUtils.isBlank(id))
|
||||
throw new JsonParseException("IdDownloadInfo id can not be null");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import org.jackhuang.hmcl.util.JavaVersion;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class LaunchOptions implements Serializable {
|
||||
|
||||
private File gameDir;
|
||||
private JavaVersion java;
|
||||
private String versionName;
|
||||
private String profileName;
|
||||
private String minecraftArgs;
|
||||
private String javaArgs;
|
||||
private Integer minMemory;
|
||||
private Integer maxMemory;
|
||||
private Integer metaspace;
|
||||
private Integer width;
|
||||
private Integer height;
|
||||
private boolean fullscreen;
|
||||
private String serverIp;
|
||||
private String wrapper;
|
||||
private String proxyHost;
|
||||
private String proxyPort;
|
||||
private String proxyUser;
|
||||
private String proxyPass;
|
||||
private boolean noGeneratedJVMArgs;
|
||||
private String precalledCommand;
|
||||
|
||||
/**
|
||||
* The game directory
|
||||
*/
|
||||
public File getGameDir() {
|
||||
return gameDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Java Environment that Minecraft runs on.
|
||||
*/
|
||||
public JavaVersion getJava() {
|
||||
return java;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will shown in the left bottom corner of the main menu of Minecraft.
|
||||
* null if use the id of launch version.
|
||||
*/
|
||||
public String getVersionName() {
|
||||
return versionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't know what the hell this is.
|
||||
*/
|
||||
public String getProfileName() {
|
||||
return profileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* User custom additional minecraft command line arguments.
|
||||
*/
|
||||
public String getMinecraftArgs() {
|
||||
return minecraftArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* User custom additional java virtual machine command line arguments.
|
||||
*/
|
||||
public String getJavaArgs() {
|
||||
return javaArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum memory that the JVM can allocate.
|
||||
*/
|
||||
public Integer getMinMemory() {
|
||||
return minMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum memory that the JVM can allocate.
|
||||
*/
|
||||
public Integer getMaxMemory() {
|
||||
return maxMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum metaspace memory that the JVM can allocate.
|
||||
* For Java 7 -XX:PermSize and Java 8 -XX:MetaspaceSize
|
||||
* Containing class instances.
|
||||
*/
|
||||
public Integer getMetaspace() {
|
||||
return metaspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial game window width
|
||||
*/
|
||||
public Integer getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial game window height
|
||||
*/
|
||||
public Integer getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is inital game window fullscreen.
|
||||
*/
|
||||
public boolean isFullscreen() {
|
||||
return fullscreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* The server ip that will connect to when enter game main menu.
|
||||
*/
|
||||
public String getServerIp() {
|
||||
return serverIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* i.e. optirun
|
||||
*/
|
||||
public String getWrapper() {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* The host of the proxy address
|
||||
*/
|
||||
public String getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* the port of the proxy address.
|
||||
*/
|
||||
public String getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user name of the proxy, optional.
|
||||
*/
|
||||
public String getProxyUser() {
|
||||
return proxyUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* The password of the proxy, optional
|
||||
*/
|
||||
public String getProxyPass() {
|
||||
return proxyPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent game launcher from generating default JVM arguments like max memory.
|
||||
*/
|
||||
public boolean isNoGeneratedJVMArgs() {
|
||||
return noGeneratedJVMArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called command line before launching the game.
|
||||
*/
|
||||
public String getPrecalledCommand() {
|
||||
return precalledCommand;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
LaunchOptions options = new LaunchOptions();
|
||||
|
||||
public LaunchOptions create() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public Builder setGameDir(File gameDir) {
|
||||
options.gameDir = gameDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJava(JavaVersion java) {
|
||||
options.java = java;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVersionName(String versionName) {
|
||||
options.versionName = versionName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProfileName(String profileName) {
|
||||
options.profileName = profileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinecraftArgs(String minecraftArgs) {
|
||||
options.minecraftArgs = minecraftArgs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJavaArgs(String javaArgs) {
|
||||
options.javaArgs = javaArgs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinMemory(Integer minMemory) {
|
||||
options.minMemory = minMemory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMaxMemory(Integer maxMemory) {
|
||||
options.maxMemory = maxMemory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMetaspace(Integer metaspace) {
|
||||
options.metaspace = metaspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWidth(Integer width) {
|
||||
options.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHeight(Integer height) {
|
||||
options.height = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFullscreen(boolean fullscreen) {
|
||||
options.fullscreen = fullscreen;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setServerIp(String serverIp) {
|
||||
options.serverIp = serverIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWrapper(String wrapper) {
|
||||
options.wrapper = wrapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProxyHost(String proxyHost) {
|
||||
options.proxyHost = proxyHost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProxyPort(String proxyPort) {
|
||||
options.proxyPort = proxyPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProxyUser(String proxyUser) {
|
||||
options.proxyUser = proxyUser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProxyPass(String proxyPass) {
|
||||
options.proxyPass = proxyPass;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNoGeneratedJVMArgs(boolean noGeneratedJVMArgs) {
|
||||
options.noGeneratedJVMArgs = noGeneratedJVMArgs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPrecalledCommand(String precalledCommand) {
|
||||
options.precalledCommand = precalledCommand;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class LibrariesDownloadInfo {
|
||||
|
||||
private final LibraryDownloadInfo artifact;
|
||||
private final Map<String, LibraryDownloadInfo> classifiers;
|
||||
|
||||
public LibrariesDownloadInfo(LibraryDownloadInfo artifact) {
|
||||
this(artifact, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
public LibrariesDownloadInfo(LibraryDownloadInfo artifact, Map<String, LibraryDownloadInfo> classifiers) {
|
||||
this.artifact = artifact;
|
||||
this.classifiers = new HashMap<>(classifiers);
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo getArtifact() {
|
||||
return artifact;
|
||||
}
|
||||
|
||||
public Map<String, LibraryDownloadInfo> getClassifiers() {
|
||||
return classifiers == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(classifiers);
|
||||
}
|
||||
|
||||
}
|
||||
203
HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java
Normal file
203
HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.Platform;
|
||||
|
||||
/**
|
||||
* A class that describes a Minecraft dependency.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class Library {
|
||||
|
||||
private final String groupId;
|
||||
private final String artifactId;
|
||||
private final String version;
|
||||
private final String classifier;
|
||||
private final String url;
|
||||
private final LibrariesDownloadInfo downloads;
|
||||
private final LibraryDownloadInfo download;
|
||||
private final ExtractRules extract;
|
||||
private final boolean lateload;
|
||||
private final Map<OperatingSystem, String> natives;
|
||||
private final List<CompatibilityRule> rules;
|
||||
|
||||
private final String path;
|
||||
|
||||
public Library(String groupId, String artifactId, String version) {
|
||||
this(groupId, artifactId, version, null, null, null);
|
||||
}
|
||||
|
||||
public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads) {
|
||||
this(groupId, artifactId, version, classifier, url, downloads, false);
|
||||
}
|
||||
|
||||
public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads, boolean lateload) {
|
||||
this(groupId, artifactId, version, classifier, url, downloads, lateload, null, null, null);
|
||||
}
|
||||
|
||||
public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads, boolean lateload, ExtractRules extract, Map<OperatingSystem, String> natives, List<CompatibilityRule> rules) {
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
if (classifier == null)
|
||||
if (natives != null && natives.containsKey(OperatingSystem.CURRENT_OS))
|
||||
this.classifier = natives.get(OperatingSystem.CURRENT_OS).replace("${arch}", Platform.PLATFORM.getBit());
|
||||
else
|
||||
this.classifier = null;
|
||||
else
|
||||
this.classifier = classifier;
|
||||
this.url = url;
|
||||
this.downloads = downloads;
|
||||
this.extract = extract;
|
||||
this.lateload = lateload;
|
||||
this.natives = natives;
|
||||
this.rules = rules;
|
||||
|
||||
LibraryDownloadInfo temp = null;
|
||||
if (downloads != null)
|
||||
if (isNative())
|
||||
temp = downloads.getClassifiers().get(this.classifier);
|
||||
else
|
||||
temp = downloads.getArtifact();
|
||||
|
||||
if (temp != null && temp.getPath() != null)
|
||||
path = temp.getPath();
|
||||
else
|
||||
path = String.format("%s/%s/%s/%s-%s", groupId.replace(".", "/"), artifactId, version, artifactId, version)
|
||||
+ (this.classifier == null ? "" : "-" + this.classifier) + ".jar";
|
||||
|
||||
download = new LibraryDownloadInfo(path,
|
||||
Lang.nonNull(Lang.nonNull(temp != null ? temp.getUrl() : null), Lang.nonNull(url, Constants.DEFAULT_LIBRARY_URL) + path),
|
||||
temp != null ? temp.getSha1() : null,
|
||||
temp != null ? temp.getSize() : 0
|
||||
);
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public String getArtifactId() {
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public ExtractRules getExtract() {
|
||||
return extract == null ? ExtractRules.EMPTY : extract;
|
||||
}
|
||||
|
||||
public boolean appliesToCurrentEnvironment() {
|
||||
return CompatibilityRule.appliesToCurrentEnvironment(rules);
|
||||
}
|
||||
|
||||
public boolean isNative() {
|
||||
return natives != null && appliesToCurrentEnvironment();
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo getDownload() {
|
||||
return download;
|
||||
}
|
||||
|
||||
public boolean isLateload() {
|
||||
return lateload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Library[" + groupId + ":" + artifactId + ":" + version + "]";
|
||||
}
|
||||
|
||||
public static Library fromName(String name) {
|
||||
return fromName(name, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public static Library fromName(String name, String url, LibrariesDownloadInfo downloads, ExtractRules extract, Map<OperatingSystem, String> natives, List<CompatibilityRule> rules) {
|
||||
String[] arr = name.split(":", 4);
|
||||
if (arr.length != 3 && arr.length != 4)
|
||||
throw new IllegalArgumentException("Library name is malformed. Correct example: group:artifact:version(:classifier).");
|
||||
|
||||
return new Library(arr[0].replace("\\", "/"), arr[1], arr[2], arr.length >= 4 ? arr[3] : null, url, downloads, false, extract, natives, rules);
|
||||
}
|
||||
|
||||
public static class Serializer implements JsonDeserializer<Library>, JsonSerializer<Library> {
|
||||
|
||||
public static final Serializer INSTANCE = new Serializer();
|
||||
|
||||
private Serializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Library deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (json == null || json == JsonNull.INSTANCE)
|
||||
return null;
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
if (!jsonObject.has("name"))
|
||||
throw new JsonParseException("Library name not found.");
|
||||
return fromName(
|
||||
jsonObject.get("name").getAsString(),
|
||||
jsonObject.has("url") ? jsonObject.get("url").getAsString() : null,
|
||||
context.deserialize(jsonObject.get("downloads"), LibrariesDownloadInfo.class),
|
||||
context.deserialize(jsonObject.get("extract"), ExtractRules.class),
|
||||
context.deserialize(jsonObject.get("natives"), new TypeToken<Map<OperatingSystem, String>>() {
|
||||
}.getType()),
|
||||
context.deserialize(jsonObject.get("rules"), new TypeToken<List<CompatibilityRule>>() {
|
||||
}.getType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Library src, Type type, JsonSerializationContext context) {
|
||||
if (src == null)
|
||||
return JsonNull.INSTANCE;
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("name", src.groupId + ":" + src.artifactId + ":" + src.version);
|
||||
obj.addProperty("url", src.url);
|
||||
obj.add("downloads", context.serialize(src.downloads));
|
||||
obj.add("extract", context.serialize(src.extract));
|
||||
obj.add("natives", context.serialize(src.natives, new TypeToken<Map<OperatingSystem, String>>() {
|
||||
}.getType()));
|
||||
obj.add("rules", context.serialize(src.rules, new TypeToken<List<CompatibilityRule>>() {
|
||||
}.getType()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public class LibraryDownloadInfo extends DownloadInfo {
|
||||
|
||||
@SerializedName("path")
|
||||
private final String path;
|
||||
|
||||
public LibraryDownloadInfo() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo(String path) {
|
||||
this(path, "");
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo(String path, String url) {
|
||||
this(path, url, null);
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo(String path, String url, String sha1) {
|
||||
this(path, url, sha1, 0);
|
||||
}
|
||||
|
||||
public LibraryDownloadInfo(String path, String url, String sha1, int size) {
|
||||
super(url, sha1, size);
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class LoggingInfo implements Validation {
|
||||
|
||||
@SerializedName("file")
|
||||
private final IdDownloadInfo file;
|
||||
@SerializedName("argument")
|
||||
private final String argument;
|
||||
@SerializedName("type")
|
||||
private final String type;
|
||||
|
||||
public LoggingInfo() {
|
||||
this(new IdDownloadInfo());
|
||||
}
|
||||
|
||||
public LoggingInfo(IdDownloadInfo file) {
|
||||
this(file, "");
|
||||
}
|
||||
|
||||
public LoggingInfo(IdDownloadInfo file, String argument) {
|
||||
this(file, argument, "");
|
||||
}
|
||||
|
||||
public LoggingInfo(IdDownloadInfo file, String argument, String type) {
|
||||
this.file = file;
|
||||
this.argument = argument;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public IdDownloadInfo getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public String getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
file.validate();
|
||||
if (StringUtils.isBlank(argument))
|
||||
throw new JsonParseException("LoggingInfo.argument is empty.");
|
||||
if (StringUtils.isBlank(type))
|
||||
throw new JsonParseException("LoggingInfo.type is empty.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.OperatingSystem;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class OSRestriction {
|
||||
|
||||
private final OperatingSystem name;
|
||||
private final String version;
|
||||
private final String arch;
|
||||
|
||||
public OSRestriction() {
|
||||
this(OperatingSystem.UNKNOWN);
|
||||
}
|
||||
|
||||
public OSRestriction(OperatingSystem name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public OSRestriction(OperatingSystem name, String version) {
|
||||
this(name, version, null);
|
||||
}
|
||||
|
||||
public OSRestriction(OperatingSystem name, String version, String arch) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public OperatingSystem getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public boolean allow() {
|
||||
if (name != OperatingSystem.UNKNOWN && name != OperatingSystem.CURRENT_OS)
|
||||
return false;
|
||||
|
||||
if (version != null)
|
||||
if (Lang.test(() -> !Pattern.compile(version).matcher(OperatingSystem.SYSTEM_VERSION).matches()))
|
||||
return false;
|
||||
|
||||
if (arch != null)
|
||||
if (Lang.test(() -> !Pattern.compile(arch).matcher(OperatingSystem.SYSTEM_ARCHITECTURE).matches()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,21 +15,28 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
enum class ReleaseType(val id: String) {
|
||||
@SerializedName("release")
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public enum ReleaseType {
|
||||
RELEASE("release"),
|
||||
@SerializedName("snapshot")
|
||||
SNAPSHOT("snapshot"),
|
||||
@SerializedName("modified")
|
||||
MODIFIED("modified"),
|
||||
@SerializedName("old-beta")
|
||||
OLD_BETA("old-beta"),
|
||||
@SerializedName("old-alpha")
|
||||
OLD_ALPHA("old-alpha"),
|
||||
@SerializedName("unknown")
|
||||
UNKNOWN("unknown")
|
||||
}
|
||||
UNKNOWN("unknown");
|
||||
|
||||
private final String id;
|
||||
|
||||
private ReleaseType(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public class RuledArgument implements Argument {
|
||||
|
||||
private final List<CompatibilityRule> rules;
|
||||
private final List<String> value;
|
||||
|
||||
public RuledArgument() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public RuledArgument(List<CompatibilityRule> rules, List<String> args) {
|
||||
this.rules = rules;
|
||||
this.value = args;
|
||||
}
|
||||
|
||||
public List<CompatibilityRule> getRules() {
|
||||
return Collections.unmodifiableList(rules);
|
||||
}
|
||||
|
||||
public List<String> getValue() {
|
||||
return Collections.unmodifiableList(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new RuledArgument(
|
||||
rules == null ? null : new ArrayList<>(rules),
|
||||
value == null ? null : new ArrayList<>(value)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> toString(Map<String, String> keys, Map<String, Boolean> features) {
|
||||
if (CompatibilityRule.appliesToCurrentEnvironment(rules) && value != null)
|
||||
return value.stream()
|
||||
.map(StringArgument::new)
|
||||
.map(str -> str.toString(keys, features).get(0))
|
||||
.collect(Collectors.toList());
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
public static class Serializer implements JsonSerializer<RuledArgument>, JsonDeserializer<RuledArgument> {
|
||||
|
||||
public static final Serializer INSTANCE = new Serializer();
|
||||
|
||||
private Serializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(RuledArgument src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.add("rules", context.serialize(src.rules));
|
||||
obj.add("value", context.serialize(src.value));
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuledArgument deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
RuledArgument a = new RuledArgument(
|
||||
context.deserialize(obj.get("rules"), new TypeToken<List<CompatibilityRule>>() {
|
||||
}.getType()),
|
||||
obj.get("value").isJsonPrimitive()
|
||||
? Collections.singletonList(obj.get("value").getAsString())
|
||||
: context.deserialize(obj.get("value"), new TypeToken<List<String>>() {
|
||||
}.getType()));
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class SimpleVersionProvider implements VersionProvider {
|
||||
|
||||
protected final Map<String, Version> versionMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean hasVersion(String id) {
|
||||
return versionMap.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getVersion(String id) {
|
||||
if (!hasVersion(id))
|
||||
throw new VersionNotFoundException("Version id " + id + " not found");
|
||||
else
|
||||
return versionMap.get(id);
|
||||
}
|
||||
|
||||
public void addVersion(Version version) {
|
||||
versionMap.put(version.getId(), version);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.hmcl.game;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class StringArgument implements Argument {
|
||||
|
||||
private final String argument;
|
||||
|
||||
public StringArgument(String argument) {
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public String getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> toString(Map<String, String> keys, Map<String, Boolean> features) {
|
||||
String res = argument;
|
||||
Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
|
||||
Matcher m = pattern.matcher(argument);
|
||||
while (m.find()) {
|
||||
String entry = m.group();
|
||||
res = res.replace(entry, keys.getOrDefault(entry, entry));
|
||||
}
|
||||
return Collections.singletonList(res);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user