mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-26 03:42:55 +00:00
Refactor existing code
This commit is contained in:
parent
7925d1cda3
commit
8b5f7dd06f
3
src/main/java/META-INF/MANIFEST.MF
Normal file
3
src/main/java/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: emu.grasscutter.Grasscutter
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
package emu.grasscutter;
|
package emu.grasscutter;
|
||||||
|
|
||||||
public class Config {
|
public final class Config {
|
||||||
public String DispatchServerIp = "127.0.0.1";
|
public String DispatchServerIp = "127.0.0.1";
|
||||||
public int DispatchServerPort = 443;
|
public int DispatchServerPort = 443;
|
||||||
public String DispatchServerKeystorePath = "./keystore.p12";
|
public String DispatchServerKeystorePath = "./keystore.p12";
|
||||||
@ -31,14 +31,14 @@ public class Config {
|
|||||||
return ServerOptions;
|
return ServerOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameRates {
|
public static class GameRates {
|
||||||
public float ADVENTURE_EXP_RATE = 1.0f;
|
public float ADVENTURE_EXP_RATE = 1.0f;
|
||||||
public float MORA_RATE = 1.0f;
|
public float MORA_RATE = 1.0f;
|
||||||
public float DOMAIN_DROP_RATE = 1.0f;
|
public float DOMAIN_DROP_RATE = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ServerOptions {
|
public static class ServerOptions {
|
||||||
public int MaxEntityLimit = 1000; // Max entity limit per world. TODO Unenforced for now
|
public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later.
|
||||||
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
||||||
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@ package emu.grasscutter;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.OpenState;
|
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
public class GenshinConstants {
|
public final class GenshinConstants {
|
||||||
public static String VERSION = "2.6.0";
|
public static String VERSION = "2.6.0";
|
||||||
|
|
||||||
public static final int MAX_TEAMS = 4;
|
public static final int MAX_TEAMS = 4;
|
||||||
@ -25,9 +24,9 @@ public class GenshinConstants {
|
|||||||
public static final int MAX_FRIENDS = 45;
|
public static final int MAX_FRIENDS = 45;
|
||||||
public static final int MAX_FRIEND_REQUESTS = 50;
|
public static final int MAX_FRIEND_REQUESTS = 50;
|
||||||
|
|
||||||
public static final int SERVER_CONSOLE_UID = 99; // uid of the fake player used for commands
|
public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player".
|
||||||
|
|
||||||
// Default entity ability hashes
|
// Default entity ability hashes.
|
||||||
public static final String[] DEFAULT_ABILITY_STRINGS = {
|
public static final String[] DEFAULT_ABILITY_STRINGS = {
|
||||||
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
|
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
|
||||||
"Avatar_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener"
|
"Avatar_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener"
|
||||||
|
@ -6,8 +6,8 @@ import java.io.FileReader;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@ -22,19 +22,25 @@ import emu.grasscutter.server.game.GameServer;
|
|||||||
import emu.grasscutter.tools.Tools;
|
import emu.grasscutter.tools.Tools;
|
||||||
import emu.grasscutter.utils.Crypto;
|
import emu.grasscutter.utils.Crypto;
|
||||||
|
|
||||||
public class Grasscutter {
|
public final class Grasscutter {
|
||||||
private static Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
private static final Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
||||||
private static Config config;
|
private static Config config;
|
||||||
|
|
||||||
private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
private static File configFile = new File("./config.json");
|
private static final File configFile = new File("./config.json");
|
||||||
|
|
||||||
public static RunMode MODE = RunMode.BOTH;
|
public static RunMode MODE = RunMode.BOTH;
|
||||||
private static DispatchServer dispatchServer;
|
private static DispatchServer dispatchServer;
|
||||||
private static GameServer gameServer;
|
private static GameServer gameServer;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Load configuration.
|
||||||
|
Grasscutter.loadConfig();
|
||||||
|
// Check server structure.
|
||||||
|
Utils.startupCheck();
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Grasscutter.loadConfig();
|
|
||||||
Crypto.loadKeys();
|
Crypto.loadKeys();
|
||||||
|
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
@ -48,29 +54,61 @@ public class Grasscutter {
|
|||||||
case "-handbook":
|
case "-handbook":
|
||||||
Tools.createGmHandbook();
|
Tools.createGmHandbook();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Startup
|
// Initialize server.
|
||||||
Grasscutter.getLogger().info("Grasscutter Emu");
|
Grasscutter.getLogger().info("Starting Grasscutter...");
|
||||||
|
|
||||||
// Load resource files
|
// Load all resources.
|
||||||
ResourceLoader.loadAll();
|
ResourceLoader.loadAll();
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
DatabaseManager.initialize();
|
DatabaseManager.initialize();
|
||||||
|
|
||||||
// Run servers
|
// Start servers.
|
||||||
dispatchServer = new DispatchServer();
|
dispatchServer = new DispatchServer();
|
||||||
dispatchServer.start();
|
dispatchServer.start();
|
||||||
|
|
||||||
gameServer = new GameServer(new InetSocketAddress(getConfig().GameServerIp, getConfig().GameServerPort));
|
gameServer = new GameServer(new InetSocketAddress(getConfig().GameServerIp, getConfig().GameServerPort));
|
||||||
gameServer.start();
|
gameServer.start();
|
||||||
|
|
||||||
|
// Open console.
|
||||||
startConsole();
|
startConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void loadConfig() {
|
||||||
|
try (FileReader file = new FileReader(configFile)) {
|
||||||
|
config = gson.fromJson(file, Config.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.config = new Config(); saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveConfig() {
|
||||||
|
try (FileWriter file = new FileWriter(configFile)) {
|
||||||
|
file.write(gson.toJson(config));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.getLogger().error("Config save error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startConsole() {
|
||||||
|
String input;
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
|
||||||
|
while ((input = br.readLine()) != null) {
|
||||||
|
ServerCommands.handle(input);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.getLogger().error("An error occurred.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RunMode {
|
||||||
|
BOTH,
|
||||||
|
AUTH,
|
||||||
|
GAME
|
||||||
|
}
|
||||||
|
|
||||||
public static Config getConfig() {
|
public static Config getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@ -90,38 +128,4 @@ public class Grasscutter {
|
|||||||
public static GameServer getGameServer() {
|
public static GameServer getGameServer() {
|
||||||
return gameServer;
|
return gameServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadConfig() {
|
|
||||||
try (FileReader file = new FileReader(configFile)) {
|
|
||||||
config = gson.fromJson(file, Config.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Grasscutter.config = new Config();
|
|
||||||
}
|
|
||||||
saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void saveConfig() {
|
|
||||||
try (FileWriter file = new FileWriter(configFile)) {
|
|
||||||
file.write(gson.toJson(config));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Grasscutter.getLogger().error("Config save error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void startConsole() {
|
|
||||||
String input;
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
|
|
||||||
while ((input = br.readLine()) != null) {
|
|
||||||
ServerCommands.handle(input);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Grasscutter.getLogger().error("Console error:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum RunMode {
|
|
||||||
BOTH,
|
|
||||||
AUTH,
|
|
||||||
GAME
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface Command {
|
public @interface Command {
|
||||||
public String[] aliases() default "";
|
String[] aliases() default "";
|
||||||
|
|
||||||
public int gmLevel() default 1;
|
int gmLevel() default 1;
|
||||||
|
|
||||||
public String helpText() default "";
|
String helpText() default "";
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package emu.grasscutter.database;
|
package emu.grasscutter.database;
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import com.mongodb.MongoClient;
|
import com.mongodb.MongoClient;
|
||||||
import com.mongodb.MongoClientURI;
|
import com.mongodb.MongoClientURI;
|
||||||
import com.mongodb.MongoCommandException;
|
import com.mongodb.MongoCommandException;
|
||||||
@ -18,12 +15,11 @@ import emu.grasscutter.game.avatar.GenshinAvatar;
|
|||||||
import emu.grasscutter.game.friends.Friendship;
|
import emu.grasscutter.game.friends.Friendship;
|
||||||
import emu.grasscutter.game.inventory.GenshinItem;
|
import emu.grasscutter.game.inventory.GenshinItem;
|
||||||
|
|
||||||
public class DatabaseManager {
|
public final class DatabaseManager {
|
||||||
private static MongoClient mongoClient;
|
private static MongoClient mongoClient;
|
||||||
private static Morphia morphia;
|
|
||||||
private static Datastore datastore;
|
private static Datastore datastore;
|
||||||
|
|
||||||
private static Class<?>[] mappedClasses = new Class<?>[] {
|
private static final Class<?>[] mappedClasses = new Class<?>[] {
|
||||||
DatabaseCounter.class, Account.class, GenshinPlayer.class, GenshinAvatar.class, GenshinItem.class, Friendship.class
|
DatabaseCounter.class, Account.class, GenshinPlayer.class, GenshinAvatar.class, GenshinItem.class, Friendship.class
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,14 +35,10 @@ public class DatabaseManager {
|
|||||||
return getDatastore().getDatabase();
|
return getDatastore().getDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Connection getConnection() throws SQLException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
// Initialize
|
// Initialize
|
||||||
mongoClient = new MongoClient(new MongoClientURI(Grasscutter.getConfig().DatabaseUrl));
|
mongoClient = new MongoClient(new MongoClientURI(Grasscutter.getConfig().DatabaseUrl));
|
||||||
morphia = new Morphia();
|
Morphia morphia = new Morphia();
|
||||||
|
|
||||||
// TODO Update when migrating to Morphia 2.0
|
// TODO Update when migrating to Morphia 2.0
|
||||||
morphia.getMapper().getOptions().setStoreEmpties(true);
|
morphia.getMapper().getOptions().setStoreEmpties(true);
|
||||||
|
@ -7,7 +7,7 @@ import java.util.Collections;
|
|||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import com.sun.net.httpserver.HttpHandler;
|
import com.sun.net.httpserver.HttpHandler;
|
||||||
|
|
||||||
public class DispatchHttpJsonHandler implements HttpHandler {
|
public final class DispatchHttpJsonHandler implements HttpHandler {
|
||||||
private final String response;
|
private final String response;
|
||||||
|
|
||||||
public DispatchHttpJsonHandler(String response) {
|
public DispatchHttpJsonHandler(String response) {
|
||||||
@ -24,5 +24,4 @@ public class DispatchHttpJsonHandler implements HttpHandler {
|
|||||||
os.write(response.getBytes());
|
os.write(response.getBytes());
|
||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,7 @@ import emu.grasscutter.utils.Utils;
|
|||||||
|
|
||||||
import com.sun.net.httpserver.HttpServer;
|
import com.sun.net.httpserver.HttpServer;
|
||||||
|
|
||||||
public class DispatchServer {
|
public final class DispatchServer {
|
||||||
private HttpsServer server;
|
|
||||||
private final InetSocketAddress address;
|
private final InetSocketAddress address;
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
private QueryCurrRegionHttpRsp currRegion;
|
private QueryCurrRegionHttpRsp currRegion;
|
||||||
@ -135,12 +134,12 @@ public class DispatchServer {
|
|||||||
this.regionCurrentBase64 = Base64.getEncoder().encodeToString(parsedRegionQuery.toByteString().toByteArray());
|
this.regionCurrentBase64 = Base64.getEncoder().encodeToString(parsedRegionQuery.toByteString().toByteArray());
|
||||||
this.currRegion = parsedRegionQuery;
|
this.currRegion = parsedRegionQuery;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Grasscutter.getLogger().error("Error while initializing region info!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
server = HttpsServer.create(getAddress(), 0);
|
HttpsServer server = HttpsServer.create(getAddress(), 0);
|
||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
|
|
||||||
try (FileInputStream fis = new FileInputStream(Grasscutter.getConfig().DispatchServerKeystorePath)) {
|
try (FileInputStream fis = new FileInputStream(Grasscutter.getConfig().DispatchServerKeystorePath)) {
|
||||||
@ -158,187 +157,169 @@ public class DispatchServer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
server.createContext("/", new HttpHandler() {
|
server.createContext("/", t -> {
|
||||||
@Override
|
//Create a response form the request query parameters
|
||||||
public void handle(HttpExchange t) throws IOException {
|
String response = "Hello";
|
||||||
//Create a response form the request query parameters
|
//Set the response header status and length
|
||||||
String response = "Hello";
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
||||||
//Set the response header status and length
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
//Write the response string
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
OutputStream os = t.getResponseBody();
|
||||||
//Write the response string
|
os.write(response.getBytes());
|
||||||
OutputStream os = t.getResponseBody();
|
os.close();
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Dispatch
|
// Dispatch
|
||||||
server.createContext("/query_region_list", new HttpHandler() {
|
server.createContext("/query_region_list", t -> {
|
||||||
@Override
|
// Log
|
||||||
public void handle(HttpExchange t) throws IOException {
|
Grasscutter.getLogger().info("Client request: query_region_list");
|
||||||
// Log
|
// Create a response form the request query parameters
|
||||||
Grasscutter.getLogger().info("Client request: query_region_list");
|
String response = regionListBase64;
|
||||||
// Create a response form the request query parameters
|
// Set the response header status and length
|
||||||
String response = regionListBase64;
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
||||||
// Set the response header status and length
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
// Write the response string
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
OutputStream os = t.getResponseBody();
|
||||||
// Write the response string
|
os.write(response.getBytes());
|
||||||
OutputStream os = t.getResponseBody();
|
os.close();
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
server.createContext("/query_cur_region", new HttpHandler() {
|
server.createContext("/query_cur_region", t -> {
|
||||||
@Override
|
// Log
|
||||||
public void handle(HttpExchange t) throws IOException {
|
Grasscutter.getLogger().info("Client request: query_cur_region");
|
||||||
// Log
|
// Create a response form the request query parameters
|
||||||
Grasscutter.getLogger().info("Client request: query_cur_region");
|
URI uri = t.getRequestURI();
|
||||||
// Create a response form the request query parameters
|
String response = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==";
|
||||||
URI uri = t.getRequestURI();
|
if (uri.getQuery() != null && uri.getQuery().length() > 0) {
|
||||||
String response = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==";
|
response = regionCurrentBase64;
|
||||||
if (uri.getQuery() != null && uri.getQuery().length() > 0) {
|
|
||||||
response = regionCurrentBase64;
|
|
||||||
}
|
|
||||||
// Set the response header status and length
|
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
|
||||||
// Write the response string
|
|
||||||
OutputStream os = t.getResponseBody();
|
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
}
|
||||||
|
// Set the response header status and length
|
||||||
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
||||||
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
|
// Write the response string
|
||||||
|
OutputStream os = t.getResponseBody();
|
||||||
|
os.write(response.getBytes());
|
||||||
|
os.close();
|
||||||
});
|
});
|
||||||
// Login via account
|
// Login via account
|
||||||
server.createContext("/hk4e_global/mdk/shield/api/login", new HttpHandler() {
|
server.createContext("/hk4e_global/mdk/shield/api/login", t -> {
|
||||||
@Override
|
// Get post data
|
||||||
public void handle(HttpExchange t) throws IOException {
|
LoginAccountRequestJson requestData = null;
|
||||||
// Get post data
|
try {
|
||||||
LoginAccountRequestJson requestData = null;
|
String body = Utils.toString(t.getRequestBody());
|
||||||
try {
|
requestData = getGsonFactory().fromJson(body, LoginAccountRequestJson.class);
|
||||||
String body = Utils.toString(t.getRequestBody());
|
} catch (Exception e) {
|
||||||
requestData = getGsonFactory().fromJson(body, LoginAccountRequestJson.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
// Create response json
|
|
||||||
if (requestData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoginResultJson responseData = new LoginResultJson();
|
|
||||||
|
|
||||||
// Login
|
|
||||||
Account account = DatabaseHelper.getAccountByName(requestData.account);
|
|
||||||
|
|
||||||
// Test
|
|
||||||
if (account == null) {
|
|
||||||
responseData.retcode = -201;
|
|
||||||
responseData.message = "Username not found.";
|
|
||||||
} else {
|
|
||||||
responseData.message = "OK";
|
|
||||||
responseData.data.account.uid = account.getId();
|
|
||||||
responseData.data.account.token = account.generateSessionKey();
|
|
||||||
responseData.data.account.email = account.getEmail();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a response
|
|
||||||
String response = getGsonFactory().toJson(responseData);
|
|
||||||
// Set the response header status and length
|
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json"));
|
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
|
||||||
// Write the response string
|
|
||||||
OutputStream os = t.getResponseBody();
|
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
}
|
||||||
|
// Create response json
|
||||||
|
if (requestData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoginResultJson responseData = new LoginResultJson();
|
||||||
|
|
||||||
|
// Login
|
||||||
|
Account account = DatabaseHelper.getAccountByName(requestData.account);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
if (account == null) {
|
||||||
|
responseData.retcode = -201;
|
||||||
|
responseData.message = "Username not found.";
|
||||||
|
} else {
|
||||||
|
responseData.message = "OK";
|
||||||
|
responseData.data.account.uid = account.getId();
|
||||||
|
responseData.data.account.token = account.generateSessionKey();
|
||||||
|
responseData.data.account.email = account.getEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a response
|
||||||
|
String response = getGsonFactory().toJson(responseData);
|
||||||
|
// Set the response header status and length
|
||||||
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json"));
|
||||||
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
|
// Write the response string
|
||||||
|
OutputStream os = t.getResponseBody();
|
||||||
|
os.write(response.getBytes());
|
||||||
|
os.close();
|
||||||
});
|
});
|
||||||
// Login via token
|
// Login via token
|
||||||
server.createContext("/hk4e_global/mdk/shield/api/verify", new HttpHandler() {
|
server.createContext("/hk4e_global/mdk/shield/api/verify", t -> {
|
||||||
@Override
|
// Get post data
|
||||||
public void handle(HttpExchange t) throws IOException {
|
LoginTokenRequestJson requestData = null;
|
||||||
// Get post data
|
try {
|
||||||
LoginTokenRequestJson requestData = null;
|
String body = Utils.toString(t.getRequestBody());
|
||||||
try {
|
requestData = getGsonFactory().fromJson(body, LoginTokenRequestJson.class);
|
||||||
String body = Utils.toString(t.getRequestBody());
|
} catch (Exception e) {
|
||||||
requestData = getGsonFactory().fromJson(body, LoginTokenRequestJson.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
// Create response json
|
|
||||||
if (requestData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoginResultJson responseData = new LoginResultJson();
|
|
||||||
|
|
||||||
// Login
|
|
||||||
Account account = DatabaseHelper.getAccountById(requestData.uid);
|
|
||||||
|
|
||||||
// Test
|
|
||||||
if (account == null || !account.getSessionKey().equals(requestData.token)) {
|
|
||||||
responseData.retcode = -111;
|
|
||||||
responseData.message = "Game account cache information error";
|
|
||||||
} else {
|
|
||||||
responseData.message = "OK";
|
|
||||||
responseData.data.account.uid = requestData.uid;
|
|
||||||
responseData.data.account.token = requestData.token;
|
|
||||||
responseData.data.account.email = account.getEmail();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a response
|
|
||||||
String response = getGsonFactory().toJson(responseData);
|
|
||||||
// Set the response header status and length
|
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json"));
|
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
|
||||||
// Write the response string
|
|
||||||
OutputStream os = t.getResponseBody();
|
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
}
|
||||||
|
// Create response json
|
||||||
|
if (requestData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoginResultJson responseData = new LoginResultJson();
|
||||||
|
|
||||||
|
// Login
|
||||||
|
Account account = DatabaseHelper.getAccountById(requestData.uid);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
if (account == null || !account.getSessionKey().equals(requestData.token)) {
|
||||||
|
responseData.retcode = -111;
|
||||||
|
responseData.message = "Game account cache information error";
|
||||||
|
} else {
|
||||||
|
responseData.message = "OK";
|
||||||
|
responseData.data.account.uid = requestData.uid;
|
||||||
|
responseData.data.account.token = requestData.token;
|
||||||
|
responseData.data.account.email = account.getEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a response
|
||||||
|
String response = getGsonFactory().toJson(responseData);
|
||||||
|
// Set the response header status and length
|
||||||
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json"));
|
||||||
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
|
// Write the response string
|
||||||
|
OutputStream os = t.getResponseBody();
|
||||||
|
os.write(response.getBytes());
|
||||||
|
os.close();
|
||||||
});
|
});
|
||||||
// Exchange for combo token
|
// Exchange for combo token
|
||||||
server.createContext("/hk4e_global/combo/granter/login/v2/login", new HttpHandler() {
|
server.createContext("/hk4e_global/combo/granter/login/v2/login", t -> {
|
||||||
@Override
|
// Get post data
|
||||||
public void handle(HttpExchange t) throws IOException {
|
ComboTokenReqJson requestData = null;
|
||||||
// Get post data
|
try {
|
||||||
ComboTokenReqJson requestData = null;
|
String body = Utils.toString(t.getRequestBody());
|
||||||
try {
|
requestData = getGsonFactory().fromJson(body, ComboTokenReqJson.class);
|
||||||
String body = Utils.toString(t.getRequestBody());
|
} catch (Exception e) {
|
||||||
requestData = getGsonFactory().fromJson(body, ComboTokenReqJson.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
// Create response json
|
|
||||||
if (requestData == null || requestData.data == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoginTokenData loginData = getGsonFactory().fromJson(requestData.data, LoginTokenData.class); // Get login data
|
|
||||||
ComboTokenResJson responseData = new ComboTokenResJson();
|
|
||||||
|
|
||||||
// Login
|
|
||||||
Account account = DatabaseHelper.getAccountById(loginData.uid);
|
|
||||||
|
|
||||||
// Test
|
|
||||||
if (account == null || !account.getSessionKey().equals(loginData.token)) {
|
|
||||||
responseData.retcode = -201;
|
|
||||||
responseData.message = "Wrong session key.";
|
|
||||||
} else {
|
|
||||||
responseData.message = "OK";
|
|
||||||
responseData.data.open_id = loginData.uid;
|
|
||||||
responseData.data.combo_id = "157795300";
|
|
||||||
responseData.data.combo_token = account.generateLoginToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a response
|
|
||||||
String response = getGsonFactory().toJson(responseData);
|
|
||||||
// Set the response header status and length
|
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json"));
|
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
|
||||||
// Write the response string
|
|
||||||
OutputStream os = t.getResponseBody();
|
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
}
|
||||||
|
// Create response json
|
||||||
|
if (requestData == null || requestData.data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoginTokenData loginData = getGsonFactory().fromJson(requestData.data, LoginTokenData.class); // Get login data
|
||||||
|
ComboTokenResJson responseData = new ComboTokenResJson();
|
||||||
|
|
||||||
|
// Login
|
||||||
|
Account account = DatabaseHelper.getAccountById(loginData.uid);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
if (account == null || !account.getSessionKey().equals(loginData.token)) {
|
||||||
|
responseData.retcode = -201;
|
||||||
|
responseData.message = "Wrong session key.";
|
||||||
|
} else {
|
||||||
|
responseData.message = "OK";
|
||||||
|
responseData.data.open_id = loginData.uid;
|
||||||
|
responseData.data.combo_id = "157795300";
|
||||||
|
responseData.data.combo_token = account.generateLoginToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a response
|
||||||
|
String response = getGsonFactory().toJson(responseData);
|
||||||
|
// Set the response header status and length
|
||||||
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json"));
|
||||||
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
|
// Write the response string
|
||||||
|
OutputStream os = t.getResponseBody();
|
||||||
|
os.write(response.getBytes());
|
||||||
|
os.close();
|
||||||
});
|
});
|
||||||
// Agreement and Protocol
|
// Agreement and Protocol
|
||||||
server.createContext( // hk4e-sdk-os.hoyoverse.com
|
server.createContext( // hk4e-sdk-os.hoyoverse.com
|
||||||
@ -420,19 +401,16 @@ public class DispatchServer {
|
|||||||
"/crash/dataUpload",
|
"/crash/dataUpload",
|
||||||
new DispatchHttpJsonHandler("{\"code\":0}")
|
new DispatchHttpJsonHandler("{\"code\":0}")
|
||||||
);
|
);
|
||||||
uploadLogServer.createContext("/gacha", new HttpHandler() {
|
uploadLogServer.createContext("/gacha", t -> {
|
||||||
@Override
|
//Create a response form the request query parameters
|
||||||
public void handle(HttpExchange t) throws IOException {
|
String response = "<!doctype html><html lang=\"en\"><head><title>Gacha</title></head><body></body></html>";
|
||||||
//Create a response form the request query parameters
|
//Set the response header status and length
|
||||||
String response = "<!doctype html><html lang=\"en\"><head><title>Gacha</title></head><body></body></html>";
|
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
||||||
//Set the response header status and length
|
t.sendResponseHeaders(200, response.getBytes().length);
|
||||||
t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8"));
|
//Write the response string
|
||||||
t.sendResponseHeaders(200, response.getBytes().length);
|
OutputStream os = t.getResponseBody();
|
||||||
//Write the response string
|
os.write(response.getBytes());
|
||||||
OutputStream os = t.getResponseBody();
|
os.close();
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
uploadLogServer.start();
|
uploadLogServer.start();
|
||||||
Grasscutter.getLogger().info("Log server (log-upload-os) started on port " + 80);
|
Grasscutter.getLogger().info("Log server (log-upload-os) started on port " + 80);
|
||||||
|
@ -8,10 +8,8 @@ import emu.grasscutter.game.props.OpenState;
|
|||||||
import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp;
|
import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp;
|
||||||
import emu.grasscutter.net.proto.GetShopRspOuterClass.GetShopRsp;
|
import emu.grasscutter.net.proto.GetShopRspOuterClass.GetShopRsp;
|
||||||
import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdateNotify;
|
import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdateNotify;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
|
||||||
|
|
||||||
public class Dumpers {
|
|
||||||
|
|
||||||
|
public final class Dumpers {
|
||||||
public static void extractBanner(byte[] data) throws Exception {
|
public static void extractBanner(byte[] data) throws Exception {
|
||||||
GetGachaInfoRsp proto = GetGachaInfoRsp.parseFrom(data);
|
GetGachaInfoRsp proto = GetGachaInfoRsp.parseFrom(data);
|
||||||
System.out.println(proto);
|
System.out.println(proto);
|
||||||
|
@ -5,6 +5,7 @@ import java.io.FileWriter;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -20,7 +21,7 @@ import emu.grasscutter.data.def.AvatarData;
|
|||||||
import emu.grasscutter.data.def.ItemData;
|
import emu.grasscutter.data.def.ItemData;
|
||||||
import emu.grasscutter.data.def.MonsterData;
|
import emu.grasscutter.data.def.MonsterData;
|
||||||
|
|
||||||
public class Tools {
|
public final class Tools {
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void createGmHandbook() throws Exception {
|
public static void createGmHandbook() throws Exception {
|
||||||
@ -40,7 +41,7 @@ public class Tools {
|
|||||||
writer.println("// Genshin Impact " + GenshinConstants.VERSION + " GM Handbook");
|
writer.println("// Genshin Impact " + GenshinConstants.VERSION + " GM Handbook");
|
||||||
writer.println("// Created " + dtf.format(now) + System.lineSeparator() + System.lineSeparator());
|
writer.println("// Created " + dtf.format(now) + System.lineSeparator() + System.lineSeparator());
|
||||||
|
|
||||||
list = GenshinData.getAvatarDataMap().keySet().stream().collect(Collectors.toList());
|
list = new ArrayList<>(GenshinData.getAvatarDataMap().keySet());
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
|
|
||||||
writer.println("// Avatars");
|
writer.println("// Avatars");
|
||||||
@ -51,7 +52,7 @@ public class Tools {
|
|||||||
|
|
||||||
writer.println();
|
writer.println();
|
||||||
|
|
||||||
list = GenshinData.getItemDataMap().keySet().stream().collect(Collectors.toList());
|
list = new ArrayList<>(GenshinData.getItemDataMap().keySet());
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
|
|
||||||
writer.println("// Items");
|
writer.println("// Items");
|
||||||
@ -63,7 +64,7 @@ public class Tools {
|
|||||||
writer.println();
|
writer.println();
|
||||||
|
|
||||||
writer.println("// Monsters");
|
writer.println("// Monsters");
|
||||||
list = GenshinData.getMonsterDataMap().keySet().stream().collect(Collectors.toList());
|
list = new ArrayList<>(GenshinData.getMonsterDataMap().keySet());
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
|
|
||||||
for (Integer id : list) {
|
for (Integer id : list) {
|
||||||
|
@ -7,8 +7,8 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.net.proto.GetPlayerTokenRspOuterClass.GetPlayerTokenRsp;
|
import emu.grasscutter.net.proto.GetPlayerTokenRspOuterClass.GetPlayerTokenRsp;
|
||||||
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
||||||
|
|
||||||
public class Crypto {
|
public final class Crypto {
|
||||||
private static SecureRandom secureRandom = new SecureRandom();
|
private static final SecureRandom secureRandom = new SecureRandom();
|
||||||
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
|
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
|
||||||
public static byte[] ENCRYPT_SEED_BUFFER = new byte[0];
|
public static byte[] ENCRYPT_SEED_BUFFER = new byte[0];
|
||||||
|
|
||||||
@ -37,8 +37,7 @@ public class Crypto {
|
|||||||
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "secretKeyBuffer.bin", p.getSecretKeyBuffer().toByteArray());
|
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "secretKeyBuffer.bin", p.getSecretKeyBuffer().toByteArray());
|
||||||
Grasscutter.getLogger().info("Secret Key: " + p.getSecretKey());
|
Grasscutter.getLogger().info("Secret Key: " + p.getSecretKey());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO Auto-generated catch block
|
Grasscutter.getLogger().error("Crypto error.", e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ public class Crypto {
|
|||||||
QueryCurrRegionHttpRsp p = QueryCurrRegionHttpRsp.parseFrom(Base64.getDecoder().decode(data));
|
QueryCurrRegionHttpRsp p = QueryCurrRegionHttpRsp.parseFrom(Base64.getDecoder().decode(data));
|
||||||
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin", p.getRegionInfo().getSecretKey().toByteArray());
|
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin", p.getRegionInfo().getSecretKey().toByteArray());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Grasscutter.getLogger().error("Crypto error.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
package emu.grasscutter.utils;
|
package emu.grasscutter.utils;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
public class FileUtils {
|
public final class FileUtils {
|
||||||
|
|
||||||
public static void write(String dest, byte[] bytes) {
|
public static void write(String dest, byte[] bytes) {
|
||||||
Path path = Paths.get(dest);
|
Path path = Paths.get(dest);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.write(path, bytes);
|
Files.write(path, bytes);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
Grasscutter.getLogger().warn("Failed to write file: " + dest);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +27,7 @@ public class FileUtils {
|
|||||||
try {
|
try {
|
||||||
return Files.readAllBytes(path);
|
return Files.readAllBytes(path);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
Grasscutter.getLogger().warn("Failed to read file: " + path);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
|
@ -3,7 +3,7 @@ package emu.grasscutter.utils;
|
|||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
import emu.grasscutter.net.proto.PropValueOuterClass.PropValue;
|
import emu.grasscutter.net.proto.PropValueOuterClass.PropValue;
|
||||||
|
|
||||||
public class ProtoHelper {
|
public final class ProtoHelper {
|
||||||
public static PropValue newPropValue(PlayerProperty key, int value) {
|
public static PropValue newPropValue(PlayerProperty key, int value) {
|
||||||
return PropValue.newBuilder().setType(key.getId()).setIval(value).setVal(value).build();
|
return PropValue.newBuilder().setType(key.getId()).setIval(value).setVal(value).build();
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package emu.grasscutter.utils;
|
package emu.grasscutter.utils;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.*;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.nio.file.Files;
|
||||||
import java.io.IOException;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import emu.grasscutter.Config;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
public class Utils {
|
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
|
||||||
|
public final class Utils {
|
||||||
public static final Random random = new Random();
|
public static final Random random = new Random();
|
||||||
|
|
||||||
public static int randomRange(int min, int max) {
|
public static int randomRange(int min, int max) {
|
||||||
@ -76,4 +78,77 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
return v7;
|
return v7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a file exists on the file system.
|
||||||
|
* @param path The path to the file.
|
||||||
|
* @return True if the file exists, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean fileExists(String path) {
|
||||||
|
return new File(path).exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a folder on the file system.
|
||||||
|
* @param path The path to the folder.
|
||||||
|
* @return True if the folder was created, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean createFolder(String path) {
|
||||||
|
return new File(path).mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a file from the archive's resources to the file system.
|
||||||
|
* @param resource The path to the resource.
|
||||||
|
* @param destination The path to copy the resource to.
|
||||||
|
* @return True if the file was copied, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean copyFromResources(String resource, String destination) {
|
||||||
|
try (InputStream stream = Grasscutter.class.getResourceAsStream(resource)) {
|
||||||
|
if(stream == null) {
|
||||||
|
Grasscutter.getLogger().warn("Could not find resource: " + resource);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.copy(stream, new File(destination).toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.getLogger().warn("Unable to copy resource " + resource + " to " + destination, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for required files and folders before startup.
|
||||||
|
*/
|
||||||
|
public static void startupCheck() {
|
||||||
|
Config config = Grasscutter.getConfig();
|
||||||
|
Logger logger = Grasscutter.getLogger();
|
||||||
|
boolean exit = false;
|
||||||
|
|
||||||
|
String resourcesFolder = config.RESOURCE_FOLDER;
|
||||||
|
String dataFolder = config.DATA_FOLDER;
|
||||||
|
|
||||||
|
// Check for resources folder.
|
||||||
|
if(!fileExists(resourcesFolder)) {
|
||||||
|
logger.info("Creating resources folder...");
|
||||||
|
logger.info("Place a copy of 'GenshinData' in the resources folder.");
|
||||||
|
createFolder(resourcesFolder); exit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for GenshinData.
|
||||||
|
if(!fileExists(resourcesFolder + "BinOutput") ||
|
||||||
|
!fileExists(resourcesFolder + "ExcelBinOutput")) {
|
||||||
|
logger.info("Place a copy of 'GenshinData' in the resources folder.");
|
||||||
|
exit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for game data.
|
||||||
|
if(!fileExists(dataFolder))
|
||||||
|
createFolder(dataFolder);
|
||||||
|
if(!fileExists(dataFolder + "AbilityEmbryos.json"))
|
||||||
|
copyFromResources("data/AbilityEmbryos.json", dataFolder);
|
||||||
|
|
||||||
|
if(exit) System.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user