Run Spotless on src/main

This commit is contained in:
KingRainbow44 2023-03-31 22:30:45 -04:00
parent 99822b0e22
commit fc05602128
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
1003 changed files with 60650 additions and 58050 deletions

View File

@ -2,7 +2,6 @@ package emu.grasscutter;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import java.util.Arrays; import java.util.Arrays;
public final class GameConstants { public final class GameConstants {
@ -21,10 +20,16 @@ public final class GameConstants {
public static final int BATTLE_PASS_CURRENT_INDEX = 2; public static final int BATTLE_PASS_CURRENT_INDEX = 2;
// 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_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener" "Avatar_DefaultAbility_AvartarInShaderChange",
"Avatar_SprintBS_Invincible",
"Avatar_Freeze_Duration_Reducer",
"Avatar_Attack_ReviveEnergy",
"Avatar_Component_Initializer",
"Avatar_FallAnthem_Achievement_Listener"
}; };
public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray(); public static final int[] DEFAULT_ABILITY_HASHES =
Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray();
public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default"); public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default");
public static String VERSION = "3.5.0"; public static String VERSION = "3.5.0";
} }

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;
@ -24,6 +27,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;
@ -35,21 +44,10 @@ 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");
@Getter private static final Logger logger = @Getter private static final Logger logger = (Logger) LoggerFactory.getLogger(Grasscutter.class);
(Logger) LoggerFactory.getLogger(Grasscutter.class);
@Getter public static ConfigContainer config; @Getter public static ConfigContainer config;
@ -165,13 +163,10 @@ public final class Grasscutter {
Grasscutter.startConsole(); Grasscutter.startConsole();
} }
/** /** Server shutdown event. */
* Server shutdown event.
*/
private static void onShutdown() { private static void onShutdown() {
// Disable all plugins. // Disable all plugins.
if (pluginManager != null) if (pluginManager != null) pluginManager.disablePlugins();
pluginManager.disablePlugins();
} }
/* /*
@ -187,9 +182,7 @@ public final class Grasscutter {
* Methods for the configuration system component. * Methods for the configuration system component.
*/ */
/** /** Attempts to load the configuration from a file. */
* Attempts to load the configuration from a file.
*/
public static void loadConfig() { public static void loadConfig() {
// Check if config.json exists. If not, we generate a new config. // Check if config.json exists. If not, we generate a new config.
if (!configFile.exists()) { if (!configFile.exists()) {
@ -203,7 +196,9 @@ public final class Grasscutter {
try { try {
config = JsonUtils.loadToClass(configFile.toPath(), ConfigContainer.class); config = JsonUtils.loadToClass(configFile.toPath(), ConfigContainer.class);
} catch (Exception exception) { } catch (Exception exception) {
getLogger().error("There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json."); getLogger()
.error(
"There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
System.exit(1); System.exit(1);
} }
} }
@ -251,9 +246,7 @@ public final class Grasscutter {
} }
} }
consoleLineReader = LineReaderBuilder.builder() consoleLineReader = LineReaderBuilder.builder().terminal(terminal).build();
.terminal(terminal)
.build();
} }
return consoleLineReader; return consoleLineReader;
@ -314,10 +307,16 @@ public final class Grasscutter {
*/ */
public enum ServerRunMode { public enum ServerRunMode {
HYBRID, DISPATCH_ONLY, GAME_ONLY HYBRID,
DISPATCH_ONLY,
GAME_ONLY
} }
public enum ServerDebugMode { public enum ServerDebugMode {
ALL, MISSING, WHITELIST, BLACKLIST, NONE ALL,
MISSING,
WHITELIST,
BLACKLIST,
NONE
} }
} }

View File

