Format code [skip actions]

This commit is contained in:
github-actions 2023-05-15 04:45:40 +00:00
parent bcc9ae10cd
commit e079eebc0f
21 changed files with 253 additions and 299 deletions

View File

@ -1,5 +1,8 @@
package emu.grasscutter; package emu.grasscutter;
import static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.utils.Language.translate;
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.Logger;
import emu.grasscutter.auth.AuthenticationSystem; import emu.grasscutter.auth.AuthenticationSystem;
@ -26,6 +29,12 @@ import emu.grasscutter.server.http.handlers.GenericHandler;
import emu.grasscutter.server.http.handlers.LogHandler; import emu.grasscutter.server.http.handlers.LogHandler;
import emu.grasscutter.tools.Tools; import emu.grasscutter.tools.Tools;
import emu.grasscutter.utils.*; import emu.grasscutter.utils.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOError;
import java.io.IOException;
import java.util.Calendar;
import javax.annotation.Nullable;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.jline.reader.EndOfFileException; import org.jline.reader.EndOfFileException;
@ -37,16 +46,6 @@ import org.jline.terminal.TerminalBuilder;
import org.reflections.Reflections; import org.reflections.Reflections;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOError;
import java.io.IOException;
import java.util.Calendar;
import static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.utils.Language.translate;
public final class Grasscutter { public final class Grasscutter {
public static final File configFile = new File("./config.json"); public static final File configFile = new File("./config.json");
public static final Reflections reflector = new Reflections("emu.grasscutter"); public static final Reflections reflector = new Reflections("emu.grasscutter");

View File

@ -4,12 +4,11 @@ import emu.grasscutter.game.Account;
import emu.grasscutter.server.http.objects.*; import emu.grasscutter.server.http.objects.*;
import emu.grasscutter.utils.DispatchUtils; import emu.grasscutter.utils.DispatchUtils;
import io.javalin.http.Context; import io.javalin.http.Context;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import javax.annotation.Nullable;
/** Defines an authenticator for the server. Can be changed by plugins. */ /** Defines an authenticator for the server. Can be changed by plugins. */
public interface AuthenticationSystem { public interface AuthenticationSystem {
@ -107,11 +106,11 @@ public interface AuthenticationSystem {
Authenticator<ComboTokenResJson> getSessionKeyAuthenticator(); Authenticator<ComboTokenResJson> getSessionKeyAuthenticator();
/** /**
* This is the authenticator used for validating session tokens. * This is the authenticator used for validating session tokens. This is a part of the logic in
* This is a part of the logic in {@link DispatchUtils#authenticate(String, String)}. * {@link DispatchUtils#authenticate(String, String)}.
* <p> *
* Plugins can override this authenticator to add * <p>Plugins can override this authenticator to add support for alternate session authentication
* support for alternate session authentication methods. * methods.
* *
* @return {@code true} if the session token is valid, {@code false} otherwise. * @return {@code true} if the session token is valid, {@code false} otherwise.
*/ */

View File

@ -1,14 +1,14 @@
package emu.grasscutter.auth; package emu.grasscutter.auth;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.DefaultAuthenticators.*; import emu.grasscutter.auth.DefaultAuthenticators.*;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.server.http.objects.ComboTokenResJson; import emu.grasscutter.server.http.objects.ComboTokenResJson;
import emu.grasscutter.server.http.objects.LoginResultJson; import emu.grasscutter.server.http.objects.LoginResultJson;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate;
/** /**
* The default Grasscutter authentication implementation. Allows all users to access any account. * The default Grasscutter authentication implementation. Allows all users to access any account.
*/ */

View File

@ -1,5 +1,8 @@
package emu.grasscutter.auth; package emu.grasscutter.auth;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate;
import at.favre.lib.crypto.bcrypt.BCrypt; import at.favre.lib.crypto.bcrypt.BCrypt;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest; import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
@ -11,17 +14,13 @@ import emu.grasscutter.server.http.objects.ComboTokenResJson;
import emu.grasscutter.server.http.objects.LoginResultJson; import emu.grasscutter.server.http.objects.LoginResultJson;
import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.crypto.Cipher;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate;
/** A class containing default authenticators. */ /** A class containing default authenticators. */
public final class DefaultAuthenticators { public final class DefaultAuthenticators {
@ -51,18 +50,18 @@ public final class DefaultAuthenticators {
if (account == null) { if (account == null) {
responseMessage = translate("messages.dispatch.account.username_create_error"); responseMessage = translate("messages.dispatch.account.username_create_error");
Grasscutter.getLogger() Grasscutter.getLogger()
.info(translate("messages.dispatch.account.account_login_create_error", address)); .info(translate("messages.dispatch.account.account_login_create_error", address));
} else { } else {
// Continue with login. // Continue with login.
successfulLogin = true; successfulLogin = true;
// Log the creation. // Log the creation.
Grasscutter.getLogger() Grasscutter.getLogger()
.info( .info(
translate( translate(
"messages.dispatch.account.account_login_create_success", "messages.dispatch.account.account_login_create_success",
address, address,
response.data.account.uid)); response.data.account.uid));
} }
} else if (account != null) successfulLogin = true; } else if (account != null) successfulLogin = true;
else else
@ -132,25 +131,25 @@ public final class DefaultAuthenticators {
if (decryptedPassword.length() >= 8) { if (decryptedPassword.length() >= 8) {
account = DatabaseHelper.createAccountWithUid(requestData.account, 0); account = DatabaseHelper.createAccountWithUid(requestData.account, 0);
account.setPassword( account.setPassword(
BCrypt.withDefaults().hashToString(12, decryptedPassword.toCharArray())); BCrypt.withDefaults().hashToString(12, decryptedPassword.toCharArray()));
account.save(); account.save();
// Check if the account was created successfully. // Check if the account was created successfully.
if (account == null) { if (account == null) {
responseMessage = translate("messages.dispatch.account.username_create_error"); responseMessage = translate("messages.dispatch.account.username_create_error");
loggerMessage = loggerMessage =
translate("messages.dispatch.account.account_login_create_error", address); translate("messages.dispatch.account.account_login_create_error", address);
} else { } else {
// Continue with login. // Continue with login.
successfulLogin = true; successfulLogin = true;
// Log the creation. // Log the creation.
Grasscutter.getLogger() Grasscutter.getLogger()
.info( .info(
translate( translate(
"messages.dispatch.account.account_login_create_success", "messages.dispatch.account.account_login_create_success",
address, address,
response.data.account.uid)); response.data.account.uid));
} }
} else { } else {
successfulLogin = false; successfulLogin = false;
@ -160,8 +159,8 @@ public final class DefaultAuthenticators {
} else if (account != null) { } else if (account != null) {
if (account.getPassword() != null && !account.getPassword().isEmpty()) { if (account.getPassword() != null && !account.getPassword().isEmpty()) {
if (BCrypt.verifyer() if (BCrypt.verifyer()
.verify(decryptedPassword.toCharArray(), account.getPassword()) .verify(decryptedPassword.toCharArray(), account.getPassword())
.verified) { .verified) {
successfulLogin = true; successfulLogin = true;
} else { } else {
successfulLogin = false; successfulLogin = false;
@ -171,7 +170,7 @@ public final class DefaultAuthenticators {
} else { } else {
successfulLogin = false; successfulLogin = false;
loggerMessage = loggerMessage =
translate("messages.dispatch.account.login_password_storage_error", address); translate("messages.dispatch.account.login_password_storage_error", address);
responseMessage = translate("messages.dispatch.account.password_storage_error"); responseMessage = translate("messages.dispatch.account.password_storage_error");
} }
} else { } else {
@ -229,7 +228,7 @@ public final class DefaultAuthenticators {
// Log the login. // Log the login.
loggerMessage = loggerMessage =
translate("messages.dispatch.account.login_token_success", address, requestData.uid); translate("messages.dispatch.account.login_token_success", address, requestData.uid);
} else { } else {
response.retcode = -201; response.retcode = -201;
response.message = translate("messages.dispatch.account.account_cache_error"); response.message = translate("messages.dispatch.account.account_cache_error");
@ -349,20 +348,21 @@ public final class DefaultAuthenticators {
var client = Grasscutter.getGameServer().getDispatchClient(); var client = Grasscutter.getGameServer().getDispatchClient();
var future = new CompletableFuture<Account>(); var future = new CompletableFuture<Account>();
client.registerCallback(PacketIds.TokenValidateRsp, packet -> { client.registerCallback(
var data = IDispatcher.decode(packet); PacketIds.TokenValidateRsp,
packet -> {
var data = IDispatcher.decode(packet);
// Check if the token is valid. // Check if the token is valid.
var valid = data.get("valid").getAsBoolean(); var valid = data.get("valid").getAsBoolean();
if (!valid) { if (!valid) {
future.complete(null); future.complete(null);
return; return;
} }
// Return the account data. // Return the account data.
future.complete(IDispatcher.decode( future.complete(IDispatcher.decode(data.get("account"), Account.class));
data.get("account"), Account.class)); });
});
client.sendMessage(PacketIds.TokenValidateReq, tokenRequest); client.sendMessage(PacketIds.TokenValidateReq, tokenRequest);
try { try {

View File

@ -1,5 +1,7 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import at.favre.lib.crypto.bcrypt.BCrypt; import at.favre.lib.crypto.bcrypt.BCrypt;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
@ -9,12 +11,9 @@ import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.database.DatabaseManager; import emu.grasscutter.database.DatabaseManager;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static emu.grasscutter.utils.Language.translate;
@Command( @Command(
label = "account", label = "account",
usage = { usage = {

View File

@ -1,5 +1,7 @@
package emu.grasscutter.database; package emu.grasscutter.database;
import static emu.grasscutter.config.Configuration.DATABASE;
import com.mongodb.MongoCommandException; import com.mongodb.MongoCommandException;
import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients; import com.mongodb.client.MongoClients;
@ -16,8 +18,6 @@ import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import org.reflections.Reflections; import org.reflections.Reflections;
import static emu.grasscutter.config.Configuration.DATABASE;
public final class DatabaseManager { public final class DatabaseManager {
private static Datastore gameDatastore; private static Datastore gameDatastore;
private static Datastore dispatchDatastore; private static Datastore dispatchDatastore;
@ -27,8 +27,7 @@ public final class DatabaseManager {
} }
public static Datastore getAccountDatastore() { public static Datastore getAccountDatastore() {
if (Grasscutter.getRunMode() == ServerRunMode.HYBRID) if (Grasscutter.getRunMode() == ServerRunMode.HYBRID) return gameDatastore;
return gameDatastore;
else return dispatchDatastore; else return dispatchDatastore;
} }

View File

@ -1,5 +1,7 @@
package emu.grasscutter.game.gacha; package emu.grasscutter.game.gacha;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import com.sun.nio.file.SensitivityWatchEventModifier; import com.sun.nio.file.SensitivityWatchEventModifier;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.DataLoader; import emu.grasscutter.data.DataLoader;
@ -29,14 +31,11 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import org.greenrobot.eventbus.Subscribe;
import java.nio.file.*; import java.nio.file.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import org.greenrobot.eventbus.Subscribe;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
public class GachaSystem extends BaseGameSystem { public class GachaSystem extends BaseGameSystem {
private static final int starglitterId = 221; private static final int starglitterId = 221;

View File

@ -1,17 +1,13 @@
package emu.grasscutter.server.dispatch; package emu.grasscutter.server.dispatch;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.http.handlers.GachaHandler; import emu.grasscutter.server.http.handlers.GachaHandler;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import lombok.Getter;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -21,17 +17,17 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import lombok.Getter;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO; import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
public final class DispatchClient extends WebSocketClient implements IDispatcher { public final class DispatchClient extends WebSocketClient implements IDispatcher {
@Getter private final Logger logger @Getter private final Logger logger = Grasscutter.getLogger();
= Grasscutter.getLogger(); @Getter private final Map<Integer, BiConsumer<WebSocket, JsonElement>> handlers = new HashMap<>();
@Getter private final Map<Integer, BiConsumer<WebSocket, JsonElement>> handlers
= new HashMap<>();
@Getter private final Map<Integer, List<Consumer<JsonElement>>> callbacks @Getter private final Map<Integer, List<Consumer<JsonElement>>> callbacks = new HashMap<>();
= new HashMap<>();
public DispatchClient(URI serverUri) { public DispatchClient(URI serverUri) {
super(serverUri); super(serverUri);
@ -58,8 +54,7 @@ public final class DispatchClient extends WebSocketClient implements IDispatcher
var response = new JsonObject(); var response = new JsonObject();
// Find a player with the specified account ID. // Find a player with the specified account ID.
var player = Grasscutter.getGameServer() var player = Grasscutter.getGameServer().getPlayerByAccountId(accountId);
.getPlayerByAccountId(accountId);
if (player == null) { if (player == null) {
response.addProperty("retcode", 1); response.addProperty("retcode", 1);
this.sendMessage(PacketIds.GachaHistoryRsp, response); this.sendMessage(PacketIds.GachaHistoryRsp, response);
@ -67,8 +62,7 @@ public final class DispatchClient extends WebSocketClient implements IDispatcher
} }
// Fetch the gacha records. // Fetch the gacha records.
GachaHandler.fetchGachaRecords( GachaHandler.fetchGachaRecords(player, response, page, type);
player, response, page, type);
// Send the response. // Send the response.
this.sendMessage(PacketIds.GachaHistoryRsp, response); this.sendMessage(PacketIds.GachaHistoryRsp, response);
@ -82,8 +76,7 @@ public final class DispatchClient extends WebSocketClient implements IDispatcher
public void sendMessage(int packetId, Object message) { public void sendMessage(int packetId, Object message) {
var serverMessage = this.encodeMessage(packetId, message); var serverMessage = this.encodeMessage(packetId, message);
// Serialize the message into JSON. // Serialize the message into JSON.
var serialized = JSON.toJson(serverMessage) var serialized = JSON.toJson(serverMessage).getBytes(StandardCharsets.UTF_8);
.getBytes(StandardCharsets.UTF_8);
// Encrypt the message. // Encrypt the message.
Crypto.xor(serialized, DISPATCH_INFO.encryptionKey); Crypto.xor(serialized, DISPATCH_INFO.encryptionKey);
// Send the message. // Send the message.
@ -100,8 +93,7 @@ public final class DispatchClient extends WebSocketClient implements IDispatcher
@Override @Override
public void onMessage(String message) { public void onMessage(String message) {
this.getLogger().debug("Received dispatch message from server:\n{}", this.getLogger().debug("Received dispatch message from server:\n{}", message);
message);
} }
@Override @Override
@ -114,17 +106,20 @@ public final class DispatchClient extends WebSocketClient implements IDispatcher
this.getLogger().info("Dispatch connection closed."); this.getLogger().info("Dispatch connection closed.");
// Attempt to reconnect. // Attempt to reconnect.
new Thread(() -> { new Thread(
try { () -> {
// Wait 5 seconds before reconnecting. try {
Thread.sleep(5000L); // Wait 5 seconds before reconnecting.
} catch (Exception ignored) { } Thread.sleep(5000L);
} catch (Exception ignored) {
}
// Attempt to reconnect. // Attempt to reconnect.
Grasscutter.getGameServer().setDispatchClient( Grasscutter.getGameServer()
new DispatchClient(GameServer.getDispatchUrl())); .setDispatchClient(new DispatchClient(GameServer.getDispatchUrl()));
Grasscutter.getGameServer().getDispatchClient().connect(); Grasscutter.getGameServer().getDispatchClient().connect();
}).start(); })
.start();
} }
@Override @Override

View File

@ -1,16 +1,12 @@
package emu.grasscutter.server.dispatch; package emu.grasscutter.server.dispatch;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import lombok.Getter;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.slf4j.Logger;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -19,18 +15,18 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import lombok.Getter;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO; import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.slf4j.Logger;
/* Internal communications server. */ /* Internal communications server. */
public final class DispatchServer extends WebSocketServer implements IDispatcher { public final class DispatchServer extends WebSocketServer implements IDispatcher {
@Getter private final Logger logger @Getter private final Logger logger = Grasscutter.getLogger();
= Grasscutter.getLogger(); @Getter private final Map<Integer, BiConsumer<WebSocket, JsonElement>> handlers = new HashMap<>();
@Getter private final Map<Integer, BiConsumer<WebSocket, JsonElement>> handlers
= new HashMap<>();
@Getter private final Map<Integer, List<Consumer<JsonElement>>> callbacks @Getter private final Map<Integer, List<Consumer<JsonElement>>> callbacks = new HashMap<>();
= new HashMap<>();
/** /**
* Constructs a new {@code DispatchServer} instance. * Constructs a new {@code DispatchServer} instance.
@ -52,15 +48,13 @@ public final class DispatchServer extends WebSocketServer implements IDispatcher
* @param object The packet data. * @param object The packet data.
*/ */
private void handleLogin(WebSocket socket, JsonElement object) { private void handleLogin(WebSocket socket, JsonElement object) {
var dispatchKey = object.getAsString() var dispatchKey = object.getAsString().replaceAll("\"", "");
.replaceAll("\"", "");
// Check if the dispatch key is valid. // Check if the dispatch key is valid.
if (!dispatchKey.equals(DISPATCH_INFO.dispatchKey)) { if (!dispatchKey.equals(DISPATCH_INFO.dispatchKey)) {
this.getLogger().warn("Invalid dispatch key received from {}.", this.getLogger()
socket.getRemoteSocketAddress()); .warn("Invalid dispatch key received from {}.", socket.getRemoteSocketAddress());
this.getLogger().debug("Expected: {}, Received: {}", this.getLogger().debug("Expected: {}, Received: {}", DISPATCH_INFO.dispatchKey, dispatchKey);
DISPATCH_INFO.dispatchKey, dispatchKey);
socket.close(); socket.close();
} else { } else {
socket.setAttachment(true); socket.setAttachment(true);
@ -84,8 +78,7 @@ public final class DispatchServer extends WebSocketServer implements IDispatcher
// Create the response message. // Create the response message.
var response = new JsonObject(); var response = new JsonObject();
response.addProperty("valid", valid); response.addProperty("valid", valid);
if (valid) response.add("account", if (valid) response.add("account", JSON.toJsonTree(account));
JSON.toJsonTree(account));
// Send the response. // Send the response.
this.sendMessage(socket, PacketIds.TokenValidateRsp, response); this.sendMessage(socket, PacketIds.TokenValidateRsp, response);
@ -98,8 +91,7 @@ public final class DispatchServer extends WebSocketServer implements IDispatcher
*/ */
public void sendMessage(int packetId, Object message) { public void sendMessage(int packetId, Object message) {
var serverMessage = this.encodeMessage(packetId, message); var serverMessage = this.encodeMessage(packetId, message);
this.getConnections().forEach( this.getConnections().forEach(socket -> this.sendMessage(socket, serverMessage));
socket -> this.sendMessage(socket, serverMessage));
} }
/** /**
@ -110,8 +102,7 @@ public final class DispatchServer extends WebSocketServer implements IDispatcher
*/ */
public void sendMessage(WebSocket socket, Object message) { public void sendMessage(WebSocket socket, Object message) {
// Serialize the message into JSON. // Serialize the message into JSON.
var serialized = JSON.toJson(message) var serialized = JSON.toJson(message).getBytes(StandardCharsets.UTF_8);
.getBytes(StandardCharsets.UTF_8);
// Encrypt the message. // Encrypt the message.
Crypto.xor(serialized, DISPATCH_INFO.encryptionKey); Crypto.xor(serialized, DISPATCH_INFO.encryptionKey);
// Send the message. // Send the message.
@ -131,20 +122,18 @@ public final class DispatchServer extends WebSocketServer implements IDispatcher
@Override @Override
public void onStart() { public void onStart() {
this.getLogger().info("Dispatch server started on port {}.", this.getLogger().info("Dispatch server started on port {}.", this.getPort());
this.getPort());
} }
@Override @Override
public void onOpen(WebSocket conn, ClientHandshake handshake) { public void onOpen(WebSocket conn, ClientHandshake handshake) {
this.getLogger().debug("Dispatch client connected from {}.", this.getLogger().debug("Dispatch client connected from {}.", conn.getRemoteSocketAddress());
conn.getRemoteSocketAddress());
} }
@Override @Override
public void onMessage(WebSocket conn, String message) { public void onMessage(WebSocket conn, String message) {
this.getLogger().debug("Received dispatch message from {}:\n{}", this.getLogger()
conn.getRemoteSocketAddress(), message); .debug("Received dispatch message from {}:\n{}", conn.getRemoteSocketAddress(), message);
} }
@Override @Override
@ -154,8 +143,7 @@ public final class DispatchServer extends WebSocketServer implements IDispatcher
@Override @Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) { public void onClose(WebSocket conn, int code, String reason, boolean remote) {
this.getLogger().debug("Dispatch client disconnected from {}.", this.getLogger().debug("Dispatch client disconnected from {}.", conn.getRemoteSocketAddress());
conn.getRemoteSocketAddress());
} }
@Override @Override

View File

@ -1,28 +1,28 @@
package emu.grasscutter.server.dispatch; package emu.grasscutter.server.dispatch;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.JsonAdapters.ByteArrayAdapter; import emu.grasscutter.utils.JsonAdapters.ByteArrayAdapter;
import org.java_websocket.WebSocket;
import org.slf4j.Logger;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.java_websocket.WebSocket;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO; import org.slf4j.Logger;
public interface IDispatcher { public interface IDispatcher {
Gson JSON = new GsonBuilder() Gson JSON =
.disableHtmlEscaping() new GsonBuilder()
.registerTypeAdapter(byte[].class, new ByteArrayAdapter()) .disableHtmlEscaping()
.create(); .registerTypeAdapter(byte[].class, new ByteArrayAdapter())
.create();
/** /**
* Decodes an escaped JSON message. * Decodes an escaped JSON message.
@ -47,8 +47,7 @@ public interface IDispatcher {
var data = element.getAsString(); var data = element.getAsString();
// Check if the element starts and ends with quotes. // Check if the element starts and ends with quotes.
if (data.startsWith("\"") if (data.startsWith("\"") && data.endsWith("\"")) {
&& data.endsWith("\"")) {
// Remove the quotes. // Remove the quotes.
data = data.substring(1, data.length() - 1); data = data.substring(1, data.length() - 1);
} }
@ -72,8 +71,7 @@ public interface IDispatcher {
// Decrypt the message. // Decrypt the message.
Crypto.xor(message, DISPATCH_INFO.encryptionKey); Crypto.xor(message, DISPATCH_INFO.encryptionKey);
// Deserialize the message. // Deserialize the message.
return JSON.fromJson(new String( return JSON.fromJson(new String(message, StandardCharsets.UTF_8), JsonObject.class);
message, StandardCharsets.UTF_8), JsonObject.class);
} }
/** /**
@ -116,8 +114,7 @@ public interface IDispatcher {
if (packetId != PacketIds.LoginNotify) { if (packetId != PacketIds.LoginNotify) {
if (socket.getAttachment() instanceof Boolean authenticated) { if (socket.getAttachment() instanceof Boolean authenticated) {
if (!authenticated) { if (!authenticated) {
this.getLogger().warn("Received packet ID {} from unauthenticated client.", this.getLogger().warn("Received packet ID {} from unauthenticated client.", packetId);
packetId);
socket.close(); socket.close();
return; return;
} }
@ -138,13 +135,11 @@ public interface IDispatcher {
// Get the callbacks. // Get the callbacks.
var callbacks = this.getCallbacks().get(packetId); var callbacks = this.getCallbacks().get(packetId);
// Call the callbacks. // Call the callbacks.
callbacks.forEach(callback -> callbacks.forEach(callback -> callback.accept(packetData));
callback.accept(packetData));
callbacks.clear(); callbacks.clear();
} }
} catch (Exception exception) { } catch (Exception exception) {
this.getLogger().warn("Exception occurred while handling packet {}.", this.getLogger().warn("Exception occurred while handling packet {}.", packetId);
packetId);
exception.printStackTrace(); exception.printStackTrace();
} }
} }

View File

@ -1,5 +1,9 @@
package emu.grasscutter.server.game; package emu.grasscutter.server.game;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
import static emu.grasscutter.config.Configuration.GAME_INFO;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.GameConstants; import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerRunMode; import emu.grasscutter.Grasscutter.ServerRunMode;
@ -37,22 +41,17 @@ import emu.grasscutter.server.event.internal.ServerStopEvent;
import emu.grasscutter.server.event.types.ServerEvent; import emu.grasscutter.server.event.types.ServerEvent;
import emu.grasscutter.server.scheduler.ServerTaskScheduler; import emu.grasscutter.server.scheduler.ServerTaskScheduler;
import emu.grasscutter.task.TaskMap; import emu.grasscutter.task.TaskMap;
import kcp.highway.ChannelConfig;
import kcp.highway.KcpServer;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.time.Instant; import java.time.Instant;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import kcp.highway.ChannelConfig;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO; import kcp.highway.KcpServer;
import static emu.grasscutter.config.Configuration.GAME_INFO; import lombok.Getter;
import static emu.grasscutter.utils.Language.translate; import lombok.Setter;
import lombok.SneakyThrows;
@Getter @Getter
public final class GameServer extends KcpServer { public final class GameServer extends KcpServer {

View File

@ -1,5 +1,7 @@
package emu.grasscutter.server.http.dispatch; package emu.grasscutter.server.http.dispatch;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.AuthenticationSystem; import emu.grasscutter.auth.AuthenticationSystem;
import emu.grasscutter.auth.OAuthAuthenticator.ClientType; import emu.grasscutter.auth.OAuthAuthenticator.ClientType;
@ -12,8 +14,6 @@ import emu.grasscutter.utils.JsonUtils;
import io.javalin.Javalin; import io.javalin.Javalin;
import io.javalin.http.Context; import io.javalin.http.Context;
import static emu.grasscutter.utils.Language.translate;
/** Handles requests related to authentication. */ /** Handles requests related to authentication. */
public final class AuthenticationHandler implements Router { public final class AuthenticationHandler implements Router {
/** /**
@ -96,7 +96,8 @@ public final class AuthenticationHandler implements Router {
// Cached token login (from registry). // Cached token login (from registry).
javalin.post("/hk4e_global/mdk/shield/api/verify", AuthenticationHandler::tokenLogin); javalin.post("/hk4e_global/mdk/shield/api/verify", AuthenticationHandler::tokenLogin);
// Combo token login (from session key). // Combo token login (from session key).
javalin.post("/hk4e_global/combo/granter/login/v2/login", AuthenticationHandler::sessionKeyLogin); javalin.post(
"/hk4e_global/combo/granter/login/v2/login", AuthenticationHandler::sessionKeyLogin);
// CN // CN
// Username & Password login (from client). // Username & Password login (from client).

View File

@ -1,5 +1,7 @@
package emu.grasscutter.server.http.dispatch; package emu.grasscutter.server.http.dispatch;
import static emu.grasscutter.config.Configuration.*;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
@ -21,15 +23,12 @@ import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import io.javalin.Javalin; import io.javalin.Javalin;
import io.javalin.http.Context; import io.javalin.http.Context;
import org.slf4j.Logger;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.slf4j.Logger;
import static emu.grasscutter.config.Configuration.*;
/** Handles requests related to region queries. */ /** Handles requests related to region queries. */
public final class RegionHandler implements Router { public final class RegionHandler implements Router {
@ -342,7 +341,8 @@ public final class RegionHandler implements Router {
* @return A {@link QueryCurrRegionHttpRsp} object. * @return A {@link QueryCurrRegionHttpRsp} object.
*/ */
public static QueryCurrRegionHttpRsp getCurrentRegion() { public static QueryCurrRegionHttpRsp getCurrentRegion() {
return Grasscutter.getRunMode() == ServerRunMode.HYBRID ? return Grasscutter.getRunMode() == ServerRunMode.HYBRID
regions.get("os_usa").getRegionQuery() : null; ? regions.get("os_usa").getRegionQuery()
: null;
} }
} }

View File

@ -1,5 +1,7 @@
package emu.grasscutter.server.http.handlers; package emu.grasscutter.server.http.handlers;
import static emu.grasscutter.utils.Language.translate;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
@ -12,16 +14,13 @@ import io.javalin.Javalin;
import io.javalin.http.ContentType; import io.javalin.http.ContentType;
import io.javalin.http.Context; import io.javalin.http.Context;
import io.javalin.http.staticfiles.Location; import io.javalin.http.staticfiles.Location;
import lombok.Getter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import lombok.Getter;
import static emu.grasscutter.utils.Language.translate;
/** Handles all gacha-related HTTP requests. */ /** Handles all gacha-related HTTP requests. */
public final class GachaHandler implements Router { public final class GachaHandler implements Router {
@ -49,8 +48,7 @@ public final class GachaHandler implements Router {
if (gachaTypeStr != null) gachaType = Integer.parseInt(gachaTypeStr); if (gachaTypeStr != null) gachaType = Integer.parseInt(gachaTypeStr);
// Make request to dispatch server. // Make request to dispatch server.
var data = DispatchUtils.fetchGachaRecords( var data = DispatchUtils.fetchGachaRecords(account.getId(), page, gachaType);
account.getId(), page, gachaType);
var records = data.get("records").getAsString(); var records = data.get("records").getAsString();
var maxPage = data.get("maxPage").getAsLong(); var maxPage = data.get("maxPage").getAsLong();
@ -77,7 +75,8 @@ public final class GachaHandler implements Router {
return; return;
} }
String template;try { String template;
try {
template = Files.readString(detailsTemplate); template = Files.readString(detailsTemplate);
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().warn("Failed to read data/gacha/details.html"); Grasscutter.getLogger().warn("Failed to read data/gacha/details.html");
@ -113,8 +112,7 @@ public final class GachaHandler implements Router {
// Add 5-star items. // Add 5-star items.
var fiveStarItems = new LinkedHashSet<String>(); var fiveStarItems = new LinkedHashSet<String>();
Arrays.stream(banner.getRateUpItems5()) Arrays.stream(banner.getRateUpItems5()).forEach(i -> fiveStarItems.add(Integer.toString(i)));
.forEach(i -> fiveStarItems.add(Integer.toString(i)));
Arrays.stream(banner.getFallbackItems5Pool1()) Arrays.stream(banner.getFallbackItems5Pool1())
.forEach(i -> fiveStarItems.add(Integer.toString(i))); .forEach(i -> fiveStarItems.add(Integer.toString(i)));
Arrays.stream(banner.getFallbackItems5Pool2()) Arrays.stream(banner.getFallbackItems5Pool2())
@ -125,8 +123,7 @@ public final class GachaHandler implements Router {
// Add 4-star items. // Add 4-star items.
var fourStarItems = new LinkedHashSet<String>(); var fourStarItems = new LinkedHashSet<String>();
Arrays.stream(banner.getRateUpItems4()) Arrays.stream(banner.getRateUpItems4()).forEach(i -> fourStarItems.add(Integer.toString(i)));
.forEach(i -> fourStarItems.add(Integer.toString(i)));
Arrays.stream(banner.getFallbackItems4Pool1()) Arrays.stream(banner.getFallbackItems4Pool1())
.forEach(i -> fourStarItems.add(Integer.toString(i))); .forEach(i -> fourStarItems.add(Integer.toString(i)));
Arrays.stream(banner.getFallbackItems4Pool2()) Arrays.stream(banner.getFallbackItems4Pool2())
@ -136,8 +133,7 @@ public final class GachaHandler implements Router {
// Add 3-star items. // Add 3-star items.
var threeStarItems = new LinkedHashSet<String>(); var threeStarItems = new LinkedHashSet<String>();
Arrays.stream(banner.getFallbackItems3()) Arrays.stream(banner.getFallbackItems3()).forEach(i -> threeStarItems.add(Integer.toString(i)));
.forEach(i -> threeStarItems.add(Integer.toString(i)));
template = template.replace("{{THREE_STARS}}", "[" + String.join(",", threeStarItems) + "]"); template = template.replace("{{THREE_STARS}}", "[" + String.join(",", threeStarItems) + "]");
// Done. // Done.
@ -153,15 +149,10 @@ public final class GachaHandler implements Router {
* @param page The page to fetch. * @param page The page to fetch.
* @param type The gacha type to fetch. * @param type The gacha type to fetch.
*/ */
public static void fetchGachaRecords( public static void fetchGachaRecords(Player player, JsonObject response, int page, int type) {
Player player, JsonObject response,
int page, int type
) {
var playerId = player.getUid(); var playerId = player.getUid();
var records = DatabaseHelper.getGachaRecords( var records = DatabaseHelper.getGachaRecords(playerId, page, type).toString();
playerId, page, type).toString(); var maxPage = DatabaseHelper.getGachaRecordsMaxPage(playerId, page, type);
var maxPage = DatabaseHelper.getGachaRecordsMaxPage(
playerId, page, type);
// Finish the response. // Finish the response.
response.addProperty("retcode", 0); response.addProperty("retcode", 0);

View File

@ -2,9 +2,7 @@ package emu.grasscutter.server.http.objects;
import lombok.Builder; import lombok.Builder;
/** /** This request object is used in both token-related authenticators. */
* This request object is used in both token-related authenticators.
*/
@Builder @Builder
public class LoginTokenRequestJson { public class LoginTokenRequestJson {
public String uid; public String uid;

View File

@ -1,5 +1,7 @@
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
@ -15,12 +17,9 @@ import emu.grasscutter.utils.ByteHelper;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.DispatchUtils; import emu.grasscutter.utils.DispatchUtils;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import javax.crypto.Cipher;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.security.Signature; import java.security.Signature;
import javax.crypto.Cipher;
import static emu.grasscutter.config.Configuration.ACCOUNT;
@Opcodes(PacketOpcodes.GetPlayerTokenReq) @Opcodes(PacketOpcodes.GetPlayerTokenReq)
public class HandlerGetPlayerTokenReq extends PacketHandler { public class HandlerGetPlayerTokenReq extends PacketHandler {
@ -30,8 +29,7 @@ public class HandlerGetPlayerTokenReq extends PacketHandler {
// Fetch the account from the ID and token. // Fetch the account from the ID and token.
var accountId = req.getAccountUid(); var accountId = req.getAccountUid();
var account = DispatchUtils.authenticate( var account = DispatchUtils.authenticate(accountId, req.getAccountToken());
accountId, req.getAccountToken());
// Check the account. // Check the account.
if (account == null) { if (account == null) {
@ -47,8 +45,7 @@ public class HandlerGetPlayerTokenReq extends PacketHandler {
// secondly !!! // secondly !!!
// TODO - optimize // TODO - optimize
boolean kicked = false; boolean kicked = false;
var exists = Grasscutter.getGameServer() var exists = Grasscutter.getGameServer().getPlayerByAccountId(accountId);
.getPlayerByAccountId(accountId);
if (exists != null) { if (exists != null) {
var existsSession = exists.getSession(); var existsSession = exists.getSession();
if (existsSession != session) { // No self-kicking if (existsSession != session) { // No self-kicking

View File

@ -1,5 +1,8 @@
package emu.grasscutter.server.packet.send; package emu.grasscutter.server.packet.send;
import static emu.grasscutter.config.Configuration.GAME_INFO;
import static emu.grasscutter.config.Configuration.lr;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerRunMode; import emu.grasscutter.Grasscutter.ServerRunMode;
@ -11,12 +14,8 @@ import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.http.dispatch.RegionHandler; import emu.grasscutter.server.http.dispatch.RegionHandler;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import java.util.Objects; import java.util.Objects;
import static emu.grasscutter.config.Configuration.GAME_INFO;
import static emu.grasscutter.config.Configuration.lr;
public class PacketPlayerLoginRsp extends BasePacket { public class PacketPlayerLoginRsp extends BasePacket {
private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache; private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache;

View File

@ -1,5 +1,7 @@
package emu.grasscutter.utils; package emu.grasscutter.utils;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest; import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
@ -9,20 +11,18 @@ import emu.grasscutter.server.dispatch.IDispatcher;
import emu.grasscutter.server.dispatch.PacketIds; import emu.grasscutter.server.dispatch.PacketIds;
import emu.grasscutter.server.http.handlers.GachaHandler; import emu.grasscutter.server.http.handlers.GachaHandler;
import emu.grasscutter.server.http.objects.LoginTokenRequestJson; import emu.grasscutter.server.http.objects.LoginTokenRequestJson;
import javax.annotation.Nullable;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
public interface DispatchUtils { public interface DispatchUtils {
/** HTTP client used for dispatch queries. */ /** HTTP client used for dispatch queries. */
HttpClient HTTP_CLIENT = HttpClient.newBuilder() HttpClient HTTP_CLIENT =
.version(HttpClient.Version.HTTP_2) HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS) .version(HttpClient.Version.HTTP_2)
.build(); .followRedirects(HttpClient.Redirect.ALWAYS)
.build();
/** /**
* @return The dispatch URL. * @return The dispatch URL.
@ -38,22 +38,16 @@ public interface DispatchUtils {
* @param token The token. * @param token The token.
* @return {@code true} if the authentication request is valid, otherwise {@code false}. * @return {@code true} if the authentication request is valid, otherwise {@code false}.
*/ */
@Nullable @Nullable static Account authenticate(String accountId, String token) {
static Account authenticate(String accountId, String token) {
return switch (Grasscutter.getRunMode()) { return switch (Grasscutter.getRunMode()) {
case GAME_ONLY -> case GAME_ONLY ->
// Use the authentication system to validate the token. // Use the authentication system to validate the token.
Grasscutter.getAuthenticationSystem() Grasscutter.getAuthenticationSystem()
.getSessionTokenValidator() .getSessionTokenValidator()
.authenticate( .authenticate(
AuthenticationRequest.builder() AuthenticationRequest.builder()
.tokenRequest( .tokenRequest(LoginTokenRequestJson.builder().uid(accountId).token(token).build())
LoginTokenRequestJson.builder() .build());
.uid(accountId)
.token(token)
.build()
).build()
);
case HYBRID, DISPATCH_ONLY -> { case HYBRID, DISPATCH_ONLY -> {
// Fetch the account from the database. // Fetch the account from the database.
var account = DatabaseHelper.getAccountById(accountId); var account = DatabaseHelper.getAccountById(accountId);
@ -86,8 +80,9 @@ public interface DispatchUtils {
var future = new CompletableFuture<JsonObject>(); var future = new CompletableFuture<JsonObject>();
// Listen for the response. // Listen for the response.
var server = Grasscutter.getDispatchServer(); var server = Grasscutter.getDispatchServer();
server.registerCallback(PacketIds.GachaHistoryRsp, packet -> server.registerCallback(
future.complete(IDispatcher.decode(packet, JsonObject.class))); PacketIds.GachaHistoryRsp,
packet -> future.complete(IDispatcher.decode(packet, JsonObject.class)));
// Broadcast the request. // Broadcast the request.
server.sendMessage(PacketIds.GachaHistoryReq, request); server.sendMessage(PacketIds.GachaHistoryReq, request);
@ -104,16 +99,14 @@ public interface DispatchUtils {
var response = new JsonObject(); var response = new JsonObject();
// Get the player's ID from the account. // Get the player's ID from the account.
var player = Grasscutter.getGameServer() var player = Grasscutter.getGameServer().getPlayerByAccountId(accountId);
.getPlayerByAccountId(accountId);
if (player == null) { if (player == null) {
response.addProperty("retcode", 1); response.addProperty("retcode", 1);
yield response; yield response;
} }
// Fetch the gacha records. // Fetch the gacha records.
GachaHandler.fetchGachaRecords( GachaHandler.fetchGachaRecords(player, response, page, gachaType);
player, response, page, gachaType);
yield response; yield response;
} }

View File

@ -11,13 +11,12 @@ import emu.grasscutter.data.common.DynamicFloat;
import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import lombok.val;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects; import java.util.Objects;
import lombok.val;
public class JsonAdapters { public class JsonAdapters {
static class DynamicFloatAdapter extends TypeAdapter<DynamicFloat> { static class DynamicFloatAdapter extends TypeAdapter<DynamicFloat> {

View File

@ -1,5 +1,9 @@
package emu.grasscutter.utils; package emu.grasscutter.utils;
import static emu.grasscutter.config.Configuration.FALLBACK_LANGUAGE;
import static emu.grasscutter.utils.FileUtils.getCachePath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
@ -13,8 +17,6 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import lombok.EqualsAndHashCode;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@ -26,10 +28,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import lombok.EqualsAndHashCode;
import static emu.grasscutter.config.Configuration.FALLBACK_LANGUAGE;
import static emu.grasscutter.utils.FileUtils.getCachePath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
public final class Language { public final class Language {
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>(); private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
@ -133,13 +132,13 @@ public final class Language {
for (var i = 0; i < args.length; i++) { for (var i = 0; i < args.length; i++) {
args[i] = args[i] =
switch (args[i].getClass().getSimpleName()) { switch (args[i].getClass().getSimpleName()) {
case "String" -> args[i]; case "String" -> args[i];
case "TextStrings" -> ((TextStrings) args[i]) case "TextStrings" -> ((TextStrings) args[i])
.getGC(langCode) .getGC(langCode)
.replace("\\\\n", "\n"); // Note that we don't unescape \n for server console .replace("\\\\n", "\n"); // Note that we don't unescape \n for server console
default -> args[i].toString(); default -> args[i].toString();
}; };
} }
try { try {

View File

@ -1,73 +1,78 @@
package emu.grasscutter.utils; package emu.grasscutter.utils;
import static emu.grasscutter.config.Configuration.*;
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.Logger;
import emu.grasscutter.BuildConfig; import emu.grasscutter.BuildConfig;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.PacketOpcodesUtils; import emu.grasscutter.net.packet.PacketOpcodesUtils;
import emu.grasscutter.tools.Dumpers; import emu.grasscutter.tools.Dumpers;
import org.slf4j.LoggerFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import org.slf4j.LoggerFactory;
import static emu.grasscutter.config.Configuration.*;
/** A parser for start-up arguments. */ /** A parser for start-up arguments. */
public final class StartupArguments { public final class StartupArguments {
/* A map of parameter -> argument handler. */ /* A map of parameter -> argument handler. */
private static final Map<String, Function<String, Boolean>> argumentHandlers = new HashMap<>() { private static final Map<String, Function<String, Boolean>> argumentHandlers =
{ new HashMap<>() {
putAll(Map.of("-dumppacketids", {
parameter -> { putAll(
PacketOpcodesUtils.dumpPacketIds(); Map.of(
return true; "-dumppacketids",
}, parameter -> {
"-version", StartupArguments::printVersion, PacketOpcodesUtils.dumpPacketIds();
"-debug", StartupArguments::enableDebug, return true;
"-lang", },
parameter -> { "-version",
Grasscutter.setPreferredLanguage(parameter); StartupArguments::printVersion,
return false; "-debug",
}, StartupArguments::enableDebug,
"-game", "-lang",
parameter -> { parameter -> {
Grasscutter.setRunModeOverride(Grasscutter.ServerRunMode.GAME_ONLY); Grasscutter.setPreferredLanguage(parameter);
return false; return false;
}, },
"-dispatch", "-game",
parameter -> { parameter -> {
Grasscutter.setRunModeOverride(Grasscutter.ServerRunMode.DISPATCH_ONLY); Grasscutter.setRunModeOverride(Grasscutter.ServerRunMode.GAME_ONLY);
return false; return false;
}, },
"-noconsole", "-dispatch",
parameter -> { parameter -> {
Grasscutter.setNoConsole(true); Grasscutter.setRunModeOverride(Grasscutter.ServerRunMode.DISPATCH_ONLY);
return false; return false;
}, },
"-test", "-noconsole",
parameter -> { parameter -> {
// Disable the console. Grasscutter.setNoConsole(true);
SERVER.game.enableConsole = false; return false;
// Disable HTTP encryption. },
SERVER.http.encryption.useEncryption = false; "-test",
return false; parameter -> {
}, // Disable the console.
"-dump", StartupArguments::dump, SERVER.game.enableConsole = false;
// Disable HTTP encryption.
SERVER.http.encryption.useEncryption = false;
return false;
},
"-dump",
StartupArguments::dump,
// Aliases. // Aliases.
"-v", StartupArguments::printVersion "-v",
)); StartupArguments::printVersion));
putAll(Map.of( putAll(
"-debugall", Map.of(
parameter -> { "-debugall",
StartupArguments.enableDebug("all"); parameter -> {
return false; StartupArguments.enableDebug("all");
return false;
}));
} }
)); };
}
};
private StartupArguments() { private StartupArguments() {
// This class is not meant to be instantiated. // This class is not meant to be instantiated.