mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-23 10:21:42 +00:00
commit
07a2316563
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;
|
||||
|
||||
public class Config {
|
||||
public final class Config {
|
||||
public String DispatchServerIp = "127.0.0.1";
|
||||
public int DispatchServerPort = 443;
|
||||
public String DispatchServerKeystorePath = "./keystore.p12";
|
||||
@ -31,14 +31,14 @@ public class Config {
|
||||
return ServerOptions;
|
||||
}
|
||||
|
||||
public class GameRates {
|
||||
public static class GameRates {
|
||||
public float ADVENTURE_EXP_RATE = 1.0f;
|
||||
public float MORA_RATE = 1.0f;
|
||||
public float DOMAIN_DROP_RATE = 1.0f;
|
||||
}
|
||||
|
||||
public class ServerOptions {
|
||||
public int MaxEntityLimit = 1000; // Max entity limit per world. TODO Unenforced for now
|
||||
public static class ServerOptions {
|
||||
public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later.
|
||||
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
||||
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ package emu.grasscutter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import emu.grasscutter.game.props.OpenState;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
public class GenshinConstants {
|
||||
public final class GenshinConstants {
|
||||
public static String VERSION = "2.6.0";
|
||||
|
||||
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_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 = {
|
||||
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
|
||||
"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.InputStreamReader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
@ -22,19 +22,25 @@ import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.tools.Tools;
|
||||
import emu.grasscutter.utils.Crypto;
|
||||
|
||||
public class Grasscutter {
|
||||
private static Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
||||
public final class Grasscutter {
|
||||
private static final Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
||||
private static Config config;
|
||||
|
||||
private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static File configFile = new File("./config.json");
|
||||
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final File configFile = new File("./config.json");
|
||||
|
||||
public static RunMode MODE = RunMode.BOTH;
|
||||
private static DispatchServer dispatchServer;
|
||||
private static GameServer gameServer;
|
||||
|
||||
static {
|
||||
// Load configuration.
|
||||
Grasscutter.loadConfig();
|
||||
// Check server structure.
|
||||
Utils.startupCheck();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Grasscutter.loadConfig();
|
||||
Crypto.loadKeys();
|
||||
|
||||
for (String arg : args) {
|
||||
@ -48,56 +54,34 @@ public class Grasscutter {
|
||||
case "-handbook":
|
||||
Tools.createGmHandbook();
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Startup
|
||||
Grasscutter.getLogger().info("Grasscutter Emu");
|
||||
// Initialize server.
|
||||
Grasscutter.getLogger().info("Starting Grasscutter...");
|
||||
|
||||
// Load resource files
|
||||
// Load all resources.
|
||||
ResourceLoader.loadAll();
|
||||
|
||||
// Database
|
||||
DatabaseManager.initialize();
|
||||
|
||||
// Run servers
|
||||
// Start servers.
|
||||
dispatchServer = new DispatchServer();
|
||||
dispatchServer.start();
|
||||
|
||||
gameServer = new GameServer(new InetSocketAddress(getConfig().GameServerIp, getConfig().GameServerPort));
|
||||
gameServer.start();
|
||||
|
||||
// Open console.
|
||||
startConsole();
|
||||
}
|
||||
|
||||
public static Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public static Gson getGsonFactory() {
|
||||
return gson;
|
||||
}
|
||||
|
||||
public static DispatchServer getDispatchServer() {
|
||||
return dispatchServer;
|
||||
}
|
||||
|
||||
public static GameServer getGameServer() {
|
||||
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();
|
||||
Grasscutter.config = new Config(); saveConfig();
|
||||
}
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
public static void saveConfig() {
|
||||
@ -115,7 +99,7 @@ public class Grasscutter {
|
||||
ServerCommands.handle(input);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("Console error:", e);
|
||||
Grasscutter.getLogger().error("An error occurred.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,4 +108,24 @@ public class Grasscutter {
|
||||
AUTH,
|
||||
GAME
|
||||
}
|
||||
|
||||
public static Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public static Gson getGsonFactory() {
|
||||
return gson;
|
||||
}
|
||||
|
||||
public static DispatchServer getDispatchServer() {
|
||||
return dispatchServer;
|
||||
}
|
||||
|
||||
public static GameServer getGameServer() {
|
||||
return gameServer;
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
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;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientURI;
|
||||
import com.mongodb.MongoCommandException;
|
||||
@ -18,12 +15,11 @@ import emu.grasscutter.game.avatar.GenshinAvatar;
|
||||
import emu.grasscutter.game.friends.Friendship;
|
||||
import emu.grasscutter.game.inventory.GenshinItem;
|
||||
|
||||
public class DatabaseManager {
|
||||
public final class DatabaseManager {
|
||||
private static MongoClient mongoClient;
|
||||
private static Morphia morphia;
|
||||
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
|
||||
};
|
||||
|
||||
@ -38,15 +34,11 @@ public class DatabaseManager {
|
||||
public static MongoDatabase getDatabase() {
|
||||
return getDatastore().getDatabase();
|
||||
}
|
||||
|
||||
public static Connection getConnection() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
// Initialize
|
||||
mongoClient = new MongoClient(new MongoClientURI(Grasscutter.getConfig().DatabaseUrl));
|
||||
morphia = new Morphia();
|
||||
Morphia morphia = new Morphia();
|
||||
|
||||
// TODO Update when migrating to Morphia 2.0
|
||||
morphia.getMapper().getOptions().setStoreEmpties(true);
|
||||
|
@ -7,7 +7,7 @@ import java.util.Collections;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
||||
public class DispatchHttpJsonHandler implements HttpHandler {
|
||||
public final class DispatchHttpJsonHandler implements HttpHandler {
|
||||
private final String response;
|
||||
|
||||
public DispatchHttpJsonHandler(String response) {
|
||||
@ -24,5 +24,4 @@ public class DispatchHttpJsonHandler implements HttpHandler {
|
||||
os.write(response.getBytes());
|
||||
os.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,8 +43,7 @@ import emu.grasscutter.utils.Utils;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
public class DispatchServer {
|
||||
private HttpsServer server;
|
||||
public final class DispatchServer {
|
||||
private final InetSocketAddress address;
|
||||
private final Gson gson;
|
||||
private QueryCurrRegionHttpRsp currRegion;
|
||||
@ -135,12 +134,12 @@ public class DispatchServer {
|
||||
this.regionCurrentBase64 = Base64.getEncoder().encodeToString(parsedRegionQuery.toByteString().toByteArray());
|
||||
this.currRegion = parsedRegionQuery;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().error("Error while initializing region info!", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void start() throws Exception {
|
||||
server = HttpsServer.create(getAddress(), 0);
|
||||
HttpsServer server = HttpsServer.create(getAddress(), 0);
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(Grasscutter.getConfig().DispatchServerKeystorePath)) {
|
||||
@ -158,187 +157,169 @@ public class DispatchServer {
|
||||
return;
|
||||
}
|
||||
|
||||
server.createContext("/", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
//Create a response form the request query parameters
|
||||
String response = "Hello";
|
||||
//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();
|
||||
}
|
||||
server.createContext("/", t -> {
|
||||
//Create a response form the request query parameters
|
||||
String response = "Hello";
|
||||
//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();
|
||||
});
|
||||
|
||||
// Dispatch
|
||||
server.createContext("/query_region_list", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
// Log
|
||||
Grasscutter.getLogger().info("Client request: query_region_list");
|
||||
// Create a response form the request query parameters
|
||||
String response = regionListBase64;
|
||||
// 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();
|
||||
}
|
||||
server.createContext("/query_region_list", t -> {
|
||||
// Log
|
||||
Grasscutter.getLogger().info("Client request: query_region_list");
|
||||
// Create a response form the request query parameters
|
||||
String response = regionListBase64;
|
||||
// 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();
|
||||
});
|
||||
server.createContext("/query_cur_region", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
// Log
|
||||
Grasscutter.getLogger().info("Client request: query_cur_region");
|
||||
// Create a response form the request query parameters
|
||||
URI uri = t.getRequestURI();
|
||||
String response = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==";
|
||||
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();
|
||||
server.createContext("/query_cur_region", t -> {
|
||||
// Log
|
||||
Grasscutter.getLogger().info("Client request: query_cur_region");
|
||||
// Create a response form the request query parameters
|
||||
URI uri = t.getRequestURI();
|
||||
String response = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==";
|
||||
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();
|
||||
});
|
||||
// Login via account
|
||||
server.createContext("/hk4e_global/mdk/shield/api/login", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
// Get post data
|
||||
LoginAccountRequestJson requestData = null;
|
||||
try {
|
||||
String body = Utils.toString(t.getRequestBody());
|
||||
requestData = getGsonFactory().fromJson(body, LoginAccountRequestJson.class);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
// Create response json
|
||||
if (requestData == null) {
|
||||
return;
|
||||
}
|
||||
LoginResultJson responseData = new LoginResultJson();
|
||||
server.createContext("/hk4e_global/mdk/shield/api/login", t -> {
|
||||
// Get post data
|
||||
LoginAccountRequestJson requestData = null;
|
||||
try {
|
||||
String body = Utils.toString(t.getRequestBody());
|
||||
requestData = getGsonFactory().fromJson(body, LoginAccountRequestJson.class);
|
||||
} catch (Exception e) {
|
||||
|
||||
// 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
|
||||
server.createContext("/hk4e_global/mdk/shield/api/verify", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
// Get post data
|
||||
LoginTokenRequestJson requestData = null;
|
||||
try {
|
||||
String body = Utils.toString(t.getRequestBody());
|
||||
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);
|
||||
server.createContext("/hk4e_global/mdk/shield/api/verify", t -> {
|
||||
// Get post data
|
||||
LoginTokenRequestJson requestData = null;
|
||||
try {
|
||||
String body = Utils.toString(t.getRequestBody());
|
||||
requestData = getGsonFactory().fromJson(body, LoginTokenRequestJson.class);
|
||||
} catch (Exception e) {
|
||||
|
||||
// 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
|
||||
server.createContext("/hk4e_global/combo/granter/login/v2/login", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
// Get post data
|
||||
ComboTokenReqJson requestData = null;
|
||||
try {
|
||||
String body = Utils.toString(t.getRequestBody());
|
||||
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);
|
||||
server.createContext("/hk4e_global/combo/granter/login/v2/login", t -> {
|
||||
// Get post data
|
||||
ComboTokenReqJson requestData = null;
|
||||
try {
|
||||
String body = Utils.toString(t.getRequestBody());
|
||||
requestData = getGsonFactory().fromJson(body, ComboTokenReqJson.class);
|
||||
} catch (Exception e) {
|
||||
|
||||
// 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
|
||||
server.createContext( // hk4e-sdk-os.hoyoverse.com
|
||||
@ -420,19 +401,16 @@ public class DispatchServer {
|
||||
"/crash/dataUpload",
|
||||
new DispatchHttpJsonHandler("{\"code\":0}")
|
||||
);
|
||||
uploadLogServer.createContext("/gacha", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange t) throws IOException {
|
||||
//Create a response form the request query parameters
|
||||
String response = "<!doctype html><html lang=\"en\"><head><title>Gacha</title></head><body></body></html>";
|
||||
//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();
|
||||
}
|
||||
uploadLogServer.createContext("/gacha", t -> {
|
||||
//Create a response form the request query parameters
|
||||
String response = "<!doctype html><html lang=\"en\"><head><title>Gacha</title></head><body></body></html>";
|
||||
//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();
|
||||
});
|
||||
uploadLogServer.start();
|
||||
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.GetShopRspOuterClass.GetShopRsp;
|
||||
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 {
|
||||
GetGachaInfoRsp proto = GetGachaInfoRsp.parseFrom(data);
|
||||
System.out.println(proto);
|
||||
|
@ -5,6 +5,7 @@ import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
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.MonsterData;
|
||||
|
||||
public class Tools {
|
||||
public final class Tools {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void createGmHandbook() throws Exception {
|
||||
@ -40,7 +41,7 @@ public class Tools {
|
||||
writer.println("// Genshin Impact " + GenshinConstants.VERSION + " GM Handbook");
|
||||
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);
|
||||
|
||||
writer.println("// Avatars");
|
||||
@ -51,7 +52,7 @@ public class Tools {
|
||||
|
||||
writer.println();
|
||||
|
||||
list = GenshinData.getItemDataMap().keySet().stream().collect(Collectors.toList());
|
||||
list = new ArrayList<>(GenshinData.getItemDataMap().keySet());
|
||||
Collections.sort(list);
|
||||
|
||||
writer.println("// Items");
|
||||
@ -63,7 +64,7 @@ public class Tools {
|
||||
writer.println();
|
||||
|
||||
writer.println("// Monsters");
|
||||
list = GenshinData.getMonsterDataMap().keySet().stream().collect(Collectors.toList());
|
||||
list = new ArrayList<>(GenshinData.getMonsterDataMap().keySet());
|
||||
Collections.sort(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.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
||||
|
||||
public class Crypto {
|
||||
private static SecureRandom secureRandom = new SecureRandom();
|
||||
public final class Crypto {
|
||||
private static final SecureRandom secureRandom = new SecureRandom();
|
||||
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
|
||||
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());
|
||||
Grasscutter.getLogger().info("Secret Key: " + p.getSecretKey());
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().error("Crypto error.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +46,7 @@ public class Crypto {
|
||||
QueryCurrRegionHttpRsp p = QueryCurrRegionHttpRsp.parseFrom(Base64.getDecoder().decode(data));
|
||||
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin", p.getRegionInfo().getSecretKey().toByteArray());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().error("Crypto error.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public final class FileUtils {
|
||||
public static void write(String dest, byte[] bytes) {
|
||||
Path path = Paths.get(dest);
|
||||
|
||||
try {
|
||||
Files.write(path, bytes);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().warn("Failed to write file: " + dest);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,8 +27,7 @@ public class FileUtils {
|
||||
try {
|
||||
return Files.readAllBytes(path);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().warn("Failed to read file: " + path);
|
||||
}
|
||||
|
||||
return new byte[0];
|
||||
|
@ -3,7 +3,7 @@ package emu.grasscutter.utils;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.net.proto.PropValueOuterClass.PropValue;
|
||||
|
||||
public class ProtoHelper {
|
||||
public final class ProtoHelper {
|
||||
public static PropValue newPropValue(PlayerProperty key, int value) {
|
||||
return PropValue.newBuilder().setType(key.getId()).setIval(value).setVal(value).build();
|
||||
}
|
||||
|
@ -1,17 +1,19 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Random;
|
||||
|
||||
import emu.grasscutter.Config;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
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 int randomRange(int min, int max) {
|
||||
@ -76,4 +78,77 @@ public class Utils {
|
||||
}
|
||||
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