@ -3,16 +3,12 @@ package emu.grasscutter.auth;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.server.http.objects.*; import emu.grasscutter.server.http.objects.*;
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 {
/** /**
@ -23,10 +19,7 @@ public interface AuthenticationSystem {
* @return An authentication request. * @return An authentication request.
*/ */
static AuthenticationRequest fromPasswordRequest(Context ctx, LoginAccountRequestJson jsonData) { static AuthenticationRequest fromPasswordRequest(Context ctx, LoginAccountRequestJson jsonData) {
return AuthenticationRequest.builder() return AuthenticationRequest.builder().context(ctx).passwordRequest(jsonData).build();
.context(ctx)
.passwordRequest(jsonData)
.build();
} }
/** /**
@ -37,10 +30,7 @@ public interface AuthenticationSystem {
* @return An authentication request. * @return An authentication request.
*/ */
static AuthenticationRequest fromTokenRequest(Context ctx, LoginTokenRequestJson jsonData) { static AuthenticationRequest fromTokenRequest(Context ctx, LoginTokenRequestJson jsonData) {
return AuthenticationRequest.builder() return AuthenticationRequest.builder().context(ctx).tokenRequest(jsonData).build();
.context(ctx)
.tokenRequest(jsonData)
.build();
} }
/** /**
@ -50,8 +40,8 @@ public interface AuthenticationSystem {
* @param jsonData The JSON data. * @param jsonData The JSON data.
* @return An authentication request. * @return An authentication request.
*/ */
static AuthenticationRequest fromComboTokenRequest(Context ctx, ComboTokenReqJson jsonData, static AuthenticationRequest fromComboTokenRequest(
ComboTokenReqJson.LoginTokenData tokenData) { Context ctx, ComboTokenReqJson jsonData, ComboTokenReqJson.LoginTokenData tokenData) {
return AuthenticationRequest.builder() return AuthenticationRequest.builder()
.context(ctx) .context(ctx)
.sessionKeyRequest(jsonData) .sessionKeyRequest(jsonData)
@ -88,7 +78,8 @@ public interface AuthenticationSystem {
* Called by plugins to internally verify a user's identity. * Called by plugins to internally verify a user's identity.
* *
* @param details A unique identifier to identify the user. (For example: a JWT token) * @param details A unique identifier to identify the user. (For example: a JWT token)
* @return The user's account if the verification was successful, null if the user was unable to be verified. * @return The user's account if the verification was successful, null if the user was unable to
* be verified.
*/ */
Account verifyUser(String details); Account verifyUser(String details);
@ -127,22 +118,16 @@ public interface AuthenticationSystem {
*/ */
OAuthAuthenticator getOAuthAuthenticator(); OAuthAuthenticator getOAuthAuthenticator();
/** /** A data container that holds relevant data for authenticating a client. */
* A data container that holds relevant data for authenticating a client.
*/
@Builder @Builder
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
class AuthenticationRequest { class AuthenticationRequest {
private final Context context; private final Context context;
@Nullable @Nullable private final LoginAccountRequestJson passwordRequest;
private final LoginAccountRequestJson passwordRequest; @Nullable private final LoginTokenRequestJson tokenRequest;
@Nullable @Nullable private final ComboTokenReqJson sessionKeyRequest;
private final LoginTokenRequestJson tokenRequest; @Nullable private final ComboTokenReqJson.LoginTokenData sessionKeyData;
@Nullable
private final ComboTokenReqJson sessionKeyRequest;
@Nullable
private final ComboTokenReqJson.LoginTokenData sessionKeyData;
} }
} }

View File

@ -6,14 +6,16 @@ import emu.grasscutter.server.http.objects.LoginResultJson;
/** /**
* Handles username/password authentication from the client. * Handles username/password authentication from the client.
* *
* @param <T> The response object type. Should be {@link LoginResultJson} or {@link ComboTokenResJson} * @param <T> The response object type. Should be {@link LoginResultJson} or {@link
* ComboTokenResJson}
*/ */
public interface Authenticator<T> { public interface Authenticator<T> {
/** /**
* Attempt to authenticate the client with the provided credentials. * Attempt to authenticate the client with the provided credentials.
* *
* @param request The authentication request wrapped in a {@link AuthenticationSystem.AuthenticationRequest} object. * @param request The authentication request wrapped in a {@link
* AuthenticationSystem.AuthenticationRequest} object.
* @return The result of the login in an object. * @return The result of the login in an object.
*/ */
T authenticate(AuthenticationSystem.AuthenticationRequest request); T authenticate(AuthenticationSystem.AuthenticationRequest request);

View File

@ -1,22 +1,22 @@
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. * The default Grasscutter authentication implementation. Allows all users to access any account.
* Allows all users to access any account.
*/ */
public final class DefaultAuthentication implements AuthenticationSystem { public final class DefaultAuthentication implements AuthenticationSystem {
private final Authenticator<LoginResultJson> passwordAuthenticator; private final Authenticator<LoginResultJson> passwordAuthenticator;
private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator(); private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator();
private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator = new SessionKeyAuthenticator(); private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator =
new SessionKeyAuthenticator();
private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication();
private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
@ -40,7 +40,8 @@ public final class DefaultAuthentication implements AuthenticationSystem {
@Override @Override
public Account verifyUser(String details) { public Account verifyUser(String details) {
Grasscutter.getLogger().info(translate("messages.dispatch.authentication.default_unable_to_verify")); Grasscutter.getLogger()
.info(translate("messages.dispatch.authentication.default_unable_to_verify"));
return null; return null;
} }

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;
@ -9,24 +12,16 @@ 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 javax.crypto.Cipher;
import static emu.grasscutter.config.Configuration.ACCOUNT; /** A class containing default authenticators. */
import static emu.grasscutter.utils.Language.translate;
/**
* A class containing default authenticators.
*/
public final class DefaultAuthenticators { public final class DefaultAuthenticators {
/** /** Handles the authentication request from the username and password form. */
* Handles the authentication request from the username and password form.
*/
public static class PasswordAuthenticator implements Authenticator<LoginResultJson> { public static class PasswordAuthenticator implements Authenticator<LoginResultJson> {
@Override @Override
public LoginResultJson authenticate(AuthenticationRequest request) { public LoginResultJson authenticate(AuthenticationRequest request) {
@ -52,16 +47,21 @@ public final class DefaultAuthenticators {
// 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");
Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_error", address)); Grasscutter.getLogger()
.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().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); Grasscutter.getLogger()
.info(
translate(
"messages.dispatch.account.account_login_create_success",
address,
response.data.account.uid));
} }
} else if (account != null) } else if (account != null) successfulLogin = true;
successfulLogin = true;
else else
loggerMessage = translate("messages.dispatch.account.account_login_exist_error", address); loggerMessage = translate("messages.dispatch.account.account_login_exist_error", address);
@ -70,7 +70,6 @@ public final class DefaultAuthenticators {
loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address);
} }
// Set response data. // Set response data.
if (successfulLogin) { if (successfulLogin) {
response.message = "OK"; response.message = "OK";
@ -78,11 +77,11 @@ public final class DefaultAuthenticators {
response.data.account.token = account.generateSessionKey(); response.data.account.token = account.generateSessionKey();
response.data.account.email = account.getEmail(); response.data.account.email = account.getEmail();
loggerMessage = translate("messages.dispatch.account.login_success", address, account.getId()); loggerMessage =
translate("messages.dispatch.account.login_success", address, account.getId());
} else { } else {
response.retcode = -201; response.retcode = -201;
response.message = responseMessage; response.message = responseMessage;
} }
Grasscutter.getLogger().info(loggerMessage); Grasscutter.getLogger().info(loggerMessage);
@ -114,7 +113,10 @@ public final class DefaultAuthenticators {
cipher.init(Cipher.DECRYPT_MODE, private_key); cipher.init(Cipher.DECRYPT_MODE, private_key);
decryptedPassword = new String(cipher.doFinal(Utils.base64Decode(request.getPasswordRequest().password)), StandardCharsets.UTF_8); decryptedPassword =
new String(
cipher.doFinal(Utils.base64Decode(request.getPasswordRequest().password)),
StandardCharsets.UTF_8);
} catch (Exception ignored) { } catch (Exception ignored) {
decryptedPassword = request.getPasswordRequest().password; decryptedPassword = request.getPasswordRequest().password;
} }
@ -133,19 +135,26 @@ public final class DefaultAuthenticators {
// This account has been created AUTOMATICALLY. There will be no permissions added. // This account has been created AUTOMATICALLY. There will be no permissions added.
if (decryptedPassword.length() >= 8) { if (decryptedPassword.length() >= 8) {
account = DatabaseHelper.createAccountWithUid(requestData.account, 0); account = DatabaseHelper.createAccountWithUid(requestData.account, 0);
account.setPassword(BCrypt.withDefaults().hashToString(12, decryptedPassword.toCharArray())); account.setPassword(
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 = translate("messages.dispatch.account.account_login_create_error", address); loggerMessage =
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().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); Grasscutter.getLogger()
.info(
translate(
"messages.dispatch.account.account_login_create_success",
address,
response.data.account.uid));
} }
} else { } else {
successfulLogin = false; successfulLogin = false;
@ -154,7 +163,9 @@ 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().verify(decryptedPassword.toCharArray(), account.getPassword()).verified) { if (BCrypt.verifyer()
.verify(decryptedPassword.toCharArray(), account.getPassword())
.verified) {
successfulLogin = true; successfulLogin = true;
} else { } else {
successfulLogin = false; successfulLogin = false;
@ -163,7 +174,8 @@ public final class DefaultAuthenticators {
} }
} else { } else {
successfulLogin = false; successfulLogin = false;
loggerMessage = translate("messages.dispatch.account.login_password_storage_error", address); loggerMessage =
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 {
@ -174,7 +186,6 @@ public final class DefaultAuthenticators {
loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address);
} }
// Set response data. // Set response data.
if (successfulLogin) { if (successfulLogin) {
response.message = "OK"; response.message = "OK";
@ -182,11 +193,11 @@ public final class DefaultAuthenticators {
response.data.account.token = account.generateSessionKey(); response.data.account.token = account.generateSessionKey();
response.data.account.email = account.getEmail(); response.data.account.email = account.getEmail();
loggerMessage = translate("messages.dispatch.account.login_success", address, account.getId()); loggerMessage =
translate("messages.dispatch.account.login_success", address, account.getId());
} else { } else {
response.retcode = -201; response.retcode = -201;
response.message = responseMessage; response.message = responseMessage;
} }
Grasscutter.getLogger().info(loggerMessage); Grasscutter.getLogger().info(loggerMessage);
@ -194,9 +205,7 @@ public final class DefaultAuthenticators {
} }
} }
/** /** Handles the authentication request from the game when using a registry token. */
* Handles the authentication request from the game when using a registry token.
*/
public static class TokenAuthenticator implements Authenticator<LoginResultJson> { public static class TokenAuthenticator implements Authenticator<LoginResultJson> {
@Override @Override
public LoginResultJson authenticate(AuthenticationRequest request) { public LoginResultJson authenticate(AuthenticationRequest request) {
@ -211,7 +220,8 @@ public final class DefaultAuthenticators {
int playerCount = Grasscutter.getGameServer().getPlayers().size(); int playerCount = Grasscutter.getGameServer().getPlayers().size();
// Log the attempt. // Log the attempt.
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_attempt", address)); Grasscutter.getLogger()
.info(translate("messages.dispatch.account.login_token_attempt", address));
if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) { if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) {
@ -229,7 +239,8 @@ public final class DefaultAuthenticators {
response.data.account.email = account.getEmail(); response.data.account.email = account.getEmail();
// Log the login. // Log the login.
loggerMessage = translate("messages.dispatch.account.login_token_success", address, requestData.uid); loggerMessage =
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");
@ -250,9 +261,7 @@ public final class DefaultAuthenticators {
} }
} }
/** /** Handles the authentication request from the game when using a combo token/session key. */
* Handles the authentication request from the game when using a combo token/session key.
*/
public static class SessionKeyAuthenticator implements Authenticator<ComboTokenResJson> { public static class SessionKeyAuthenticator implements Authenticator<ComboTokenResJson> {
@Override @Override
public ComboTokenResJson authenticate(AuthenticationRequest request) { public ComboTokenResJson authenticate(AuthenticationRequest request) {
@ -304,43 +313,51 @@ public final class DefaultAuthenticators {
} }
} }
/** /** Handles authentication requests from external sources. */
* Handles authentication requests from external sources.
*/
public static class ExternalAuthentication implements ExternalAuthenticator { public static class ExternalAuthentication implements ExternalAuthenticator {
@Override @Override
public void handleLogin(AuthenticationRequest request) { public void handleLogin(AuthenticationRequest request) {
request.getContext().result("Authentication is not available with the default authentication method."); request
.getContext()
.result("Authentication is not available with the default authentication method.");
} }
@Override @Override
public void handleAccountCreation(AuthenticationRequest request) { public void handleAccountCreation(AuthenticationRequest request) {
request.getContext().result("Authentication is not available with the default authentication method."); request
.getContext()
.result("Authentication is not available with the default authentication method.");
} }
@Override @Override
public void handlePasswordReset(AuthenticationRequest request) { public void handlePasswordReset(AuthenticationRequest request) {
request.getContext().result("Authentication is not available with the default authentication method."); request
.getContext()
.result("Authentication is not available with the default authentication method.");
} }
} }
/** /** Handles authentication requests from OAuth sources.Zenlith */
* Handles authentication requests from OAuth sources.Zenlith
*/
public static class OAuthAuthentication implements OAuthAuthenticator { public static class OAuthAuthentication implements OAuthAuthenticator {
@Override @Override
public void handleLogin(AuthenticationRequest request) { public void handleLogin(AuthenticationRequest request) {
request.getContext().result("Authentication is not available with the default authentication method."); request
.getContext()
.result("Authentication is not available with the default authentication method.");
} }
@Override @Override
public void handleRedirection(AuthenticationRequest request, ClientType type) { public void handleRedirection(AuthenticationRequest request, ClientType type) {
request.getContext().result("Authentication is not available with the default authentication method."); request
.getContext()
.result("Authentication is not available with the default authentication method.");
} }
@Override @Override
public void handleTokenProcess(AuthenticationRequest request) { public void handleTokenProcess(AuthenticationRequest request) {
request.getContext().result("Authentication is not available with the default authentication method."); request
.getContext()
.result("Authentication is not available with the default authentication method.");
} }
} }
} }

View File

@ -2,9 +2,7 @@ package emu.grasscutter.auth;
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest; import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
/** /** Handles authentication via external routes. */
* Handles authentication via external routes.
*/
public interface ExternalAuthenticator { public interface ExternalAuthenticator {
/** /**
@ -18,9 +16,8 @@ public interface ExternalAuthenticator {
* Called when an external account creation request is made. * Called when an external account creation request is made.
* *
* @param request The authentication request. * @param request The authentication request.
* <p> * <p>For developers: Use AuthenticationRequest#getRequest() to get the request body. Use
* For developers: Use AuthenticationRequest#getRequest() to get the request body. * AuthenticationRequest#getResponse() to get the response body.
* Use AuthenticationRequest#getResponse() to get the response body.
*/ */
void handleAccountCreation(AuthenticationRequest request); void handleAccountCreation(AuthenticationRequest request);
@ -28,9 +25,8 @@ public interface ExternalAuthenticator {
* Called when an external password reset request is made. * Called when an external password reset request is made.
* *
* @param request The authentication request. * @param request The authentication request.
* <p> * <p>For developers: Use AuthenticationRequest#getRequest() to get the request body. Use
* For developers: Use AuthenticationRequest#getRequest() to get the request body. * AuthenticationRequest#getResponse() to get the response body.
* Use AuthenticationRequest#getResponse() to get the response body.
*/ */
void handlePasswordReset(AuthenticationRequest request); void handlePasswordReset(AuthenticationRequest request);
} }

View File

@ -2,9 +2,7 @@ package emu.grasscutter.auth;
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest; import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
/** /** Handles authentication via OAuth routes. */
* Handles authentication via OAuth routes.
*/
public interface OAuthAuthenticator { public interface OAuthAuthenticator {
/** /**
@ -28,11 +26,9 @@ public interface OAuthAuthenticator {
*/ */
void handleTokenProcess(AuthenticationRequest request); void handleTokenProcess(AuthenticationRequest request);
/** /** The type of the client. Used for handling redirection. */
* The type of the client.
* Used for handling redirection.
*/
enum ClientType { enum ClientType {
DESKTOP, MOBILE DESKTOP,
MOBILE
} }
} }

View File

@ -1,14 +1,13 @@
package emu.grasscutter.command; package emu.grasscutter.command;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent; import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
import java.util.List; import java.util.List;
import java.util.StringJoiner; import java.util.StringJoiner;
import static emu.grasscutter.utils.Language.translate;
public interface CommandHandler { public interface CommandHandler {
/** /**
@ -42,23 +41,23 @@ public interface CommandHandler {
String usage_prefix = translate(player, "commands.execution.usage_prefix"); String usage_prefix = translate(player, "commands.execution.usage_prefix");
String command = annotation.label(); String command = annotation.label();
for (String alias : annotation.aliases()) { for (String alias : annotation.aliases()) {
if (alias.length() < command.length()) if (alias.length() < command.length()) command = alias;
command = alias;
} }
if (player != null) { if (player != null) {
command = "/" + command; command = "/" + command;
} }
String target = switch (annotation.targetRequirement()) { String target =
switch (annotation.targetRequirement()) {
case NONE -> ""; case NONE -> "";
case OFFLINE -> "@<UID> "; // TODO: make translation keys for offline and online players case OFFLINE -> "@<UID> "; // TODO: make translation keys for offline and online players
case ONLINE -> case ONLINE -> (player == null)
(player == null) ? "@<UID> " : "[@<UID>] "; // TODO: make translation keys for offline and online players ? "@<UID> "
: "[@<UID>] "; // TODO: make translation keys for offline and online players
case PLAYER -> (player == null) ? "@<UID> " : "[@<UID>] "; case PLAYER -> (player == null) ? "@<UID> " : "[@<UID>] ";
}; };
String[] usages = annotation.usage(); String[] usages = annotation.usage();
StringJoiner joiner = new StringJoiner("\n\t"); StringJoiner joiner = new StringJoiner("\n\t");
for (String usage : usages) for (String usage : usages) joiner.add(usage_prefix + command + " " + target + usage);
joiner.add(usage_prefix + command + " " + target + usage);
return joiner.toString(); return joiner.toString();
} }
@ -85,6 +84,5 @@ public interface CommandHandler {
* @param sender The player/console that invoked the command. * @param sender The player/console that invoked the command.
* @param args The arguments to the command. * @param args The arguments to the command.
*/ */
default void execute(Player sender, Player targetPlayer, List<String> args) { default void execute(Player sender, Player targetPlayer, List<String> args) {}
}
} }

View File

@ -1,15 +1,17 @@
package emu.grasscutter.command; package emu.grasscutter.command;
import javax.annotation.Nonnull;
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.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Nonnull;
public class CommandHelpers { public class CommandHelpers {
public static final Pattern lvlRegex = Pattern.compile("(?<!\\w)l(?:vl?)?(\\d+)"); // Java doesn't have raw string literals :( public static final Pattern lvlRegex =
public static final Pattern amountRegex = Pattern.compile("((?<=(?<!\\w)x)\\d+|\\d+(?=x)(?!x\\d))"); Pattern.compile("(?<!\\w)l(?:vl?)?(\\d+)"); // Java doesn't have raw string literals :(
public static final Pattern amountRegex =
Pattern.compile("((?<=(?<!\\w)x)\\d+|\\d+(?=x)(?!x\\d))");
public static final Pattern refineRegex = Pattern.compile("(?<!\\w)r(\\d+)"); public static final Pattern refineRegex = Pattern.compile("(?<!\\w)r(\\d+)");
public static final Pattern rankRegex = Pattern.compile("(\\d+)\\*"); public static final Pattern rankRegex = Pattern.compile("(\\d+)\\*");
public static final Pattern constellationRegex = Pattern.compile("(?<!\\w)c(\\d+)"); public static final Pattern constellationRegex = Pattern.compile("(?<!\\w)c(\\d+)");
@ -27,13 +29,18 @@ public class CommandHelpers {
public static int matchIntOrNeg(Pattern pattern, String arg) { public static int matchIntOrNeg(Pattern pattern, String arg) {
Matcher match = pattern.matcher(arg); Matcher match = pattern.matcher(arg);
if (match.find()) { if (match.find()) {
return Integer.parseInt(match.group(1)); // This should be exception-safe as only \d+ can be passed to it (i.e. non-empty string of pure digits) return Integer.parseInt(
match.group(
1)); // This should be exception-safe as only \d+ can be passed to it (i.e. non-empty
// string of pure digits)
} }
return -1; return -1;
} }
public static <T> List<String> parseIntParameters(List<String> args, @Nonnull T params, Map<Pattern, BiConsumer<T, Integer>> map) { public static <T> List<String> parseIntParameters(
args.removeIf(arg -> { List<String> args, @Nonnull T params, Map<Pattern, BiConsumer<T, Integer>> map) {
args.removeIf(
arg -> {
var argL = arg.toLowerCase(); var argL = arg.toLowerCase();
boolean deleteArg = false; boolean deleteArg = false;
for (var entry : map.entrySet()) { for (var entry : map.entrySet()) {

View File

@ -1,15 +1,14 @@
package emu.grasscutter.command; package emu.grasscutter.command;
import static emu.grasscutter.config.Configuration.SERVER;
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;
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 org.reflections.Reflections;
import java.util.*; import java.util.*;
import org.reflections.Reflections;
import static emu.grasscutter.config.Configuration.SERVER;
@SuppressWarnings({"UnusedReturnValue", "unused"}) @SuppressWarnings({"UnusedReturnValue", "unused"})
public final class CommandMap { public final class CommandMap {
@ -131,7 +130,8 @@ public final class CommandMap {
return handler; return handler;
} }
private Player getTargetPlayer(String playerId, Player player, Player targetPlayer, List<String> args) { private Player getTargetPlayer(
String playerId, Player player, Player targetPlayer, List<String> args) {
// Top priority: If any @UID argument is present, override targetPlayer with it. // Top priority: If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
String arg = args.get(i); String arg = args.get(i);
@ -139,7 +139,8 @@ public final class CommandMap {
arg = args.remove(i).substring(1); arg = args.remove(i).substring(1);
if (arg.equals("")) { if (arg.equals("")) {
// This is a special case to target nothing, distinct from failing to assign a target. // This is a special case to target nothing, distinct from failing to assign a target.
// This is specifically to allow in-game players to run a command without targeting themselves or anyone else. // This is specifically to allow in-game players to run a command without targeting
// themselves or anyone else.
return null; return null;
} }
int uid = getUidFromString(arg); int uid = getUidFromString(arg);
@ -164,7 +165,8 @@ public final class CommandMap {
// Next priority: Use previously-set target. (see /target [[@]UID]) // Next priority: Use previously-set target. (see /target [[@]UID])
if (targetPlayerIds.containsKey(playerId)) { if (targetPlayerIds.containsKey(playerId)) {
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.getInt(playerId), true); targetPlayer =
Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.getInt(playerId), true);
// We check every time in case the target is deleted after being targeted // We check every time in case the target is deleted after being targeted
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error"); CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
@ -173,7 +175,8 @@ public final class CommandMap {
return targetPlayer; return targetPlayer;
} }
// Lowest priority: Target the player invoking the command. In the case of the console, this will return null. // Lowest priority: Target the player invoking the command. In the case of the console, this
// will return null.
return player; return player;
} }
@ -199,7 +202,12 @@ public final class CommandMap {
targetPlayerIds.put(playerId, uid); targetPlayerIds.put(playerId, uid);
String target = uid + " (" + targetPlayer.getAccount().getUsername() + ")"; String target = uid + " (" + targetPlayer.getAccount().getUsername() + ")";
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", target); CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", target);
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline() ? "commands.execution.set_target_online" : "commands.execution.set_target_offline", target); CommandHandler.sendTranslatedMessage(
player,
targetPlayer.isOnline()
? "commands.execution.set_target_online"
: "commands.execution.set_target_offline",
target);
return true; return true;
} }
@ -213,7 +221,14 @@ public final class CommandMap {
// The console outputs in-game command. [{Account Username} (Player UID: {Player Uid})] // The console outputs in-game command. [{Account Username} (Player UID: {Player Uid})]
if (SERVER.logCommands) { if (SERVER.logCommands) {
if (player != null) { if (player != null) {
Grasscutter.getLogger().info("Command used by [" + player.getAccount().getUsername() + " (Player UID: " + player.getUid() + ")]: " + rawMessage); Grasscutter.getLogger()
.info(
"Command used by ["
+ player.getAccount().getUsername()
+ " (Player UID: "
+ player.getUid()
+ ")]: "
+ rawMessage);
} else { } else {
Grasscutter.getLogger().info("Command used by server console: " + rawMessage); Grasscutter.getLogger().info("Command used by server console: " + rawMessage);
} }
@ -269,7 +284,12 @@ public final class CommandMap {
} }
// Check for permissions. // Check for permissions.
if (!Grasscutter.getPermissionHandler().checkPermission(player, targetPlayer, annotation.permission(), this.annotations.get(label).permissionTargeted())) { if (!Grasscutter.getPermissionHandler()
.checkPermission(
player,
targetPlayer,
annotation.permission(),
this.annotations.get(label).permissionTargeted())) {
return; return;
} }
@ -308,22 +328,26 @@ public final class CommandMap {
} }
} }
/** /** Scans for all classes annotated with {@link Command} and registers them. */
* Scans for all classes annotated with {@link Command} and registers them.
*/
private void scan() { private void scan() {
Reflections reflector = Grasscutter.reflector; Reflections reflector = Grasscutter.reflector;
Set<Class<?>> classes = reflector.getTypesAnnotatedWith(Command.class); Set<Class<?>> classes = reflector.getTypesAnnotatedWith(Command.class);
classes.forEach(annotated -> { classes.forEach(
annotated -> {
try { try {
Command cmdData = annotated.getAnnotation(Command.class); Command cmdData = annotated.getAnnotation(Command.class);
Object object = annotated.getDeclaredConstructor().newInstance(); Object object = annotated.getDeclaredConstructor().newInstance();
if (object instanceof CommandHandler) if (object instanceof CommandHandler)
this.registerCommand(cmdData.label(), (CommandHandler) object); this.registerCommand(cmdData.label(), (CommandHandler) object);
else Grasscutter.getLogger().error("Class " + annotated.getName() + " is not a CommandHandler!"); else
Grasscutter.getLogger()
.error("Class " + annotated.getName() + " is not a CommandHandler!");
} catch (Exception exception) { } catch (Exception exception) {
Grasscutter.getLogger().error("Failed to register command handler for " + annotated.getSimpleName(), exception); Grasscutter.getLogger()
.error(
"Failed to register command handler for " + annotated.getSimpleName(),
exception);
} }
}); });
} }

View File

@ -10,7 +10,8 @@ public class DefaultPermissionHandler implements PermissionHandler {
} }
@Override @Override
public boolean checkPermission(Player player, Player targetPlayer, String permissionNode, String permissionNodeTargeted) { public boolean checkPermission(
Player player, Player targetPlayer, String permissionNode, String permissionNodeTargeted) {
if (player == null) { if (player == null) {
return true; return true;
} }

View File

@ -5,5 +5,6 @@ import emu.grasscutter.game.player.Player;
public interface PermissionHandler { public interface PermissionHandler {
boolean EnablePermissionCommand(); boolean EnablePermissionCommand();
boolean checkPermission(Player player, Player targetPlayer, String permissionNode, String permissionNodeTargeted); boolean checkPermission(
Player player, Player targetPlayer, String permissionNode, String permissionNodeTargeted);
} }

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;
@ -8,18 +10,16 @@ import emu.grasscutter.config.Configuration;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
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 static emu.grasscutter.utils.Language.translate;
@Command( @Command(
label = "account", label = "account",
usage = { usage = {
"create <username> [<UID>]", // Only with EXPERIMENTAL_RealPassword == false "create <username> [<UID>]", // Only with EXPERIMENTAL_RealPassword == false
"delete <username>", "delete <username>",
"create <username> <password> [<UID>]", // Only with EXPERIMENTAL_RealPassword == true "create <username> <password> [<UID>]", // Only with EXPERIMENTAL_RealPassword == true
"resetpass <username> <password>"}, // Only with EXPERIMENTAL_RealPassword == true "resetpass <username> <password>"
}, // Only with EXPERIMENTAL_RealPassword == true
targetRequirement = Command.TargetRequirement.NONE) targetRequirement = Command.TargetRequirement.NONE)
public final class AccountCommand implements CommandHandler { public final class AccountCommand implements CommandHandler {
@Override @Override
@ -47,7 +47,8 @@ public final class AccountCommand implements CommandHandler {
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
if (args.size() < 3) { if (args.size() < 3) {
CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires a password argument"); CommandHandler.sendMessage(
sender, "EXPERIMENTAL_RealPassword requires a password argument");
CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]"); CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]");
return; return;
} }
@ -59,8 +60,11 @@ public final class AccountCommand implements CommandHandler {
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid")); CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid"));
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid"); CommandHandler.sendMessage(
CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]"); sender,
"EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid");
CommandHandler.sendMessage(
sender, "Usage: account create <username> <password> [uid]");
} }
return; return;
} }
@ -87,7 +91,8 @@ public final class AccountCommand implements CommandHandler {
account.addPermission("*"); account.addPermission("*");
account.save(); // Save account to database. account.save(); // Save account to database.
CommandHandler.sendMessage(sender, translate(sender, "commands.account.create", account.getReservedPlayerUid())); CommandHandler.sendMessage(
sender, translate(sender, "commands.account.create", account.getReservedPlayerUid()));
} }
return; return;
case "delete": case "delete":
@ -104,7 +109,8 @@ public final class AccountCommand implements CommandHandler {
return; return;
case "resetpass": case "resetpass":
if (!Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) { if (!Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage(sender, "resetpass requires EXPERIMENTAL_RealPassword to be true."); CommandHandler.sendMessage(
sender, "resetpass requires EXPERIMENTAL_RealPassword to be true.");
return; return;
} }

View File

@ -7,14 +7,18 @@ import emu.grasscutter.data.excels.AchievementData;
import emu.grasscutter.game.achievement.AchievementControlReturns; import emu.grasscutter.game.achievement.AchievementControlReturns;
import emu.grasscutter.game.achievement.Achievements; import emu.grasscutter.game.achievement.Achievements;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@Command( @Command(
label = "achievement", label = "achievement",
usage = {"(grant|revoke) <achievementId>", "progress <achievementId> <progress>", "grantall", "revokeall"}, usage = {
"(grant|revoke) <achievementId>",
"progress <achievementId> <progress>",
"grantall",
"revokeall"
},
aliases = {"am"}, aliases = {"am"},
permission = "player.achievement", permission = "player.achievement",
permissionTargeted = "player.achievement.others", permissionTargeted = "player.achievement.others",
@ -22,7 +26,8 @@ import java.util.concurrent.atomic.AtomicInteger;
threading = true) threading = true)
public class AchievementCommand implements CommandHandler { public class AchievementCommand implements CommandHandler {
private static void sendSuccessMessage(Player sender, String cmd, Object... args) { private static void sendSuccessMessage(Player sender, String cmd, Object... args) {
CommandHandler.sendTranslatedMessage(sender, AchievementControlReturns.Return.SUCCESS.getKey() + cmd, args); CommandHandler.sendTranslatedMessage(
sender, AchievementControlReturns.Return.SUCCESS.getKey() + cmd, args);
} }
private static Optional<Integer> parseInt(String s) { private static Optional<Integer> parseInt(String s) {
@ -38,7 +43,8 @@ public class AchievementCommand implements CommandHandler {
GameData.getAchievementDataMap().values().stream() GameData.getAchievementDataMap().values().stream()
.filter(AchievementData::isUsed) .filter(AchievementData::isUsed)
.filter(AchievementData::isParent) .filter(AchievementData::isParent)
.forEach(data -> { .forEach(
data -> {
var success = achievements.grant(data.getId()); var success = achievements.grant(data.getId());
if (success.getRet() == AchievementControlReturns.Return.SUCCESS) { if (success.getRet() == AchievementControlReturns.Return.SUCCESS) {
counter.addAndGet(success.getChangedAchievementStatusNum()); counter.addAndGet(success.getChangedAchievementStatusNum());
@ -53,7 +59,8 @@ public class AchievementCommand implements CommandHandler {
GameData.getAchievementDataMap().values().stream() GameData.getAchievementDataMap().values().stream()
.filter(AchievementData::isUsed) .filter(AchievementData::isUsed)
.filter(AchievementData::isParent) .filter(AchievementData::isParent)
.forEach(data -> { .forEach(
data -> {
var success = achievements.revoke(data.getId()); var success = achievements.revoke(data.getId());
if (success.getRet() == AchievementControlReturns.Return.SUCCESS) { if (success.getRet() == AchievementControlReturns.Return.SUCCESS) {
counter.addAndGet(success.getChangedAchievementStatusNum()); counter.addAndGet(success.getChangedAchievementStatusNum());
@ -82,52 +89,70 @@ public class AchievementCommand implements CommandHandler {
} }
} }
private void grant(Player sender, Player targetPlayer, Achievements achievements, List<String> args) { private void grant(
Player sender, Player targetPlayer, Achievements achievements, List<String> args) {
if (args.size() < 1) { if (args.size() < 1) {
this.sendUsageMessage(sender); this.sendUsageMessage(sender);
} }
parseInt(args.remove(0)).ifPresentOrElse(integer -> { parseInt(args.remove(0))
.ifPresentOrElse(
integer -> {
var ret = achievements.grant(integer); var ret = achievements.grant(integer);
switch (ret.getRet()) { switch (ret.getRet()) {
case SUCCESS -> sendSuccessMessage(sender, "grant", targetPlayer.getNickname()); case SUCCESS -> sendSuccessMessage(sender, "grant", targetPlayer.getNickname());
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey()); case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(
case ALREADY_ACHIEVED -> sender, ret.getRet().getKey());
CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey(), targetPlayer.getNickname()); case ALREADY_ACHIEVED -> CommandHandler.sendTranslatedMessage(
sender, ret.getRet().getKey(), targetPlayer.getNickname());
} }
}, () -> this.sendUsageMessage(sender)); },
() -> this.sendUsageMessage(sender));
} }
private void revoke(Player sender, Player targetPlayer, Achievements achievements, List<String> args) { private void revoke(
Player sender, Player targetPlayer, Achievements achievements, List<String> args) {
if (args.size() < 1) { if (args.size() < 1) {
this.sendUsageMessage(sender); this.sendUsageMessage(sender);
} }
parseInt(args.remove(0)).ifPresentOrElse(integer -> { parseInt(args.remove(0))
.ifPresentOrElse(
integer -> {
var ret = achievements.revoke(integer); var ret = achievements.revoke(integer);
switch (ret.getRet()) { switch (ret.getRet()) {
case SUCCESS -> sendSuccessMessage(sender, "revoke", targetPlayer.getNickname()); case SUCCESS -> sendSuccessMessage(sender, "revoke", targetPlayer.getNickname());
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey()); case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(
case NOT_YET_ACHIEVED -> sender, ret.getRet().getKey());
CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey(), targetPlayer.getNickname()); case NOT_YET_ACHIEVED -> CommandHandler.sendTranslatedMessage(
sender, ret.getRet().getKey(), targetPlayer.getNickname());
} }
}, () -> this.sendUsageMessage(sender)); },
() -> this.sendUsageMessage(sender));
} }
private void progress(Player sender, Player targetPlayer, Achievements achievements, List<String> args) { private void progress(
Player sender, Player targetPlayer, Achievements achievements, List<String> args) {
if (args.size() < 2) { if (args.size() < 2) {
this.sendUsageMessage(sender); this.sendUsageMessage(sender);
} }
parseInt(args.remove(0)).ifPresentOrElse(integer -> { parseInt(args.remove(0))
parseInt(args.remove(0)).ifPresentOrElse(progress -> { .ifPresentOrElse(
integer -> {
parseInt(args.remove(0))
.ifPresentOrElse(
progress -> {
var ret = achievements.progress(integer, progress); var ret = achievements.progress(integer, progress);
switch (ret.getRet()) { switch (ret.getRet()) {
case SUCCESS -> case SUCCESS -> sendSuccessMessage(
sendSuccessMessage(sender, "progress", targetPlayer.getNickname(), integer, progress); sender, "progress", targetPlayer.getNickname(), integer, progress);
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey()); case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(
sender, ret.getRet().getKey());
} }
}, () -> this.sendUsageMessage(sender)); },
}, () -> this.sendUsageMessage(sender)); () -> this.sendUsageMessage(sender));
},
() -> this.sendUsageMessage(sender));
} }
} }

View File

@ -1,18 +1,18 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketServerAnnounceNotify; import emu.grasscutter.server.packet.send.PacketServerAnnounceNotify;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "announce",
@Command(label = "announce",
usage = {"<content>", "refresh", "(tpl|revoke) <templateId>"}, usage = {"<content>", "refresh", "(tpl|revoke) <templateId>"},
permission = "server.announce", permission = "server.announce",
aliases = {"a"}, aliases = {"a"},
@ -37,17 +37,20 @@ public final class AnnounceCommand implements CommandHandler {
var templateId = Integer.parseInt(args.get(1)); var templateId = Integer.parseInt(args.get(1));
var tpl = manager.getAnnounceConfigItemMap().get(templateId); var tpl = manager.getAnnounceConfigItemMap().get(templateId);
if (tpl == null) { if (tpl == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.not_found", templateId)); CommandHandler.sendMessage(
sender, translate(sender, "commands.announce.not_found", templateId));
return; return;
} }
manager.broadcast(Collections.singletonList(tpl)); manager.broadcast(Collections.singletonList(tpl));
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.send_success", tpl.getTemplateId())); CommandHandler.sendMessage(
sender, translate(sender, "commands.announce.send_success", tpl.getTemplateId()));
break; break;
case "refresh": case "refresh":
var num = manager.refresh(); var num = manager.refresh();
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.refresh_success", num)); CommandHandler.sendMessage(
sender, translate(sender, "commands.announce.refresh_success", num));
break; break;
case "revoke": case "revoke":
@ -58,16 +61,18 @@ public final class AnnounceCommand implements CommandHandler {
var templateId1 = Integer.parseInt(args.get(1)); var templateId1 = Integer.parseInt(args.get(1));
manager.revoke(templateId1); manager.revoke(templateId1);
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.revoke_done", templateId1)); CommandHandler.sendMessage(
sender, translate(sender, "commands.announce.revoke_done", templateId1));
break; break;
default: default:
var id = new Random().nextInt(10000, 99999); var id = new Random().nextInt(10000, 99999);
var text = String.join(" ", args); var text = String.join(" ", args);
manager.getOnlinePlayers().forEach(i -> i.sendPacket(new PacketServerAnnounceNotify(text, id))); manager
.getOnlinePlayers()
.forEach(i -> i.sendPacket(new PacketServerAnnounceNotify(text, id)));
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.send_success", id)); CommandHandler.sendMessage(sender, translate(sender, "commands.announce.send_success", id));
} }
} }
} }

View File

@ -5,15 +5,13 @@ import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import java.util.List; import java.util.List;
@Command( @Command(
label = "ban", label = "ban",
usage = {"[<time> [<reason>]]"}, usage = {"[<time> [<reason>]]"},
permission = "server.ban", permission = "server.ban",
targetRequirement = Command.TargetRequirement.PLAYER targetRequirement = Command.TargetRequirement.PLAYER)
)
public final class BanCommand implements CommandHandler { public final class BanCommand implements CommandHandler {
private boolean banAccount(Player targetPlayer, int time, String reason) { private boolean banAccount(Player targetPlayer, int time, String reason) {

View File

@ -1,20 +1,19 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.command.CommandHelpers.*;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.inventory.Inventory;
import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import lombok.Setter;
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.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
import lombok.Setter;
import static emu.grasscutter.command.CommandHelpers.*;
@Command( @Command(
label = "clear", label = "clear",
@ -23,13 +22,14 @@ import static emu.grasscutter.command.CommandHelpers.*;
permissionTargeted = "player.clearinv.others") permissionTargeted = "player.clearinv.others")
public final class ClearCommand implements CommandHandler { public final class ClearCommand implements CommandHandler {
private static final Map<Pattern, BiConsumer<ClearItemParameters, Integer>> intCommandHandlers = Map.ofEntries( private static final Map<Pattern, BiConsumer<ClearItemParameters, Integer>> intCommandHandlers =
Map.ofEntries(
Map.entry(lvlRegex, ClearItemParameters::setLvl), Map.entry(lvlRegex, ClearItemParameters::setLvl),
Map.entry(refineRegex, ClearItemParameters::setRefinement), Map.entry(refineRegex, ClearItemParameters::setRefinement),
Map.entry(rankRegex, ClearItemParameters::setRank) Map.entry(rankRegex, ClearItemParameters::setRank));
);
private Stream<GameItem> getOther(ItemType type, Inventory playerInventory, ClearItemParameters param) { private Stream<GameItem> getOther(
ItemType type, Inventory playerInventory, ClearItemParameters param) {
return playerInventory.getItems().values().stream() return playerInventory.getItems().values().stream()
.filter(item -> item.getItemType() == type) .filter(item -> item.getItemType() == type)
.filter(item -> item.getItemData().getRankLevel() <= param.rank) .filter(item -> item.getItemData().getRankLevel() <= param.rank)
@ -71,7 +71,8 @@ public final class ClearCommand implements CommandHandler {
CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString);
} }
case "mat" -> { case "mat" -> {
playerInventory.removeItems(getOther(ItemType.ITEM_MATERIAL, playerInventory, param).toList()); playerInventory.removeItems(
getOther(ItemType.ITEM_MATERIAL, playerInventory, param).toList());
CommandHandler.sendTranslatedMessage(sender, "commands.clear.materials", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.materials", playerString);
} }
case "all" -> { case "all" -> {
@ -79,13 +80,17 @@ public final class ClearCommand implements CommandHandler {
CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString);
playerInventory.removeItems(getWeapons(playerInventory, param).toList()); playerInventory.removeItems(getWeapons(playerInventory, param).toList());
CommandHandler.sendTranslatedMessage(sender, "commands.clear.weapons", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.weapons", playerString);
playerInventory.removeItems(getOther(ItemType.ITEM_MATERIAL, playerInventory, param).toList()); playerInventory.removeItems(
getOther(ItemType.ITEM_MATERIAL, playerInventory, param).toList());
CommandHandler.sendTranslatedMessage(sender, "commands.clear.materials", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.materials", playerString);
playerInventory.removeItems(getOther(ItemType.ITEM_FURNITURE, playerInventory, param).toList()); playerInventory.removeItems(
getOther(ItemType.ITEM_FURNITURE, playerInventory, param).toList());
CommandHandler.sendTranslatedMessage(sender, "commands.clear.furniture", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.furniture", playerString);
playerInventory.removeItems(getOther(ItemType.ITEM_DISPLAY, playerInventory, param).toList()); playerInventory.removeItems(
getOther(ItemType.ITEM_DISPLAY, playerInventory, param).toList());
CommandHandler.sendTranslatedMessage(sender, "commands.clear.displays", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.displays", playerString);
playerInventory.removeItems(getOther(ItemType.ITEM_VIRTUAL, playerInventory, param).toList()); playerInventory.removeItems(
getOther(ItemType.ITEM_VIRTUAL, playerInventory, param).toList());
CommandHandler.sendTranslatedMessage(sender, "commands.clear.virtuals", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.virtuals", playerString);
CommandHandler.sendTranslatedMessage(sender, "commands.clear.everything", playerString); CommandHandler.sendTranslatedMessage(sender, "commands.clear.everything", playerString);
} }
@ -93,11 +98,8 @@ public final class ClearCommand implements CommandHandler {
} }
private static class ClearItemParameters { private static class ClearItemParameters {
@Setter @Setter public int lvl = 1;
public int lvl = 1; @Setter public int refinement = 1;
@Setter @Setter public int rank = 4;
public int refinement = 1;
@Setter
public int rank = 4;
} }
} }

View File

@ -4,10 +4,13 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
@Command(label = "coop", usage = {"[<host UID>]"}, permission = "server.coop", permissionTargeted = "server.coop.others") @Command(
label = "coop",
usage = {"[<host UID>]"},
permission = "server.coop",
permissionTargeted = "server.coop.others")
public final class CoopCommand implements CommandHandler { public final class CoopCommand implements CommandHandler {
@Override @Override
@ -38,12 +41,17 @@ public final class CoopCommand implements CommandHandler {
return; return;
} }
// There's no target==host check but this just places them in multiplayer in their own world which seems fine. // There's no target==host check but this just places them in multiplayer in their own world
// which seems fine.
if (targetPlayer.isInMultiplayer()) { if (targetPlayer.isInMultiplayer()) {
targetPlayer.getServer().getMultiplayerSystem().leaveCoop(targetPlayer); targetPlayer.getServer().getMultiplayerSystem().leaveCoop(targetPlayer);
} }
host.getServer().getMultiplayerSystem().applyEnterMp(targetPlayer, host.getUid()); host.getServer().getMultiplayerSystem().applyEnterMp(targetPlayer, host.getUid());
targetPlayer.getServer().getMultiplayerSystem().applyEnterMpReply(host, targetPlayer.getUid(), true); targetPlayer
CommandHandler.sendTranslatedMessage(sender, "commands.coop.success", targetPlayer.getNickname(), host.getNickname()); .getServer()
.getMultiplayerSystem()
.applyEnterMpReply(host, targetPlayer.getUid(), true);
CommandHandler.sendTranslatedMessage(
sender, "commands.coop.success", targetPlayer.getNickname(), host.getNickname());
} }
} }

View File

@ -1,14 +1,18 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "enter_dungeon",
@Command(label = "enter_dungeon", aliases = {"enterdungeon", "dungeon"}, usage = {"<dungeonId>"}, permission = "player.enterdungeon", permissionTargeted = "player.enterdungeon.others") aliases = {"enterdungeon", "dungeon"},
usage = {"<dungeonId>"},
permission = "player.enterdungeon",
permissionTargeted = "player.enterdungeon.others")
public final class EnterDungeonCommand implements CommandHandler { public final class EnterDungeonCommand implements CommandHandler {
@Override @Override
@ -21,16 +25,23 @@ public final class EnterDungeonCommand implements CommandHandler {
try { try {
int dungeonId = Integer.parseInt(args.get(0)); int dungeonId = Integer.parseInt(args.get(0));
if (dungeonId == targetPlayer.getSceneId()) { if (dungeonId == targetPlayer.getSceneId()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.in_dungeon_error")); CommandHandler.sendMessage(
sender, translate(sender, "commands.enter_dungeon.in_dungeon_error"));
return; return;
} }
boolean result = targetPlayer.getServer().getDungeonSystem().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId); boolean result =
targetPlayer
.getServer()
.getDungeonSystem()
.enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId);
if (!result) { if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.not_found_error")); CommandHandler.sendMessage(
sender, translate(sender, "commands.enter_dungeon.not_found_error"));
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.changed", dungeonId)); CommandHandler.sendMessage(
sender, translate(sender, "commands.enter_dungeon.changed", dungeonId));
} }
} catch (Exception e) { } catch (Exception e) {
sendUsageMessage(sender); sendUsageMessage(sender);

View File

@ -1,30 +1,42 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "heal",
@Command(label = "heal", aliases = {"h"}, permission = "player.heal", permissionTargeted = "player.heal.others") aliases = {"h"},
permission = "player.heal",
permissionTargeted = "player.heal.others")
public final class HealCommand implements CommandHandler { public final class HealCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
targetPlayer.getTeamManager().getActiveTeam().forEach(entity -> { targetPlayer
.getTeamManager()
.getActiveTeam()
.forEach(
entity -> {
boolean isAlive = entity.isAlive(); boolean isAlive = entity.isAlive();
entity.setFightProperty( entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP, FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP));
); entity
entity.getWorld().broadcastPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); .getWorld()
.broadcastPacket(
new PacketAvatarFightPropUpdateNotify(
entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
if (!isAlive) { if (!isAlive) {
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); entity
.getWorld()
.broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
} }
}); });
CommandHandler.sendMessage(sender, translate(sender, "commands.heal.success")); CommandHandler.sendMessage(sender, translate(sender, "commands.heal.success"));

View File

@ -1,22 +1,26 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.CommandMap; import emu.grasscutter.command.CommandMap;
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.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "help",
@Command(label = "help", usage = {"[<command>]"}, targetRequirement = Command.TargetRequirement.NONE) usage = {"[<command>]"},
targetRequirement = Command.TargetRequirement.NONE)
public final class HelpCommand implements CommandHandler { public final class HelpCommand implements CommandHandler {
private final boolean SHOW_COMMANDS_WITHOUT_PERMISSIONS = false; // TODO: Make this into a server config key private final boolean SHOW_COMMANDS_WITHOUT_PERMISSIONS =
false; // TODO: Make this into a server config key
private String createCommand(Player player, CommandHandler command, List<String> args) { private String createCommand(Player player, CommandHandler command, List<String> args) {
StringBuilder builder = new StringBuilder(command.getLabel()) StringBuilder builder =
new StringBuilder(command.getLabel())
.append(" - ") .append(" - ")
.append(command.getDescriptionString(player)) .append(command.getDescriptionString(player))
.append("\n\t") .append("\n\t")
@ -39,7 +43,9 @@ public final class HelpCommand implements CommandHandler {
if (!annotation.permissionTargeted().isEmpty()) { if (!annotation.permissionTargeted().isEmpty()) {
String permissionTargeted = annotation.permissionTargeted(); String permissionTargeted = annotation.permissionTargeted();
builder.append(" ").append(translate(player, "commands.help.tip_permission_targeted", permissionTargeted)); builder
.append(" ")
.append(translate(player, "commands.help.tip_permission_targeted", permissionTargeted));
} }
return builder.toString(); return builder.toString();
} }
@ -51,7 +57,10 @@ public final class HelpCommand implements CommandHandler {
List<String> commands = new ArrayList<>(); List<String> commands = new ArrayList<>();
List<String> commands_no_permission = new ArrayList<>(); List<String> commands_no_permission = new ArrayList<>();
if (args.isEmpty()) { if (args.isEmpty()) {
commandMap.getHandlers().forEach((key, command) -> { commandMap
.getHandlers()
.forEach(
(key, command) -> {
Command annotation = command.getClass().getAnnotation(Command.class); Command annotation = command.getClass().getAnnotation(Command.class);
if (player == null || account.hasPermission(annotation.permission())) { if (player == null || account.hasPermission(annotation.permission())) {
commands.add(createCommand(player, command, args)); commands.add(createCommand(player, command, args));

View File

@ -3,21 +3,30 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
@Command(label = "kick", aliases = {"restart"}, permissionTargeted = "server.kick") @Command(
label = "kick",
aliases = {"restart"},
permissionTargeted = "server.kick")
public final class KickCommand implements CommandHandler { public final class KickCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender != null) { if (sender != null) {
CommandHandler.sendTranslatedMessage(sender, "commands.kick.player_kick_player", CommandHandler.sendTranslatedMessage(
sender.getUid(), sender.getAccount().getUsername(), sender,
targetPlayer.getUid(), targetPlayer.getAccount().getUsername()); "commands.kick.player_kick_player",
sender.getUid(),
sender.getAccount().getUsername(),
targetPlayer.getUid(),
targetPlayer.getAccount().getUsername());
} else { } else {
CommandHandler.sendTranslatedMessage(sender, "commands.kick.server_kick_player", CommandHandler.sendTranslatedMessage(
targetPlayer.getUid(), targetPlayer.getAccount().getUsername()); sender,
"commands.kick.server_kick_player",
targetPlayer.getUid(),
targetPlayer.getAccount().getUsername());
} }
targetPlayer.getSession().close(); targetPlayer.getSession().close();

View File

@ -1,17 +1,20 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "killall",
@Command(label = "killall", usage = {"[<sceneId>]"}, permission = "server.killall", permissionTargeted = "server.killall.others") usage = {"[<sceneId>]"},
permission = "server.killall",
permissionTargeted = "server.killall.others")
public final class KillAllCommand implements CommandHandler { public final class KillAllCommand implements CommandHandler {
@Override @Override
@ -32,16 +35,20 @@ public final class KillAllCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
} }
if (scene == null) { if (scene == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.scene_not_found_in_player_world")); CommandHandler.sendMessage(
sender, translate(sender, "commands.killall.scene_not_found_in_player_world"));
return; return;
} }
// Separate into list to avoid concurrency issue // Separate into list to avoid concurrency issue
final Scene sceneF = scene; final Scene sceneF = scene;
List<GameEntity> toKill = sceneF.getEntities().values().stream() List<GameEntity> toKill =
sceneF.getEntities().values().stream()
.filter(entity -> entity instanceof EntityMonster) .filter(entity -> entity instanceof EntityMonster)
.toList(); .toList();
toKill.forEach(entity -> sceneF.killEntity(entity, 0)); toKill.forEach(entity -> sceneF.killEntity(entity, 0));
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", toKill.size(), scene.getId())); CommandHandler.sendMessage(
sender,
translate(sender, "commands.killall.kill_monsters_in_scene", toKill.size(), scene.getId()));
} }
} }

View File

@ -1,5 +1,7 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
@ -8,12 +10,13 @@ import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.LifeState;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "killCharacter",
@Command(label = "killCharacter", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others") aliases = {"suicide", "kill"},
permission = "player.killcharacter",
permissionTargeted = "player.killcharacter.others")
public final class KillCharacterCommand implements CommandHandler { public final class KillCharacterCommand implements CommandHandler {
@Override @Override
@ -21,12 +24,18 @@ public final class KillCharacterCommand implements CommandHandler {
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f); entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
// Packets // Packets
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); entity
entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD)); .getWorld()
.broadcastPacket(
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
entity
.getWorld()
.broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
// remove // remove
targetPlayer.getScene().removeEntity(entity); targetPlayer.getScene().removeEntity(entity);
entity.onDeath(0); entity.onDeath(0);
CommandHandler.sendMessage(sender, translate(sender, "commands.killCharacter.success", targetPlayer.getNickname())); CommandHandler.sendMessage(
sender, translate(sender, "commands.killCharacter.success", targetPlayer.getNickname()));
} }
} }

View File

@ -1,17 +1,20 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "language",
@Command(label = "language", usage = {"[<language code>]"}, aliases = {"lang"}, targetRequirement = Command.TargetRequirement.NONE) usage = {"[<language code>]"},
aliases = {"lang"},
targetRequirement = Command.TargetRequirement.NONE)
public final class LanguageCommand implements CommandHandler { public final class LanguageCommand implements CommandHandler {
@Override @Override
@ -23,7 +26,8 @@ public final class LanguageCommand implements CommandHandler {
} else { } else {
curLangCode = Grasscutter.getLanguage().getLanguageCode(); curLangCode = Grasscutter.getLanguage().getLanguageCode();
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.language.current_language", curLangCode)); CommandHandler.sendMessage(
sender, translate(sender, "commands.language.current_language", curLangCode));
return; return;
} }
@ -44,10 +48,11 @@ public final class LanguageCommand implements CommandHandler {
} }
if (!langCode.equals(actualLangCode)) { if (!langCode.equals(actualLangCode)) {
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_not_found", langCode)); CommandHandler.sendMessage(
sender, translate(sender, "commands.language.language_not_found", langCode));
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_changed", actualLangCode)); CommandHandler.sendMessage(
sender, translate(sender, "commands.language.language_changed", actualLangCode));
} }
} }

View File

@ -1,16 +1,19 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "list",
@Command(label = "list", aliases = {"players"}, usage = {"[<UID>]"}, targetRequirement = Command.TargetRequirement.NONE) aliases = {"players"},
usage = {"[<UID>]"},
targetRequirement = Command.TargetRequirement.NONE)
public final class ListCommand implements CommandHandler { public final class ListCommand implements CommandHandler {
@Override @Override
@ -22,24 +25,24 @@ public final class ListCommand implements CommandHandler {
needUID = args.get(0).equals("uid"); needUID = args.get(0).equals("uid");
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.list.success", playersMap.size())); CommandHandler.sendMessage(
sender, translate(sender, "commands.list.success", playersMap.size()));
if (playersMap.size() != 0) { if (playersMap.size() != 0) {
StringBuilder playerSet = new StringBuilder(); StringBuilder playerSet = new StringBuilder();
boolean finalNeedUID = needUID; boolean finalNeedUID = needUID;
playersMap.values().forEach(player -> { playersMap
.values()
.forEach(
player -> {
playerSet.append(player.getNickname()); playerSet.append(player.getNickname());
if (finalNeedUID) { if (finalNeedUID) {
if (sender != null) { if (sender != null) {
playerSet.append(" <color=green>(") playerSet.append(" <color=green>(").append(player.getUid()).append(")</color>");
.append(player.getUid())
.append(")</color>");
} else { } else {
playerSet.append(" (") playerSet.append(" (").append(player.getUid()).append(")");
.append(player.getUid())
.append(")");
} }
} }

View File

@ -1,22 +1,20 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.Command.TargetRequirement; import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
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 static emu.grasscutter.utils.Language.translate; @Command(
label = "permission",
@Command(label = "permission", usage = { usage = {"add <permission>", "remove <permission>", "clear", "list"},
"add <permission>", permission = "permission",
"remove <permission>", targetRequirement = TargetRequirement.PLAYER)
"clear",
"list"
}, permission = "permission", targetRequirement = TargetRequirement.PLAYER)
public final class PermissionCommand implements CommandHandler { public final class PermissionCommand implements CommandHandler {
@Override @Override
@ -52,12 +50,15 @@ public final class PermissionCommand implements CommandHandler {
sendUsageMessage(sender); sendUsageMessage(sender);
} else if (account.addPermission(permission)) { } else if (account.addPermission(permission)) {
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.add")); CommandHandler.sendMessage(sender, translate(sender, "commands.permission.add"));
} else CommandHandler.sendMessage(sender, translate(sender, "commands.permission.has_error")); } else
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.has_error"));
break; break;
case "remove": case "remove":
if (account.removePermission(permission)) { if (account.removePermission(permission)) {
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.remove")); CommandHandler.sendMessage(sender, translate(sender, "commands.permission.remove"));
} else CommandHandler.sendMessage(sender, translate(sender, "commands.permission.not_have_error")); } else
CommandHandler.sendMessage(
sender, translate(sender, "commands.permission.not_have_error"));
break; break;
case "clear": case "clear":
account.clearPermission(); account.clearPermission();

View File

@ -4,17 +4,26 @@ import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
@Command(label = "position", aliases = {"pos"}) @Command(
label = "position",
aliases = {"pos"})
public final class PositionCommand implements CommandHandler { public final class PositionCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
Position pos = targetPlayer.getPosition(); Position pos = targetPlayer.getPosition();
Position rot = targetPlayer.getRotation(); Position rot = targetPlayer.getRotation();
CommandHandler.sendTranslatedMessage(sender, "commands.position.success", CommandHandler.sendTranslatedMessage(
pos.getX(), pos.getY(), pos.getZ(), rot.getX(), rot.getY(), rot.getZ(), targetPlayer.getSceneId()); sender,
"commands.position.success",
pos.getX(),
pos.getY(),
pos.getZ(),
rot.getX(),
rot.getY(),
rot.getZ(),
targetPlayer.getSceneId());
} }
} }

View File

@ -1,15 +1,15 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "quest",
@Command(label = "quest",
aliases = {"q"}, aliases = {"q"},
usage = {"(add|finish) [<questId>]"}, usage = {"(add|finish) [<questId>]"},
permission = "player.quest", permission = "player.quest",

View File

@ -1,15 +1,17 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "reload",
@Command(label = "reload", permission = "server.reload", targetRequirement = Command.TargetRequirement.NONE) permission = "server.reload",
targetRequirement = Command.TargetRequirement.NONE)
public final class ReloadCommand implements CommandHandler { public final class ReloadCommand implements CommandHandler {
@Override @Override

View File

@ -1,15 +1,14 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command( @Command(
label = "resetConst", label = "resetConst",
aliases = {"resetconstellation"}, aliases = {"resetconstellation"},
@ -32,7 +31,9 @@ public final class ResetConstCommand implements CommandHandler {
Avatar avatar = entity.getAvatar(); Avatar avatar = entity.getAvatar();
this.resetConstellation(avatar); this.resetConstellation(avatar);
CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.success", avatar.getAvatarData().getName())); CommandHandler.sendMessage(
sender,
translate(sender, "commands.resetConst.success", avatar.getAvatarData().getName()));
} }
} }

View File

@ -1,14 +1,17 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "resetShopLimit",
@Command(label = "resetShopLimit", aliases = {"resetshop"}, permission = "server.resetshop", permissionTargeted = "server.resetshop.others") aliases = {"resetshop"},
permission = "server.resetshop",
permissionTargeted = "server.resetshop.others")
public final class ResetShopLimitCommand implements CommandHandler { public final class ResetShopLimitCommand implements CommandHandler {
@Override @Override

View File

@ -1,18 +1,17 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@Command( @Command(
label = "sendMail", label = "sendMail",
@ -21,12 +20,15 @@ import static emu.grasscutter.utils.Language.translate;
targetRequirement = Command.TargetRequirement.NONE) targetRequirement = Command.TargetRequirement.NONE)
public final class SendMailCommand implements CommandHandler { public final class SendMailCommand implements CommandHandler {
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish // TODO: You should be able to do /sendmail and then just send subsequent messages until you
// However, due to the current nature of the command system, I don't think this is possible without rewriting // finish
// However, due to the current nature of the command system, I don't think this is possible
// without rewriting
// the command system (again). For now this will do // the command system (again). For now this will do
// Key = User that is constructing the mail. // Key = User that is constructing the mail.
private static final HashMap<Integer, MailBuilder> mailBeingConstructed = new HashMap<Integer, MailBuilder>(); private static final HashMap<Integer, MailBuilder> mailBeingConstructed =
new HashMap<Integer, MailBuilder>();
// Yes this is awful and I hate it. // Yes this is awful and I hate it.
@Override @Override
@ -52,16 +54,20 @@ public final class SendMailCommand implements CommandHandler {
if (DatabaseHelper.getPlayerByUid(Integer.parseInt(args.get(0))) != null) { if (DatabaseHelper.getPlayerByUid(Integer.parseInt(args.get(0))) != null) {
mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail()); mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail());
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.user_not_exist", args.get(0))); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.user_not_exist", args.get(0)));
return; return;
} }
} }
} }
mailBeingConstructed.put(senderId, mailBuilder); mailBeingConstructed.put(senderId, mailBuilder);
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.start_composition")); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.start_composition"));
} }
case 2 -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.templates")); case 2 -> CommandHandler.sendMessage(
default -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments")); sender, translate(sender, "commands.sendMail.templates"));
default -> CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.invalid_arguments"));
} }
} else { } else {
MailBuilder mailBuilder = mailBeingConstructed.get(senderId); MailBuilder mailBuilder = mailBeingConstructed.get(senderId);
@ -75,41 +81,63 @@ public final class SendMailCommand implements CommandHandler {
case "finish" -> { case "finish" -> {
if (mailBuilder.constructionStage == 3) { if (mailBuilder.constructionStage == 3) {
if (!mailBuilder.sendToAll) { if (!mailBuilder.sendToAll) {
Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail); Grasscutter.getGameServer()
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", mailBuilder.recipient)); .getPlayerByUid(mailBuilder.recipient, true)
.sendMail(mailBuilder.mail);
CommandHandler.sendMessage(
sender,
translate(sender, "commands.sendMail.send_done", mailBuilder.recipient));
} else { } else {
DatabaseHelper.getByGameClass(Player.class).forEach(player -> { DatabaseHelper.getByGameClass(Player.class)
var onlinePlayer = Grasscutter.getGameServer().getPlayerByUid(player.getUid(), false); .forEach(
Objects.requireNonNullElse(onlinePlayer, player).sendMail(mailBuilder.mail); player -> {
var onlinePlayer =
Grasscutter.getGameServer().getPlayerByUid(player.getUid(), false);
Objects.requireNonNullElse(onlinePlayer, player)
.sendMail(mailBuilder.mail);
}); });
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_all_done")); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.send_all_done"));
} }
mailBeingConstructed.remove(senderId); mailBeingConstructed.remove(senderId);
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage, sender))); CommandHandler.sendMessage(
sender,
translate(
sender,
"commands.sendMail.not_composition_end",
getConstructionArgs(mailBuilder.constructionStage, sender)));
} }
} }
case "help" -> { case "help" -> {
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage, sender))); CommandHandler.sendMessage(
sender,
translate(
sender,
"commands.sendMail.please_use",
getConstructionArgs(mailBuilder.constructionStage, sender)));
} }
default -> { default -> {
switch (mailBuilder.constructionStage) { switch (mailBuilder.constructionStage) {
case 0 -> { case 0 -> {
String title = String.join(" ", args.subList(0, args.size())); String title = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.title = title; mailBuilder.mail.mailContent.title = title;
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_title", title)); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.set_title", title));
mailBuilder.constructionStage++; mailBuilder.constructionStage++;
} }
case 1 -> { case 1 -> {
String contents = String.join(" ", args.subList(0, args.size())); String contents = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.content = contents; mailBuilder.mail.mailContent.content = contents;
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_contents", contents)); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.set_contents", contents));
mailBuilder.constructionStage++; mailBuilder.constructionStage++;
} }
case 2 -> { case 2 -> {
String msgSender = String.join(" ", args.subList(0, args.size())); String msgSender = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.sender = msgSender; mailBuilder.mail.mailContent.sender = msgSender;
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_message_sender", msgSender)); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.set_message_sender", msgSender));
mailBuilder.constructionStage++; mailBuilder.constructionStage++;
} }
case 3 -> { case 3 -> {
@ -118,25 +146,29 @@ public final class SendMailCommand implements CommandHandler {
int amount = 1; int amount = 1;
int refinement = 0; int refinement = 0;
switch (args.size()) { switch (args.size()) {
case 4: // <itemId|itemName> [amount] [level] [refinement] // TODO: this requires Mail support but there's no harm leaving it here for now case 4: // <itemId|itemName> [amount] [level] [refinement] // TODO: this requires
// Mail support but there's no harm leaving it here for now
try { try {
refinement = Integer.parseInt(args.get(3)); refinement = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement")); CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.itemRefinement"));
return; return;
} // Fallthrough } // Fallthrough
case 3: // <itemId|itemName> [amount] [level] case 3: // <itemId|itemName> [amount] [level]
try { try {
lvl = Integer.parseInt(args.get(2)); lvl = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel")); CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.itemLevel"));
return; return;
} // Fallthrough } // Fallthrough
case 2: // <itemId|itemName> [amount] case 2: // <itemId|itemName> [amount]
try { try {
amount = Integer.parseInt(args.get(1)); amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount")); CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.amount"));
return; return;
} // Fallthrough } // Fallthrough
case 1: // <itemId|itemName> case 1: // <itemId|itemName>
@ -144,7 +176,8 @@ public final class SendMailCommand implements CommandHandler {
item = Integer.parseInt(args.get(0)); item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook. // TODO: Parse from item name using GM Handbook.
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId")); CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.itemId"));
return; return;
} }
break; break;
@ -153,13 +186,19 @@ public final class SendMailCommand implements CommandHandler {
return; return;
} }
mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl)); mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl));
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send", amount, item, lvl)); CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.send", amount, item, lvl));
} }
} }
} }
} }
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments_please_use", getConstructionArgs(mailBuilder.constructionStage, sender))); CommandHandler.sendMessage(
sender,
translate(
sender,
"commands.sendMail.invalid_arguments_please_use",
getConstructionArgs(mailBuilder.constructionStage, sender)));
} }
} }
} }

