Run Spotless on src/main

This commit is contained in:
KingRainbow44
2023-03-31 22:30:45 -04:00
parent 99822b0e22
commit fc05602128
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.Utils;
import java.util.Arrays;
public final class GameConstants {
@@ -21,10 +20,16 @@ public final class GameConstants {
public static final int BATTLE_PASS_CURRENT_INDEX = 2;
// Default entity ability hashes.
public static final String[] DEFAULT_ABILITY_STRINGS = {
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
"Avatar_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener"
"Avatar_DefaultAbility_VisionReplaceDieInvincible",
"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 String VERSION = "3.5.0";
}

View File

@@ -1,5 +1,8 @@
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.Logger;
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.tools.Tools;
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.Setter;
import org.jline.reader.EndOfFileException;
@@ -35,21 +44,10 @@ import org.jline.terminal.TerminalBuilder;
import org.reflections.Reflections;
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 static final File configFile = new File("./config.json");
public static final Reflections reflector = new Reflections("emu.grasscutter");
@Getter private static final Logger logger =
(Logger) LoggerFactory.getLogger(Grasscutter.class);
@Getter private static final Logger logger = (Logger) LoggerFactory.getLogger(Grasscutter.class);
@Getter public static ConfigContainer config;
@@ -165,13 +163,10 @@ public final class Grasscutter {
Grasscutter.startConsole();
}
/**
* Server shutdown event.
*/
/** Server shutdown event. */
private static void onShutdown() {
// Disable all plugins.
if (pluginManager != null)
pluginManager.disablePlugins();
if (pluginManager != null) pluginManager.disablePlugins();
}
/*
@@ -187,9 +182,7 @@ public final class Grasscutter {
* 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() {
// Check if config.json exists. If not, we generate a new config.
if (!configFile.exists()) {
@@ -203,7 +196,9 @@ public final class Grasscutter {
try {
config = JsonUtils.loadToClass(configFile.toPath(), ConfigContainer.class);
} 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);
}
}
@@ -251,9 +246,7 @@ public final class Grasscutter {
}
}
consoleLineReader = LineReaderBuilder.builder()
.terminal(terminal)
.build();
consoleLineReader = LineReaderBuilder.builder().terminal(terminal).build();
}
return consoleLineReader;
@@ -314,10 +307,16 @@ public final class Grasscutter {
*/
public enum ServerRunMode {
HYBRID, DISPATCH_ONLY, GAME_ONLY
HYBRID,
DISPATCH_ONLY,
GAME_ONLY
}
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.server.http.objects.*;
import io.javalin.http.Context;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Builder;
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 {
/**
@@ -23,10 +19,7 @@ public interface AuthenticationSystem {
* @return An authentication request.
*/
static AuthenticationRequest fromPasswordRequest(Context ctx, LoginAccountRequestJson jsonData) {
return AuthenticationRequest.builder()
.context(ctx)
.passwordRequest(jsonData)
.build();
return AuthenticationRequest.builder().context(ctx).passwordRequest(jsonData).build();
}
/**
@@ -37,10 +30,7 @@ public interface AuthenticationSystem {
* @return An authentication request.
*/
static AuthenticationRequest fromTokenRequest(Context ctx, LoginTokenRequestJson jsonData) {
return AuthenticationRequest.builder()
.context(ctx)
.tokenRequest(jsonData)
.build();
return AuthenticationRequest.builder().context(ctx).tokenRequest(jsonData).build();
}
/**
@@ -50,8 +40,8 @@ public interface AuthenticationSystem {
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromComboTokenRequest(Context ctx, ComboTokenReqJson jsonData,
ComboTokenReqJson.LoginTokenData tokenData) {
static AuthenticationRequest fromComboTokenRequest(
Context ctx, ComboTokenReqJson jsonData, ComboTokenReqJson.LoginTokenData tokenData) {
return AuthenticationRequest.builder()
.context(ctx)
.sessionKeyRequest(jsonData)
@@ -88,7 +78,8 @@ public interface AuthenticationSystem {
* Called by plugins to internally verify a user's identity.
*
* @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);
@@ -127,22 +118,16 @@ public interface AuthenticationSystem {
*/
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
@AllArgsConstructor
@Getter
class AuthenticationRequest {
private final Context context;
@Nullable
private final LoginAccountRequestJson passwordRequest;
@Nullable
private final LoginTokenRequestJson tokenRequest;
@Nullable
private final ComboTokenReqJson sessionKeyRequest;
@Nullable
private final ComboTokenReqJson.LoginTokenData sessionKeyData;
@Nullable private final LoginAccountRequestJson passwordRequest;
@Nullable private final LoginTokenRequestJson tokenRequest;
@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.
*
* @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> {
/**
* 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.
*/
T authenticate(AuthenticationSystem.AuthenticationRequest request);

View File

@@ -1,22 +1,22 @@
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.auth.DefaultAuthenticators.*;
import emu.grasscutter.game.Account;
import emu.grasscutter.server.http.objects.ComboTokenResJson;
import emu.grasscutter.server.http.objects.LoginResultJson;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate;
/**
* The default Grasscutter authentication implementation.
* Allows all users to access any account.
* The default Grasscutter authentication implementation. Allows all users to access any account.
*/
public final class DefaultAuthentication implements AuthenticationSystem {
private final Authenticator<LoginResultJson> passwordAuthenticator;
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 OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
@@ -40,7 +40,8 @@ public final class DefaultAuthentication implements AuthenticationSystem {
@Override
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;
}

View File

@@ -1,5 +1,8 @@
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 emu.grasscutter.Grasscutter;
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.utils.FileUtils;
import emu.grasscutter.utils.Utils;
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.Cipher;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate;
/**
* A class containing default authenticators.
*/
/** A class containing default authenticators. */
public final class DefaultAuthenticators {
/**
* 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> {
@Override
public LoginResultJson authenticate(AuthenticationRequest request) {
@@ -52,16 +47,21 @@ public final class DefaultAuthenticators {
// Check if the account was created successfully.
if (account == null) {
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 {
// Continue with login.
successfulLogin = true;
// 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)
successfulLogin = true;
} else if (account != null) successfulLogin = true;
else
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);
}
// Set response data.
if (successfulLogin) {
response.message = "OK";
@@ -78,11 +77,11 @@ public final class DefaultAuthenticators {
response.data.account.token = account.generateSessionKey();
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 {
response.retcode = -201;
response.message = responseMessage;
}
Grasscutter.getLogger().info(loggerMessage);
@@ -114,7 +113,10 @@ public final class DefaultAuthenticators {
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) {
decryptedPassword = request.getPasswordRequest().password;
}
@@ -133,19 +135,26 @@ public final class DefaultAuthenticators {
// This account has been created AUTOMATICALLY. There will be no permissions added.
if (decryptedPassword.length() >= 8) {
account = DatabaseHelper.createAccountWithUid(requestData.account, 0);
account.setPassword(BCrypt.withDefaults().hashToString(12, decryptedPassword.toCharArray()));
account.setPassword(
BCrypt.withDefaults().hashToString(12, decryptedPassword.toCharArray()));
account.save();
// Check if the account was created successfully.
if (account == null) {
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 {
// Continue with login.
successfulLogin = true;
// 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 {
successfulLogin = false;
@@ -154,7 +163,9 @@ public final class DefaultAuthenticators {
}
} else if (account != null) {
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;
} else {
successfulLogin = false;
@@ -163,7 +174,8 @@ public final class DefaultAuthenticators {
}
} else {
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");
}
} else {
@@ -174,7 +186,6 @@ public final class DefaultAuthenticators {
loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address);
}
// Set response data.
if (successfulLogin) {
response.message = "OK";
@@ -182,11 +193,11 @@ public final class DefaultAuthenticators {
response.data.account.token = account.generateSessionKey();
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 {
response.retcode = -201;
response.message = responseMessage;
}
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> {
@Override
public LoginResultJson authenticate(AuthenticationRequest request) {
@@ -211,7 +220,8 @@ public final class DefaultAuthenticators {
int playerCount = Grasscutter.getGameServer().getPlayers().size();
// 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) {
@@ -229,7 +239,8 @@ public final class DefaultAuthenticators {
response.data.account.email = account.getEmail();
// 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 {
response.retcode = -201;
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> {
@Override
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 {
@Override
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
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
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 {
@Override
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
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
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;
/**
* Handles authentication via external routes.
*/
/** Handles authentication via external routes. */
public interface ExternalAuthenticator {
/**
@@ -18,9 +16,8 @@ public interface ExternalAuthenticator {
* Called when an external account creation request is made.
*
* @param request The authentication request.
* <p>
* For developers: Use AuthenticationRequest#getRequest() to get the request body.
* Use AuthenticationRequest#getResponse() to get the response body.
* <p>For developers: Use AuthenticationRequest#getRequest() to get the request body. Use
* AuthenticationRequest#getResponse() to get the response body.
*/
void handleAccountCreation(AuthenticationRequest request);
@@ -28,9 +25,8 @@ public interface ExternalAuthenticator {
* Called when an external password reset request is made.
*
* @param request The authentication request.
* <p>
* For developers: Use AuthenticationRequest#getRequest() to get the request body.
* Use AuthenticationRequest#getResponse() to get the response body.
* <p>For developers: Use AuthenticationRequest#getRequest() to get the request body. Use
* AuthenticationRequest#getResponse() to get the response body.
*/
void handlePasswordReset(AuthenticationRequest request);
}

View File

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

View File

@@ -1,14 +1,13 @@
package emu.grasscutter.command;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
import java.util.List;
import java.util.StringJoiner;
import static emu.grasscutter.utils.Language.translate;
public interface CommandHandler {
/**
@@ -42,23 +41,23 @@ public interface CommandHandler {
String usage_prefix = translate(player, "commands.execution.usage_prefix");
String command = annotation.label();
for (String alias : annotation.aliases()) {
if (alias.length() < command.length())
command = alias;
if (alias.length() < command.length()) command = alias;
}
if (player != null) {
command = "/" + command;
}
String target = switch (annotation.targetRequirement()) {
String target =
switch (annotation.targetRequirement()) {
case NONE -> "";
case OFFLINE -> "@<UID> "; // TODO: make translation keys for offline and online players
case ONLINE ->
(player == null) ? "@<UID> " : "[@<UID>] "; // TODO: make translation keys for offline and online players
case ONLINE -> (player == null)
? "@<UID> "
: "[@<UID>] "; // TODO: make translation keys for offline and online players
case PLAYER -> (player == null) ? "@<UID> " : "[@<UID>] ";
};
String[] usages = annotation.usage();
StringJoiner joiner = new StringJoiner("\n\t");
for (String usage : usages)
joiner.add(usage_prefix + command + " " + target + usage);
for (String usage : usages) joiner.add(usage_prefix + command + " " + target + usage);
return joiner.toString();
}
@@ -85,6 +84,5 @@ public interface CommandHandler {
* @param sender The player/console that invoked 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;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
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 amountRegex = Pattern.compile("((?<=(?<!\\w)x)\\d+|\\d+(?=x)(?!x\\d))");
public static final Pattern lvlRegex =
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 rankRegex = Pattern.compile("(\\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) {
Matcher match = pattern.matcher(arg);
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;
}
public static <T> List<String> parseIntParameters(List<String> args, @Nonnull T params, Map<Pattern, BiConsumer<T, Integer>> map) {
args.removeIf(arg -> {
public static <T> List<String> parseIntParameters(
List<String> args, @Nonnull T params, Map<Pattern, BiConsumer<T, Integer>> map) {
args.removeIf(
arg -> {
var argL = arg.toLowerCase();
boolean deleteArg = false;
for (var entry : map.entrySet()) {

View File

@@ -1,15 +1,14 @@
package emu.grasscutter.command;
import static emu.grasscutter.config.Configuration.SERVER;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.reflections.Reflections;
import java.util.*;
import static emu.grasscutter.config.Configuration.SERVER;
import org.reflections.Reflections;
@SuppressWarnings({"UnusedReturnValue", "unused"})
public final class CommandMap {
@@ -131,7 +130,8 @@ public final class CommandMap {
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.
for (int i = 0; i < args.size(); i++) {
String arg = args.get(i);
@@ -139,7 +139,8 @@ public final class CommandMap {
arg = args.remove(i).substring(1);
if (arg.equals("")) {
// 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;
}
int uid = getUidFromString(arg);
@@ -164,7 +165,8 @@ public final class CommandMap {
// Next priority: Use previously-set target. (see /target [[@]UID])
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
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
@@ -173,7 +175,8 @@ public final class CommandMap {
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;
}
@@ -199,7 +202,12 @@ public final class CommandMap {
targetPlayerIds.put(playerId, uid);
String target = uid + " (" + targetPlayer.getAccount().getUsername() + ")";
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;
}
@@ -213,7 +221,14 @@ public final class CommandMap {
// The console outputs in-game command. [{Account Username} (Player UID: {Player Uid})]
if (SERVER.logCommands) {
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 {
Grasscutter.getLogger().info("Command used by server console: " + rawMessage);
}
@@ -269,7 +284,12 @@ public final class CommandMap {
}
// 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;
}
@@ -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() {
Reflections reflector = Grasscutter.reflector;
Set<Class<?>> classes = reflector.getTypesAnnotatedWith(Command.class);
classes.forEach(annotated -> {
classes.forEach(
annotated -> {
try {
Command cmdData = annotated.getAnnotation(Command.class);
Object object = annotated.getDeclaredConstructor().newInstance();
if (object instanceof CommandHandler)
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) {
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
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) {
return true;
}

View File

@@ -5,5 +5,6 @@ import emu.grasscutter.game.player.Player;
public interface PermissionHandler {
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;
import static emu.grasscutter.utils.Language.translate;
import at.favre.lib.crypto.bcrypt.BCrypt;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
@@ -8,18 +10,16 @@ import emu.grasscutter.config.Configuration;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(
label = "account",
usage = {
"create <username> [<UID>]", // Only with EXPERIMENTAL_RealPassword == false
"delete <username>",
"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)
public final class AccountCommand implements CommandHandler {
@Override
@@ -47,7 +47,8 @@ public final class AccountCommand implements CommandHandler {
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
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]");
return;
}
@@ -59,8 +60,11 @@ public final class AccountCommand implements CommandHandler {
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid"));
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid");
CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]");
CommandHandler.sendMessage(
sender,
"EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid");
CommandHandler.sendMessage(
sender, "Usage: account create <username> <password> [uid]");
}
return;
}
@@ -87,7 +91,8 @@ public final class AccountCommand implements CommandHandler {
account.addPermission("*");
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;
case "delete":
@@ -104,7 +109,8 @@ public final class AccountCommand implements CommandHandler {
return;
case "resetpass":
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;
}

View File

@@ -7,14 +7,18 @@ import emu.grasscutter.data.excels.AchievementData;
import emu.grasscutter.game.achievement.AchievementControlReturns;
import emu.grasscutter.game.achievement.Achievements;
import emu.grasscutter.game.player.Player;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
@Command(
label = "achievement",
usage = {"(grant|revoke) <achievementId>", "progress <achievementId> <progress>", "grantall", "revokeall"},
usage = {
"(grant|revoke) <achievementId>",
"progress <achievementId> <progress>",
"grantall",
"revokeall"
},
aliases = {"am"},
permission = "player.achievement",
permissionTargeted = "player.achievement.others",
@@ -22,7 +26,8 @@ import java.util.concurrent.atomic.AtomicInteger;
threading = true)
public class AchievementCommand implements CommandHandler {
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) {
@@ -38,7 +43,8 @@ public class AchievementCommand implements CommandHandler {
GameData.getAchievementDataMap().values().stream()
.filter(AchievementData::isUsed)
.filter(AchievementData::isParent)
.forEach(data -> {
.forEach(
data -> {
var success = achievements.grant(data.getId());
if (success.getRet() == AchievementControlReturns.Return.SUCCESS) {
counter.addAndGet(success.getChangedAchievementStatusNum());
@@ -53,7 +59,8 @@ public class AchievementCommand implements CommandHandler {
GameData.getAchievementDataMap().values().stream()
.filter(AchievementData::isUsed)
.filter(AchievementData::isParent)
.forEach(data -> {
.forEach(
data -> {
var success = achievements.revoke(data.getId());
if (success.getRet() == AchievementControlReturns.Return.SUCCESS) {
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) {
this.sendUsageMessage(sender);
}
parseInt(args.remove(0)).ifPresentOrElse(integer -> {
parseInt(args.remove(0))
.ifPresentOrElse(
integer -> {
var ret = achievements.grant(integer);
switch (ret.getRet()) {
case SUCCESS -> sendSuccessMessage(sender, "grant", targetPlayer.getNickname());
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey());
case ALREADY_ACHIEVED ->
CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey(), targetPlayer.getNickname());
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(
sender, ret.getRet().getKey());
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) {
this.sendUsageMessage(sender);
}
parseInt(args.remove(0)).ifPresentOrElse(integer -> {
parseInt(args.remove(0))
.ifPresentOrElse(
integer -> {
var ret = achievements.revoke(integer);
switch (ret.getRet()) {
case SUCCESS -> sendSuccessMessage(sender, "revoke", targetPlayer.getNickname());
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey());
case NOT_YET_ACHIEVED ->
CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey(), targetPlayer.getNickname());
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(
sender, ret.getRet().getKey());
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) {
this.sendUsageMessage(sender);
}
parseInt(args.remove(0)).ifPresentOrElse(integer -> {
parseInt(args.remove(0)).ifPresentOrElse(progress -> {
parseInt(args.remove(0))
.ifPresentOrElse(
integer -> {
parseInt(args.remove(0))
.ifPresentOrElse(
progress -> {
var ret = achievements.progress(integer, progress);
switch (ret.getRet()) {
case SUCCESS ->
sendSuccessMessage(sender, "progress", targetPlayer.getNickname(), integer, progress);
case ACHIEVEMENT_NOT_FOUND -> CommandHandler.sendTranslatedMessage(sender, ret.getRet().getKey());
case SUCCESS -> sendSuccessMessage(
sender, "progress", targetPlayer.getNickname(), integer, progress);
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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketServerAnnounceNotify;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "announce",
@Command(
label = "announce",
usage = {"<content>", "refresh", "(tpl|revoke) <templateId>"},
permission = "server.announce",
aliases = {"a"},
@@ -37,17 +37,20 @@ public final class AnnounceCommand implements CommandHandler {
var templateId = Integer.parseInt(args.get(1));
var tpl = manager.getAnnounceConfigItemMap().get(templateId);
if (tpl == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.not_found", templateId));
CommandHandler.sendMessage(
sender, translate(sender, "commands.announce.not_found", templateId));
return;
}
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;
case "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;
case "revoke":
@@ -58,16 +61,18 @@ public final class AnnounceCommand implements CommandHandler {
var templateId1 = Integer.parseInt(args.get(1));
manager.revoke(templateId1);
CommandHandler.sendMessage(sender, translate(sender, "commands.announce.revoke_done", templateId1));
CommandHandler.sendMessage(
sender, translate(sender, "commands.announce.revoke_done", templateId1));
break;
default:
var id = new Random().nextInt(10000, 99999);
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));
}
}
}

View File

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

View File

@@ -1,20 +1,19 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.command.CommandHelpers.*;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.Inventory;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player;
import lombok.Setter;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import static emu.grasscutter.command.CommandHelpers.*;
import lombok.Setter;
@Command(
label = "clear",
@@ -23,13 +22,14 @@ import static emu.grasscutter.command.CommandHelpers.*;
permissionTargeted = "player.clearinv.others")
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(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()
.filter(item -> item.getItemType() == type)
.filter(item -> item.getItemData().getRankLevel() <= param.rank)
@@ -71,7 +71,8 @@ public final class ClearCommand implements CommandHandler {
CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString);
}
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);
}
case "all" -> {
@@ -79,13 +80,17 @@ public final class ClearCommand implements CommandHandler {
CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString);
playerInventory.removeItems(getWeapons(playerInventory, param).toList());
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);
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);
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);
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.everything", playerString);
}
@@ -93,11 +98,8 @@ public final class ClearCommand implements CommandHandler {
}
private static class ClearItemParameters {
@Setter
public int lvl = 1;
@Setter
public int refinement = 1;
@Setter
public int rank = 4;
@Setter public int lvl = 1;
@Setter 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.CommandHandler;
import emu.grasscutter.game.player.Player;
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 {
@Override
@@ -38,12 +41,17 @@ public final class CoopCommand implements CommandHandler {
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()) {
targetPlayer.getServer().getMultiplayerSystem().leaveCoop(targetPlayer);
}
host.getServer().getMultiplayerSystem().applyEnterMp(targetPlayer, host.getUid());
targetPlayer.getServer().getMultiplayerSystem().applyEnterMpReply(host, targetPlayer.getUid(), true);
CommandHandler.sendTranslatedMessage(sender, "commands.coop.success", targetPlayer.getNickname(), host.getNickname());
targetPlayer
.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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "enter_dungeon", aliases = {"enterdungeon", "dungeon"}, usage = {"<dungeonId>"}, permission = "player.enterdungeon", permissionTargeted = "player.enterdungeon.others")
@Command(
label = "enter_dungeon",
aliases = {"enterdungeon", "dungeon"},
usage = {"<dungeonId>"},
permission = "player.enterdungeon",
permissionTargeted = "player.enterdungeon.others")
public final class EnterDungeonCommand implements CommandHandler {
@Override
@@ -21,16 +25,23 @@ public final class EnterDungeonCommand implements CommandHandler {
try {
int dungeonId = Integer.parseInt(args.get(0));
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;
}
boolean result = targetPlayer.getServer().getDungeonSystem().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId);
boolean result =
targetPlayer
.getServer()
.getDungeonSystem()
.enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId);
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 {
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.changed", dungeonId));
CommandHandler.sendMessage(
sender, translate(sender, "commands.enter_dungeon.changed", dungeonId));
}
} catch (Exception e) {
sendUsageMessage(sender);

View File

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

View File

@@ -1,22 +1,26 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import java.util.ArrayList;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "help", usage = {"[<command>]"}, targetRequirement = Command.TargetRequirement.NONE)
@Command(
label = "help",
usage = {"[<command>]"},
targetRequirement = Command.TargetRequirement.NONE)
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) {
StringBuilder builder = new StringBuilder(command.getLabel())
StringBuilder builder =
new StringBuilder(command.getLabel())
.append(" - ")
.append(command.getDescriptionString(player))
.append("\n\t")
@@ -39,7 +43,9 @@ public final class HelpCommand implements CommandHandler {
if (!annotation.permissionTargeted().isEmpty()) {
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();
}
@@ -51,7 +57,10 @@ public final class HelpCommand implements CommandHandler {
List<String> commands = new ArrayList<>();
List<String> commands_no_permission = new ArrayList<>();
if (args.isEmpty()) {
commandMap.getHandlers().forEach((key, command) -> {
commandMap
.getHandlers()
.forEach(
(key, command) -> {
Command annotation = command.getClass().getAnnotation(Command.class);
if (player == null || account.hasPermission(annotation.permission())) {
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.CommandHandler;
import emu.grasscutter.game.player.Player;
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 {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender != null) {
CommandHandler.sendTranslatedMessage(sender, "commands.kick.player_kick_player",
sender.getUid(), sender.getAccount().getUsername(),
targetPlayer.getUid(), targetPlayer.getAccount().getUsername());
CommandHandler.sendTranslatedMessage(
sender,
"commands.kick.player_kick_player",
sender.getUid(),
sender.getAccount().getUsername(),
targetPlayer.getUid(),
targetPlayer.getAccount().getUsername());
} else {
CommandHandler.sendTranslatedMessage(sender, "commands.kick.server_kick_player",
targetPlayer.getUid(), targetPlayer.getAccount().getUsername());
CommandHandler.sendTranslatedMessage(
sender,
"commands.kick.server_kick_player",
targetPlayer.getUid(),
targetPlayer.getAccount().getUsername());
}
targetPlayer.getSession().close();

View File

@@ -1,17 +1,20 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Scene;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "killall", usage = {"[<sceneId>]"}, permission = "server.killall", permissionTargeted = "server.killall.others")
@Command(
label = "killall",
usage = {"[<sceneId>]"},
permission = "server.killall",
permissionTargeted = "server.killall.others")
public final class KillAllCommand implements CommandHandler {
@Override
@@ -32,16 +35,20 @@ public final class KillAllCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
}
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;
}
// Separate into list to avoid concurrency issue
final Scene sceneF = scene;
List<GameEntity> toKill = sceneF.getEntities().values().stream()
List<GameEntity> toKill =
sceneF.getEntities().values().stream()
.filter(entity -> entity instanceof EntityMonster)
.toList();
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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
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.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "killCharacter", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others")
@Command(
label = "killCharacter",
aliases = {"suicide", "kill"},
permission = "player.killcharacter",
permissionTargeted = "player.killcharacter.others")
public final class KillCharacterCommand implements CommandHandler {
@Override
@@ -21,12 +24,18 @@ public final class KillCharacterCommand implements CommandHandler {
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
// Packets
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
entity
.getWorld()
.broadcastPacket(
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
entity
.getWorld()
.broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
// remove
targetPlayer.getScene().removeEntity(entity);
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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Utils;
import java.util.List;
import java.util.Locale;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "language", usage = {"[<language code>]"}, aliases = {"lang"}, targetRequirement = Command.TargetRequirement.NONE)
@Command(
label = "language",
usage = {"[<language code>]"},
aliases = {"lang"},
targetRequirement = Command.TargetRequirement.NONE)
public final class LanguageCommand implements CommandHandler {
@Override
@@ -23,7 +26,8 @@ public final class LanguageCommand implements CommandHandler {
} else {
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;
}
@@ -44,10 +48,11 @@ public final class LanguageCommand implements CommandHandler {
}
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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import java.util.Map;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "list", aliases = {"players"}, usage = {"[<UID>]"}, targetRequirement = Command.TargetRequirement.NONE)
@Command(
label = "list",
aliases = {"players"},
usage = {"[<UID>]"},
targetRequirement = Command.TargetRequirement.NONE)
public final class ListCommand implements CommandHandler {
@Override
@@ -22,24 +25,24 @@ public final class ListCommand implements CommandHandler {
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) {
StringBuilder playerSet = new StringBuilder();
boolean finalNeedUID = needUID;
playersMap.values().forEach(player -> {
playersMap
.values()
.forEach(
player -> {
playerSet.append(player.getNickname());
if (finalNeedUID) {
if (sender != null) {
playerSet.append(" <color=green>(")
.append(player.getUid())
.append(")</color>");
playerSet.append(" <color=green>(").append(player.getUid()).append(")</color>");
} else {
playerSet.append(" (")
.append(player.getUid())
.append(")");
playerSet.append(" (").append(player.getUid()).append(")");
}
}

View File

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

View File

@@ -4,17 +4,26 @@ import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Position;
import java.util.List;
@Command(label = "position", aliases = {"pos"})
@Command(
label = "position",
aliases = {"pos"})
public final class PositionCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
Position pos = targetPlayer.getPosition();
Position rot = targetPlayer.getRotation();
CommandHandler.sendTranslatedMessage(sender, "commands.position.success",
pos.getX(), pos.getY(), pos.getZ(), rot.getX(), rot.getY(), rot.getZ(), targetPlayer.getSceneId());
CommandHandler.sendTranslatedMessage(
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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameQuest;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "quest",
@Command(
label = "quest",
aliases = {"q"},
usage = {"(add|finish) [<questId>]"},
permission = "player.quest",

View File

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

View File

@@ -1,15 +1,14 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(
label = "resetConst",
aliases = {"resetconstellation"},
@@ -32,7 +31,9 @@ public final class ResetConstCommand implements CommandHandler {
Avatar avatar = entity.getAvatar();
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;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "resetShopLimit", aliases = {"resetshop"}, permission = "server.resetshop", permissionTargeted = "server.resetshop.others")
@Command(
label = "resetShopLimit",
aliases = {"resetshop"},
permission = "server.resetshop",
permissionTargeted = "server.resetshop.others")
public final class ResetShopLimitCommand implements CommandHandler {
@Override

View File

@@ -1,18 +1,17 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings("ConstantConditions")
@Command(
label = "sendMail",
@@ -21,12 +20,15 @@ import static emu.grasscutter.utils.Language.translate;
targetRequirement = Command.TargetRequirement.NONE)
public final class SendMailCommand implements CommandHandler {
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish
// However, due to the current nature of the command system, I don't think this is possible without rewriting
// TODO: You should be able to do /sendmail and then just send subsequent messages until you
// 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
// 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.
@Override
@@ -52,16 +54,20 @@ public final class SendMailCommand implements CommandHandler {
if (DatabaseHelper.getPlayerByUid(Integer.parseInt(args.get(0))) != null) {
mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail());
} 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;
}
}
}
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"));
default -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments"));
case 2 -> CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.templates"));
default -> CommandHandler.sendMessage(
sender, translate(sender, "commands.sendMail.invalid_arguments"));
}
} else {
MailBuilder mailBuilder = mailBeingConstructed.get(senderId);
@@ -75,41 +81,63 @@ public final class SendMailCommand implements CommandHandler {
case "finish" -> {
if (mailBuilder.constructionStage == 3) {
if (!mailBuilder.sendToAll) {
Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail);
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", mailBuilder.recipient));
Grasscutter.getGameServer()
.getPlayerByUid(mailBuilder.recipient, true)
.sendMail(mailBuilder.mail);
CommandHandler.sendMessage(
sender,
translate(sender, "commands.sendMail.send_done", mailBuilder.recipient));
} else {
DatabaseHelper.getByGameClass(Player.class).forEach(player -> {
var onlinePlayer = Grasscutter.getGameServer().getPlayerByUid(player.getUid(), false);
Objects.requireNonNullElse(onlinePlayer, player).sendMail(mailBuilder.mail);
DatabaseHelper.getByGameClass(Player.class)
.forEach(
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);
} 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" -> {
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 -> {
switch (mailBuilder.constructionStage) {
case 0 -> {
String title = String.join(" ", args.subList(0, args.size()));
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++;
}
case 1 -> {
String contents = String.join(" ", args.subList(0, args.size()));
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++;
}
case 2 -> {
String msgSender = String.join(" ", args.subList(0, args.size()));
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++;
}
case 3 -> {
@@ -118,25 +146,29 @@ public final class SendMailCommand implements CommandHandler {
int amount = 1;
int refinement = 0;
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 {
refinement = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.itemRefinement"));
return;
} // Fallthrough
case 3: // <itemId|itemName> [amount] [level]
try {
lvl = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.itemLevel"));
return;
} // Fallthrough
case 2: // <itemId|itemName> [amount]
try {
amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.amount"));
return;
} // Fallthrough
case 1: // <itemId|itemName>
@@ -144,7 +176,8 @@ public final class SendMailCommand implements CommandHandler {
item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
// 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;
}
break;
@@ -153,13 +186,19 @@ public final class SendMailCommand implements CommandHandler {
return;
}
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 {
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.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
@Command(

View File

@@ -9,7 +9,6 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.utils.Position;
import java.util.List;
@Command(
@@ -38,10 +37,12 @@ public final class SetConstCommand implements CommandHandler {
if (entity == null) return;
Avatar avatar = entity.getAvatar();
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;
}
// 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")) {
this.setAllConstellation(targetPlayer, 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) {
player.getAvatars().forEach(avatar -> {
player
.getAvatars()
.forEach(
avatar -> {
avatar.forceConstellationLevel(constLevel);
avatar.recalcConstellations();
avatar.recalcStats(true);

View File

@@ -1,16 +1,15 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(
label = "setFetterLevel",
usage = {"<level>"},
@@ -29,7 +28,8 @@ public final class SetFetterLevelCommand implements CommandHandler {
try {
int fetterLevel = Integer.parseInt(args.get(0));
if (fetterLevel < 0 || fetterLevel > 10) {
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.range_error"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.setFetterLevel.range_error"));
return;
}
Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
@@ -41,10 +41,10 @@ public final class SetFetterLevelCommand implements CommandHandler {
avatar.save();
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) {
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.PacketSceneAreaUnlockNotify;
import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
import java.util.HashMap;
import java.util.List;
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 {
// List of map areas. Unfortunately, there is no readily available source for them in excels or 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);
// List of map areas. Unfortunately, there is no readily available source for them in excels or
// 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;
public SetPropCommand() {
@@ -29,7 +37,8 @@ public final class SetPropCommand implements CommandHandler {
this.props.put(key, new Prop(name, prop));
}
// 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("wl", worldlevel);
@@ -89,7 +98,8 @@ public final class SetPropCommand implements CommandHandler {
return;
}
try {
value = switch (valueStr.toLowerCase()) {
value =
switch (valueStr.toLowerCase()) {
case "on", "true" -> 1;
case "off", "false" -> 0;
case "toggle" -> -1;
@@ -103,12 +113,13 @@ public final class SetPropCommand implements CommandHandler {
boolean success = false;
Prop prop = props.get(propStr);
success = switch (prop.pseudoProp) {
success =
switch (prop.pseudoProp) {
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY ->
this.setBool(sender, targetPlayer, prop.pseudoProp, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool(
sender, targetPlayer, prop.pseudoProp, value);
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
case UNLOCK_MAP -> unlockMap(targetPlayer);
@@ -117,16 +128,20 @@ public final class SetPropCommand implements CommandHandler {
if (success) {
if (targetPlayer == sender) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", prop.name, valueStr);
CommandHandler.sendTranslatedMessage(
sender, "commands.generic.set_to", prop.name, valueStr);
} else {
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 {
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 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) {
List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors();
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;
}
@@ -151,19 +167,26 @@ public final class SetPropCommand implements CommandHandler {
}
// Six stars required on Floor 8 to unlock Floor 9+
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;
}
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 UNLIMITED_STAMINA -> targetPlayer.getUnlimitedStamina();
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage();
default -> false;
};
enabled = switch (value) {
enabled =
switch (value) {
case -1 -> !enabled;
case 0 -> false;
default -> true;
@@ -192,7 +215,9 @@ public final class SetPropCommand implements CommandHandler {
private boolean unlockMap(Player targetPlayer) {
// Unlock.
GameData.getScenePointsPerScene().forEach((sceneId, scenePoints) -> {
GameData.getScenePointsPerScene()
.forEach(
(sceneId, scenePoints) -> {
// Unlock trans points.
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints);
@@ -202,8 +227,12 @@ public final class SetPropCommand implements CommandHandler {
// Send notify.
int playerScene = targetPlayer.getSceneId();
targetPlayer.sendPacket(new PacketScenePointUnlockNotify(playerScene, targetPlayer.getUnlockedScenePoints(playerScene)));
targetPlayer.sendPacket(new PacketSceneAreaUnlockNotify(playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
targetPlayer.sendPacket(
new PacketScenePointUnlockNotify(
playerScene, targetPlayer.getUnlockedScenePoints(playerScene)));
targetPlayer.sendPacket(
new PacketSceneAreaUnlockNotify(
playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
return true;
}

View File

@@ -7,7 +7,6 @@ import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -18,7 +17,8 @@ import java.util.Map;
usage = {
"[set] <stat> <value>",
"(lock|freeze) <stat> [<value>]", // Can lock to current value
"(unlock|unfreeze) <stat>"},
"(unlock|unfreeze) <stat>"
},
permission = "player.setstats",
permissionTargeted = "player.setstats.others")
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("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("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("ecryo", this.stats.get("cryo%"));
this.stats.put("edendro", this.stats.get("dendro%"));
@@ -78,7 +82,8 @@ public final class SetStatsCommand implements CommandHandler {
// Get the action and stat
String arg0 = args.remove(0).toLowerCase();
Action action = switch (arg0) {
Action action =
switch (arg0) {
default -> {
statStr = arg0;
yield Action.ACTION_SET;
@@ -150,7 +155,8 @@ public final class SetStatsCommand implements CommandHandler {
CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr);
} else {
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;
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.CommandHandler;
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.world.Scene;
import emu.grasscutter.utils.Position;
import lombok.Setter;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import static emu.grasscutter.command.CommandHelpers.*;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import static emu.grasscutter.utils.Language.translate;
import lombok.Setter;
@Command(
label = "spawn",
@@ -29,11 +28,13 @@ import static emu.grasscutter.utils.Language.translate;
usage = {
"<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>",
"<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",
permissionTargeted = "server.spawn.others")
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(amountRegex, SpawnParameters::setAmount),
Map.entry(stateRegex, SpawnParameters::setState),
@@ -44,8 +45,7 @@ public final class SpawnCommand implements CommandHandler {
Map.entry(hpRegex, SpawnParameters::setHp),
Map.entry(defRegex, SpawnParameters::setDef),
Map.entry(atkRegex, SpawnParameters::setAtk),
Map.entry(aiRegex, SpawnParameters::setAi)
);
Map.entry(aiRegex, SpawnParameters::setAi));
@Override
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));
param.pos = new Position(x, y, z);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough
case 1:
try {
param.id = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.generic.invalid.entityId"));
}
break;
default:
@@ -92,8 +94,13 @@ public final class SpawnCommand implements CommandHandler {
param.scene = targetPlayer.getScene();
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);
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.limit_reached", param.amount));
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) {
return;
}
@@ -121,14 +128,16 @@ public final class SpawnCommand implements CommandHandler {
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) {
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);
if (param.ai != -1) {
entity.setAiId(param.ai);
@@ -136,10 +145,13 @@ public final class SpawnCommand implements CommandHandler {
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;
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 {
entity = new EntityGadget(param.scene, param.id, pos, targetPlayer.getRotation());
if (param.state != -1) {
@@ -165,7 +177,8 @@ public final class SpawnCommand implements CommandHandler {
entity.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, param.maxHP);
}
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) {
entity.setFightProperty(FightProperty.FIGHT_PROP_ATTACK, param.atk);
@@ -186,32 +199,19 @@ public final class SpawnCommand implements CommandHandler {
}
private static class SpawnParameters {
@Setter
public int id;
@Setter
public int lvl = 1;
@Setter
public int amount = 1;
@Setter
public int blockId = -1;
@Setter
public int groupId = -1;
@Setter
public int configId = -1;
@Setter
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;
@Setter public int id;
@Setter public int lvl = 1;
@Setter public int amount = 1;
@Setter public int blockId = -1;
@Setter public int groupId = -1;
@Setter public int configId = -1;
@Setter 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;
}
}

View File

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

View File

@@ -7,7 +7,6 @@ import emu.grasscutter.data.excels.AvatarSkillDepotData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Language;
import java.util.List;
@Command(
@@ -20,7 +19,8 @@ public final class TalentCommand implements CommandHandler {
if (avatar.setSkillLevel(skillId, newLevel)) {
long nameHash = GameData.getAvatarSkillDataMap().get(skillId).getNameTextMapHash();
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 {
CommandHandler.sendTranslatedMessage(sender, "commands.talent.out_of_range");
}
@@ -35,7 +35,9 @@ public final class TalentCommand implements CommandHandler {
Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
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");
return;
}
@@ -79,7 +81,8 @@ public final class TalentCommand implements CommandHandler {
return;
}
skillId = switch (cmdSwitch) {
skillId =
switch (cmdSwitch) {
default -> skillDepot.getSkills().get(0);
case "e" -> skillDepot.getSkills().get(1);
case "q" -> skillDepot.getEnergySkill();
@@ -103,16 +106,22 @@ public final class TalentCommand implements CommandHandler {
return;
}
int finalNewLevel = newLevel;
skillDepot.getSkillsAndEnergySkill().forEach(id -> setTalentLevel(sender, avatar, id, finalNewLevel));
skillDepot
.getSkillsAndEnergySkill()
.forEach(id -> setTalentLevel(sender, avatar, id, finalNewLevel));
}
case "getid" -> {
var map = GameData.getAvatarSkillDataMap();
skillDepot.getSkillsAndEnergySkill().forEach(id -> {
skillDepot
.getSkillsAndEnergySkill()
.forEach(
id -> {
var talent = map.get(id);
if (talent == null) return;
var talentName = Language.getTextMapKey(talent.getNameTextMapHash());
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;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
@Command(
label = "team",
usage = {"add <avatarId,...>", "(remove|set) [index|first|last|index-index,...]"},
@@ -45,8 +44,11 @@ public final class TeamCommand implements CommandHandler {
return;
}
targetPlayer.getTeamManager().updateTeamEntities(
new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo()));
targetPlayer
.getTeamManager()
.updateTeamEntities(
new PacketChangeMpTeamAvatarRsp(
targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo()));
}
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();
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;
}
for (var avatarId : avatarIds) {
int id = Integer.parseInt(avatarId);
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;
}
return true;
@@ -101,7 +105,8 @@ public final class TeamCommand implements CommandHandler {
// step 1: parse metaIndex to indexes
var subIndexes = transformToIndexes(metaIndex, avatarCount);
if (subIndexes == null) {
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", metaIndex);
CommandHandler.sendTranslatedMessage(
sender, "commands.team.failed_to_parse_index", metaIndex);
continue;
}
@@ -146,7 +151,8 @@ public final class TeamCommand implements CommandHandler {
index = Integer.parseInt(args.get(1)) - 1;
if (index < 0) index = 0;
} 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;
}
@@ -159,7 +165,8 @@ public final class TeamCommand implements CommandHandler {
try {
avatarId = Integer.parseInt(args.get(2));
} 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;
}
if (avatarId < BASE_AVATARID) {
@@ -167,7 +174,8 @@ public final class TeamCommand implements CommandHandler {
}
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;
}
@@ -186,7 +194,8 @@ public final class TeamCommand implements CommandHandler {
}
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
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;
}
if (!targetPlayer.getAvatars().hasAvatar(avatarId)) {
@@ -218,13 +227,15 @@ public final class TeamCommand implements CommandHandler {
int min, max;
try {
min = switch (range[0]) {
min =
switch (range[0]) {
case "first" -> 1;
case "last" -> listLength;
default -> Integer.parseInt(range[0]);
};
max = switch (range[1]) {
max =
switch (range[1]) {
case "first" -> 1;
case "last" -> listLength;
default -> Integer.parseInt(range[1]);
@@ -254,5 +265,4 @@ public final class TeamCommand implements CommandHandler {
return null;
}
}
}

View File

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

View File

@@ -1,19 +1,24 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.utils.Position;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "teleport", aliases = {"tp"}, usage = {"<x> <y> <z> [sceneId]"}, permission = "player.teleport", permissionTargeted = "player.teleport.others")
@Command(
label = "teleport",
aliases = {"tp"},
usage = {"<x> <y> <z> [sceneId]"},
permission = "player.teleport",
permissionTargeted = "player.teleport.others")
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.equals("~")) { // Relative with offset
current += Float.parseFloat(input.replace("~", ""));
@@ -37,7 +42,8 @@ public final class TeleportCommand implements CommandHandler {
try {
sceneId = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough
case 3:
try {
@@ -45,7 +51,8 @@ public final class TeleportCommand implements CommandHandler {
y = this.parseRelative(args.get(1), y);
z = this.parseRelative(args.get(2), z);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
CommandHandler.sendMessage(
sender, translate(sender, "commands.teleport.invalid_position"));
}
break;
default:
@@ -54,15 +61,18 @@ public final class TeleportCommand implements CommandHandler {
}
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) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
} else {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
targetPlayer.getNickname(), x, y, z, sceneId)
);
CommandHandler.sendMessage(
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.game.Account;
import emu.grasscutter.game.player.Player;
import java.util.List;
@Command(
label = "unban",
permission = "server.ban",
targetRequirement = Command.TargetRequirement.PLAYER
)
targetRequirement = Command.TargetRequirement.PLAYER)
public final class UnBanCommand implements CommandHandler {
private boolean unBanAccount(Player targetPlayer) {

View File

@@ -1,19 +1,22 @@
package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.PlayerProgressManager;
import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "unlockall", usage = {""}, permission = "player.unlockall", permissionTargeted = "player.unlockall.others")
@Command(
label = "unlockall",
usage = {""},
permission = "player.unlockall",
permissionTargeted = "player.unlockall.others")
public final class UnlockAllCommand implements CommandHandler {
@Override
@@ -34,6 +37,7 @@ public final class UnlockAllCommand implements CommandHandler {
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.game.player.Player;
import emu.grasscutter.game.props.ClimateType;
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 {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
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()) {
climate = targetPlayer.getClimate();
CommandHandler.sendTranslatedMessage(sender, "commands.weather.status", weatherId, climate.getShortName());
CommandHandler.sendTranslatedMessage(
sender, "commands.weather.status", weatherId, climate.getShortName());
return;
}
@@ -38,6 +46,7 @@ public final class WeatherCommand implements CommandHandler {
targetPlayer.setWeather(weatherId, climate);
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;
import emu.grasscutter.utils.FileUtils;
import java.nio.file.Path;
import java.util.Locale;
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.
* <p>
* Use `import static emu.grasscutter.Configuration.*;`
* to import all configuration constants.
*
* <p>Use `import static emu.grasscutter.Configuration.*;` to import all configuration constants.
*/
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 Files HTTP_STATIC_FILES = config.server.http.files;
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 PLUGINS_FOLDER = config.folderStructure.plugins;
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.JsonUtils;
import emu.grasscutter.utils.TsvUtils;
import lombok.val;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -16,11 +14,13 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import lombok.val;
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.
* @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.
* @return InputStreamReader of the data file.
@@ -40,7 +41,8 @@ public class DataLoader {
* @throws FileNotFoundException
* @see #load(String, boolean)
*/
public static InputStreamReader loadReader(String resourcePath) throws IOException, FileNotFoundException {
public static InputStreamReader loadReader(String resourcePath)
throws IOException, FileNotFoundException {
try {
InputStream is = load(resourcePath, true);
return new InputStreamReader(is);
@@ -53,20 +55,22 @@ public class DataLoader {
* Load a data file by its name.
*
* @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.
* @throws FileNotFoundException
*/
public static InputStream load(String resourcePath, boolean useFallback) throws FileNotFoundException {
Path path = useFallback
? FileUtils.getDataPath(resourcePath)
: FileUtils.getDataUserPath(resourcePath);
public static InputStream load(String resourcePath, boolean useFallback)
throws FileNotFoundException {
Path path =
useFallback ? FileUtils.getDataPath(resourcePath) : FileUtils.getDataUserPath(resourcePath);
if (Files.exists(path)) {
// Data is in the resource directory
try {
return Files.newInputStream(path);
} 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;
@@ -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)) {
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);
Grasscutter.getLogger().debug("Loading data table from: " + path);
return switch (FileUtils.getFileExtension(path)) {
@@ -107,7 +113,7 @@ public class DataLoader {
if (filenames == null) {
Grasscutter.getLogger().error("We were unable to locate your default data files.");
} //else for (Path file : filenames) {
} // else for (Path file : filenames) {
// String relativePath = String.valueOf(file).split("defaults[\\\\\\/]data[\\\\\\/]")[1];
// checkAndCopyData(relativePath);

View File

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

View File

@@ -9,50 +9,57 @@ import emu.grasscutter.game.world.SpawnDataEntry;
import emu.grasscutter.utils.WeightedList;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
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<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot =
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
@Setter
private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
@Getter
private static final HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>();
@Getter
@Setter
private static BlossomConfig blossomConfig;
private static final HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists =
new HashMap<>();
@Getter @Setter private static BlossomConfig blossomConfig;
public static void load() {
for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) {
if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) {
continue;
}
List<ReliquaryMainPropData> list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>());
List<ReliquaryMainPropData> list =
relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>());
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);
}
for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) {
if (data.getWeight() <= 0 || data.getDepotId() <= 0) {
continue;
}
List<ReliquaryAffixData> list = relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>());
List<ReliquaryAffixData> list =
relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>());
list.add(data);
}
// Let the server owner know if theyre missing weights
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);
}
public static void addSpawnListById(HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> data) {
public static void addSpawnListById(
HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> data) {
spawnLists.putAll(data);
}
}

View File

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

View File

@@ -1,5 +1,9 @@
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 emu.grasscutter.Grasscutter;
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.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import lombok.val;
import org.reflections.Reflections;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
@@ -30,10 +31,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import static emu.grasscutter.utils.FileUtils.getDataPath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
import static emu.grasscutter.utils.Language.translate;
import lombok.val;
import org.reflections.Reflections;
public class ResourceLoader {
@@ -46,14 +45,18 @@ public class ResourceLoader {
Set<?> classes = reflections.getSubTypesOf(GameResource.class);
List<Class<?>> classList = new ArrayList<>(classes.size());
classes.forEach(o -> {
classes.forEach(
o -> {
Class<?> c = (Class<?>) o;
if (c.getAnnotation(ResourceType.class) != null) {
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;
}
@@ -67,7 +70,8 @@ public class ResourceLoader {
val map = new LinkedHashMap<ResourceType.LoadPriority, Set<Class<?>>>(priorities.size());
priorities.forEach(p -> map.put(p, new HashSet<>()));
classes.forEach(c -> {
classes.forEach(
c -> {
// val c = (Class<?>) o;
val annotation = c.getAnnotation(ResourceType.class);
if (annotation != null) {
@@ -112,12 +116,18 @@ public class ResourceLoader {
public static void loadResources(boolean doReload) {
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()
.parallel().unordered()
.forEach(c -> {
.parallel()
.unordered()
.forEach(
c -> {
val type = c.getAnnotation(ResourceType.class);
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 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");
}
@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();
if (doReload || !loadedResources.contains(simpleName)) {
for (String name : type.name()) {
@@ -149,15 +163,18 @@ public class ResourceLoader {
}
@SuppressWarnings({"rawtypes", "unchecked"})
protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map) throws Exception {
val results = switch (FileUtils.getFileExtension(filename)) {
protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map)
throws Exception {
val results =
switch (FileUtils.getFileExtension(filename)) {
case "json" -> JsonUtils.loadToList(filename, c);
case "tsj" -> TsvUtils.loadTsjToListSetField(filename, c);
case "tsv" -> TsvUtils.loadTsvToListSetField(filename, c);
default -> null;
};
if (results == null) return;
results.forEach(o -> {
results.forEach(
o -> {
GameResource res = (GameResource) o;
res.onLoad();
map.put(res.getId(), res);
@@ -165,8 +182,11 @@ public class ResourceLoader {
}
@SuppressWarnings({"rawtypes", "unchecked"})
protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map) throws Exception {
JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c).forEach(o -> {
protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map)
throws Exception {
JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c)
.forEach(
o -> {
GameResource res = (GameResource) o;
res.onLoad();
map.put(res.getId(), res);
@@ -176,7 +196,9 @@ public class ResourceLoader {
private static void loadScenePoints() {
val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
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());
if (!matcher.find()) return;
int sceneId = Integer.parseInt(matcher.group(1));
@@ -192,7 +214,8 @@ public class ResourceLoader {
if (config.points == null) return;
val scenePoints = new IntArrayList();
config.points.forEach((pointId, pointData) -> {
config.points.forEach(
(pointId, pointData) -> {
val scenePoint = new ScenePointEntry(sceneId, pointData);
scenePoints.add(pointId);
pointData.setId(pointId);
@@ -206,21 +229,28 @@ public class ResourceLoader {
GameData.getScenePointsPerScene().put(sceneId, scenePoints);
});
} 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() {
// All known levels, keyed by proudSkillGroupId
GameData.getProudSkillDataMap().forEach((id, data) ->
GameData.getProudSkillDataMap()
.forEach(
(id, data) ->
GameData.proudSkillGroupLevels
.computeIfAbsent(data.getProudSkillGroupId(), i -> new IntArraySet())
.add(data.getLevel()));
// All known levels, keyed by avatarSkillId
GameData.getAvatarSkillDataMap().forEach((id, data) ->
GameData.avatarSkillLevels.put((int) id, GameData.proudSkillGroupLevels.get(data.getProudSkillGroupId())));
GameData.getAvatarSkillDataMap()
.forEach(
(id, data) ->
GameData.avatarSkillLevels.put(
(int) id, GameData.proudSkillGroupLevels.get(data.getProudSkillGroupId())));
// 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()));
}
@@ -229,7 +259,8 @@ public class ResourceLoader {
// Read from cached file if exists
try {
embryoList = JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
embryoList =
JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
} catch (Exception ignored) {
}
@@ -239,7 +270,9 @@ public class ResourceLoader {
val l = new ArrayList<AbilityEmbryoEntry>();
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());
if (!matcher.find()) return;
String avatarName = matcher.group(1);
@@ -255,7 +288,12 @@ public class ResourceLoader {
if (config.abilities == null) return;
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);
});
} catch (IOException e) {
@@ -266,7 +304,12 @@ public class ResourceLoader {
embryoList = l;
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) {
Grasscutter.getLogger().error("Error loading player abilities:", e);
}
@@ -285,7 +328,10 @@ public class ResourceLoader {
private static void loadAbilityModifiers() {
// Load from BinOutput
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) {
Grasscutter.getLogger().error("Error loading ability modifiers: ", e);
}
@@ -296,9 +342,11 @@ public class ResourceLoader {
private static void loadAbilityModifiers(Path path) {
try {
JsonUtils.loadToList(path, AbilityConfigData.class).forEach(data -> loadAbilityData(data.Default));
JsonUtils.loadToList(path, AbilityConfigData.class)
.forEach(data -> loadAbilityData(data.Default));
} 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;
AbilityModifierEntry modifierEntry = new AbilityModifierEntry(name);
modifiers.forEach((key, modifier) -> {
Stream.ofNullable(modifier.onAdded).flatMap(Stream::of)
modifiers.forEach(
(key, modifier) -> {
Stream.ofNullable(modifier.onAdded)
.flatMap(Stream::of)
// .map(action -> {modifierActionTypes.add(action.$type); return action;})
.filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.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;})
.filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.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;})
.filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.forEach(action -> modifierEntry.getOnRemoved().add(action));
@@ -347,9 +399,11 @@ public class ResourceLoader {
}
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) {
entry.getSpawns().forEach(
entry
.getSpawns()
.forEach(
s -> {
s.setGroup(entry);
GridBlockId point = s.getBlockId();
@@ -357,8 +411,7 @@ public class ResourceLoader {
areaSort.put(point, new ArrayList<>());
}
areaSort.get(point).add(s);
}
);
});
}
GameDepot.addSpawnListById(areaSort);
}
@@ -378,7 +431,9 @@ public class ResourceLoader {
for (String folderName : folderNames) {
try {
Files.newDirectoryStream(getResourcePath(folderName), "*.json").forEach(path -> {
Files.newDirectoryStream(getResourcePath(folderName), "*.json")
.forEach(
path -> {
try {
JsonUtils.loadToMap(path, String.class, OpenConfigData[].class)
.forEach((name, data) -> map.put(name, new OpenConfigEntry(name, data)));
@@ -387,7 +442,8 @@ public class ResourceLoader {
}
});
} 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;
}
}
@@ -407,7 +463,9 @@ public class ResourceLoader {
private static void loadQuests() {
try {
Files.list(getResourcePath("BinOutput/Quest/")).forEach(path -> {
Files.list(getResourcePath("BinOutput/Quest/"))
.forEach(
path -> {
try {
val mainQuest = JsonUtils.loadToClass(path, MainQuestData.class);
GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest);
@@ -424,11 +482,13 @@ public class ResourceLoader {
val questEncryptionMap = GameData.getMainQuestEncryptionMap();
String path = "QuestEncryptionKeys.json";
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) {
}
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) {
}
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().debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas.");
Grasscutter.getLogger()
.debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas.");
}
public static void loadScriptSceneData() {
try {
Files.list(getResourcePath("ScriptSceneData/")).forEach(path -> {
Files.list(getResourcePath("ScriptSceneData/"))
.forEach(
path -> {
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) {
e.printStackTrace();
}
});
Grasscutter.getLogger().debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas.");
Grasscutter.getLogger()
.debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas.");
} catch (IOException e) {
Grasscutter.getLogger().debug("ScriptSceneData folder missing or empty.");
}
@@ -457,7 +524,10 @@ public class ResourceLoader {
private static void loadHomeworldDefaultSaveData() {
val pattern = Pattern.compile("scene([0-9]+)_home_config\\.json");
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());
if (!matcher.find()) return;
@@ -468,7 +538,11 @@ public class ResourceLoader {
} catch (Exception ignored) {
}
});
Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas.");
Grasscutter.getLogger()
.debug(
"Loaded "
+ GameData.getHomeworldDefaultSaveData().size()
+ " HomeworldDefaultSaveDatas.");
} catch (IOException e) {
Grasscutter.getLogger().error("Failed to load HomeworldDefaultSave folder.");
}
@@ -476,19 +550,24 @@ public class ResourceLoader {
private static void loadNpcBornData() {
try {
Files.newDirectoryStream(getResourcePath("BinOutput/Scene/SceneNpcBorn/"), "*.json").forEach(path -> {
Files.newDirectoryStream(getResourcePath("BinOutput/Scene/SceneNpcBorn/"), "*.json")
.forEach(
path -> {
try {
val data = JsonUtils.loadToClass(path, SceneNpcBornData.class);
if (data.getBornPosList() == null || data.getBornPosList().size() == 0) {
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);
} catch (IOException ignored) {
}
});
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
Grasscutter.getLogger()
.debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
} catch (IOException e) {
Grasscutter.getLogger().error("Failed to load SceneNpcBorn folder.");
}
@@ -496,15 +575,20 @@ public class ResourceLoader {
private static void loadGadgetConfigData() {
try {
Files.newDirectoryStream(getResourcePath("BinOutput/Gadget/"), "*.json").forEach(path -> {
Files.newDirectoryStream(getResourcePath("BinOutput/Gadget/"), "*.json")
.forEach(
path -> {
try {
GameData.getGadgetConfigData().putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class));
GameData.getGadgetConfigData()
.putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class));
} 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) {
Grasscutter.getLogger().error("Failed to load ConfigGadget folder.");
}
@@ -525,7 +609,9 @@ public class ResourceLoader {
}
public static class AvatarConfig {
@SerializedName(value = "abilities", alternate = {"targetAbilities"})
@SerializedName(
value = "abilities",
alternate = {"targetAbilities"})
public ArrayList<AvatarConfigAbility> abilities;
}
@@ -547,13 +633,19 @@ public class ResourceLoader {
public String $type;
public String abilityName;
@SerializedName(value = "talentIndex", alternate = {"OJOFFKLNAHN"})
@SerializedName(
value = "talentIndex",
alternate = {"OJOFFKLNAHN"})
public int talentIndex;
@SerializedName(value = "skillID", alternate = {"overtime"})
@SerializedName(
value = "skillID",
alternate = {"overtime"})
public int skillID;
@SerializedName(value = "pointDelta", alternate = {"IGEBKIHPOIF"})
@SerializedName(
value = "pointDelta",
alternate = {"IGEBKIHPOIF"})
public int pointDelta;
}

View File

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

View File

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

View File

@@ -2,93 +2,266 @@ package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.common.DynamicFloat;
import java.io.Serializable;
public class AbilityModifier implements Serializable {
private static final long serialVersionUID = -2001232313615923575L;
@SerializedName(value = "onAdded", alternate = {"KCICDEJLIJD"})
@SerializedName(
value = "onAdded",
alternate = {"KCICDEJLIJD"})
public AbilityModifierAction[] onAdded;
@SerializedName(value = "onThinkInterval", alternate = {"PBDDACFFPOE"})
@SerializedName(
value = "onThinkInterval",
alternate = {"PBDDACFFPOE"})
public AbilityModifierAction[] onThinkInterval;
public AbilityModifierAction[] onRemoved;
public DynamicFloat duration = DynamicFloat.ZERO;
public static class AbilityModifierAction {
@SerializedName("$type")
public Type type;
public String target;
@SerializedName(value = "amount", alternate = "PDLLIFICICJ")
public DynamicFloat amount = DynamicFloat.ZERO;
public DynamicFloat amountByCasterAttackRatio = DynamicFloat.ZERO;
public DynamicFloat amountByCasterCurrentHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByCasterMaxHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByGetDamage = DynamicFloat.ZERO;
public DynamicFloat amountByTargetCurrentHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByTargetMaxHPRatio = DynamicFloat.ZERO;
@SerializedName(value = "ignoreAbilityProperty", alternate = "HHFGADCJJDI")
public boolean ignoreAbilityProperty;
public String modifierName;
public enum Type {
ActCameraRadialBlur, ActCameraShake, AddAvatarSkillInfo, AddChargeBarValue,
AddClimateMeter, AddElementDurability, AddGlobalValue, AddGlobalValueToTarget,
AddRegionalPlayVarValue, ApplyModifier, AttachAbilityStateResistance, AttachBulletAimPoint,
AttachEffect, AttachEffectFirework, AttachElementTypeResistance, AttachModifier,
AttachUIEffect, AvatarCameraParam, AvatarEnterCameraShot, AvatarEnterFocus,
AvatarEnterViewBias, AvatarExitCameraShot, AvatarExitClimb, AvatarExitFocus,
AvatarExitViewBias, AvatarShareCDSkillStart, AvatarSkillStart, BroadcastNeuronStimulate,
CalcDvalinS04RebornPoint, CallLuaTask, ChangeEnviroWeather, ChangeFollowDampTime,
ChangeGadgetUIInteractHint, ChangePlayMode, ChangeTag, ChangeUGCRayTag,
ClearEndura, ClearGlobalPos, ClearGlobalValue, ClearLocalGadgets,
ClearLockTarget, ClearPos, ConfigAbilityAction, ControlEmotion,
CopyGlobalValue, CreateGadget, CreateMovingPlatform, CreateTile,
DamageByAttackValue, DebugLog, DestroyTile, DoBlink,
DoTileAction, 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
ActCameraRadialBlur,
ActCameraShake,
AddAvatarSkillInfo,
AddChargeBarValue,
AddClimateMeter,
AddElementDurability,
AddGlobalValue,
AddGlobalValueToTarget,
AddRegionalPlayVarValue,
ApplyModifier,
AttachAbilityStateResistance,
AttachBulletAimPoint,
AttachEffect,
AttachEffectFirework,
AttachElementTypeResistance,
AttachModifier,
AttachUIEffect,
AvatarCameraParam,
AvatarEnterCameraShot,
AvatarEnterFocus,
AvatarEnterViewBias,
AvatarExitCameraShot,
AvatarExitClimb,
AvatarExitFocus,
AvatarExitViewBias,
AvatarShareCDSkillStart,
AvatarSkillStart,
BroadcastNeuronStimulate,
CalcDvalinS04RebornPoint,
CallLuaTask,
ChangeEnviroWeather,
ChangeFollowDampTime,
ChangeGadgetUIInteractHint,
ChangePlayMode,
ChangeTag,
ChangeUGCRayTag,
ClearEndura,
ClearGlobalPos,
ClearGlobalValue,
ClearLocalGadgets,
ClearLockTarget,
ClearPos,
ConfigAbilityAction,
ControlEmotion,
CopyGlobalValue,
CreateGadget,
CreateMovingPlatform,
CreateTile,
DamageByAttackValue,
DebugLog,
DestroyTile,
DoBlink,
DoTileAction,
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 boolean isFormula;
// public boolean isDynamic;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,6 @@
package emu.grasscutter.data.binout;
import emu.grasscutter.data.ResourceLoader.OpenConfigData;
import java.util.ArrayList;
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.geometry.Geometry;
import emu.grasscutter.scripts.data.SceneGroup;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@@ -17,13 +16,9 @@ public class SceneNpcBornData {
int sceneId;
List<SceneNpcBornEntry> bornPosList;
/**
* Spatial Index For NPC
*/
/** Spatial Index For NPC */
transient RTree<SceneNpcBornEntry, Geometry> index;
/**
* npc groups
*/
/** npc groups */
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 emu.grasscutter.utils.Position;
import java.util.List;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import java.util.List;
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SceneNpcBornEntry {
@SerializedName(value = "id", alternate = {"_id", "ID"})
@SerializedName(
value = "id",
alternate = {"_id", "ID"})
int id;
@SerializedName(value = "configId", alternate = {"_configId"})
@SerializedName(
value = "configId",
alternate = {"_configId"})
int configId;
@SerializedName(value = "pos", alternate = {"_pos"})
@SerializedName(
value = "pos",
alternate = {"_pos"})
Position pos;
@SerializedName(value = "rot", alternate = {"_rot"})
@SerializedName(
value = "rot",
alternate = {"_rot"})
Position rot;
@SerializedName(value = "groupId", alternate = {"_groupId"})
@SerializedName(
value = "groupId",
alternate = {"_groupId"})
int groupId;
@SerializedName(value = "suiteIdList", alternate = {"_suiteIdList"})
@SerializedName(
value = "suiteIdList",
alternate = {"_suiteIdList"})
List<Integer> suiteIdList;
}

View File

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

View File

@@ -1,10 +1,9 @@
package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.util.List;
import java.util.Map;
import lombok.Data;
@Data
public class ScriptSceneData {
@@ -12,10 +11,8 @@ public class ScriptSceneData {
@Data
public static class ScriptObject {
//private SceneGroup groups;
// private SceneGroup groups;
@SerializedName("dummy_points")
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.objects.Object2FloatArrayMap;
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import lombok.val;
import java.util.List;
import java.util.Optional;
import lombok.val;
public class DynamicFloat {
public static DynamicFloat ZERO = new DynamicFloat(0f);
private List<StackOp> ops;
private boolean dynamic = false;
private float constant = 0f;
public DynamicFloat(float constant) {
this.constant = constant;
}
@@ -43,8 +43,7 @@ public class DynamicFloat {
}
public float get(Object2FloatMap<String> props) {
if (!dynamic)
return constant;
if (!dynamic) return constant;
val fl = new FloatArrayList();
for (var op : this.ops) {
@@ -52,8 +51,8 @@ public class DynamicFloat {
case CONSTANT -> fl.push(op.fValue);
case KEY -> fl.push(props.getOrDefault(op.sValue, 0f));
case ADD -> fl.push(fl.popFloat() + fl.popFloat());
case SUB ->
fl.push(-fl.popFloat() + fl.popFloat()); // [f0, f1, f2] -> [f0, f1-f2] (opposite of RPN order)
case SUB -> fl.push(
-fl.popFloat() + fl.popFloat()); // [f0, f1, f2] -> [f0, f1-f2] (opposite of RPN order)
case MUL -> fl.push(fl.popFloat() * fl.popFloat());
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));
@@ -69,6 +68,7 @@ public class DynamicFloat {
public float fValue;
public String sValue;
public boolean bValue;
public StackOp(String s) {
switch (s.toUpperCase()) {
case "ADD" -> this.op = Op.ADD;
@@ -92,6 +92,14 @@ public class DynamicFloat {
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
public class ItemParamData {
@SerializedName(value = "id", alternate = {"itemId"})
@SerializedName(
value = "id",
alternate = {"itemId"})
private int id;
@SerializedName(value = "count", alternate = {"itemCount"})
@SerializedName(
value = "count",
alternate = {"itemCount"})
private int count;
public ItemParamData() {
}
public ItemParamData() {}
public ItemParamData(int id, int count) {
this.id = id;

View File

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

View File

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

View File

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

View File

@@ -4,13 +4,12 @@ import com.github.davidmoten.guavamini.Lists;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.Getter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import lombok.Getter;
@Getter
@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() {
@@ -91,6 +92,8 @@ public class AchievementData extends GameResource {
}
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.GameResource;
import emu.grasscutter.data.ResourceType;
import java.util.List;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import java.util.List;
import java.util.Objects;
@ResourceType(name = "NewActivityExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW)
@ResourceType(
name = "NewActivityExcelConfigData.json",
loadPriority = ResourceType.LoadPriority.LOW)
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ActivityData extends GameResource {
@@ -27,9 +28,10 @@ public class ActivityData extends GameResource {
@Override
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)
.toList();
}
}

View File

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

View File

@@ -3,25 +3,28 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.WatcherTriggerType;
import java.util.List;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import java.util.List;
@ResourceType(name = "NewActivityWatcherConfigData.json", loadPriority = ResourceType.LoadPriority.HIGH)
@ResourceType(
name = "NewActivityWatcherConfigData.json",
loadPriority = ResourceType.LoadPriority.HIGH)
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ActivityWatcherData extends GameResource {
@Getter(onMethod_ = @Override)
int id;
int rewardID;
int progress;
WatcherTrigger triggerConfig;
@Override
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);
}
@@ -33,5 +36,4 @@ public class ActivityWatcherData extends GameResource {
transient WatcherTriggerType watcherTriggerType;
}
}

View File

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

View File

@@ -3,7 +3,6 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.CurveInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
@@ -31,6 +30,7 @@ public class AvatarCurveData extends GameResource {
@Override
public void onLoad() {
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
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.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData;
import java.util.ArrayList;
@ResourceType(name = "AvatarPromoteExcelConfigData.json")

View File

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

View File

@@ -11,17 +11,17 @@ import emu.grasscutter.game.props.ElementType;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import lombok.Getter;
@ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH)
@Getter
public class AvatarSkillDepotData extends GameResource {
@Getter(onMethod_ = @Override)
private int id;
private int energySkill;
private int attackModeSkill;
@@ -61,7 +61,10 @@ public class AvatarSkillDepotData extends GameResource {
AvatarConfig config = GameDepot.getPlayerAbilities().get(getSkillDepotAbilityGroup());
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.LoadPriority;
import emu.grasscutter.data.common.FightPropData;
import java.util.ArrayList;
@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.WatcherTriggerType;
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
import lombok.Getter;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.Getter;
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
@Getter
public class BattlePassMissionData extends GameResource {
@Getter(onMethod_ = @Override)
private int id;
private int addPoint;
private int scheduleId;
private int progress;
@@ -29,13 +29,16 @@ public class BattlePassMissionData extends GameResource {
}
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() {
return getRefreshType() == null ||
getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE ||
getScheduleId() == 2701;
return getRefreshType() == null
|| getRefreshType()
== BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE
|| getScheduleId() == 2701;
}
@Override
@@ -43,13 +46,15 @@ public class BattlePassMissionData extends GameResource {
if (this.getTriggerConfig() != null) {
var params = getTriggerConfig().getParamList()[0];
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() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
var protoBuilder =
emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
protoBuilder
.setMissionId(getId())

View File

@@ -2,9 +2,8 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.Getter;
import java.util.List;
import lombok.Getter;
@ResourceType(name = "BattlePassRewardExcelConfigData.json")
@Getter
@@ -22,6 +21,5 @@ public class BattlePassRewardData extends GameResource {
}
@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.ResourceType;
import lombok.Getter;
import java.util.List;
import lombok.Getter;
@ResourceType(name = "BlossomRefreshExcelConfigData.json")
@Getter
@@ -19,7 +18,9 @@ public class BlossomRefreshExcelConfigData extends GameResource {
// Refresh details
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 RefreshCond[] refreshCondVec; // AR requirements etc.

View File

@@ -22,6 +22,7 @@ public class BuffData extends GameResource {
}
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.ResourceType;
import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
import java.util.HashMap;
import java.util.Map;
@ResourceType(name = "ChapterExcelConfigData.json")
@Getter
@Setter // TODO: remove on next API break
@@ -18,8 +17,10 @@ public class ChapterData extends GameResource {
// Why public? TODO: privatise next API break
public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>();
public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>();
@Getter(onMethod_ = @Override)
int id;
int beginQuestId;
int endQuestId;
int needPlayerLevel;

View File

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

View File

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

View File

@@ -9,24 +9,15 @@ import lombok.Getter;
@ResourceType(name = {"ReliquaryCodexExcelConfigData.json"})
public class CodexReliquaryData extends GameResource {
@Getter
private int Id;
@Getter
private int suitId;
@Getter
private int level;
@Getter
private int cupId;
@Getter
private int leatherId;
@Getter
private int capId;
@Getter
private int flowerId;
@Getter
private int sandId;
@Getter
private int sortOrder;
@Getter private int Id;
@Getter private int suitId;
@Getter private int level;
@Getter private int cupId;
@Getter private int leatherId;
@Getter private int capId;
@Getter private int flowerId;
@Getter private int sandId;
@Getter private int sortOrder;
private transient IntCollection ids;
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.ResourceType;
import emu.grasscutter.data.common.ItemParamData;
import java.util.List;
import java.util.stream.Collectors;
@@ -31,8 +30,10 @@ public class CombineData extends GameResource {
public void onLoad() {
super.onLoad();
// clean data
randomItems = randomItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList());
materialItems = materialItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList());
randomItems =
randomItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList());
materialItems =
materialItems.stream().filter(item -> item.getId() > 0).collect(Collectors.toList());
}
public int getCombineId() {
@@ -78,5 +79,4 @@ public class CombineData extends GameResource {
public String getRecipeType() {
return recipeType;
}
}

View File

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

View File

@@ -4,7 +4,9 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
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 {
private int avatarId;
private int recipeId;
@@ -37,6 +39,5 @@ public class CookBonusData extends GameResource {
}
@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.LoadPriority;
import emu.grasscutter.data.common.ItemParamData;
import java.util.List;
import lombok.Getter;
import java.util.List;
@ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW)
@ResourceType(
name = {"CookRecipeExcelConfigData.json"},
loadPriority = LoadPriority.LOW)
@Getter
public class CookRecipeData extends GameResource {
@Getter(onMethod_ = @Override)

View File

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

View File

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

View File

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

View File

@@ -3,10 +3,11 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemParamData;
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 {
private int animalId;
private String entityType;

View File

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

View File

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

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