View File

@ -5,7 +5,6 @@ import emu.grasscutter.command.Command;
import emu.grasscutter.command.Command.TargetRequirement; import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
@Command( @Command(

View File

@ -9,7 +9,6 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
@Command( @Command(
@ -38,10 +37,12 @@ public final class SetConstCommand implements CommandHandler {
if (entity == null) return; if (entity == null) return;
Avatar avatar = entity.getAvatar(); Avatar avatar = entity.getAvatar();
this.setConstellation(targetPlayer, avatar, constLevel); this.setConstellation(targetPlayer, avatar, constLevel);
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.success", avatar.getAvatarData().getName(), constLevel); CommandHandler.sendTranslatedMessage(
sender, "commands.setConst.success", avatar.getAvatarData().getName(), constLevel);
return; return;
} }
// Check if there's an additional argument which is "all", if it does then go setAllConstellation // Check if there's an additional argument which is "all", if it does then go
// setAllConstellation
if (args.size() > 1 && args.get(1).equalsIgnoreCase("all")) { if (args.size() > 1 && args.get(1).equalsIgnoreCase("all")) {
this.setAllConstellation(targetPlayer, constLevel); this.setAllConstellation(targetPlayer, constLevel);
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.successall", constLevel); CommandHandler.sendTranslatedMessage(sender, "commands.setConst.successall", constLevel);
@ -67,7 +68,10 @@ public final class SetConstCommand implements CommandHandler {
} }
private void setAllConstellation(Player player, int constLevel) { private void setAllConstellation(Player player, int constLevel) {
player.getAvatars().forEach(avatar -> { player
.getAvatars()
.forEach(
avatar -> {
avatar.forceConstellationLevel(constLevel); avatar.forceConstellationLevel(constLevel);
avatar.recalcConstellations(); avatar.recalcConstellations();
avatar.recalcStats(true); avatar.recalcStats(true);

View File

@ -1,16 +1,15 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify; import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command( @Command(
label = "setFetterLevel", label = "setFetterLevel",
usage = {"<level>"}, usage = {"<level>"},
@ -29,7 +28,8 @@ public final class SetFetterLevelCommand implements CommandHandler {
try { try {
int fetterLevel = Integer.parseInt(args.get(0)); int fetterLevel = Integer.parseInt(args.get(0));
if (fetterLevel < 0 || fetterLevel > 10) { if (fetterLevel < 0 || fetterLevel > 10) {
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.range_error")); CommandHandler.sendMessage(
sender, translate(sender, "commands.setFetterLevel.range_error"));
return; return;
} }
Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar(); Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
@ -41,10 +41,10 @@ public final class SetFetterLevelCommand implements CommandHandler {
avatar.save(); avatar.save();
targetPlayer.sendPacket(new PacketAvatarFetterDataNotify(avatar)); targetPlayer.sendPacket(new PacketAvatarFetterDataNotify(avatar));
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.success", fetterLevel)); CommandHandler.sendMessage(
sender, translate(sender, "commands.setFetterLevel.success", fetterLevel));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.level_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.level_error"));
} }
} }
} }

View File

@ -9,15 +9,23 @@ import emu.grasscutter.game.tower.TowerLevelRecord;
import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify; import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify;
import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify; import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Command(label = "setProp", aliases = {"prop"}, usage = {"<prop> <value>"}, permission = "player.setprop", permissionTargeted = "player.setprop.others") @Command(
label = "setProp",
aliases = {"prop"},
usage = {"<prop> <value>"},
permission = "player.setprop",
permissionTargeted = "player.setprop.others")
public final class SetPropCommand implements CommandHandler { public final class SetPropCommand implements CommandHandler {
// List of map areas. Unfortunately, there is no readily available source for them in excels or bins. // List of map areas. Unfortunately, there is no readily available source for them in excels or
private static final List<Integer> sceneAreas = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403); // bins.
private static final List<Integer> sceneAreas =
List.of(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 32, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403);
Map<String, Prop> props; Map<String, Prop> props;
public SetPropCommand() { public SetPropCommand() {
@ -29,7 +37,8 @@ public final class SetPropCommand implements CommandHandler {
this.props.put(key, new Prop(name, prop)); this.props.put(key, new Prop(name, prop));
} }
// Add special props // Add special props
Prop worldlevel = new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL); Prop worldlevel =
new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL);
this.props.put("worldlevel", worldlevel); this.props.put("worldlevel", worldlevel);
this.props.put("wl", worldlevel); this.props.put("wl", worldlevel);
@ -89,7 +98,8 @@ public final class SetPropCommand implements CommandHandler {
return; return;
} }
try { try {
value = switch (valueStr.toLowerCase()) { value =
switch (valueStr.toLowerCase()) {
case "on", "true" -> 1; case "on", "true" -> 1;
case "off", "false" -> 0; case "off", "false" -> 0;
case "toggle" -> -1; case "toggle" -> -1;
@ -103,12 +113,13 @@ public final class SetPropCommand implements CommandHandler {
boolean success = false; boolean success = false;
Prop prop = props.get(propStr); Prop prop = props.get(propStr);
success = switch (prop.pseudoProp) { success =
switch (prop.pseudoProp) {
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value); case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value); case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value); case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool(
this.setBool(sender, targetPlayer, prop.pseudoProp, value); sender, targetPlayer, prop.pseudoProp, value);
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1); case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0); case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
case UNLOCK_MAP -> unlockMap(targetPlayer); case UNLOCK_MAP -> unlockMap(targetPlayer);
@ -117,16 +128,20 @@ public final class SetPropCommand implements CommandHandler {
if (success) { if (success) {
if (targetPlayer == sender) { if (targetPlayer == sender) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", prop.name, valueStr); CommandHandler.sendTranslatedMessage(
sender, "commands.generic.set_to", prop.name, valueStr);
} else { } else {
String uidStr = targetPlayer.getAccount().getId(); String uidStr = targetPlayer.getAccount().getId();
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr); CommandHandler.sendTranslatedMessage(
sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr);
} }
} else { } else {
if (prop.prop != PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages if (prop.prop
!= PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages
int min = targetPlayer.getPropertyMin(prop.prop); int min = targetPlayer.getPropertyMin(prop.prop);
int max = targetPlayer.getPropertyMax(prop.prop); int max = targetPlayer.getPropertyMax(prop.prop);
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", prop.name, min, max); CommandHandler.sendTranslatedMessage(
sender, "commands.generic.invalid.value_between", prop.name, min, max);
} }
} }
} }
@ -134,7 +149,8 @@ public final class SetPropCommand implements CommandHandler {
private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) { private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors(); List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors();
if (topFloor < 0 || topFloor > floorIds.size()) { if (topFloor < 0 || topFloor > floorIds.size()) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size()); CommandHandler.sendTranslatedMessage(
sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size());
return false; return false;
} }
@ -151,19 +167,26 @@ public final class SetPropCommand implements CommandHandler {
} }
// Six stars required on Floor 8 to unlock Floor 9+ // Six stars required on Floor 8 to unlock Floor 9+
if (topFloor > 8) { if (topFloor > 8) {
recordMap.get(floorIds.get(7)).setLevelStars(0, 6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at all recordMap
.get(floorIds.get(7))
.setLevelStars(
0,
6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at
// all
} }
return true; return true;
} }
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) { private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
boolean enabled = switch (pseudoProp) { boolean enabled =
switch (pseudoProp) {
case GOD_MODE -> targetPlayer.inGodmode(); case GOD_MODE -> targetPlayer.inGodmode();
case UNLIMITED_STAMINA -> targetPlayer.getUnlimitedStamina(); case UNLIMITED_STAMINA -> targetPlayer.getUnlimitedStamina();
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage(); case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage();
default -> false; default -> false;
}; };
enabled = switch (value) { enabled =
switch (value) {
case -1 -> !enabled; case -1 -> !enabled;
case 0 -> false; case 0 -> false;
default -> true; default -> true;
@ -192,7 +215,9 @@ public final class SetPropCommand implements CommandHandler {
private boolean unlockMap(Player targetPlayer) { private boolean unlockMap(Player targetPlayer) {
// Unlock. // Unlock.
GameData.getScenePointsPerScene().forEach((sceneId, scenePoints) -> { GameData.getScenePointsPerScene()
.forEach(
(sceneId, scenePoints) -> {
// Unlock trans points. // Unlock trans points.
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints); targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints);
@ -202,8 +227,12 @@ public final class SetPropCommand implements CommandHandler {
// Send notify. // Send notify.
int playerScene = targetPlayer.getSceneId(); int playerScene = targetPlayer.getSceneId();
targetPlayer.sendPacket(new PacketScenePointUnlockNotify(playerScene, targetPlayer.getUnlockedScenePoints(playerScene))); targetPlayer.sendPacket(
targetPlayer.sendPacket(new PacketSceneAreaUnlockNotify(playerScene, targetPlayer.getUnlockedSceneAreas(playerScene))); new PacketScenePointUnlockNotify(
playerScene, targetPlayer.getUnlockedScenePoints(playerScene)));
targetPlayer.sendPacket(
new PacketSceneAreaUnlockNotify(
playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
return true; return true;
} }

View File

@ -7,7 +7,6 @@ import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -18,7 +17,8 @@ import java.util.Map;
usage = { usage = {
"[set] <stat> <value>", "[set] <stat> <value>",
"(lock|freeze) <stat> [<value>]", // Can lock to current value "(lock|freeze) <stat> [<value>]", // Can lock to current value
"(unlock|unfreeze) <stat>"}, "(unlock|unfreeze) <stat>"
},
permission = "player.setstats", permission = "player.setstats",
permissionTargeted = "player.setstats.others") permissionTargeted = "player.setstats.others")
public final class SetStatsCommand implements CommandHandler { public final class SetStatsCommand implements CommandHandler {
@ -43,7 +43,11 @@ public final class SetStatsCommand implements CommandHandler {
this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP
this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK
this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE
this.stats.put("atkb", this.stats.get("_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff. this.stats.put(
"atkb",
this.stats.get(
"_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only
// useful for stuff like Bennett's buff.
this.stats.put("eanemo", this.stats.get("anemo%")); this.stats.put("eanemo", this.stats.get("anemo%"));
this.stats.put("ecryo", this.stats.get("cryo%")); this.stats.put("ecryo", this.stats.get("cryo%"));
this.stats.put("edendro", this.stats.get("dendro%")); this.stats.put("edendro", this.stats.get("dendro%"));
@ -78,7 +82,8 @@ public final class SetStatsCommand implements CommandHandler {
// Get the action and stat // Get the action and stat
String arg0 = args.remove(0).toLowerCase(); String arg0 = args.remove(0).toLowerCase();
Action action = switch (arg0) { Action action =
switch (arg0) {
default -> { default -> {
statStr = arg0; statStr = arg0;
yield Action.ACTION_SET; yield Action.ACTION_SET;
@ -150,7 +155,8 @@ public final class SetStatsCommand implements CommandHandler {
CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr); CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr);
} else { } else {
String uidStr = targetPlayer.getAccount().getId(); String uidStr = targetPlayer.getAccount().getId();
CommandHandler.sendTranslatedMessage(sender, action.messageKeyOther, stat.name, uidStr, valueStr); CommandHandler.sendTranslatedMessage(
sender, action.messageKeyOther, stat.name, uidStr, valueStr);
} }
} }

View File

@ -1,5 +1,9 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.command.CommandHelpers.*;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
@ -12,16 +16,11 @@ import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import lombok.Setter;
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.regex.Pattern; import java.util.regex.Pattern;
import lombok.Setter;
import static emu.grasscutter.command.CommandHelpers.*;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import static emu.grasscutter.utils.Language.translate;
@Command( @Command(
label = "spawn", label = "spawn",
@ -29,11 +28,13 @@ import static emu.grasscutter.utils.Language.translate;
usage = { usage = {
"<itemId> [x<amount>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>", "<itemId> [x<amount>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>",
"<gadgetId> [x<amount>] [state<state>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>", "<gadgetId> [x<amount>] [state<state>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>",
"<monsterId> [x<amount>] [lv<level>] [ai<aiId>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>"}, "<monsterId> [x<amount>] [lv<level>] [ai<aiId>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>"
},
permission = "server.spawn", permission = "server.spawn",
permissionTargeted = "server.spawn.others") permissionTargeted = "server.spawn.others")
public final class SpawnCommand implements CommandHandler { public final class SpawnCommand implements CommandHandler {
private static final Map<Pattern, BiConsumer<SpawnParameters, Integer>> intCommandHandlers = Map.ofEntries( private static final Map<Pattern, BiConsumer<SpawnParameters, Integer>> intCommandHandlers =
Map.ofEntries(
Map.entry(lvlRegex, SpawnParameters::setLvl), Map.entry(lvlRegex, SpawnParameters::setLvl),
Map.entry(amountRegex, SpawnParameters::setAmount), Map.entry(amountRegex, SpawnParameters::setAmount),
Map.entry(stateRegex, SpawnParameters::setState), Map.entry(stateRegex, SpawnParameters::setState),
@ -44,8 +45,7 @@ public final class SpawnCommand implements CommandHandler {
Map.entry(hpRegex, SpawnParameters::setHp), Map.entry(hpRegex, SpawnParameters::setHp),
Map.entry(defRegex, SpawnParameters::setDef), Map.entry(defRegex, SpawnParameters::setDef),
Map.entry(atkRegex, SpawnParameters::setAtk), Map.entry(atkRegex, SpawnParameters::setAtk),
Map.entry(aiRegex, SpawnParameters::setAi) Map.entry(aiRegex, SpawnParameters::setAi));
);
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
@ -67,13 +67,15 @@ public final class SpawnCommand implements CommandHandler {
z = Float.parseFloat(args.get(3)); z = Float.parseFloat(args.get(3));
param.pos = new Position(x, y, z); param.pos = new Position(x, y, z);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error")); CommandHandler.sendMessage(
sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough } // Fallthrough
case 1: case 1:
try { try {
param.id = Integer.parseInt(args.get(0)); param.id = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId")); CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.entityId"));
} }
break; break;
default: default:
@ -92,8 +94,13 @@ public final class SpawnCommand implements CommandHandler {
param.scene = targetPlayer.getScene(); param.scene = targetPlayer.getScene();
if (param.scene.getEntities().size() + param.amount > GAME_OPTIONS.sceneEntityLimit) { if (param.scene.getEntities().size() + param.amount > GAME_OPTIONS.sceneEntityLimit) {
param.amount = Math.max(Math.min(GAME_OPTIONS.sceneEntityLimit - param.scene.getEntities().size(), param.amount), 0); param.amount =
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.limit_reached", param.amount)); Math.max(
Math.min(
GAME_OPTIONS.sceneEntityLimit - param.scene.getEntities().size(), param.amount),
0);
CommandHandler.sendMessage(
sender, translate(sender, "commands.spawn.limit_reached", param.amount));
if (param.amount <= 0) { if (param.amount <= 0) {
return; return;
} }
@ -121,14 +128,16 @@ public final class SpawnCommand implements CommandHandler {
param.scene.addEntity(entity); param.scene.addEntity(entity);
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", param.amount, param.id)); CommandHandler.sendMessage(
sender, translate(sender, "commands.spawn.success", param.amount, param.id));
} }
private EntityItem createItem(ItemData itemData, SpawnParameters param, Position pos) { private EntityItem createItem(ItemData itemData, SpawnParameters param, Position pos) {
return new EntityItem(param.scene, null, itemData, pos, 1, true); return new EntityItem(param.scene, null, itemData, pos, 1, true);
} }
private EntityMonster createMonster(MonsterData monsterData, SpawnParameters param, Position pos) { private EntityMonster createMonster(
MonsterData monsterData, SpawnParameters param, Position pos) {
var entity = new EntityMonster(param.scene, monsterData, pos, param.lvl); var entity = new EntityMonster(param.scene, monsterData, pos, param.lvl);
if (param.ai != -1) { if (param.ai != -1) {
entity.setAiId(param.ai); entity.setAiId(param.ai);
@ -136,10 +145,13 @@ public final class SpawnCommand implements CommandHandler {
return entity; return entity;
} }
private EntityBaseGadget createGadget(GadgetData gadgetData, SpawnParameters param, Position pos, Player targetPlayer) { private EntityBaseGadget createGadget(
GadgetData gadgetData, SpawnParameters param, Position pos, Player targetPlayer) {
EntityBaseGadget entity; EntityBaseGadget entity;
if (gadgetData.getType() == EntityType.Vehicle) { if (gadgetData.getType() == EntityType.Vehicle) {
entity = new EntityVehicle(param.scene, targetPlayer, param.id, 0, pos, targetPlayer.getRotation()); entity =
new EntityVehicle(
param.scene, targetPlayer, param.id, 0, pos, targetPlayer.getRotation());
} else { } else {
entity = new EntityGadget(param.scene, param.id, pos, targetPlayer.getRotation()); entity = new EntityGadget(param.scene, param.id, pos, targetPlayer.getRotation());
if (param.state != -1) { if (param.state != -1) {
@ -165,7 +177,8 @@ public final class SpawnCommand implements CommandHandler {
entity.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, param.maxHP); entity.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, param.maxHP);
} }
if (param.hp != -1) { if (param.hp != -1) {
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, param.hp == 0 ? Float.MAX_VALUE : param.hp); entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP, param.hp == 0 ? Float.MAX_VALUE : param.hp);
} }
if (param.atk != -1) { if (param.atk != -1) {
entity.setFightProperty(FightProperty.FIGHT_PROP_ATTACK, param.atk); entity.setFightProperty(FightProperty.FIGHT_PROP_ATTACK, param.atk);
@ -186,32 +199,19 @@ public final class SpawnCommand implements CommandHandler {
} }
private static class SpawnParameters { private static class SpawnParameters {
@Setter @Setter public int id;
public int id; @Setter public int lvl = 1;
@Setter @Setter public int amount = 1;
public int lvl = 1; @Setter public int blockId = -1;
@Setter @Setter public int groupId = -1;
public int amount = 1; @Setter public int configId = -1;
@Setter @Setter public int state = -1;
public int blockId = -1; @Setter public int hp = -1;
@Setter @Setter public int maxHP = -1;
public int groupId = -1; @Setter public int atk = -1;
@Setter @Setter public int def = -1;
public int configId = -1; @Setter public int ai = -1;
@Setter @Setter public Position pos = null;
public int state = -1;
@Setter
public int hp = -1;
@Setter
public int maxHP = -1;
@Setter
public int atk = -1;
@Setter
public int def = -1;
@Setter
public int ai = -1;
@Setter
public Position pos = null;
public Scene scene = null; public Scene scene = null;
} }
} }

View File

@ -1,15 +1,18 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "stop",
@Command(label = "stop", aliases = {"shutdown"}, permission = "server.stop", targetRequirement = Command.TargetRequirement.NONE) aliases = {"shutdown"},
permission = "server.stop",
targetRequirement = Command.TargetRequirement.NONE)
public final class StopCommand implements CommandHandler { public final class StopCommand implements CommandHandler {
@Override @Override

View File

@ -7,7 +7,6 @@ import emu.grasscutter.data.excels.AvatarSkillDepotData;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Language; import emu.grasscutter.utils.Language;
import java.util.List; import java.util.List;
@Command( @Command(
@ -20,7 +19,8 @@ public final class TalentCommand implements CommandHandler {
if (avatar.setSkillLevel(skillId, newLevel)) { if (avatar.setSkillLevel(skillId, newLevel)) {
long nameHash = GameData.getAvatarSkillDataMap().get(skillId).getNameTextMapHash(); long nameHash = GameData.getAvatarSkillDataMap().get(skillId).getNameTextMapHash();
var name = Language.getTextMapKey(nameHash); var name = Language.getTextMapKey(nameHash);
CommandHandler.sendTranslatedMessage(sender, "commands.talent.set_id", skillId, name, newLevel); CommandHandler.sendTranslatedMessage(
sender, "commands.talent.set_id", skillId, name, newLevel);
} else { } else {
CommandHandler.sendTranslatedMessage(sender, "commands.talent.out_of_range"); CommandHandler.sendTranslatedMessage(sender, "commands.talent.out_of_range");
} }
@ -35,7 +35,9 @@ public final class TalentCommand implements CommandHandler {
Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar(); Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
AvatarSkillDepotData skillDepot = avatar.getSkillDepot(); AvatarSkillDepotData skillDepot = avatar.getSkillDepot();
if (skillDepot == null) { // Avatars without skill depots aren't a suitable target even with manual skillId specified if (skillDepot
== null) { // Avatars without skill depots aren't a suitable target even with manual skillId
// specified
CommandHandler.sendTranslatedMessage(sender, "commands.talent.invalid_skill_id"); CommandHandler.sendTranslatedMessage(sender, "commands.talent.invalid_skill_id");
return; return;
} }
@ -79,7 +81,8 @@ public final class TalentCommand implements CommandHandler {
return; return;
} }
skillId = switch (cmdSwitch) { skillId =
switch (cmdSwitch) {
default -> skillDepot.getSkills().get(0); default -> skillDepot.getSkills().get(0);
case "e" -> skillDepot.getSkills().get(1); case "e" -> skillDepot.getSkills().get(1);
case "q" -> skillDepot.getEnergySkill(); case "q" -> skillDepot.getEnergySkill();
@ -103,16 +106,22 @@ public final class TalentCommand implements CommandHandler {
return; return;
} }
int finalNewLevel = newLevel; int finalNewLevel = newLevel;
skillDepot.getSkillsAndEnergySkill().forEach(id -> setTalentLevel(sender, avatar, id, finalNewLevel)); skillDepot
.getSkillsAndEnergySkill()
.forEach(id -> setTalentLevel(sender, avatar, id, finalNewLevel));
} }
case "getid" -> { case "getid" -> {
var map = GameData.getAvatarSkillDataMap(); var map = GameData.getAvatarSkillDataMap();
skillDepot.getSkillsAndEnergySkill().forEach(id -> { skillDepot
.getSkillsAndEnergySkill()
.forEach(
id -> {
var talent = map.get(id); var talent = map.get(id);
if (talent == null) return; if (talent == null) return;
var talentName = Language.getTextMapKey(talent.getNameTextMapHash()); var talentName = Language.getTextMapKey(talent.getNameTextMapHash());
var talentDesc = Language.getTextMapKey(talent.getDescTextMapHash()); var talentDesc = Language.getTextMapKey(talent.getDescTextMapHash());
CommandHandler.sendTranslatedMessage(sender, "commands.talent.id_desc", id, talentName, talentDesc); CommandHandler.sendTranslatedMessage(
sender, "commands.talent.id_desc", id, talentName, talentDesc);
}); });
} }
} }

View File

@ -1,16 +1,15 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp; import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
@Command( @Command(
label = "team", label = "team",
usage = {"add <avatarId,...>", "(remove|set) [index|first|last|index-index,...]"}, usage = {"add <avatarId,...>", "(remove|set) [index|first|last|index-index,...]"},
@ -45,8 +44,11 @@ public final class TeamCommand implements CommandHandler {
return; return;
} }
targetPlayer.getTeamManager().updateTeamEntities( targetPlayer
new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo())); .getTeamManager()
.updateTeamEntities(
new PacketChangeMpTeamAvatarRsp(
targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo()));
} }
private boolean addCommand(Player sender, Player targetPlayer, List<String> args) { private boolean addCommand(Player sender, Player targetPlayer, List<String> args) {
@ -71,14 +73,16 @@ public final class TeamCommand implements CommandHandler {
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
if (currentTeamAvatars.size() + avatarIds.length > GAME_OPTIONS.avatarLimits.singlePlayerTeam) { if (currentTeamAvatars.size() + avatarIds.length > GAME_OPTIONS.avatarLimits.singlePlayerTeam) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.add_too_much", GAME_OPTIONS.avatarLimits.singlePlayerTeam); CommandHandler.sendTranslatedMessage(
sender, "commands.team.add_too_much", GAME_OPTIONS.avatarLimits.singlePlayerTeam);
return false; return false;
} }
for (var avatarId : avatarIds) { for (var avatarId : avatarIds) {
int id = Integer.parseInt(avatarId); int id = Integer.parseInt(avatarId);
if (!addAvatar(sender, targetPlayer, id, index)) if (!addAvatar(sender, targetPlayer, id, index))
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_add_avatar", avatarId); CommandHandler.sendTranslatedMessage(
sender, "commands.team.failed_to_add_avatar", avatarId);
if (index > 0) ++index; if (index > 0) ++index;
} }
return true; return true;
@ -101,7 +105,8 @@ public final class TeamCommand implements CommandHandler {
// step 1: parse metaIndex to indexes // step 1: parse metaIndex to indexes
var subIndexes = transformToIndexes(metaIndex, avatarCount); var subIndexes = transformToIndexes(metaIndex, avatarCount);
if (subIndexes == null) { if (subIndexes == null) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", metaIndex); CommandHandler.sendTranslatedMessage(
sender, "commands.team.failed_to_parse_index", metaIndex);
continue; continue;
} }
@ -146,7 +151,8 @@ public final class TeamCommand implements CommandHandler {
index = Integer.parseInt(args.get(1)) - 1; index = Integer.parseInt(args.get(1)) - 1;
if (index < 0) index = 0; if (index < 0) index = 0;
} catch (Exception e) { } catch (Exception e) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", args.get(1)); CommandHandler.sendTranslatedMessage(
sender, "commands.team.failed_to_parse_index", args.get(1));
return false; return false;
} }
@ -159,7 +165,8 @@ public final class TeamCommand implements CommandHandler {
try { try {
avatarId = Integer.parseInt(args.get(2)); avatarId = Integer.parseInt(args.get(2));
} catch (Exception e) { } catch (Exception e) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_parse_avatar_id", args.get(2)); CommandHandler.sendTranslatedMessage(
sender, "commands.team.failed_parse_avatar_id", args.get(2));
return false; return false;
} }
if (avatarId < BASE_AVATARID) { if (avatarId < BASE_AVATARID) {
@ -167,7 +174,8 @@ public final class TeamCommand implements CommandHandler {
} }
if (currentTeamAvatars.contains(avatarId)) { if (currentTeamAvatars.contains(avatarId)) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId); CommandHandler.sendTranslatedMessage(
sender, "commands.team.avatar_already_in_team", avatarId);
return false; return false;
} }
@ -186,7 +194,8 @@ public final class TeamCommand implements CommandHandler {
} }
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
if (currentTeamAvatars.contains(avatarId)) { if (currentTeamAvatars.contains(avatarId)) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId); CommandHandler.sendTranslatedMessage(
sender, "commands.team.avatar_already_in_team", avatarId);
return false; return false;
} }
if (!targetPlayer.getAvatars().hasAvatar(avatarId)) { if (!targetPlayer.getAvatars().hasAvatar(avatarId)) {
@ -218,13 +227,15 @@ public final class TeamCommand implements CommandHandler {
int min, max; int min, max;
try { try {
min = switch (range[0]) { min =
switch (range[0]) {
case "first" -> 1; case "first" -> 1;
case "last" -> listLength; case "last" -> listLength;
default -> Integer.parseInt(range[0]); default -> Integer.parseInt(range[0]);
}; };
max = switch (range[1]) { max =
switch (range[1]) {
case "first" -> 1; case "first" -> 1;
case "last" -> listLength; case "last" -> listLength;
default -> Integer.parseInt(range[1]); default -> Integer.parseInt(range[1]);
@ -254,5 +265,4 @@ public final class TeamCommand implements CommandHandler {
return null; return null;
} }
} }
} }

View File

@ -1,15 +1,18 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "teleportAll",
@Command(label = "teleportAll", aliases = {"tpall"}, permission = "player.tpall", permissionTargeted = "player.tpall.others") aliases = {"tpall"},
permission = "player.tpall",
permissionTargeted = "player.tpall.others")
public final class TeleportAllCommand implements CommandHandler { public final class TeleportAllCommand implements CommandHandler {
@Override @Override
@ -20,10 +23,12 @@ public final class TeleportAllCommand implements CommandHandler {
} }
for (Player player : targetPlayer.getWorld().getPlayers()) { for (Player player : targetPlayer.getWorld().getPlayers()) {
if (player.equals(targetPlayer)) if (player.equals(targetPlayer)) continue;
continue;
player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), TeleportType.COMMAND, targetPlayer.getPosition()); player
.getWorld()
.transferPlayerToScene(
player, targetPlayer.getSceneId(), TeleportType.COMMAND, targetPlayer.getPosition());
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success"));

View File

@ -1,19 +1,24 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "teleport",
@Command(label = "teleport", aliases = {"tp"}, usage = {"<x> <y> <z> [sceneId]"}, permission = "player.teleport", permissionTargeted = "player.teleport.others") aliases = {"tp"},
usage = {"<x> <y> <z> [sceneId]"},
permission = "player.teleport",
permissionTargeted = "player.teleport.others")
public final class TeleportCommand implements CommandHandler { public final class TeleportCommand implements CommandHandler {
private float parseRelative(String input, Float current) { // TODO: Maybe this will be useful elsewhere later private float parseRelative(
String input, Float current) { // TODO: Maybe this will be useful elsewhere later
if (input.contains("~")) { // Relative if (input.contains("~")) { // Relative
if (!input.equals("~")) { // Relative with offset if (!input.equals("~")) { // Relative with offset
current += Float.parseFloat(input.replace("~", "")); current += Float.parseFloat(input.replace("~", ""));
@ -37,7 +42,8 @@ public final class TeleportCommand implements CommandHandler {
try { try {
sceneId = Integer.parseInt(args.get(3)); sceneId = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error")); CommandHandler.sendMessage(
sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough } // Fallthrough
case 3: case 3:
try { try {
@ -45,7 +51,8 @@ public final class TeleportCommand implements CommandHandler {
y = this.parseRelative(args.get(1), y); y = this.parseRelative(args.get(1), y);
z = this.parseRelative(args.get(2), z); z = this.parseRelative(args.get(2), z);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position")); CommandHandler.sendMessage(
sender, translate(sender, "commands.teleport.invalid_position"));
} }
break; break;
default: default:
@ -54,15 +61,18 @@ public final class TeleportCommand implements CommandHandler {
} }
Position target_pos = new Position(x, y, z); Position target_pos = new Position(x, y, z);
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos); boolean result =
targetPlayer
.getWorld()
.transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos);
if (!result) { if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", CommandHandler.sendMessage(
targetPlayer.getNickname(), x, y, z, sceneId) sender,
); translate(
} sender, "commands.teleport.success", targetPlayer.getNickname(), x, y, z, sceneId));
}
} }
} }

View File

@ -4,14 +4,12 @@ import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
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;
@Command( @Command(
label = "unban", label = "unban",
permission = "server.ban", permission = "server.ban",
targetRequirement = Command.TargetRequirement.PLAYER targetRequirement = Command.TargetRequirement.PLAYER)
)
public final class UnBanCommand implements CommandHandler { public final class UnBanCommand implements CommandHandler {
private boolean unBanAccount(Player targetPlayer) { private boolean unBanAccount(Player targetPlayer) {

View File

@ -1,19 +1,22 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.PlayerProgressManager; import emu.grasscutter.game.player.PlayerProgressManager;
import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static emu.grasscutter.utils.Language.translate; @Command(
label = "unlockall",
@Command(label = "unlockall", usage = {""}, permission = "player.unlockall", permissionTargeted = "player.unlockall.others") usage = {""},
permission = "player.unlockall",
permissionTargeted = "player.unlockall.others")
public final class UnlockAllCommand implements CommandHandler { public final class UnlockAllCommand implements CommandHandler {
@Override @Override
@ -34,6 +37,7 @@ public final class UnlockAllCommand implements CommandHandler {
targetPlayer.sendPacket(new PacketOpenStateChangeNotify(changed)); targetPlayer.sendPacket(new PacketOpenStateChangeNotify(changed));
CommandHandler.sendMessage(sender, translate(sender, "commands.unlockall.success", targetPlayer.getNickname())); CommandHandler.sendMessage(
sender, translate(sender, "commands.unlockall.success", targetPlayer.getNickname()));
} }
} }

View File

@ -4,20 +4,28 @@ import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.ClimateType;
import java.util.List; import java.util.List;
@Command(label = "weather", aliases = {"w"}, usage = {"weather [<weatherId>] [<climateType>]"}, permission = "player.weather", permissionTargeted = "player.weather.others") @Command(
label = "weather",
aliases = {"w"},
usage = {"weather [<weatherId>] [<climateType>]"},
permission = "player.weather",
permissionTargeted = "player.weather.others")
public final class WeatherCommand implements CommandHandler { public final class WeatherCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
int weatherId = targetPlayer.getWeatherId(); int weatherId = targetPlayer.getWeatherId();
ClimateType climate = ClimateType.CLIMATE_NONE; // Sending ClimateType.CLIMATE_NONE to Scene.setWeather will use the default climate for that weather ClimateType climate =
ClimateType
.CLIMATE_NONE; // Sending ClimateType.CLIMATE_NONE to Scene.setWeather will use the
// default climate for that weather
if (args.isEmpty()) { if (args.isEmpty()) {
climate = targetPlayer.getClimate(); climate = targetPlayer.getClimate();
CommandHandler.sendTranslatedMessage(sender, "commands.weather.status", weatherId, climate.getShortName()); CommandHandler.sendTranslatedMessage(
sender, "commands.weather.status", weatherId, climate.getShortName());
return; return;
} }
@ -38,6 +46,7 @@ public final class WeatherCommand implements CommandHandler {
targetPlayer.setWeather(weatherId, climate); targetPlayer.setWeather(weatherId, climate);
climate = targetPlayer.getClimate(); // Might be different to what we set climate = targetPlayer.getClimate(); // Might be different to what we set
CommandHandler.sendTranslatedMessage(sender, "commands.weather.success", weatherId, climate.getShortName()); CommandHandler.sendTranslatedMessage(
sender, "commands.weather.success", weatherId, climate.getShortName());
} }
} }

View File

@ -1,18 +1,15 @@
package emu.grasscutter.config; package emu.grasscutter.config;
import emu.grasscutter.utils.FileUtils;
import java.nio.file.Path;
import java.util.Locale;
import static emu.grasscutter.Grasscutter.config; import static emu.grasscutter.Grasscutter.config;
import emu.grasscutter.utils.FileUtils;
import java.nio.file.Path;
import java.util.Locale;
/** /**
* A data container for the server's configuration. * A data container for the server's configuration.
* <p> *
* Use `import static emu.grasscutter.Configuration.*;` * <p>Use `import static emu.grasscutter.Configuration.*;` to import all configuration constants.
* to import all configuration constants.
*/ */
public final class Configuration extends ConfigContainer { public final class Configuration extends ConfigContainer {
@ -37,7 +34,8 @@ public final class Configuration extends ConfigContainer {
public static final Policies HTTP_POLICIES = config.server.http.policies; public static final Policies HTTP_POLICIES = config.server.http.policies;
public static final Files HTTP_STATIC_FILES = config.server.http.files; public static final Files HTTP_STATIC_FILES = config.server.http.files;
public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions; public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions;
public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits; public static final GameOptions.InventoryLimits INVENTORY_LIMITS =
config.server.game.gameOptions.inventoryLimits;
private static final String DATA_FOLDER = config.folderStructure.data; private static final String DATA_FOLDER = config.folderStructure.data;
private static final String PLUGINS_FOLDER = config.folderStructure.plugins; private static final String PLUGINS_FOLDER = config.folderStructure.plugins;
private static final String SCRIPTS_FOLDER = config.folderStructure.scripts; private static final String SCRIPTS_FOLDER = config.folderStructure.scripts;

View File

@ -6,8 +6,6 @@ import emu.grasscutter.tools.Tools;
import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.JsonUtils; import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.TsvUtils; import emu.grasscutter.utils.TsvUtils;
import lombok.val;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -16,11 +14,13 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.val;
public class DataLoader { public class DataLoader {
/** /**
* Load a data file by its name. If the file isn't found within the /data directory then it will fallback to the default within the jar resources * Load a data file by its name. If the file isn't found within the /data directory then it will
* fallback to the default within the jar resources
* *
* @param resourcePath The path to the data file to be loaded. * @param resourcePath The path to the data file to be loaded.
* @return InputStream of the data file. * @return InputStream of the data file.
@ -32,7 +32,8 @@ public class DataLoader {
} }
/** /**
* Creates an input stream reader for a data file. If the file isn't found within the /data directory then it will fallback to the default within the jar resources * Creates an input stream reader for a data file. If the file isn't found within the /data
* directory then it will fallback to the default within the jar resources
* *
* @param resourcePath The path to the data file to be loaded. * @param resourcePath The path to the data file to be loaded.
* @return InputStreamReader of the data file. * @return InputStreamReader of the data file.
@ -40,7 +41,8 @@ public class DataLoader {
* @throws FileNotFoundException * @throws FileNotFoundException
* @see #load(String, boolean) * @see #load(String, boolean)
*/ */
public static InputStreamReader loadReader(String resourcePath) throws IOException, FileNotFoundException { public static InputStreamReader loadReader(String resourcePath)
throws IOException, FileNotFoundException {
try { try {
InputStream is = load(resourcePath, true); InputStream is = load(resourcePath, true);
return new InputStreamReader(is); return new InputStreamReader(is);
@ -53,20 +55,22 @@ public class DataLoader {
* Load a data file by its name. * Load a data file by its name.
* *
* @param resourcePath The path to the data file to be loaded. * @param resourcePath The path to the data file to be loaded.
* @param useFallback If the file does not exist in the /data directory, should it use the default file in the jar? * @param useFallback If the file does not exist in the /data directory, should it use the default
* file in the jar?
* @return InputStream of the data file. * @return InputStream of the data file.
* @throws FileNotFoundException * @throws FileNotFoundException
*/ */
public static InputStream load(String resourcePath, boolean useFallback) throws FileNotFoundException { public static InputStream load(String resourcePath, boolean useFallback)
Path path = useFallback throws FileNotFoundException {
? FileUtils.getDataPath(resourcePath) Path path =
: FileUtils.getDataUserPath(resourcePath); useFallback ? FileUtils.getDataPath(resourcePath) : FileUtils.getDataUserPath(resourcePath);
if (Files.exists(path)) { if (Files.exists(path)) {
// Data is in the resource directory // Data is in the resource directory
try { try {
return Files.newInputStream(path); return Files.newInputStream(path);
} catch (IOException e) { } catch (IOException e) {
throw new FileNotFoundException(e.getMessage()); // This is evil but so is changing the function signature at this point throw new FileNotFoundException(
e.getMessage()); // This is evil but so is changing the function signature at this point
} }
} }
return null; return null;
@ -84,13 +88,15 @@ public class DataLoader {
} }
} }
public static <T1, T2> Map<T1, T2> loadMap(String resourcePath, Class<T1> keyType, Class<T2> valueType) throws IOException { public static <T1, T2> Map<T1, T2> loadMap(
String resourcePath, Class<T1> keyType, Class<T2> valueType) throws IOException {
try (InputStreamReader reader = loadReader(resourcePath)) { try (InputStreamReader reader = loadReader(resourcePath)) {
return JsonUtils.loadToMap(reader, keyType, valueType); return JsonUtils.loadToMap(reader, keyType, valueType);
} }
} }
public static <T> List<T> loadTableToList(String resourcePath, Class<T> classType) throws IOException { public static <T> List<T> loadTableToList(String resourcePath, Class<T> classType)
throws IOException {
val path = FileUtils.getDataPathTsjJsonTsv(resourcePath); val path = FileUtils.getDataPathTsjJsonTsv(resourcePath);
Grasscutter.getLogger().debug("Loading data table from: " + path); Grasscutter.getLogger().debug("Loading data table from: " + path);
return switch (FileUtils.getFileExtension(path)) { return switch (FileUtils.getFileExtension(path)) {

View File

@ -6,30 +6,33 @@ import emu.grasscutter.data.excels.*;
import emu.grasscutter.game.quest.QuestEncryptionKey; import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.ints.*;
import java.lang.reflect.Field;
import java.util.*;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.Tolerate; import lombok.experimental.Tolerate;
import java.lang.reflect.Field;
import java.util.*;
public class GameData { public class GameData {
protected static final Map<String, AbilityData> abilityDataMap = new HashMap<>(); protected static final Map<String, AbilityData> abilityDataMap = new HashMap<>();
protected static final Int2ObjectMap<ScenePointEntry> scenePointEntryMap = new Int2ObjectOpenHashMap<>(); protected static final Int2ObjectMap<ScenePointEntry> scenePointEntryMap =
new Int2ObjectOpenHashMap<>();
// BinOutputs // BinOutputs
@Getter @Getter
private static final Int2ObjectMap<HomeworldDefaultSaveData> homeworldDefaultSaveData = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<HomeworldDefaultSaveData> homeworldDefaultSaveData =
@Getter new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<String> abilityHashes = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<String> abilityHashes = new Int2ObjectOpenHashMap<>();
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
@Getter @Getter
private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>(); private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>();
@Getter
private static final Map<String, ConfigGadget> gadgetConfigData = new HashMap<>(); @Getter private static final Map<String, ConfigGadget> gadgetConfigData = new HashMap<>();
@Getter @Getter private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
@Getter @Getter
private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>(); private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<QuestEncryptionKey> questsKeys = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<QuestEncryptionKey> questsKeys = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<SceneNpcBornData> npcBornData = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<SceneNpcBornData> npcBornData = new Int2ObjectOpenHashMap<>();
@ -38,164 +41,286 @@ public class GameData {
// ExcelConfigs // ExcelConfigs
@Getter @Getter
private static final ArrayList<CodexReliquaryData> codexReliquaryArrayList = new ArrayList<>(); private static final ArrayList<CodexReliquaryData> codexReliquaryArrayList = new ArrayList<>();
private static final Int2ObjectMap<AchievementData> achievementDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AchievementData> achievementDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AchievementGoalData> achievementGoalDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AchievementGoalData> achievementGoalDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ActivityShopData> activityShopDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ActivityShopData> activityShopDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataItemIdMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataItemIdMap =
new Int2ObjectLinkedOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap =
new Int2ObjectLinkedOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap =
new Int2ObjectLinkedOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarData> avatarDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarData> avatarDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarFlycloakData> avatarFlycloakDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarFlycloakData> avatarFlycloakDataMap =
new Int2ObjectLinkedOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarLevelData> avatarLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarLevelData> avatarLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<BlossomRefreshExcelConfigData> blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BlossomRefreshExcelConfigData>
@Getter blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<BuffData> buffDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<BuffData> buffDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap =
@Getter new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CookBonusData> cookBonusDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CookBonusData> cookBonusDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<CompoundData> compoundDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CompoundData> compoundDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ForgeData> forgeDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ForgeData> forgeDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<FurnitureMakeConfigData> furnitureMakeConfigDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FurnitureMakeConfigData> furnitureMakeConfigDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<GadgetData> gadgetDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<GadgetData> gadgetDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<GatherData> gatherDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<GatherData> gatherDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap =
new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ItemData> itemDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ItemData> itemDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<MonsterCurveData> monsterCurveDataMap =
@Getter new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<MonsterCurveData> monsterCurveDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<MonsterData> monsterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<MonsterData> monsterDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<MonsterDescribeData> monsterDescribeDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<MonsterDescribeData> monsterDescribeDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap =
new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<NpcData> npcDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<NpcData> npcDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<OpenStateData> openStateDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<OpenStateData> openStateDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<PersonalLineData> personalLineDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<PersonalLineData> personalLineDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<PlayerLevelData> playerLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<PlayerLevelData> playerLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap =
@Getter new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<QuestData> questDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<QuestData> questDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ReliquaryAffixData> reliquaryAffixDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ReliquaryAffixData> reliquaryAffixDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ReliquaryMainPropData> reliquaryMainPropDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ReliquaryMainPropData> reliquaryMainPropDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<ReliquarySetData> reliquarySetDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ReliquarySetData> reliquarySetDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<TriggerExcelConfigData> triggerExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<TriggerExcelConfigData> triggerExcelConfigDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<WeaponCurveData> weaponCurveDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WeaponCurveData> weaponCurveDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<WeaponLevelData> weaponLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WeaponLevelData> weaponLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<WeaponPromoteData> weaponPromoteDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WeaponPromoteData> weaponPromoteDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<WeatherData> weatherDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WeatherData> weatherDataMap = new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<WorldAreaData> worldAreaDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WorldAreaData> worldAreaDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap =
private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap =
new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<ReliquaryLevelData> reliquaryLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ReliquaryLevelData> reliquaryLevelDataMap =
private static final Int2ObjectMap<ShopGoodsData> shopGoodsDataMap = new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<ShopGoodsData> shopGoodsDataMap =
new Int2ObjectOpenHashMap<>();
// The following are accessed via getMapByResourceDef, and will show as unused // The following are accessed via getMapByResourceDef, and will show as unused
private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataMap =
private static final Int2ObjectMap<CodexQuestData> codexQuestDataMap = new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexQuestData> codexQuestDataMap =
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataMap = new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataMap =
new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataMap =
new Int2ObjectOpenHashMap<>();
// Cache // Cache
@Getter @Getter private static final IntList scenePointIdList = new IntArrayList();
private static final IntList scenePointIdList = new IntArrayList(); @Getter private static final List<OpenStateData> openStateList = new ArrayList<>();
@Getter @Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
private static final List<OpenStateData> openStateList = new ArrayList<>(); @Getter private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
@Getter
private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
@Getter
private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
protected static Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>(); protected static Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>();
protected static Int2IntMap proudSkillGroupMaxLevels = new Int2IntOpenHashMap(); protected static Int2IntMap proudSkillGroupMaxLevels = new Int2IntOpenHashMap();
protected static Int2ObjectMap<IntSet> avatarSkillLevels = new Int2ObjectOpenHashMap<>(); protected static Int2ObjectMap<IntSet> avatarSkillLevels = new Int2ObjectOpenHashMap<>();
@ -236,7 +361,8 @@ public class GameData {
return abilityEmbryos; return abilityEmbryos;
} }
// Getters that get values rather than containers. If Lombok ever gets syntactic sugar for this, we should adopt that. // Getters that get values rather than containers. If Lombok ever gets syntactic sugar for this,
// we should adopt that.
public static AbilityData getAbilityData(String abilityName) { public static AbilityData getAbilityData(String abilityName) {
return abilityDataMap.get(abilityName); return abilityDataMap.get(abilityName);
} }
@ -283,25 +409,26 @@ public class GameData {
return Optional.ofNullable(getRelicLevelData(rankLevel, level)).map(d -> d.getExp()).orElse(0); return Optional.ofNullable(getRelicLevelData(rankLevel, level)).map(d -> d.getExp()).orElse(0);
} }
// Generic getter // Generic getter
public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) { public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) {
Int2ObjectMap<?> map = null; Int2ObjectMap<?> map = null;
try { try {
Field field = GameData.class.getDeclaredField(Utils.lowerCaseFirstChar(resourceDefinition.getSimpleName()) + "Map"); Field field =
GameData.class.getDeclaredField(
Utils.lowerCaseFirstChar(resourceDefinition.getSimpleName()) + "Map");
field.setAccessible(true); field.setAccessible(true);
map = (Int2ObjectMap<?>) field.get(null); map = (Int2ObjectMap<?>) field.get(null);
field.setAccessible(false); field.setAccessible(false);
} catch (Exception e) { } catch (Exception e) {
Grasscutter.getLogger().error("Error fetching resource map for " + resourceDefinition.getSimpleName(), e); Grasscutter.getLogger()
.error("Error fetching resource map for " + resourceDefinition.getSimpleName(), e);
} }
return map; return map;
} }
public static int getWeaponExpRequired(int rankLevel, int level) { public static int getWeaponExpRequired(int rankLevel, int level) {
WeaponLevelData levelData = weaponLevelDataMap.get(level); WeaponLevelData levelData = weaponLevelDataMap.get(level);
if (levelData == null) { if (levelData == null) {
@ -316,7 +443,8 @@ public class GameData {
public static Map<Integer, List<Integer>> getFetterDataEntries() { public static Map<Integer, List<Integer>> getFetterDataEntries() {
if (fetters.isEmpty()) { if (fetters.isEmpty()) {
fetterDataMap.forEach((k, v) -> { fetterDataMap.forEach(
(k, v) -> {
if (!fetters.containsKey(v.getAvatarId())) { if (!fetters.containsKey(v.getAvatarId())) {
fetters.put(v.getAvatarId(), new ArrayList<>()); fetters.put(v.getAvatarId(), new ArrayList<>());
} }
@ -329,7 +457,8 @@ public class GameData {
public static Map<Integer, List<ShopGoodsData>> getShopGoodsDataEntries() { public static Map<Integer, List<ShopGoodsData>> getShopGoodsDataEntries() {
if (shopGoods.isEmpty()) { if (shopGoods.isEmpty()) {
shopGoodsDataMap.forEach((k, v) -> { shopGoodsDataMap.forEach(
(k, v) -> {
if (!shopGoods.containsKey(v.getShopType())) if (!shopGoods.containsKey(v.getShopType()))
shopGoods.put(v.getShopType(), new ArrayList<>()); shopGoods.put(v.getShopType(), new ArrayList<>());
shopGoods.get(v.getShopType()).add(v); shopGoods.get(v.getShopType()).add(v);

View File

@ -9,50 +9,57 @@ import emu.grasscutter.game.world.SpawnDataEntry;
import emu.grasscutter.utils.WeightedList; import emu.grasscutter.utils.WeightedList;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.Getter;
import lombok.Setter;
public class GameDepot { public class GameDepot {
public static final int[] BLOCK_SIZE = new int[] {50, 500}; // Scales public static final int[] BLOCK_SIZE = new int[] {50, 500}; // Scales
private static final Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot =
private static final Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot =
new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot =
new Int2ObjectOpenHashMap<>();
@Getter @Setter private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
@Getter @Getter
@Setter private static final HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists =
private static Map<String, AvatarConfig> playerAbilities = new HashMap<>(); new HashMap<>();
@Getter
private static final HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>(); @Getter @Setter private static BlossomConfig blossomConfig;
@Getter
@Setter
private static BlossomConfig blossomConfig;
public static void load() { public static void load() {
for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) { for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) {
if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) { if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) {
continue; continue;
} }
List<ReliquaryMainPropData> list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>()); List<ReliquaryMainPropData> list =
relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>());
list.add(data); list.add(data);
WeightedList<ReliquaryMainPropData> weightedList = relicRandomMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new WeightedList<>()); WeightedList<ReliquaryMainPropData> weightedList =
relicRandomMainPropDepot.computeIfAbsent(
data.getPropDepotId(), k -> new WeightedList<>());
weightedList.add(data.getWeight(), data); weightedList.add(data.getWeight(), data);
} }
for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) { for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) {
if (data.getWeight() <= 0 || data.getDepotId() <= 0) { if (data.getWeight() <= 0 || data.getDepotId() <= 0) {
continue; continue;
} }
List<ReliquaryAffixData> list = relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>()); List<ReliquaryAffixData> list =
relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>());
list.add(data); list.add(data);
} }
// Let the server owner know if theyre missing weights // Let the server owner know if theyre missing weights
if (relicMainPropDepot.size() == 0 || relicAffixDepot.size() == 0) { if (relicMainPropDepot.size() == 0 || relicAffixDepot.size() == 0) {
Grasscutter.getLogger().error("Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder."); Grasscutter.getLogger()
.error(
"Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder.");
} }
} }
@ -72,7 +79,8 @@ public class GameDepot {
return relicAffixDepot.get(depot); return relicAffixDepot.get(depot);
} }
public static void addSpawnListById(HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> data) { public static void addSpawnListById(
HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> data) {
spawnLists.putAll(data); spawnLists.putAll(data);
} }
} }

View File

@ -6,7 +6,5 @@ public abstract class GameResource {
return 0; return 0;
} }
public void onLoad() { public void onLoad() {}
}
} }

View File

@ -1,5 +1,9 @@
package emu.grasscutter.data; package emu.grasscutter.data;
import static emu.grasscutter.utils.FileUtils.getDataPath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
import static emu.grasscutter.utils.Language.translate;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*; import emu.grasscutter.data.binout.*;
@ -18,9 +22,6 @@ import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntArraySet;
import lombok.val;
import org.reflections.Reflections;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.file.Files; import java.nio.file.Files;
@ -30,10 +31,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
import lombok.val;
import static emu.grasscutter.utils.FileUtils.getDataPath; import org.reflections.Reflections;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
import static emu.grasscutter.utils.Language.translate;
public class ResourceLoader { public class ResourceLoader {
@ -46,14 +45,18 @@ public class ResourceLoader {
Set<?> classes = reflections.getSubTypesOf(GameResource.class); Set<?> classes = reflections.getSubTypesOf(GameResource.class);
List<Class<?>> classList = new ArrayList<>(classes.size()); List<Class<?>> classList = new ArrayList<>(classes.size());
classes.forEach(o -> { classes.forEach(
o -> {
Class<?> c = (Class<?>) o; Class<?> c = (Class<?>) o;
if (c.getAnnotation(ResourceType.class) != null) { if (c.getAnnotation(ResourceType.class) != null) {
classList.add(c); classList.add(c);
} }
}); });
classList.sort((a, b) -> b.getAnnotation(ResourceType.class).loadPriority().value() - a.getAnnotation(ResourceType.class).loadPriority().value()); classList.sort(
(a, b) ->
b.getAnnotation(ResourceType.class).loadPriority().value()
- a.getAnnotation(ResourceType.class).loadPriority().value());
return classList; return classList;
} }
@ -67,7 +70,8 @@ public class ResourceLoader {
val map = new LinkedHashMap<ResourceType.LoadPriority, Set<Class<?>>>(priorities.size()); val map = new LinkedHashMap<ResourceType.LoadPriority, Set<Class<?>>>(priorities.size());
priorities.forEach(p -> map.put(p, new HashSet<>())); priorities.forEach(p -> map.put(p, new HashSet<>()));
classes.forEach(c -> { classes.forEach(
c -> {
// val c = (Class<?>) o; // val c = (Class<?>) o;
val annotation = c.getAnnotation(ResourceType.class); val annotation = c.getAnnotation(ResourceType.class);
if (annotation != null) { if (annotation != null) {
@ -112,12 +116,18 @@ public class ResourceLoader {
public static void loadResources(boolean doReload) { public static void loadResources(boolean doReload) {
long startTime = System.nanoTime(); long startTime = System.nanoTime();
val errors = new ConcurrentLinkedQueue<Pair<String, Exception>>(); // Logger in a parallel stream will deadlock val errors =
new ConcurrentLinkedQueue<
Pair<String, Exception>>(); // Logger in a parallel stream will deadlock
getResourceDefClassesPrioritySets().forEach(classes -> { getResourceDefClassesPrioritySets()
.forEach(
classes -> {
classes.stream() classes.stream()
.parallel().unordered() .parallel()
.forEach(c -> { .unordered()
.forEach(
c -> {
val type = c.getAnnotation(ResourceType.class); val type = c.getAnnotation(ResourceType.class);
if (type == null) return; if (type == null) return;
@ -131,14 +141,18 @@ public class ResourceLoader {
} }
}); });
}); });
errors.forEach(pair -> Grasscutter.getLogger().error("Error loading resource file: " + pair.left(), pair.right())); errors.forEach(
pair ->
Grasscutter.getLogger()
.error("Error loading resource file: " + pair.left(), pair.right()));
long endTime = System.nanoTime(); long endTime = System.nanoTime();
long ns = (endTime - startTime); // divide by 1000000 to get milliseconds. long ns = (endTime - startTime); // divide by 1000000 to get milliseconds.
Grasscutter.getLogger().debug("Loading resources took " + ns + "ns == " + ns / 1000000 + "ms"); Grasscutter.getLogger().debug("Loading resources took " + ns + "ns == " + ns / 1000000 + "ms");
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception { protected static void loadFromResource(
Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception {
val simpleName = c.getSimpleName(); val simpleName = c.getSimpleName();
if (doReload || !loadedResources.contains(simpleName)) { if (doReload || !loadedResources.contains(simpleName)) {
for (String name : type.name()) { for (String name : type.name()) {
@ -149,15 +163,18 @@ public class ResourceLoader {
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map) throws Exception { protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map)
val results = switch (FileUtils.getFileExtension(filename)) { throws Exception {
val results =
switch (FileUtils.getFileExtension(filename)) {
case "json" -> JsonUtils.loadToList(filename, c); case "json" -> JsonUtils.loadToList(filename, c);
case "tsj" -> TsvUtils.loadTsjToListSetField(filename, c); case "tsj" -> TsvUtils.loadTsjToListSetField(filename, c);
case "tsv" -> TsvUtils.loadTsvToListSetField(filename, c); case "tsv" -> TsvUtils.loadTsvToListSetField(filename, c);
default -> null; default -> null;
}; };
if (results == null) return; if (results == null) return;
results.forEach(o -> { results.forEach(
o -> {
GameResource res = (GameResource) o; GameResource res = (GameResource) o;
res.onLoad(); res.onLoad();
map.put(res.getId(), res); map.put(res.getId(), res);
@ -165,8 +182,11 @@ public class ResourceLoader {
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map) throws Exception { protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map)
JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c).forEach(o -> { throws Exception {
JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c)
.forEach(
o -> {
GameResource res = (GameResource) o; GameResource res = (GameResource) o;
res.onLoad(); res.onLoad();
map.put(res.getId(), res); map.put(res.getId(), res);
@ -176,7 +196,9 @@ public class ResourceLoader {
private static void loadScenePoints() { private static void loadScenePoints() {
val pattern = Pattern.compile("scene([0-9]+)_point\\.json"); val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
try { try {
Files.newDirectoryStream(getResourcePath("BinOutput/Scene/Point"), "scene*_point.json").forEach(path -> { Files.newDirectoryStream(getResourcePath("BinOutput/Scene/Point"), "scene*_point.json")
.forEach(
path -> {
val matcher = pattern.matcher(path.getFileName().toString()); val matcher = pattern.matcher(path.getFileName().toString());
if (!matcher.find()) return; if (!matcher.find()) return;
int sceneId = Integer.parseInt(matcher.group(1)); int sceneId = Integer.parseInt(matcher.group(1));
@ -192,7 +214,8 @@ public class ResourceLoader {
if (config.points == null) return; if (config.points == null) return;
val scenePoints = new IntArrayList(); val scenePoints = new IntArrayList();
config.points.forEach((pointId, pointData) -> { config.points.forEach(
(pointId, pointData) -> {
val scenePoint = new ScenePointEntry(sceneId, pointData); val scenePoint = new ScenePointEntry(sceneId, pointData);
scenePoints.add(pointId); scenePoints.add(pointId);
pointData.setId(pointId); pointData.setId(pointId);
@ -206,21 +229,28 @@ public class ResourceLoader {
GameData.getScenePointsPerScene().put(sceneId, scenePoints); GameData.getScenePointsPerScene().put(sceneId, scenePoints);
}); });
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!"); Grasscutter.getLogger()
.error("Scene point files cannot be found, you cannot use teleport waypoints!");
} }
} }
private static void cacheTalentLevelSets() { private static void cacheTalentLevelSets() {
// All known levels, keyed by proudSkillGroupId // All known levels, keyed by proudSkillGroupId
GameData.getProudSkillDataMap().forEach((id, data) -> GameData.getProudSkillDataMap()
.forEach(
(id, data) ->
GameData.proudSkillGroupLevels GameData.proudSkillGroupLevels
.computeIfAbsent(data.getProudSkillGroupId(), i -> new IntArraySet()) .computeIfAbsent(data.getProudSkillGroupId(), i -> new IntArraySet())
.add(data.getLevel())); .add(data.getLevel()));
// All known levels, keyed by avatarSkillId // All known levels, keyed by avatarSkillId
GameData.getAvatarSkillDataMap().forEach((id, data) -> GameData.getAvatarSkillDataMap()
GameData.avatarSkillLevels.put((int) id, GameData.proudSkillGroupLevels.get(data.getProudSkillGroupId()))); .forEach(
(id, data) ->
GameData.avatarSkillLevels.put(
(int) id, GameData.proudSkillGroupLevels.get(data.getProudSkillGroupId())));
// Maximum known levels, keyed by proudSkillGroupId // Maximum known levels, keyed by proudSkillGroupId
GameData.proudSkillGroupLevels.forEach((id, set) -> GameData.proudSkillGroupLevels.forEach(
(id, set) ->
GameData.proudSkillGroupMaxLevels.put((int) id, set.intStream().max().getAsInt())); GameData.proudSkillGroupMaxLevels.put((int) id, set.intStream().max().getAsInt()));
} }
@ -229,7 +259,8 @@ public class ResourceLoader {
// Read from cached file if exists // Read from cached file if exists
try { try {
embryoList = JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class); embryoList =
JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
@ -239,7 +270,9 @@ public class ResourceLoader {
val l = new ArrayList<AbilityEmbryoEntry>(); val l = new ArrayList<AbilityEmbryoEntry>();
try { try {
Files.newDirectoryStream(getResourcePath("BinOutput/Avatar/"), "ConfigAvatar_*.json").forEach(path -> { Files.newDirectoryStream(getResourcePath("BinOutput/Avatar/"), "ConfigAvatar_*.json")
.forEach(
path -> {
val matcher = pattern.matcher(path.getFileName().toString()); val matcher = pattern.matcher(path.getFileName().toString());
if (!matcher.find()) return; if (!matcher.find()) return;
String avatarName = matcher.group(1); String avatarName = matcher.group(1);
@ -255,7 +288,12 @@ public class ResourceLoader {
if (config.abilities == null) return; if (config.abilities == null) return;
int s = config.abilities.size(); int s = config.abilities.size();
AbilityEmbryoEntry al = new AbilityEmbryoEntry(avatarName, config.abilities.stream().map(Object::toString).toArray(size -> new String[s])); AbilityEmbryoEntry al =
new AbilityEmbryoEntry(
avatarName,
config.abilities.stream()
.map(Object::toString)
.toArray(size -> new String[s]));
l.add(al); l.add(al);
}); });
} catch (IOException e) { } catch (IOException e) {
@ -266,7 +304,12 @@ public class ResourceLoader {
embryoList = l; embryoList = l;
try { try {
GameDepot.setPlayerAbilities(JsonUtils.loadToMap(getResourcePath("BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"), String.class, AvatarConfig.class)); GameDepot.setPlayerAbilities(
JsonUtils.loadToMap(
getResourcePath(
"BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"),
String.class,
AvatarConfig.class));
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Error loading player abilities:", e); Grasscutter.getLogger().error("Error loading player abilities:", e);
} }
@ -285,7 +328,10 @@ public class ResourceLoader {
private static void loadAbilityModifiers() { private static void loadAbilityModifiers() {
// Load from BinOutput // Load from BinOutput
try (Stream<Path> paths = Files.walk(getResourcePath("BinOutput/Ability/Temp/"))) { try (Stream<Path> paths = Files.walk(getResourcePath("BinOutput/Ability/Temp/"))) {
paths.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".json")).forEach(ResourceLoader::loadAbilityModifiers); paths
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".json"))
.forEach(ResourceLoader::loadAbilityModifiers);
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers: ", e); Grasscutter.getLogger().error("Error loading ability modifiers: ", e);
} }
@ -296,9 +342,11 @@ public class ResourceLoader {
private static void loadAbilityModifiers(Path path) { private static void loadAbilityModifiers(Path path) {
try { try {
JsonUtils.loadToList(path, AbilityConfigData.class).forEach(data -> loadAbilityData(data.Default)); JsonUtils.loadToList(path, AbilityConfigData.class)
.forEach(data -> loadAbilityData(data.Default));
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers from path " + path.toString() + ": ", e); Grasscutter.getLogger()
.error("Error loading ability modifiers from path " + path.toString() + ": ", e);
} }
} }
@ -310,16 +358,20 @@ public class ResourceLoader {
String name = data.abilityName; String name = data.abilityName;
AbilityModifierEntry modifierEntry = new AbilityModifierEntry(name); AbilityModifierEntry modifierEntry = new AbilityModifierEntry(name);
modifiers.forEach((key, modifier) -> { modifiers.forEach(
Stream.ofNullable(modifier.onAdded).flatMap(Stream::of) (key, modifier) -> {
Stream.ofNullable(modifier.onAdded)
.flatMap(Stream::of)
// .map(action -> {modifierActionTypes.add(action.$type); return action;}) // .map(action -> {modifierActionTypes.add(action.$type); return action;})
.filter(action -> action.type == AbilityModifierAction.Type.HealHP) .filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.forEach(action -> modifierEntry.getOnAdded().add(action)); .forEach(action -> modifierEntry.getOnAdded().add(action));
Stream.ofNullable(modifier.onThinkInterval).flatMap(Stream::of) Stream.ofNullable(modifier.onThinkInterval)
.flatMap(Stream::of)
// .map(action -> {modifierActionTypes.add(action.$type); return action;}) // .map(action -> {modifierActionTypes.add(action.$type); return action;})
.filter(action -> action.type == AbilityModifierAction.Type.HealHP) .filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.forEach(action -> modifierEntry.getOnThinkInterval().add(action)); .forEach(action -> modifierEntry.getOnThinkInterval().add(action));
Stream.ofNullable(modifier.onRemoved).flatMap(Stream::of) Stream.ofNullable(modifier.onRemoved)
.flatMap(Stream::of)
// .map(action -> {modifierActionTypes.add(action.$type); return action;}) // .map(action -> {modifierActionTypes.add(action.$type); return action;})
.filter(action -> action.type == AbilityModifierAction.Type.HealHP) .filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.forEach(action -> modifierEntry.getOnRemoved().add(action)); .forEach(action -> modifierEntry.getOnRemoved().add(action));
@ -349,7 +401,9 @@ public class ResourceLoader {
HashMap<GridBlockId, ArrayList<SpawnDataEntry>> areaSort = new HashMap<>(); HashMap<GridBlockId, ArrayList<SpawnDataEntry>> areaSort = new HashMap<>();
// key = sceneId,x,z , value = ArrayList<SpawnDataEntry> // key = sceneId,x,z , value = ArrayList<SpawnDataEntry>
for (SpawnGroupEntry entry : spawnEntryMap) { for (SpawnGroupEntry entry : spawnEntryMap) {
entry.getSpawns().forEach( entry
.getSpawns()
.forEach(
s -> { s -> {
s.setGroup(entry); s.setGroup(entry);
GridBlockId point = s.getBlockId(); GridBlockId point = s.getBlockId();
@ -357,8 +411,7 @@ public class ResourceLoader {
areaSort.put(point, new ArrayList<>()); areaSort.put(point, new ArrayList<>());
} }
areaSort.get(point).add(s); areaSort.get(point).add(s);
} });
);
} }
GameDepot.addSpawnListById(areaSort); GameDepot.addSpawnListById(areaSort);
} }
@ -378,7 +431,9 @@ public class ResourceLoader {
for (String folderName : folderNames) { for (String folderName : folderNames) {
try { try {
Files.newDirectoryStream(getResourcePath(folderName), "*.json").forEach(path -> { Files.newDirectoryStream(getResourcePath(folderName), "*.json")
.forEach(
path -> {
try { try {
JsonUtils.loadToMap(path, String.class, OpenConfigData[].class) JsonUtils.loadToMap(path, String.class, OpenConfigData[].class)
.forEach((name, data) -> map.put(name, new OpenConfigEntry(name, data))); .forEach((name, data) -> map.put(name, new OpenConfigEntry(name, data)));
@ -387,7 +442,8 @@ public class ResourceLoader {
} }
}); });
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Error loading open config: no files found in " + folderName); Grasscutter.getLogger()
.error("Error loading open config: no files found in " + folderName);
return; return;
} }
} }
@ -407,7 +463,9 @@ public class ResourceLoader {
private static void loadQuests() { private static void loadQuests() {
try { try {
Files.list(getResourcePath("BinOutput/Quest/")).forEach(path -> { Files.list(getResourcePath("BinOutput/Quest/"))
.forEach(
path -> {
try { try {
val mainQuest = JsonUtils.loadToClass(path, MainQuestData.class); val mainQuest = JsonUtils.loadToClass(path, MainQuestData.class);
GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest); GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest);
@ -424,11 +482,13 @@ public class ResourceLoader {
val questEncryptionMap = GameData.getMainQuestEncryptionMap(); val questEncryptionMap = GameData.getMainQuestEncryptionMap();
String path = "QuestEncryptionKeys.json"; String path = "QuestEncryptionKeys.json";
try { try {
JsonUtils.loadToList(getResourcePath(path), QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key)); JsonUtils.loadToList(getResourcePath(path), QuestEncryptionKey.class)
.forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key));
} catch (IOException | NullPointerException ignored) { } catch (IOException | NullPointerException ignored) {
} }
try { try {
DataLoader.loadList(path, QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key)); DataLoader.loadList(path, QuestEncryptionKey.class)
.forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key));
} catch (IOException | NullPointerException ignored) { } catch (IOException | NullPointerException ignored) {
} }
Grasscutter.getLogger().debug("Loaded {} quest keys.", questEncryptionMap.size()); Grasscutter.getLogger().debug("Loaded {} quest keys.", questEncryptionMap.size());
@ -436,19 +496,26 @@ public class ResourceLoader {
Grasscutter.getLogger().error("Unable to load quest keys.", e); Grasscutter.getLogger().error("Unable to load quest keys.", e);
} }
Grasscutter.getLogger().debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas."); Grasscutter.getLogger()
.debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas.");
} }
public static void loadScriptSceneData() { public static void loadScriptSceneData() {
try { try {
Files.list(getResourcePath("ScriptSceneData/")).forEach(path -> { Files.list(getResourcePath("ScriptSceneData/"))
.forEach(
path -> {
try { try {
GameData.getScriptSceneDataMap().put(path.getFileName().toString(), JsonUtils.loadToClass(path, ScriptSceneData.class)); GameData.getScriptSceneDataMap()
.put(
path.getFileName().toString(),
JsonUtils.loadToClass(path, ScriptSceneData.class));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
}); });
Grasscutter.getLogger().debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas."); Grasscutter.getLogger()
.debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas.");
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().debug("ScriptSceneData folder missing or empty."); Grasscutter.getLogger().debug("ScriptSceneData folder missing or empty.");
} }
@ -457,7 +524,10 @@ public class ResourceLoader {
private static void loadHomeworldDefaultSaveData() { private static void loadHomeworldDefaultSaveData() {
val pattern = Pattern.compile("scene([0-9]+)_home_config\\.json"); val pattern = Pattern.compile("scene([0-9]+)_home_config\\.json");
try { try {
Files.newDirectoryStream(getResourcePath("BinOutput/HomeworldDefaultSave"), "scene*_home_config.json").forEach(path -> { Files.newDirectoryStream(
getResourcePath("BinOutput/HomeworldDefaultSave"), "scene*_home_config.json")
.forEach(
path -> {
val matcher = pattern.matcher(path.getFileName().toString()); val matcher = pattern.matcher(path.getFileName().toString());
if (!matcher.find()) return; if (!matcher.find()) return;
@ -468,7 +538,11 @@ public class ResourceLoader {
} catch (Exception ignored) { } catch (Exception ignored) {
} }
}); });
Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas."); Grasscutter.getLogger()
.debug(
"Loaded "
+ GameData.getHomeworldDefaultSaveData().size()
+ " HomeworldDefaultSaveDatas.");
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Failed to load HomeworldDefaultSave folder."); Grasscutter.getLogger().error("Failed to load HomeworldDefaultSave folder.");
} }
@ -476,19 +550,24 @@ public class ResourceLoader {
private static void loadNpcBornData() { private static void loadNpcBornData() {
try { try {
Files.newDirectoryStream(getResourcePath("BinOutput/Scene/SceneNpcBorn/"), "*.json").forEach(path -> { Files.newDirectoryStream(getResourcePath("BinOutput/Scene/SceneNpcBorn/"), "*.json")
.forEach(
path -> {
try { try {
val data = JsonUtils.loadToClass(path, SceneNpcBornData.class); val data = JsonUtils.loadToClass(path, SceneNpcBornData.class);
if (data.getBornPosList() == null || data.getBornPosList().size() == 0) { if (data.getBornPosList() == null || data.getBornPosList().size() == 0) {
return; return;
} }
data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint())); data.setIndex(
SceneIndexManager.buildIndex(
3, data.getBornPosList(), item -> item.getPos().toPoint()));
GameData.getSceneNpcBornData().put(data.getSceneId(), data); GameData.getSceneNpcBornData().put(data.getSceneId(), data);
} catch (IOException ignored) { } catch (IOException ignored) {
} }
}); });
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas."); Grasscutter.getLogger()
.debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Failed to load SceneNpcBorn folder."); Grasscutter.getLogger().error("Failed to load SceneNpcBorn folder.");
} }
@ -496,15 +575,20 @@ public class ResourceLoader {
private static void loadGadgetConfigData() { private static void loadGadgetConfigData() {
try { try {
Files.newDirectoryStream(getResourcePath("BinOutput/Gadget/"), "*.json").forEach(path -> { Files.newDirectoryStream(getResourcePath("BinOutput/Gadget/"), "*.json")
.forEach(
path -> {
try { try {
GameData.getGadgetConfigData().putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class)); GameData.getGadgetConfigData()
.putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class));
} catch (Exception e) { } catch (Exception e) {
Grasscutter.getLogger().error("failed to load ConfigGadget entries for " + path.toString(), e); Grasscutter.getLogger()
.error("failed to load ConfigGadget entries for " + path.toString(), e);
} }
}); });
Grasscutter.getLogger().debug("Loaded {} ConfigGadget entries.", GameData.getGadgetConfigData().size()); Grasscutter.getLogger()
.debug("Loaded {} ConfigGadget entries.", GameData.getGadgetConfigData().size());
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Failed to load ConfigGadget folder."); Grasscutter.getLogger().error("Failed to load ConfigGadget folder.");
} }
@ -525,7 +609,9 @@ public class ResourceLoader {
} }
public static class AvatarConfig { public static class AvatarConfig {
@SerializedName(value = "abilities", alternate = {"targetAbilities"}) @SerializedName(
value = "abilities",
alternate = {"targetAbilities"})
public ArrayList<AvatarConfigAbility> abilities; public ArrayList<AvatarConfigAbility> abilities;
} }
@ -547,13 +633,19 @@ public class ResourceLoader {
public String $type; public String $type;
public String abilityName; public String abilityName;
@SerializedName(value = "talentIndex", alternate = {"OJOFFKLNAHN"}) @SerializedName(
value = "talentIndex",
alternate = {"OJOFFKLNAHN"})
public int talentIndex; public int talentIndex;
@SerializedName(value = "skillID", alternate = {"overtime"}) @SerializedName(
value = "skillID",
alternate = {"overtime"})
public int skillID; public int skillID;
@SerializedName(value = "pointDelta", alternate = {"IGEBKIHPOIF"}) @SerializedName(
value = "pointDelta",
alternate = {"IGEBKIHPOIF"})
public int pointDelta; public int pointDelta;
} }

View File

@ -8,9 +8,7 @@ import java.util.stream.Stream;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ResourceType { public @interface ResourceType {
/** /** Names of the file that this Resource loads from */
* Names of the file that this Resource loads from
*/
String[] name(); String[] name();
/** /**

View File

@ -4,9 +4,7 @@ public class AbilityEmbryoEntry {
private String name; private String name;
private String[] abilities; private String[] abilities;
public AbilityEmbryoEntry() { public AbilityEmbryoEntry() {}
}
public AbilityEmbryoEntry(String avatarName, String[] array) { public AbilityEmbryoEntry(String avatarName, String[] array) {
this.name = avatarName; this.name = avatarName;

View File

@ -2,93 +2,266 @@ package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.common.DynamicFloat; import emu.grasscutter.data.common.DynamicFloat;
import java.io.Serializable; import java.io.Serializable;
public class AbilityModifier implements Serializable { public class AbilityModifier implements Serializable {
private static final long serialVersionUID = -2001232313615923575L; private static final long serialVersionUID = -2001232313615923575L;
@SerializedName(value = "onAdded", alternate = {"KCICDEJLIJD"}) @SerializedName(
value = "onAdded",
alternate = {"KCICDEJLIJD"})
public AbilityModifierAction[] onAdded; public AbilityModifierAction[] onAdded;
@SerializedName(value = "onThinkInterval", alternate = {"PBDDACFFPOE"})
@SerializedName(
value = "onThinkInterval",
alternate = {"PBDDACFFPOE"})
public AbilityModifierAction[] onThinkInterval; public AbilityModifierAction[] onThinkInterval;
public AbilityModifierAction[] onRemoved; public AbilityModifierAction[] onRemoved;
public DynamicFloat duration = DynamicFloat.ZERO; public DynamicFloat duration = DynamicFloat.ZERO;
public static class AbilityModifierAction { public static class AbilityModifierAction {
@SerializedName("$type") @SerializedName("$type")
public Type type; public Type type;
public String target; public String target;
@SerializedName(value = "amount", alternate = "PDLLIFICICJ") @SerializedName(value = "amount", alternate = "PDLLIFICICJ")
public DynamicFloat amount = DynamicFloat.ZERO; public DynamicFloat amount = DynamicFloat.ZERO;
public DynamicFloat amountByCasterAttackRatio = DynamicFloat.ZERO; public DynamicFloat amountByCasterAttackRatio = DynamicFloat.ZERO;
public DynamicFloat amountByCasterCurrentHPRatio = DynamicFloat.ZERO; public DynamicFloat amountByCasterCurrentHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByCasterMaxHPRatio = DynamicFloat.ZERO; public DynamicFloat amountByCasterMaxHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByGetDamage = DynamicFloat.ZERO; public DynamicFloat amountByGetDamage = DynamicFloat.ZERO;
public DynamicFloat amountByTargetCurrentHPRatio = DynamicFloat.ZERO; public DynamicFloat amountByTargetCurrentHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByTargetMaxHPRatio = DynamicFloat.ZERO; public DynamicFloat amountByTargetMaxHPRatio = DynamicFloat.ZERO;
@SerializedName(value = "ignoreAbilityProperty", alternate = "HHFGADCJJDI") @SerializedName(value = "ignoreAbilityProperty", alternate = "HHFGADCJJDI")
public boolean ignoreAbilityProperty; public boolean ignoreAbilityProperty;
public String modifierName; public String modifierName;
public enum Type { public enum Type {
ActCameraRadialBlur, ActCameraShake, AddAvatarSkillInfo, AddChargeBarValue, ActCameraRadialBlur,
AddClimateMeter, AddElementDurability, AddGlobalValue, AddGlobalValueToTarget, ActCameraShake,
AddRegionalPlayVarValue, ApplyModifier, AttachAbilityStateResistance, AttachBulletAimPoint, AddAvatarSkillInfo,
AttachEffect, AttachEffectFirework, AttachElementTypeResistance, AttachModifier, AddChargeBarValue,
AttachUIEffect, AvatarCameraParam, AvatarEnterCameraShot, AvatarEnterFocus, AddClimateMeter,
AvatarEnterViewBias, AvatarExitCameraShot, AvatarExitClimb, AvatarExitFocus, AddElementDurability,
AvatarExitViewBias, AvatarShareCDSkillStart, AvatarSkillStart, BroadcastNeuronStimulate, AddGlobalValue,
CalcDvalinS04RebornPoint, CallLuaTask, ChangeEnviroWeather, ChangeFollowDampTime, AddGlobalValueToTarget,
ChangeGadgetUIInteractHint, ChangePlayMode, ChangeTag, ChangeUGCRayTag, AddRegionalPlayVarValue,
ClearEndura, ClearGlobalPos, ClearGlobalValue, ClearLocalGadgets, ApplyModifier,
ClearLockTarget, ClearPos, ConfigAbilityAction, ControlEmotion, AttachAbilityStateResistance,
CopyGlobalValue, CreateGadget, CreateMovingPlatform, CreateTile, AttachBulletAimPoint,
DamageByAttackValue, DebugLog, DestroyTile, DoBlink, AttachEffect,
DoTileAction, DoWatcherSystemAction, DoWidgetSystemAction, DropSubfield, AttachEffectFirework,
DummyAction, DungeonFogEffects, ElementAttachForActivityGacha, EnableAIStealthy, AttachElementTypeResistance,
EnableAfterImage, EnableAvatarFlyStateTrail, EnableAvatarMoveOnWater, EnableBulletCollisionPluginTrigger, AttachModifier,
EnableGadgetIntee, EnableHeadControl, EnableHitBoxByName, EnableMainInterface, AttachUIEffect,
EnablePartControl, EnablePositionSynchronization, EnablePushColliderName, EnableRocketJump, AvatarCameraParam,
EnableSceneTransformByName, EnterCameraLock, EntityDoSkill, EquipAffixStart, AvatarEnterCameraShot,
ExecuteGadgetLua, FireAISoundEvent, FireChargeBarEffect, FireEffect, AvatarEnterFocus,
FireEffectFirework, FireEffectForStorm, FireFishingEvent, FireHitEffect, AvatarEnterViewBias,
FireSubEmitterEffect, FireUIEffect, FixedMonsterRushMove, ForceAirStateFly, AvatarExitCameraShot,
ForceEnableShakeOffButton, GenerateElemBall, GetFightProperty, GetInteractIdToGlobalValue, AvatarExitClimb,
GetPos, HealHP, HideUIBillBoard, IgnoreMoveColToRockCol, AvatarExitFocus,
KillGadget, KillPlayEntity, KillSelf, KillServerGadget, AvatarExitViewBias,
LoseHP, ModifyAvatarSkillCD, ModifyVehicleSkillCD, PlayEmoSync, AvatarShareCDSkillStart,
Predicated, PushDvalinS01Process, PushInterActionByConfigPath, PushPos, AvatarSkillStart,
Randomed, ReTriggerAISkillInitialCD, RefreshUICombatBarLayout, RegisterAIActionPoint, BroadcastNeuronStimulate,
ReleaseAIActionPoint, RemoveAvatarSkillInfo, RemoveModifier, RemoveModifierByAbilityStateResistanceID, CalcDvalinS04RebornPoint,
RemoveServerBuff, RemoveUniqueModifier, RemoveVelocityForce, Repeated, CallLuaTask,
ResetAIAttackTarget, ResetAIResistTauntLevel, ResetAIThreatBroadcastRange, ResetAnimatorTrigger, ChangeEnviroWeather,
ReviveDeadAvatar, ReviveElemEnergy, ReviveStamina, SectorCityManeuver, ChangeFollowDampTime,
SendEffectTrigger, SendEffectTriggerToLineEffect, SendEvtElectricCoreMoveEnterP1, SendEvtElectricCoreMoveInterrupt, ChangeGadgetUIInteractHint,
ServerLuaCall, ServerLuaTriggerEvent, ServerMonsterLog, SetAIHitFeeling, ChangePlayMode,
SetAISkillCDAvailableNow, SetAISkillCDMultiplier, SetAISkillGCD, SetAnimatorBool, ChangeTag,
SetAnimatorFloat, SetAnimatorInt, SetAnimatorTrigger, SetAvatarCanShakeOff, ChangeUGCRayTag,
SetAvatarHitBuckets, SetCanDieImmediately, SetChargeBarValue, SetDvalinS01FlyState, ClearEndura,
SetEmissionScaler, SetEntityScale, SetExtraAbilityEnable, SetExtraAbilityState, ClearGlobalPos,
SetGlobalDir, SetGlobalPos, SetGlobalValue, SetGlobalValueByTargetDistance, ClearGlobalValue,
SetGlobalValueToOverrideMap, SetKeepInAirVelocityForce, SetMaterialParamFloatByTransform, SetNeuronEnable, ClearLocalGadgets,
SetOverrideMapValue, SetPartControlTarget, SetPoseBool, SetPoseFloat, ClearLockTarget,
SetPoseInt, SetRandomOverrideMapValue, SetRegionalPlayVarValue, SetSelfAttackTarget, ClearPos,
SetSkillAnchor, SetSpecialCamera, SetSurroundAnchor, SetSystemValueToOverrideMap, ConfigAbilityAction,
SetTargetNumToGlobalValue, SetUICombatBarAsh, SetUICombatBarSpark, SetVelocityIgnoreAirGY, ControlEmotion,
SetWeaponAttachPointRealName, SetWeaponBindState, ShowExtraAbility, ShowProgressBarAction, CopyGlobalValue,
ShowReminder, ShowScreenEffect, ShowTextMap, ShowUICombatBar, CreateGadget,
StartDither, SumTargetWeightToSelfGlobalValue, Summon, SyncToStageScript, CreateMovingPlatform,
TriggerAbility, TriggerAttackEvent, TriggerAttackTargetMapEvent, TriggerAudio, CreateTile,
TriggerAuxWeaponTrans, TriggerBullet, TriggerCreateGadgetToEquipPart, TriggerDropEquipParts, DamageByAttackValue,
TriggerFaceAnimation, TriggerGadgetInteractive, TriggerHideWeapon, TriggerSetCastShadow, DebugLog,
TriggerSetPassThrough, TriggerSetRenderersEnable, TriggerSetShadowRamp, TriggerSetVisible, DestroyTile,
TriggerTaunt, TriggerThrowEquipPart, TriggerUGCGadgetMove, TryFindBlinkPoint, DoBlink,
TryFindBlinkPointByBorn, TryTriggerPlatformStartMove, TurnDirection, TurnDirectionToPos, DoTileAction,
UpdateReactionDamage, UseSkillEliteSet, WidgetSkillStart DoWatcherSystemAction,
DoWidgetSystemAction,
DropSubfield,
DummyAction,
DungeonFogEffects,
ElementAttachForActivityGacha,
EnableAIStealthy,
EnableAfterImage,
EnableAvatarFlyStateTrail,
EnableAvatarMoveOnWater,
EnableBulletCollisionPluginTrigger,
EnableGadgetIntee,
EnableHeadControl,
EnableHitBoxByName,
EnableMainInterface,
EnablePartControl,
EnablePositionSynchronization,
EnablePushColliderName,
EnableRocketJump,
EnableSceneTransformByName,
EnterCameraLock,
EntityDoSkill,
EquipAffixStart,
ExecuteGadgetLua,
FireAISoundEvent,
FireChargeBarEffect,
FireEffect,
FireEffectFirework,
FireEffectForStorm,
FireFishingEvent,
FireHitEffect,
FireSubEmitterEffect,
FireUIEffect,
FixedMonsterRushMove,
ForceAirStateFly,
ForceEnableShakeOffButton,
GenerateElemBall,
GetFightProperty,
GetInteractIdToGlobalValue,
GetPos,
HealHP,
HideUIBillBoard,
IgnoreMoveColToRockCol,
KillGadget,
KillPlayEntity,
KillSelf,
KillServerGadget,
LoseHP,
ModifyAvatarSkillCD,
ModifyVehicleSkillCD,
PlayEmoSync,
Predicated,
PushDvalinS01Process,
PushInterActionByConfigPath,
PushPos,
Randomed,
ReTriggerAISkillInitialCD,
RefreshUICombatBarLayout,
RegisterAIActionPoint,
ReleaseAIActionPoint,
RemoveAvatarSkillInfo,
RemoveModifier,
RemoveModifierByAbilityStateResistanceID,
RemoveServerBuff,
RemoveUniqueModifier,
RemoveVelocityForce,
Repeated,
ResetAIAttackTarget,
ResetAIResistTauntLevel,
ResetAIThreatBroadcastRange,
ResetAnimatorTrigger,
ReviveDeadAvatar,
ReviveElemEnergy,
ReviveStamina,
SectorCityManeuver,
SendEffectTrigger,
SendEffectTriggerToLineEffect,
SendEvtElectricCoreMoveEnterP1,
SendEvtElectricCoreMoveInterrupt,
ServerLuaCall,
ServerLuaTriggerEvent,
ServerMonsterLog,
SetAIHitFeeling,
SetAISkillCDAvailableNow,
SetAISkillCDMultiplier,
SetAISkillGCD,
SetAnimatorBool,
SetAnimatorFloat,
SetAnimatorInt,
SetAnimatorTrigger,
SetAvatarCanShakeOff,
SetAvatarHitBuckets,
SetCanDieImmediately,
SetChargeBarValue,
SetDvalinS01FlyState,
SetEmissionScaler,
SetEntityScale,
SetExtraAbilityEnable,
SetExtraAbilityState,
SetGlobalDir,
SetGlobalPos,
SetGlobalValue,
SetGlobalValueByTargetDistance,
SetGlobalValueToOverrideMap,
SetKeepInAirVelocityForce,
SetMaterialParamFloatByTransform,
SetNeuronEnable,
SetOverrideMapValue,
SetPartControlTarget,
SetPoseBool,
SetPoseFloat,
SetPoseInt,
SetRandomOverrideMapValue,
SetRegionalPlayVarValue,
SetSelfAttackTarget,
SetSkillAnchor,
SetSpecialCamera,
SetSurroundAnchor,
SetSystemValueToOverrideMap,
SetTargetNumToGlobalValue,
SetUICombatBarAsh,
SetUICombatBarSpark,
SetVelocityIgnoreAirGY,
SetWeaponAttachPointRealName,
SetWeaponBindState,
ShowExtraAbility,
ShowProgressBarAction,
ShowReminder,
ShowScreenEffect,
ShowTextMap,
ShowUICombatBar,
StartDither,
SumTargetWeightToSelfGlobalValue,
Summon,
SyncToStageScript,
TriggerAbility,
TriggerAttackEvent,
TriggerAttackTargetMapEvent,
TriggerAudio,
TriggerAuxWeaponTrans,
TriggerBullet,
TriggerCreateGadgetToEquipPart,
TriggerDropEquipParts,
TriggerFaceAnimation,
TriggerGadgetInteractive,
TriggerHideWeapon,
TriggerSetCastShadow,
TriggerSetPassThrough,
TriggerSetRenderersEnable,
TriggerSetShadowRamp,
TriggerSetVisible,
TriggerTaunt,
TriggerThrowEquipPart,
TriggerUGCGadgetMove,
TryFindBlinkPoint,
TryFindBlinkPointByBorn,
TryTriggerPlatformStartMove,
TurnDirection,
TurnDirectionToPos,
UpdateReactionDamage,
UseSkillEliteSet,
WidgetSkillStart
} }
} }
//The following should be implemented into DynamicFloat if older resource formats need to be supported // The following should be implemented into DynamicFloat if older resource formats need to be
// supported
// public static class AbilityModifierValue { // public static class AbilityModifierValue {
// public boolean isFormula; // public boolean isFormula;
// public boolean isDynamic; // public boolean isDynamic;

View File

@ -1,7 +1,6 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -33,5 +32,4 @@ public class AbilityModifierEntry {
public List<AbilityModifierAction> getOnRemoved() { public List<AbilityModifierAction> getOnRemoved() {
return onRemoved; return onRemoved;
} }
} }

View File

@ -1,15 +1,13 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import javax.annotation.Nullable;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import javax.annotation.Nullable;
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class ConfigGadget { public class ConfigGadget {
// There are more values that can be added that might be useful in the json // There are more values that can be added that might be useful in the json
@Nullable @Nullable ConfigGadgetCombat combat;
ConfigGadgetCombat combat;
} }

View File

@ -2,29 +2,33 @@ package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.List;
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class HomeworldDefaultSaveData { public class HomeworldDefaultSaveData {
@SerializedName(value = "KFHBFNPDJBE", alternate = "PKACPHDGGEI") @SerializedName(value = "KFHBFNPDJBE", alternate = "PKACPHDGGEI")
List<HomeBlock> homeBlockLists; List<HomeBlock> homeBlockLists;
@SerializedName(value = "IJNPADKGNKE", alternate = "MINCKHBNING") @SerializedName(value = "IJNPADKGNKE", alternate = "MINCKHBNING")
Position bornPos; Position bornPos;
@SerializedName("IPIIGEMFLHK") @SerializedName("IPIIGEMFLHK")
Position bornRot; Position bornRot;
@SerializedName("HHOLBNPIHEM") @SerializedName("HHOLBNPIHEM")
Position djinPos; Position djinPos;
@SerializedName("KNHCJKHCOAN") @SerializedName("KNHCJKHCOAN")
HomeFurniture mainhouse; HomeFurniture mainhouse;
@SerializedName("NIHOJFEKFPG") @SerializedName("NIHOJFEKFPG")
List<HomeFurniture> doorLists; List<HomeFurniture> doorLists;
@SerializedName("EPGELGEFJFK") @SerializedName("EPGELGEFJFK")
List<HomeFurniture> stairLists; List<HomeFurniture> stairLists;
@ -48,6 +52,7 @@ public class HomeworldDefaultSaveData {
@SerializedName(value = "ENHNGKJBJAB", alternate = "KMAAJJHPNBA") @SerializedName(value = "ENHNGKJBJAB", alternate = "KMAAJJHPNBA")
int id; int id;
@SerializedName(value = "NGIEEIOLPPO", alternate = "JFKAHNCPDME") @SerializedName(value = "NGIEEIOLPPO", alternate = "JFKAHNCPDME")
Position pos; Position pos;
// @SerializedName(value = "HEOCEHKEBFM", alternate = "LKCKOOGFDBM") // @SerializedName(value = "HEOCEHKEBFM", alternate = "LKCKOOGFDBM")

View File

@ -2,10 +2,9 @@ package emu.grasscutter.data.binout;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import emu.grasscutter.game.quest.enums.QuestType; import emu.grasscutter.game.quest.enums.QuestType;
import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import lombok.Data;
public class MainQuestData { public class MainQuestData {
private int id; private int id;
@ -63,15 +62,13 @@ public class MainQuestData {
private int order; private int order;
} }
@Data @Data
@Entity @Entity
public static class TalkData { public static class TalkData {
private int id; private int id;
private String heroTalk; private String heroTalk;
public TalkData() { public TalkData() {}
}
public TalkData(int id, String heroTalk) { public TalkData(int id, String heroTalk) {
this.id = id; this.id = id;

View File

@ -1,7 +1,6 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import emu.grasscutter.data.ResourceLoader.OpenConfigData; import emu.grasscutter.data.ResourceLoader.OpenConfigData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -3,13 +3,12 @@ package emu.grasscutter.data.binout;
import com.github.davidmoten.rtreemulti.RTree; import com.github.davidmoten.rtreemulti.RTree;
import com.github.davidmoten.rtreemulti.geometry.Geometry; import com.github.davidmoten.rtreemulti.geometry.Geometry;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneGroup;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
@ -17,13 +16,9 @@ public class SceneNpcBornData {
int sceneId; int sceneId;
List<SceneNpcBornEntry> bornPosList; List<SceneNpcBornEntry> bornPosList;
/** /** Spatial Index For NPC */
* Spatial Index For NPC
*/
transient RTree<SceneNpcBornEntry, Geometry> index; transient RTree<SceneNpcBornEntry, Geometry> index;
/** /** npc groups */
* npc groups
*/
transient Map<Integer, SceneGroup> groups = new ConcurrentHashMap<>(); transient Map<Integer, SceneGroup> groups = new ConcurrentHashMap<>();
} }

View File

@ -2,30 +2,41 @@ package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.List;
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class SceneNpcBornEntry { public class SceneNpcBornEntry {
@SerializedName(value = "id", alternate = {"_id", "ID"}) @SerializedName(
value = "id",
alternate = {"_id", "ID"})
int id; int id;
@SerializedName(value = "configId", alternate = {"_configId"}) @SerializedName(
value = "configId",
alternate = {"_configId"})
int configId; int configId;
@SerializedName(value = "pos", alternate = {"_pos"}) @SerializedName(
value = "pos",
alternate = {"_pos"})
Position pos; Position pos;
@SerializedName(value = "rot", alternate = {"_rot"}) @SerializedName(
value = "rot",
alternate = {"_rot"})
Position rot; Position rot;
@SerializedName(value = "groupId", alternate = {"_groupId"}) @SerializedName(
value = "groupId",
alternate = {"_groupId"})
int groupId; int groupId;
@SerializedName(value = "suiteIdList", alternate = {"_suiteIdList"}) @SerializedName(
value = "suiteIdList",
alternate = {"_suiteIdList"})
List<Integer> suiteIdList; List<Integer> suiteIdList;
} }

View File

@ -4,10 +4,8 @@ import emu.grasscutter.data.common.PointData;
import lombok.Getter; import lombok.Getter;
public class ScenePointEntry { public class ScenePointEntry {
@Getter @Getter private final int sceneId;
final private int sceneId; @Getter private final PointData pointData;
@Getter
final private PointData pointData;
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
public ScenePointEntry(String name, PointData pointData) { public ScenePointEntry(String name, PointData pointData) {

View File

@ -1,10 +1,9 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.Data;
@Data @Data
public class ScriptSceneData { public class ScriptSceneData {
@ -15,7 +14,5 @@ public class ScriptSceneData {
// private SceneGroup groups; // private SceneGroup groups;
@SerializedName("dummy_points") @SerializedName("dummy_points")
private Map<String, List<Float>> dummyPoints; private Map<String, List<Float>> dummyPoints;
} }
} }

View File

@ -3,16 +3,16 @@ package emu.grasscutter.data.common;
import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.objects.Object2FloatArrayMap; import it.unimi.dsi.fastutil.objects.Object2FloatArrayMap;
import it.unimi.dsi.fastutil.objects.Object2FloatMap; import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import lombok.val;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import lombok.val;
public class DynamicFloat { public class DynamicFloat {
public static DynamicFloat ZERO = new DynamicFloat(0f); public static DynamicFloat ZERO = new DynamicFloat(0f);
private List<StackOp> ops; private List<StackOp> ops;
private boolean dynamic = false; private boolean dynamic = false;
private float constant = 0f; private float constant = 0f;
public DynamicFloat(float constant) { public DynamicFloat(float constant) {
this.constant = constant; this.constant = constant;
} }
@ -43,8 +43,7 @@ public class DynamicFloat {
} }
public float get(Object2FloatMap<String> props) { public float get(Object2FloatMap<String> props) {
if (!dynamic) if (!dynamic) return constant;
return constant;
val fl = new FloatArrayList(); val fl = new FloatArrayList();
for (var op : this.ops) { for (var op : this.ops) {
@ -52,8 +51,8 @@ public class DynamicFloat {
case CONSTANT -> fl.push(op.fValue); case CONSTANT -> fl.push(op.fValue);
case KEY -> fl.push(props.getOrDefault(op.sValue, 0f)); case KEY -> fl.push(props.getOrDefault(op.sValue, 0f));
case ADD -> fl.push(fl.popFloat() + fl.popFloat()); case ADD -> fl.push(fl.popFloat() + fl.popFloat());
case SUB -> case SUB -> fl.push(
fl.push(-fl.popFloat() + fl.popFloat()); // [f0, f1, f2] -> [f0, f1-f2] (opposite of RPN order) -fl.popFloat() + fl.popFloat()); // [f0, f1, f2] -> [f0, f1-f2] (opposite of RPN order)
case MUL -> fl.push(fl.popFloat() * fl.popFloat()); case MUL -> fl.push(fl.popFloat() * fl.popFloat());
case DIV -> fl.push((1f / fl.popFloat()) * fl.popFloat()); // [f0, f1, f2] -> [f0, f1/f2] case DIV -> fl.push((1f / fl.popFloat()) * fl.popFloat()); // [f0, f1, f2] -> [f0, f1/f2]
case NEXBOOLEAN -> fl.push(props.getOrDefault(Optional.of(op.bValue), 0f)); case NEXBOOLEAN -> fl.push(props.getOrDefault(Optional.of(op.bValue), 0f));
@ -69,6 +68,7 @@ public class DynamicFloat {
public float fValue; public float fValue;
public String sValue; public String sValue;
public boolean bValue; public boolean bValue;
public StackOp(String s) { public StackOp(String s) {
switch (s.toUpperCase()) { switch (s.toUpperCase()) {
case "ADD" -> this.op = Op.ADD; case "ADD" -> this.op = Op.ADD;
@ -92,6 +92,14 @@ public class DynamicFloat {
this.fValue = f; this.fValue = f;
} }
enum Op {CONSTANT, KEY, ADD, SUB, MUL, DIV, NEXBOOLEAN} enum Op {
CONSTANT,
KEY,
ADD,
SUB,
MUL,
DIV,
NEXBOOLEAN
}
} }
} }

View File

@ -4,14 +4,17 @@ import com.google.gson.annotations.SerializedName;
// Used in excels // Used in excels
public class ItemParamData { public class ItemParamData {
@SerializedName(value = "id", alternate = {"itemId"}) @SerializedName(
value = "id",
alternate = {"itemId"})
private int id; private int id;
@SerializedName(value = "count", alternate = {"itemCount"}) @SerializedName(
value = "count",
alternate = {"itemCount"})
private int count; private int count;
public ItemParamData() { public ItemParamData() {}
}
public ItemParamData(int id, int count) { public ItemParamData(int id, int count) {
this.id = id; this.id = id;

View File

@ -4,8 +4,7 @@ public class ItemParamStringData {
private int id; private int id;
private String count; private String count;
public ItemParamStringData() { public ItemParamStringData() {}
}
public int getId() { public int getId() {
return id; return id;

View File

@ -11,22 +11,25 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class PointData { public class PointData {
@Getter @Getter @Setter private int id;
@Setter
private int id;
private String $type; private String $type;
@Getter @Getter private Position tranPos;
private Position tranPos;
@SerializedName(value = "dungeonIds", alternate = {"JHHFPGJNMIN"}) @SerializedName(
value = "dungeonIds",
alternate = {"JHHFPGJNMIN"})
@Getter @Getter
private int[] dungeonIds; private int[] dungeonIds;
@SerializedName(value = "dungeonRandomList", alternate = {"OIBKFJNBLHO"}) @SerializedName(
value = "dungeonRandomList",
alternate = {"OIBKFJNBLHO"})
@Getter @Getter
private int[] dungeonRandomList; private int[] dungeonRandomList;
@SerializedName(value = "tranSceneId", alternate = {"JHBICGBAPIH"}) @SerializedName(
value = "tranSceneId",
alternate = {"JHBICGBAPIH"})
@Getter @Getter
@Setter @Setter
private int tranSceneId; private int tranSceneId;

View File

@ -11,5 +11,4 @@ public class PropGrowCurve {
public String getGrowCurve() { public String getGrowCurve() {
return this.growCurve; return this.growCurve;
} }
} }

View File

@ -4,13 +4,12 @@ import com.github.davidmoten.guavamini.Lists;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Getter;
@Getter @Getter
@ResourceType(name = "AchievementExcelConfigData.json") @ResourceType(name = "AchievementExcelConfigData.json")
@ -71,7 +70,9 @@ public class AchievementData extends GameResource {
} }
} }
map.values().stream().filter(a -> !a.hasGroupAchievements() && a.isUsed()).forEach(a -> a.isParent = true); map.values().stream()
.filter(a -> !a.hasGroupAchievements() && a.isUsed())
.forEach(a -> a.isParent = true);
} }
public boolean hasPreStageAchievement() { public boolean hasPreStageAchievement() {
@ -91,6 +92,8 @@ public class AchievementData extends GameResource {
} }
public Set<Integer> getExcludedGroupAchievementIdList() { public Set<Integer> getExcludedGroupAchievementIdList() {
return this.groupAchievementIdList.stream().filter(integer -> integer != this.getId()).collect(Collectors.toUnmodifiableSet()); return this.groupAchievementIdList.stream()
.filter(integer -> integer != this.getId())
.collect(Collectors.toUnmodifiableSet());
} }
} }

View File

@ -3,14 +3,15 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import java.util.List;
import java.util.Objects;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.List; @ResourceType(
import java.util.Objects; name = "NewActivityExcelConfigData.json",
loadPriority = ResourceType.LoadPriority.LOW)
@ResourceType(name = "NewActivityExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW)
@Getter @Getter
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class ActivityData extends GameResource { public class ActivityData extends GameResource {
@ -27,9 +28,10 @@ public class ActivityData extends GameResource {
@Override @Override
public void onLoad() { public void onLoad() {
this.watcherDataList = watcherId.stream().map(item -> GameData.getActivityWatcherDataMap().get(item.intValue())) this.watcherDataList =
watcherId.stream()
.map(item -> GameData.getActivityWatcherDataMap().get(item.intValue()))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
} }
} }

View File

@ -3,19 +3,14 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.shop.ShopType; import emu.grasscutter.game.shop.ShopType;
import lombok.Getter;
import java.util.List; import java.util.List;
import lombok.Getter;
@ResourceType(name = "ActivityShopOverallExcelConfigData.json") @ResourceType(name = "ActivityShopOverallExcelConfigData.json")
public class ActivityShopData extends GameResource { public class ActivityShopData extends GameResource {
@Getter @Getter private int scheduleId;
private int scheduleId; @Getter private ShopType shopType;
@Getter @Getter private List<Integer> sheetList;
private ShopType shopType;
@Getter
private List<Integer> sheetList;
@Override @Override
public int getId() { public int getId() {
@ -23,8 +18,7 @@ public class ActivityShopData extends GameResource {
} }
public int getShopTypeId() { public int getShopTypeId() {
if (this.shopType == null) if (this.shopType == null) this.shopType = ShopType.SHOP_TYPE_NONE;
this.shopType = ShopType.SHOP_TYPE_NONE;
return shopType.shopTypeId; return shopType.shopTypeId;
} }
} }

View File

@ -3,25 +3,28 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.props.WatcherTriggerType;
import java.util.List;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.List; @ResourceType(
name = "NewActivityWatcherConfigData.json",
@ResourceType(name = "NewActivityWatcherConfigData.json", loadPriority = ResourceType.LoadPriority.HIGH) loadPriority = ResourceType.LoadPriority.HIGH)
@Getter @Getter
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class ActivityWatcherData extends GameResource { public class ActivityWatcherData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
int id; int id;
int rewardID; int rewardID;
int progress; int progress;
WatcherTrigger triggerConfig; WatcherTrigger triggerConfig;
@Override @Override
public void onLoad() { public void onLoad() {
triggerConfig.paramList = triggerConfig.paramList.stream().filter(x -> (x != null) && !x.isBlank()).toList(); triggerConfig.paramList =
triggerConfig.paramList.stream().filter(x -> (x != null) && !x.isBlank()).toList();
triggerConfig.watcherTriggerType = WatcherTriggerType.getTypeByName(triggerConfig.triggerType); triggerConfig.watcherTriggerType = WatcherTriggerType.getTypeByName(triggerConfig.triggerType);
} }
@ -33,5 +36,4 @@ public class ActivityWatcherData extends GameResource {
transient WatcherTriggerType watcherTriggerType; transient WatcherTriggerType watcherTriggerType;
} }
} }

View File

@ -9,6 +9,7 @@ import emu.grasscutter.data.ResourceType;
public class AvatarCostumeData extends GameResource { public class AvatarCostumeData extends GameResource {
@SerializedName(value = "skinId", alternate = "costumeId") @SerializedName(value = "skinId", alternate = "costumeId")
private int skinId; private int skinId;
private int itemId; private int itemId;
private int characterId; private int characterId;
private int quality; private int quality;

View File

@ -3,7 +3,6 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.CurveInfo; import emu.grasscutter.data.common.CurveInfo;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -31,6 +30,7 @@ public class AvatarCurveData extends GameResource {
@Override @Override
public void onLoad() { public void onLoad() {
this.curveInfoMap = new HashMap<>(); this.curveInfoMap = new HashMap<>();
Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue())); Stream.of(this.curveInfos)
.forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue()));
} }
} }

View File

@ -18,7 +18,5 @@ public class AvatarFlycloakData extends GameResource {
} }
@Override @Override
public void onLoad() { public void onLoad() {}
}
} }

View File

@ -4,7 +4,6 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import java.util.ArrayList; import java.util.ArrayList;
@ResourceType(name = "AvatarPromoteExcelConfigData.json") @ResourceType(name = "AvatarPromoteExcelConfigData.json")

View File

@ -11,6 +11,7 @@ import lombok.Getter;
public class AvatarSkillData extends GameResource { public class AvatarSkillData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private float cdTime; private float cdTime;
private int costElemVal; private int costElemVal;
private int maxChargeNum; private int maxChargeNum;

View File

@ -11,17 +11,17 @@ import emu.grasscutter.game.props.ElementType;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
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.Getter;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import lombok.Getter;
@ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH) @ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH)
@Getter @Getter
public class AvatarSkillDepotData extends GameResource { public class AvatarSkillDepotData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int energySkill; private int energySkill;
private int attackModeSkill; private int attackModeSkill;
@ -61,7 +61,10 @@ public class AvatarSkillDepotData extends GameResource {
AvatarConfig config = GameDepot.getPlayerAbilities().get(getSkillDepotAbilityGroup()); AvatarConfig config = GameDepot.getPlayerAbilities().get(getSkillDepotAbilityGroup());
if (config != null) { if (config != null) {
this.setAbilities(new AbilityEmbryoEntry(getSkillDepotAbilityGroup(), config.abilities.stream().map(Object::toString).toArray(String[]::new))); this.setAbilities(
new AbilityEmbryoEntry(
getSkillDepotAbilityGroup(),
config.abilities.stream().map(Object::toString).toArray(String[]::new)));
} }
} }

View File

@ -4,7 +4,6 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import java.util.ArrayList; import java.util.ArrayList;
@ResourceType(name = "AvatarTalentExcelConfigData.json", loadPriority = LoadPriority.HIGHEST) @ResourceType(name = "AvatarTalentExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)

View File

@ -5,17 +5,17 @@ import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.BattlePassMissionRefreshType; import emu.grasscutter.game.props.BattlePassMissionRefreshType;
import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus; import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
import lombok.Getter;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Getter;
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"}) @ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
@Getter @Getter
public class BattlePassMissionData extends GameResource { public class BattlePassMissionData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int addPoint; private int addPoint;
private int scheduleId; private int scheduleId;
private int progress; private int progress;
@ -29,13 +29,16 @@ public class BattlePassMissionData extends GameResource {
} }
public boolean isCycleRefresh() { public boolean isCycleRefresh() {
return getRefreshType() == null || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE; return getRefreshType() == null
|| getRefreshType()
== BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE;
} }
public boolean isValidRefreshType() { public boolean isValidRefreshType() {
return getRefreshType() == null || return getRefreshType() == null
getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE || || getRefreshType()
getScheduleId() == 2701; == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE
|| getScheduleId() == 2701;
} }
@Override @Override
@ -43,13 +46,15 @@ public class BattlePassMissionData extends GameResource {
if (this.getTriggerConfig() != null) { if (this.getTriggerConfig() != null) {
var params = getTriggerConfig().getParamList()[0]; var params = getTriggerConfig().getParamList()[0];
if ((params != null) && !params.isEmpty()) { if ((params != null) && !params.isEmpty()) {
this.mainParams = Arrays.stream(params.split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet()); this.mainParams =
Arrays.stream(params.split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet());
} }
} }
} }
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() { public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder(); var protoBuilder =
emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
protoBuilder protoBuilder
.setMissionId(getId()) .setMissionId(getId())

View File

@ -2,9 +2,8 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter;
import java.util.List; import java.util.List;
import lombok.Getter;
@ResourceType(name = "BattlePassRewardExcelConfigData.json") @ResourceType(name = "BattlePassRewardExcelConfigData.json")
@Getter @Getter
@ -22,6 +21,5 @@ public class BattlePassRewardData extends GameResource {
} }
@Override @Override
public void onLoad() { public void onLoad() {}
}
} }

View File

@ -2,9 +2,8 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter;
import java.util.List; import java.util.List;
import lombok.Getter;
@ResourceType(name = "BlossomRefreshExcelConfigData.json") @ResourceType(name = "BlossomRefreshExcelConfigData.json")
@Getter @Getter
@ -19,7 +18,9 @@ public class BlossomRefreshExcelConfigData extends GameResource {
// Refresh details // Refresh details
private String refreshType; // Leyline blossoms, magical ore outcrops private String refreshType; // Leyline blossoms, magical ore outcrops
private int refreshCount; // Number of entries to spawn at refresh (1 for each leyline type for each city, 4 for magical ore for each city) private int
refreshCount; // Number of entries to spawn at refresh (1 for each leyline type for each city,
// 4 for magical ore for each city)
private String refreshTime; // Server time-of-day to refresh at private String refreshTime; // Server time-of-day to refresh at
private RefreshCond[] refreshCondVec; // AR requirements etc. private RefreshCond[] refreshCondVec; // AR requirements etc.

View File

@ -22,6 +22,7 @@ public class BuffData extends GameResource {
} }
public void onLoad() { public void onLoad() {
this.serverBuffType = this.serverBuffType != null ? this.serverBuffType : ServerBuffType.SERVER_BUFF_NONE; this.serverBuffType =
this.serverBuffType != null ? this.serverBuffType : ServerBuffType.SERVER_BUFF_NONE;
} }
} }

View File

@ -2,14 +2,13 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.HashMap;
import java.util.Map;
@ResourceType(name = "ChapterExcelConfigData.json") @ResourceType(name = "ChapterExcelConfigData.json")
@Getter @Getter
@Setter // TODO: remove on next API break @Setter // TODO: remove on next API break
@ -18,8 +17,10 @@ public class ChapterData extends GameResource {
// Why public? TODO: privatise next API break // Why public? TODO: privatise next API break
public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>(); public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>();
public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>(); public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>();
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
int id; int id;
int beginQuestId; int beginQuestId;
int endQuestId; int endQuestId;
int needPlayerLevel; int needPlayerLevel;

View File

@ -2,13 +2,12 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import java.util.List;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.List;
@ResourceType(name = "CityConfigData.json", loadPriority = ResourceType.LoadPriority.HIGH) @ResourceType(name = "CityConfigData.json", loadPriority = ResourceType.LoadPriority.HIGH)
@Getter @Getter
@Setter @Setter

View File

@ -10,10 +10,14 @@ import lombok.Getter;
public class CodexAnimalData extends GameResource { public class CodexAnimalData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int Id; private int Id;
private String type; private String type;
private int describeId; private int describeId;
private int sortOrder; private int sortOrder;
@SerializedName(value = "countType", alternate = {"OCCLHPBCDGL"})
@SerializedName(
value = "countType",
alternate = {"OCCLHPBCDGL"})
private CountType countType; private CountType countType;
public enum CountType { public enum CountType {

View File

@ -9,24 +9,15 @@ import lombok.Getter;
@ResourceType(name = {"ReliquaryCodexExcelConfigData.json"}) @ResourceType(name = {"ReliquaryCodexExcelConfigData.json"})
public class CodexReliquaryData extends GameResource { public class CodexReliquaryData extends GameResource {
@Getter @Getter private int Id;
private int Id; @Getter private int suitId;
@Getter @Getter private int level;
private int suitId; @Getter private int cupId;
@Getter @Getter private int leatherId;
private int level; @Getter private int capId;
@Getter @Getter private int flowerId;
private int cupId; @Getter private int sandId;
@Getter @Getter private int sortOrder;
private int leatherId;
@Getter
private int capId;
@Getter
private int flowerId;
@Getter
private int sandId;
@Getter
private int sortOrder;
private transient IntCollection ids; private transient IntCollection ids;
public boolean containsId(int id) { public boolean containsId(int id) {

View File

@ -3,7 +3,6 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -31,8 +30,10 @@ public class CombineData extends GameResource {
public void onLoad() { public void onLoad() {
super.onLoad(); super.onLoad();
// clean data // clean data
randomItems = randomItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList()); randomItems =
materialItems = materialItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList()); randomItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList());
materialItems =
materialItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList());
} }
public int getCombineId() { public int getCombineId() {
@ -78,5 +79,4 @@ public class CombineData extends GameResource {
public String getRecipeType() { public String getRecipeType() {
return recipeType; return recipeType;
} }
} }

View File

@ -3,15 +3,17 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import java.util.List;
import lombok.Getter; import lombok.Getter;
import java.util.List; @ResourceType(
name = {"CompoundExcelConfigData.json"},
@ResourceType(name = {"CompoundExcelConfigData.json"}, loadPriority = ResourceType.LoadPriority.LOW) loadPriority = ResourceType.LoadPriority.LOW)
@Getter @Getter
public class CompoundData extends GameResource { public class CompoundData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int groupID; private int groupID;
private int rankLevel; private int rankLevel;
private boolean isDefaultUnlocked; private boolean isDefaultUnlocked;

View File

@ -4,7 +4,9 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
@ResourceType(name = {"CookBonusExcelConfigData.json"}, loadPriority = LoadPriority.LOW) @ResourceType(
name = {"CookBonusExcelConfigData.json"},
loadPriority = LoadPriority.LOW)
public class CookBonusData extends GameResource { public class CookBonusData extends GameResource {
private int avatarId; private int avatarId;
private int recipeId; private int recipeId;
@ -37,6 +39,5 @@ public class CookBonusData extends GameResource {
} }
@Override @Override
public void onLoad() { public void onLoad() {}
}
} }

View File

@ -4,11 +4,12 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import java.util.List;
import lombok.Getter; import lombok.Getter;
import java.util.List; @ResourceType(
name = {"CookRecipeExcelConfigData.json"},
@ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW) loadPriority = LoadPriority.LOW)
@Getter @Getter
public class CookRecipeData extends GameResource { public class CookRecipeData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)

View File

@ -4,16 +4,17 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import java.util.Calendar; import java.util.Calendar;
import lombok.Getter;
@ResourceType(name = "DailyDungeonConfigData.json") @ResourceType(name = "DailyDungeonConfigData.json")
public class DailyDungeonData extends GameResource { public class DailyDungeonData extends GameResource {
private static final int[] empty = new int[0]; private static final int[] empty = new int[0];
private final Int2ObjectMap<int[]> map; private final Int2ObjectMap<int[]> map;
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int[] monday; private int[] monday;
private int[] tuesday; private int[] tuesday;
private int[] wednesday; private int[] wednesday;

View File

@ -9,19 +9,16 @@ import lombok.Getter;
public class DungeonData extends GameResource { public class DungeonData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
@Getter
private int sceneId; @Getter private int sceneId;
@Getter @Getter private int showLevel;
private int showLevel;
private int passRewardPreviewID; private int passRewardPreviewID;
private String involveType; // TODO enum private String involveType; // TODO enum
private RewardPreviewData previewData; private RewardPreviewData previewData;
@Getter @Getter private int statueCostID;
private int statueCostID; @Getter private int statueCostCount;
@Getter
private int statueCostCount;
public RewardPreviewData getRewardPreview() { public RewardPreviewData getRewardPreview() {
return previewData; return previewData;

View File

@ -11,6 +11,7 @@ import lombok.Setter;
public class DungeonEntryData extends GameResource { public class DungeonEntryData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int dungeonEntryId; private int dungeonEntryId;
private int sceneId; private int sceneId;
} }

View File

@ -3,10 +3,11 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import java.util.List; import java.util.List;
@ResourceType(name = "EnvAnimalGatherExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW) @ResourceType(
name = "EnvAnimalGatherExcelConfigData.json",
loadPriority = ResourceType.LoadPriority.LOW)
public class EnvAnimalGatherConfigData extends GameResource { public class EnvAnimalGatherConfigData extends GameResource {
private int animalId; private int animalId;
private String entityType; private String entityType;

View File

@ -3,7 +3,6 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import java.util.ArrayList; import java.util.ArrayList;
@ResourceType(name = "EquipAffixExcelConfigData.json") @ResourceType(name = "EquipAffixExcelConfigData.json")

View File

@ -19,6 +19,5 @@ public class FetterCharacterCardData extends GameResource {
} }
@Override @Override
public void onLoad() { public void onLoad() {}
}
} }

Some files were not shown because too many files have changed in this diff Show More