Run IntelliJ IDEA code formatter

This commit is contained in:
KingRainbow44 2023-03-31 17:19:26 -04:00
parent 5bf5fb07a2
commit 15e2f3ca34
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
917 changed files with 30030 additions and 22446 deletions

View File

@ -1,30 +1,24 @@
package emu.grasscutter; package emu.grasscutter;
import java.util.Arrays;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
public final class GameConstants { import java.util.Arrays;
public static String VERSION = "3.5.0";
public final class GameConstants {
public static final int DEFAULT_TEAMS = 4; public static final int DEFAULT_TEAMS = 4;
public static final int MAX_TEAMS = 10; public static final int MAX_TEAMS = 10;
public static final int MAIN_CHARACTER_MALE = 10000005; public static final int MAIN_CHARACTER_MALE = 10000005;
public static final int MAIN_CHARACTER_FEMALE = 10000007; public static final int MAIN_CHARACTER_FEMALE = 10000007;
public static final Position START_POSITION = new Position(2747, 194, -1719); public static final Position START_POSITION = new Position(2747, 194, -1719);
public static final int MAX_FRIENDS = 60; public static final int MAX_FRIENDS = 60;
public static final int MAX_FRIEND_REQUESTS = 50; public static final int MAX_FRIEND_REQUESTS = 50;
public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player". public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player".
public static final int BATTLE_PASS_MAX_LEVEL = 50; public static final int BATTLE_PASS_MAX_LEVEL = 50;
public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000; public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000;
public static final int BATTLE_PASS_POINT_PER_WEEK = 10000; public static final int BATTLE_PASS_POINT_PER_WEEK = 10000;
public static final int BATTLE_PASS_LEVEL_PRICE = 150; public static final int BATTLE_PASS_LEVEL_PRICE = 150;
public static final int BATTLE_PASS_CURRENT_INDEX = 2; public static final int BATTLE_PASS_CURRENT_INDEX = 2;
// Default entity ability hashes. // Default entity ability hashes.
public static final String[] DEFAULT_ABILITY_STRINGS = { public static final String[] DEFAULT_ABILITY_STRINGS = {
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible", "Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
@ -32,4 +26,5 @@ public final class GameConstants {
}; };
public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray(); public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray();
public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default"); public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default");
public static String VERSION = "3.5.0";
} }

View File

@ -2,7 +2,6 @@ package emu.grasscutter;
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.Logger;
import emu.grasscutter.auth.AuthenticationSystem; import emu.grasscutter.auth.AuthenticationSystem;
import emu.grasscutter.auth.DefaultAuthentication; import emu.grasscutter.auth.DefaultAuthentication;
import emu.grasscutter.command.CommandMap; import emu.grasscutter.command.CommandMap;
@ -24,11 +23,7 @@ import emu.grasscutter.server.http.handlers.GachaHandler;
import emu.grasscutter.server.http.handlers.GenericHandler; import emu.grasscutter.server.http.handlers.GenericHandler;
import emu.grasscutter.server.http.handlers.LogHandler; import emu.grasscutter.server.http.handlers.LogHandler;
import emu.grasscutter.tools.Tools; import emu.grasscutter.tools.Tools;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.*;
import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.Language;
import emu.grasscutter.utils.StartupArguments;
import emu.grasscutter.utils.Utils;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.jline.reader.EndOfFileException; import org.jline.reader.EndOfFileException;
@ -41,34 +36,47 @@ import org.reflections.Reflections;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.*; import java.io.File;
import java.io.FileWriter;
import java.io.IOError;
import java.io.IOException;
import java.util.Calendar; import java.util.Calendar;
import static emu.grasscutter.config.Configuration.SERVER; import static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
public final class Grasscutter { public final class Grasscutter {
@Getter private static final Logger logger = (Logger) LoggerFactory.getLogger(Grasscutter.class);
private static LineReader consoleLineReader = null;
@Getter @Setter private static Language language;
public static final File configFile = new File("./config.json"); public static final File configFile = new File("./config.json");
@Setter private static ServerRunMode runModeOverride = null; // Config override for run mode
@Getter private static int currentDayOfWeek;
@Getter @Setter private static String preferredLanguage;
@Getter private static HttpServer httpServer;
@Getter private static GameServer gameServer;
@Getter private static PluginManager pluginManager;
@Getter private static CommandMap commandMap;
@Getter @Setter private static AuthenticationSystem authenticationSystem;
@Getter @Setter private static PermissionHandler permissionHandler;
public static final Reflections reflector = new Reflections("emu.grasscutter"); public static final Reflections reflector = new Reflections("emu.grasscutter");
@Getter public static ConfigContainer config; @Getter
private static final Logger logger = (Logger) LoggerFactory.getLogger(Grasscutter.class);
@Getter
public static ConfigContainer config;
private static LineReader consoleLineReader = null;
@Getter
@Setter
private static Language language;
@Setter
private static ServerRunMode runModeOverride = null; // Config override for run mode
@Getter
private static int currentDayOfWeek;
@Getter
@Setter
private static String preferredLanguage;
@Getter
private static HttpServer httpServer;
@Getter
private static GameServer gameServer;
@Getter
private static PluginManager pluginManager;
@Getter
private static CommandMap commandMap;
@Getter
@Setter
private static AuthenticationSystem authenticationSystem;
@Getter
@Setter
private static PermissionHandler permissionHandler;
static { static {
// Declare logback configuration. // Declare logback configuration.
@ -265,7 +273,7 @@ public final class Grasscutter {
public static void updateDayOfWeek() { public static void updateDayOfWeek() {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
Grasscutter.currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); Grasscutter.currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
Grasscutter.getLogger().debug("Set day of week to "+currentDayOfWeek); Grasscutter.getLogger().debug("Set day of week to " + currentDayOfWeek);
} }
public static void startConsole() { public static void startConsole() {

View File

@ -15,8 +15,63 @@ import javax.annotation.Nullable;
*/ */
public interface AuthenticationSystem { public interface AuthenticationSystem {
/**
* Generates an authentication request from a {@link LoginAccountRequestJson} object.
*
* @param ctx The Javalin context.
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromPasswordRequest(Context ctx, LoginAccountRequestJson jsonData) {
return AuthenticationRequest.builder()
.context(ctx)
.passwordRequest(jsonData)
.build();
}
/**
* Generates an authentication request from a {@link LoginTokenRequestJson} object.
*
* @param ctx The Javalin context.
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromTokenRequest(Context ctx, LoginTokenRequestJson jsonData) {
return AuthenticationRequest.builder()
.context(ctx)
.tokenRequest(jsonData)
.build();
}
/**
* Generates an authentication request from a {@link ComboTokenReqJson} object.
*
* @param ctx The Javalin context.
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromComboTokenRequest(Context ctx, ComboTokenReqJson jsonData,
ComboTokenReqJson.LoginTokenData tokenData) {
return AuthenticationRequest.builder()
.context(ctx)
.sessionKeyRequest(jsonData)
.sessionKeyData(tokenData)
.build();
}
/**
* Generates an authentication request from a {@link Context} object.
*
* @param ctx The Javalin context.
* @return An authentication request.
*/
static AuthenticationRequest fromExternalRequest(Context ctx) {
return AuthenticationRequest.builder().context(ctx).build();
}
/** /**
* Called when a user requests to make an account. * Called when a user requests to make an account.
*
* @param username The provided username. * @param username The provided username.
* @param password The provided password. (SHA-256'ed) * @param password The provided password. (SHA-256'ed)
*/ */
@ -24,12 +79,14 @@ public interface AuthenticationSystem {
/** /**
* Called when a user requests to reset their password. * Called when a user requests to reset their password.
*
* @param username The username of the account to reset. * @param username The username of the account to reset.
*/ */
void resetPassword(String username); void resetPassword(String username);
/** /**
* Called by plugins to internally verify a user's identity. * Called by plugins to internally verify a user's identity.
*
* @param details A unique identifier to identify the user. (For example: a JWT token) * @param details A unique identifier to identify the user. (For example: a JWT token)
* @return The user's account if the verification was successful, null if the user was unable to be verified. * @return The user's account if the verification was successful, null if the user was unable to be verified.
*/ */
@ -37,30 +94,35 @@ public interface AuthenticationSystem {
/** /**
* This is the authenticator used for password authentication. * This is the authenticator used for password authentication.
*
* @return An authenticator. * @return An authenticator.
*/ */
Authenticator<LoginResultJson> getPasswordAuthenticator(); Authenticator<LoginResultJson> getPasswordAuthenticator();
/** /**
* This is the authenticator used for token authentication. * This is the authenticator used for token authentication.
*
* @return An authenticator. * @return An authenticator.
*/ */
Authenticator<LoginResultJson> getTokenAuthenticator(); Authenticator<LoginResultJson> getTokenAuthenticator();
/** /**
* This is the authenticator used for session authentication. * This is the authenticator used for session authentication.
*
* @return An authenticator. * @return An authenticator.
*/ */
Authenticator<ComboTokenResJson> getSessionKeyAuthenticator(); Authenticator<ComboTokenResJson> getSessionKeyAuthenticator();
/** /**
* This is the authenticator used for handling external authentication requests. * This is the authenticator used for handling external authentication requests.
*
* @return An authenticator. * @return An authenticator.
*/ */
ExternalAuthenticator getExternalAuthenticator(); ExternalAuthenticator getExternalAuthenticator();
/** /**
* This is the authenticator used for handling OAuth authentication requests. * This is the authenticator used for handling OAuth authentication requests.
*
* @return An authenticator. * @return An authenticator.
*/ */
OAuthAuthenticator getOAuthAuthenticator(); OAuthAuthenticator getOAuthAuthenticator();
@ -68,63 +130,19 @@ public interface AuthenticationSystem {
/** /**
* 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 @Builder
@AllArgsConstructor
@Getter
class AuthenticationRequest { class AuthenticationRequest {
private final Context context; private final Context context;
@Nullable private final LoginAccountRequestJson passwordRequest; @Nullable
@Nullable private final LoginTokenRequestJson tokenRequest; private final LoginAccountRequestJson passwordRequest;
@Nullable private final ComboTokenReqJson sessionKeyRequest; @Nullable
@Nullable private final ComboTokenReqJson.LoginTokenData sessionKeyData; private final LoginTokenRequestJson tokenRequest;
} @Nullable
private final ComboTokenReqJson sessionKeyRequest;
/** @Nullable
* Generates an authentication request from a {@link LoginAccountRequestJson} object. private final ComboTokenReqJson.LoginTokenData sessionKeyData;
* @param ctx The Javalin context.
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromPasswordRequest(Context ctx, LoginAccountRequestJson jsonData) {
return AuthenticationRequest.builder()
.context(ctx)
.passwordRequest(jsonData)
.build();
}
/**
* Generates an authentication request from a {@link LoginTokenRequestJson} object.
* @param ctx The Javalin context.
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromTokenRequest(Context ctx, LoginTokenRequestJson jsonData) {
return AuthenticationRequest.builder()
.context(ctx)
.tokenRequest(jsonData)
.build();
}
/**
* Generates an authentication request from a {@link ComboTokenReqJson} object.
* @param ctx The Javalin context.
* @param jsonData The JSON data.
* @return An authentication request.
*/
static AuthenticationRequest fromComboTokenRequest(Context ctx, ComboTokenReqJson jsonData,
ComboTokenReqJson.LoginTokenData tokenData) {
return AuthenticationRequest.builder()
.context(ctx)
.sessionKeyRequest(jsonData)
.sessionKeyData(tokenData)
.build();
}
/**
* Generates an authentication request from a {@link Context} object.
* @param ctx The Javalin context.
* @return An authentication request.
*/
static AuthenticationRequest fromExternalRequest(Context ctx) {
return AuthenticationRequest.builder().context(ctx).build();
} }
} }

View File

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

View File

@ -14,11 +14,11 @@ import static emu.grasscutter.utils.Language.translate;
* Allows all users to access any account. * Allows all users to access any account.
*/ */
public final class DefaultAuthentication implements AuthenticationSystem { public final class DefaultAuthentication implements AuthenticationSystem {
private Authenticator<LoginResultJson> passwordAuthenticator; private final Authenticator<LoginResultJson> passwordAuthenticator;
private Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator(); private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator();
private Authenticator<ComboTokenResJson> sessionKeyAuthenticator = new SessionKeyAuthenticator(); private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator = new SessionKeyAuthenticator();
private ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication();
private OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
public DefaultAuthentication() { public DefaultAuthentication() {
if (ACCOUNT.EXPERIMENTAL_RealPassword) { if (ACCOUNT.EXPERIMENTAL_RealPassword) {

View File

@ -5,7 +5,8 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest; import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.server.http.objects.*; import emu.grasscutter.server.http.objects.ComboTokenResJson;
import emu.grasscutter.server.http.objects.LoginResultJson;
import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
@ -15,7 +16,7 @@ import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
/** /**

View File

@ -9,25 +9,28 @@ public interface ExternalAuthenticator {
/** /**
* Called when an external login request is made. * Called when an external login request is made.
*
* @param request The authentication request. * @param request The authentication request.
*/ */
void handleLogin(AuthenticationRequest request); void handleLogin(AuthenticationRequest request);
/** /**
* Called when an external account creation request is made. * Called when an external account creation request is made.
* @param request The authentication request.
* *
* For developers: Use AuthenticationRequest#getRequest() to get the request body. * @param request The authentication request.
* 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); void handleAccountCreation(AuthenticationRequest request);
/** /**
* Called when an external password reset request is made. * Called when an external password reset request is made.
* @param request The authentication request.
* *
* For developers: Use AuthenticationRequest#getRequest() to get the request body. * @param request The authentication request.
* 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); void handlePasswordReset(AuthenticationRequest request);
} }

View File

@ -9,18 +9,21 @@ public interface OAuthAuthenticator {
/** /**
* Called when an OAuth login request is made. * Called when an OAuth login request is made.
*
* @param request The authentication request. * @param request The authentication request.
*/ */
void handleLogin(AuthenticationRequest request); void handleLogin(AuthenticationRequest request);
/** /**
* Called when a client requests to redirect to login page. * Called when a client requests to redirect to login page.
*
* @param request The authentication request. * @param request The authentication request.
*/ */
void handleRedirection(AuthenticationRequest request, ClientType clientType); void handleRedirection(AuthenticationRequest request, ClientType clientType);
/** /**
* Called when an OAuth login requests callback. * Called when an OAuth login requests callback.
*
* @param request The authentication request. * @param request The authentication request.
*/ */
void handleTokenProcess(AuthenticationRequest request); void handleTokenProcess(AuthenticationRequest request);

View File

@ -15,13 +15,14 @@ public @interface Command {
String permissionTargeted() default ""; String permissionTargeted() default "";
public enum TargetRequirement { TargetRequirement targetRequirement() default TargetRequirement.ONLINE;
boolean threading() default false;
enum TargetRequirement {
NONE, // targetPlayer is not required NONE, // targetPlayer is not required
OFFLINE, // targetPlayer must be offline OFFLINE, // targetPlayer must be offline
PLAYER, // targetPlayer can be online or offline PLAYER, // targetPlayer can be online or offline
ONLINE // targetPlayer must be online ONLINE // targetPlayer must be online
} }
TargetRequirement targetRequirement() default TargetRequirement.ONLINE;
boolean threading() default false;
} }

View File

@ -3,13 +3,12 @@ package emu.grasscutter.command;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent; import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
import emu.grasscutter.utils.Language;
import static emu.grasscutter.utils.Language.translate;
import java.util.List; import java.util.List;
import java.util.StringJoiner; import java.util.StringJoiner;
import static emu.grasscutter.utils.Language.translate;
public interface CommandHandler { public interface CommandHandler {
/** /**
@ -52,7 +51,8 @@ public interface CommandHandler {
String target = switch (annotation.targetRequirement()) { String target = switch (annotation.targetRequirement()) {
case NONE -> ""; case NONE -> "";
case OFFLINE -> "@<UID> "; // TODO: make translation keys for offline and online players case OFFLINE -> "@<UID> "; // TODO: make translation keys for offline and online players
case ONLINE -> (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>] "; case PLAYER -> (player == null) ? "@<UID> " : "[@<UID>] ";
}; };
String[] usages = annotation.usage(); String[] usages = annotation.usage();
@ -81,8 +81,9 @@ public interface CommandHandler {
/** /**
* Called when a player/console invokes a command. * Called when a player/console invokes a command.
*
* @param sender The player/console that invoked the command. * @param sender The player/console that invoked the command.
* @param args The arguments to the command. * @param args The arguments to the command.
*/ */
default void execute(Player sender, Player targetPlayer, List<String> args) { default void execute(Player sender, Player targetPlayer, List<String> args) {
} }

View File

@ -5,23 +5,20 @@ import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.reflections.Reflections; import org.reflections.Reflections;
import java.net.IDN;
import java.util.*; import java.util.*;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.config.Configuration.SERVER; import static emu.grasscutter.config.Configuration.SERVER;
@SuppressWarnings({"UnusedReturnValue", "unused"}) @SuppressWarnings({"UnusedReturnValue", "unused"})
public final class CommandMap { public final class CommandMap {
private static final int INVALID_UID = Integer.MIN_VALUE;
private static final String consoleId = "console";
private final Map<String, CommandHandler> commands = new TreeMap<>(); private final Map<String, CommandHandler> commands = new TreeMap<>();
private final Map<String, CommandHandler> aliases = new TreeMap<>(); private final Map<String, CommandHandler> aliases = new TreeMap<>();
private final Map<String, Command> annotations = new TreeMap<>(); private final Map<String, Command> annotations = new TreeMap<>();
private final Object2IntMap<String> targetPlayerIds = new Object2IntOpenHashMap<>(); private final Object2IntMap<String> targetPlayerIds = new Object2IntOpenHashMap<>();
private static final int INVALID_UID = Integer.MIN_VALUE;
private static final String consoleId = "console";
public CommandMap() { public CommandMap() {
this(false); this(false);
@ -35,6 +32,20 @@ public final class CommandMap {
return Grasscutter.getCommandMap(); return Grasscutter.getCommandMap();
} }
private static int getUidFromString(String input) {
try {
return Integer.parseInt(input);
} catch (NumberFormatException ignored) {
var account = DatabaseHelper.getAccountByName(input);
if (account == null) return INVALID_UID;
var player = DatabaseHelper.getPlayerByAccount(account);
if (player == null) return INVALID_UID;
// We will be immediately fetching the player again after this,
// but offline vs online Player safety is more important than saving a lookup
return player.getUid();
}
}
/** /**
* Register a command handler. * Register a command handler.
* *
@ -52,11 +63,9 @@ public final class CommandMap {
this.commands.put(label, command); this.commands.put(label, command);
// Register aliases. // Register aliases.
if (annotation.aliases().length > 0) { for (String alias : annotation.aliases()) {
for (String alias : annotation.aliases()) { this.aliases.put(alias, command);
this.aliases.put(alias, command); this.annotations.put(alias, annotation);
this.annotations.put(alias, annotation);
}
} }
return this; return this;
} }
@ -78,11 +87,9 @@ public final class CommandMap {
this.commands.remove(label); this.commands.remove(label);
// Unregister aliases. // Unregister aliases.
if (annotation.aliases().length > 0) { for (String alias : annotation.aliases()) {
for (String alias : annotation.aliases()) { this.aliases.remove(alias);
this.aliases.remove(alias); this.annotations.remove(alias);
this.annotations.remove(alias);
}
} }
return this; return this;
@ -124,20 +131,6 @@ public final class CommandMap {
return handler; return handler;
} }
private static int getUidFromString(String input) {
try {
return Integer.parseInt(input);
} catch (NumberFormatException ignored) {
var account = DatabaseHelper.getAccountByName(input);
if (account == null) return INVALID_UID;
var player = DatabaseHelper.getPlayerByAccount(account);
if (player == null) return INVALID_UID;
// We will be immediately fetching the player again after this,
// but offline vs online Player safety is more important than saving a lookup
return player.getUid();
}
}
private Player getTargetPlayer(String playerId, Player player, Player targetPlayer, List<String> args) { private Player getTargetPlayer(String playerId, Player player, Player targetPlayer, List<String> args) {
// Top priority: If any @UID argument is present, override targetPlayer with it. // Top priority: If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {

View File

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

View File

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

View File

@ -45,7 +45,7 @@ public final class AccountCommand implements CommandHandler {
int uid = 0; int uid = 0;
String password = ""; String password = "";
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
if (args.size() < 3) { if (args.size() < 3) {
CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires a password argument"); CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires a password argument");
CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]"); CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]");
@ -58,7 +58,7 @@ public final class AccountCommand implements CommandHandler {
uid = Integer.parseInt(args.get(3)); uid = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid")); CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid"));
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a 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]"); CommandHandler.sendMessage(sender, "Usage: account create <username> <password> [uid]");
} }
@ -81,7 +81,7 @@ public final class AccountCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.exists")); CommandHandler.sendMessage(sender, translate(sender, "commands.account.exists"));
return; return;
} else { } else {
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
account.setPassword(BCrypt.withDefaults().hashToString(12, password.toCharArray())); account.setPassword(BCrypt.withDefaults().hashToString(12, password.toCharArray()));
} }
account.addPermission("*"); account.addPermission("*");
@ -103,7 +103,7 @@ public final class AccountCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.delete")); CommandHandler.sendMessage(sender, translate(sender, "commands.account.delete"));
return; return;
case "resetpass": case "resetpass":
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) { if (!Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage(sender, "resetpass requires EXPERIMENTAL_RealPassword to be true."); CommandHandler.sendMessage(sender, "resetpass requires EXPERIMENTAL_RealPassword to be true.");
return; return;
} }
@ -127,7 +127,6 @@ public final class AccountCommand implements CommandHandler {
toUpdate.setPassword(BCrypt.withDefaults().hashToString(12, args.get(2).toCharArray())); toUpdate.setPassword(BCrypt.withDefaults().hashToString(12, args.get(2).toCharArray()));
toUpdate.save(); toUpdate.save();
CommandHandler.sendMessage(sender, "Password Updated."); CommandHandler.sendMessage(sender, "Password Updated.");
return;
} }
} }

View File

@ -21,71 +21,6 @@ import java.util.concurrent.atomic.AtomicInteger;
targetRequirement = Command.TargetRequirement.PLAYER, targetRequirement = Command.TargetRequirement.PLAYER,
threading = true) threading = true)
public class AchievementCommand implements CommandHandler { public class AchievementCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
this.sendUsageMessage(sender);
return;
}
var command = args.remove(0).toLowerCase();
var achievements = Achievements.getByPlayer(targetPlayer);
switch (command) {
case "grant" -> this.grant(sender, targetPlayer, achievements, args);
case "revoke" -> this.revoke(sender, targetPlayer, achievements, args);
case "progress" -> this.progress(sender, targetPlayer, achievements, args);
case "grantall" -> grantAll(sender, targetPlayer, achievements);
case "revokeall" -> revokeAll(sender, targetPlayer, achievements);
default -> this.sendUsageMessage(sender);
}
}
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 -> {
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());
}
}, () -> this.sendUsageMessage(sender));
}
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 -> {
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());
}
}, () -> this.sendUsageMessage(sender));
}
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 -> {
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());
}
}, () -> this.sendUsageMessage(sender));
}, () -> this.sendUsageMessage(sender));
}
private static void sendSuccessMessage(Player sender, String cmd, Object... args) { private static void sendSuccessMessage(Player sender, String cmd, Object... args) {
CommandHandler.sendTranslatedMessage(sender, AchievementControlReturns.Return.SUCCESS.getKey() + cmd, args); CommandHandler.sendTranslatedMessage(sender, AchievementControlReturns.Return.SUCCESS.getKey() + cmd, args);
} }
@ -127,4 +62,72 @@ public class AchievementCommand implements CommandHandler {
sendSuccessMessage(sender, "revokeall", counter.intValue(), targetPlayer.getNickname()); sendSuccessMessage(sender, "revokeall", counter.intValue(), targetPlayer.getNickname());
} }
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
this.sendUsageMessage(sender);
return;
}
var command = args.remove(0).toLowerCase();
var achievements = Achievements.getByPlayer(targetPlayer);
switch (command) {
case "grant" -> this.grant(sender, targetPlayer, achievements, args);
case "revoke" -> this.revoke(sender, targetPlayer, achievements, args);
case "progress" -> this.progress(sender, targetPlayer, achievements, args);
case "grantall" -> grantAll(sender, targetPlayer, achievements);
case "revokeall" -> revokeAll(sender, targetPlayer, achievements);
default -> this.sendUsageMessage(sender);
}
}
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 -> {
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());
}
}, () -> this.sendUsageMessage(sender));
}
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 -> {
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());
}
}, () -> this.sendUsageMessage(sender));
}
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 -> {
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());
}
}, () -> this.sendUsageMessage(sender));
}, () -> this.sendUsageMessage(sender));
}
} }

View File

@ -1,13 +1,13 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import java.util.List;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import java.util.List;
@Command( @Command(
label = "ban", label = "ban",
usage = {"[<time> [<reason>]]"}, usage = {"[<time> [<reason>]]"},

View File

@ -29,28 +29,22 @@ public final class ClearCommand implements CommandHandler {
Map.entry(rankRegex, ClearItemParameters::setRank) Map.entry(rankRegex, ClearItemParameters::setRank)
); );
private static class ClearItemParameters {
@Setter public int lvl = 1;
@Setter public int refinement = 1;
@Setter public int rank = 4;
}
private Stream<GameItem> getOther(ItemType type, Inventory playerInventory, ClearItemParameters param) { private Stream<GameItem> getOther(ItemType type, Inventory playerInventory, ClearItemParameters param) {
return playerInventory.getItems().values().stream() return playerInventory.getItems().values().stream()
.filter(item -> item.getItemType() == type) .filter(item -> item.getItemType() == type)
.filter(item -> item.getItemData().getRankLevel() <= param.rank) .filter(item -> item.getItemData().getRankLevel() <= param.rank)
.filter(item -> !item.isLocked() && !item.isEquipped()); .filter(item -> !item.isLocked() && !item.isEquipped());
} }
private Stream<GameItem> getWeapons(Inventory playerInventory, ClearItemParameters param) { private Stream<GameItem> getWeapons(Inventory playerInventory, ClearItemParameters param) {
return getOther(ItemType.ITEM_WEAPON, playerInventory, param) return getOther(ItemType.ITEM_WEAPON, playerInventory, param)
.filter(item -> item.getLevel() <= param.lvl) .filter(item -> item.getLevel() <= param.lvl)
.filter(item -> item.getRefinement() < param.refinement); .filter(item -> item.getRefinement() < param.refinement);
} }
private Stream<GameItem> getRelics(Inventory playerInventory, ClearItemParameters param) { private Stream<GameItem> getRelics(Inventory playerInventory, ClearItemParameters param) {
return getOther(ItemType.ITEM_RELIQUARY, playerInventory, param) return getOther(ItemType.ITEM_RELIQUARY, playerInventory, param)
.filter(item -> item.getLevel() <= param.lvl + 1); .filter(item -> item.getLevel() <= param.lvl + 1);
} }
@Override @Override
@ -97,4 +91,13 @@ 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;
}
} }

View File

@ -5,7 +5,6 @@ import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.excels.AvatarData; import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.data.excels.AvatarSkillDepotData;
import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.data.excels.ReliquaryAffixData; import emu.grasscutter.data.excels.ReliquaryAffixData;
import emu.grasscutter.data.excels.ReliquaryMainPropData; import emu.grasscutter.data.excels.ReliquaryMainPropData;
@ -36,14 +35,6 @@ import static emu.grasscutter.command.CommandHelpers.*;
permissionTargeted = "player.give.others", permissionTargeted = "player.give.others",
threading = true) threading = true)
public final class GiveCommand implements CommandHandler { public final class GiveCommand implements CommandHandler {
private enum GiveAllType {
NONE,
ALL,
WEAPONS,
MATS,
AVATARS
}
private static final Map<Pattern, BiConsumer<GiveItemParameters, Integer>> intCommandHandlers = Map.ofEntries( private static final Map<Pattern, BiConsumer<GiveItemParameters, Integer>> intCommandHandlers = Map.ofEntries(
Map.entry(lvlRegex, GiveItemParameters::setLvl), Map.entry(lvlRegex, GiveItemParameters::setLvl),
Map.entry(refineRegex, GiveItemParameters::setRefinement), Map.entry(refineRegex, GiveItemParameters::setRefinement),
@ -51,168 +42,18 @@ public final class GiveCommand implements CommandHandler {
Map.entry(constellationRegex, GiveItemParameters::setConstellation), Map.entry(constellationRegex, GiveItemParameters::setConstellation),
Map.entry(skillLevelRegex, GiveItemParameters::setSkillLevel) Map.entry(skillLevelRegex, GiveItemParameters::setSkillLevel)
); );
private static final SparseSet illegalWeaponIds = new SparseSet("""
private static class GiveItemParameters { 10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509,
public int id; 13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
@Setter public int lvl = 0; """);
@Setter public int amount = 1; private static final SparseSet illegalRelicIds = new SparseSet("""
@Setter public int refinement = 1; 20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554
@Setter public int constellation = -1; """);
@Setter public int skillLevel = 1; private static final SparseSet illegalItemIds = new SparseSet("""
public int mainPropId = -1; 100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000,
public List<Integer> appendPropIdList; 105001, 105004, 106000-107000, 107011, 108000, 109000-110000,
public ItemData data; 115000-130000, 200200-200899, 220050, 220054
public AvatarData avatarData; """);
public GiveAllType giveAllType = GiveAllType.NONE;
}
private GiveItemParameters parseArgs(Player sender, List<String> args) throws IllegalArgumentException {
GiveItemParameters param = new GiveItemParameters();
// Extract any tagged arguments (e.g. "lv90", "x100", "r5")
parseIntParameters(args, param, intCommandHandlers);
// At this point, first remaining argument MUST be itemId/avatarId
if (args.size() < 1) {
sendUsageMessage(sender); // Reachable if someone does `/give lv90` or similar
throw new IllegalArgumentException();
}
String id = args.remove(0);
boolean isRelic = false;
switch (id) {
case "all":
param.giveAllType = GiveAllType.ALL;
break;
case "weapons":
param.giveAllType = GiveAllType.WEAPONS;
break;
case "mats":
param.giveAllType = GiveAllType.MATS;
break;
case "avatars":
param.giveAllType = GiveAllType.AVATARS;
break;
default:
try {
param.id = Integer.parseInt(id);
} catch (NumberFormatException e) {
// TODO: Parse from item name using GM Handbook.
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.itemId");
throw e;
}
param.data = GameData.getItemDataMap().get(param.id);
if ((param.id > 10_000_000) && (param.id < 12_000_000))
param.avatarData = GameData.getAvatarDataMap().get(param.id);
else if ((param.id > 1000) && (param.id < 1100))
param.avatarData = GameData.getAvatarDataMap().get(param.id - 1000 + 10_000_000);
isRelic = ((param.data != null) && (param.data.getItemType() == ItemType.ITEM_RELIQUARY));
if (!isRelic && !args.isEmpty() && (param.amount == 1)) { // A concession for the people that truly hate [x<amount>].
try {
param.amount = Integer.parseInt(args.remove(0));
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.amount");
throw e;
}
}
}
if (param.amount < 1) param.amount = 1;
if (param.refinement < 1) param.refinement = 1;
if (param.refinement > 5) param.refinement = 5;
if (isRelic) {
// Input 0-20 to match game, instead of 1-21 which is the real level
if (param.lvl < 0) param.lvl = 0;
if (param.lvl > 20) param.lvl = 20;
param.lvl += 1;
if (illegalRelicIds.contains(param.id))
CommandHandler.sendTranslatedMessage(sender, "commands.give.illegal_relic");
} else {
// Suitable for Avatars and Weapons
if (param.lvl < 1) param.lvl = 1;
if (param.lvl > 90) param.lvl = 90;
}
if (!args.isEmpty()) {
if (isRelic) {
try {
parseRelicArgs(param, args);
} catch (IllegalArgumentException e) {
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
CommandHandler.sendTranslatedMessage(sender, "commands.give.usage_relic");
throw e;
}
} else {
sendUsageMessage(sender);
throw new IllegalArgumentException();
}
}
return param;
}
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) { // *No args*
sendUsageMessage(sender);
return;
}
try {
GiveItemParameters param = parseArgs(sender, args);
switch (param.giveAllType) {
case ALL:
giveAll(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case WEAPONS:
giveAllWeapons(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case MATS:
giveAllMats(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case AVATARS:
giveAllAvatars(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case NONE:
break;
}
// Check if this is an avatar
if (param.avatarData != null) {
Avatar avatar = makeAvatar(param);
targetPlayer.addAvatar(avatar);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_avatar", param.id, param.lvl, targetPlayer.getUid());
return;
}
// If it's not an avatar, it needs to be a valid item
if (param.data == null) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.itemId");
return;
}
switch (param.data.getItemType()) {
case ITEM_WEAPON:
targetPlayer.getInventory().addItems(makeUnstackableItems(param), ActionReason.SubfieldDrop);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_with_level_and_refinement", param.id, param.lvl, param.refinement, param.amount, targetPlayer.getUid());
return;
case ITEM_RELIQUARY:
targetPlayer.getInventory().addItems(makeArtifacts(param), ActionReason.SubfieldDrop);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_level", param.id, param.lvl, param.amount, targetPlayer.getUid());
return;
default:
targetPlayer.getInventory().addItem(new GameItem(param.data, param.amount), ActionReason.SubfieldDrop);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given", param.amount, param.id, targetPlayer.getUid());
return;
}
} catch (IllegalArgumentException ignored) {
return;
}
}
private static Avatar makeAvatar(GiveItemParameters param) { private static Avatar makeAvatar(GiveItemParameters param) {
return makeAvatar(param.avatarData, param.lvl, Avatar.getMinPromoteLevel(param.lvl), param.constellation, param.skillLevel); return makeAvatar(param.avatarData, param.lvl, Avatar.getMinPromoteLevel(param.lvl), param.constellation, param.skillLevel);
@ -231,7 +72,8 @@ public final class GiveCommand implements CommandHandler {
private static void giveAllAvatars(Player player, GiveItemParameters param) { private static void giveAllAvatars(Player player, GiveItemParameters param) {
int promoteLevel = Avatar.getMinPromoteLevel(param.lvl); int promoteLevel = Avatar.getMinPromoteLevel(param.lvl);
if (param.constellation < 0 || param.constellation > 6) param.constellation = 6; // constellation's default is -1 so if no parameters set for constellations it'll automatically be 6 if (param.constellation < 0 || param.constellation > 6)
param.constellation = 6; // constellation's default is -1 so if no parameters set for constellations it'll automatically be 6
for (AvatarData avatarData : GameData.getAvatarDataMap().values()) { for (AvatarData avatarData : GameData.getAvatarDataMap().values()) {
int id = avatarData.getId(); int id = avatarData.getId();
if (id < 10000002 || id >= 11000000) continue; // Exclude test avatars if (id < 10000002 || id >= 11000000) continue; // Exclude test avatars
@ -276,7 +118,7 @@ public final class GiveCommand implements CommandHandler {
GameItem item = new GameItem(param.data); GameItem item = new GameItem(param.data);
item.setLevel(param.lvl); item.setLevel(param.lvl);
item.setTotalExp(totalExp); item.setTotalExp(totalExp);
int numAffixes = param.data.getAppendPropNum() + (param.lvl-1)/4; int numAffixes = param.data.getAppendPropNum() + (param.lvl - 1) / 4;
if (param.mainPropId > 0) // Keep random mainProp if we didn't specify one if (param.mainPropId > 0) // Keep random mainProp if we didn't specify one
item.setMainPropId(param.mainPropId); item.setMainPropId(param.mainPropId);
if (param.appendPropIdList != null) { if (param.appendPropIdList != null) {
@ -431,18 +273,176 @@ public final class GiveCommand implements CommandHandler {
giveAllWeapons(player, param); giveAllWeapons(player, param);
} }
private static final SparseSet illegalWeaponIds = new SparseSet(""" private GiveItemParameters parseArgs(Player sender, List<String> args) throws IllegalArgumentException {
10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509, GiveItemParameters param = new GiveItemParameters();
13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
""");
private static final SparseSet illegalRelicIds = new SparseSet(""" // Extract any tagged arguments (e.g. "lv90", "x100", "r5")
20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554 parseIntParameters(args, param, intCommandHandlers);
""");
private static final SparseSet illegalItemIds = new SparseSet(""" // At this point, first remaining argument MUST be itemId/avatarId
100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000, if (args.size() < 1) {
105001, 105004, 106000-107000, 107011, 108000, 109000-110000, sendUsageMessage(sender); // Reachable if someone does `/give lv90` or similar
115000-130000, 200200-200899, 220050, 220054 throw new IllegalArgumentException();
"""); }
String id = args.remove(0);
boolean isRelic = false;
switch (id) {
case "all":
param.giveAllType = GiveAllType.ALL;
break;
case "weapons":
param.giveAllType = GiveAllType.WEAPONS;
break;
case "mats":
param.giveAllType = GiveAllType.MATS;
break;
case "avatars":
param.giveAllType = GiveAllType.AVATARS;
break;
default:
try {
param.id = Integer.parseInt(id);
} catch (NumberFormatException e) {
// TODO: Parse from item name using GM Handbook.
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.itemId");
throw e;
}
param.data = GameData.getItemDataMap().get(param.id);
if ((param.id > 10_000_000) && (param.id < 12_000_000))
param.avatarData = GameData.getAvatarDataMap().get(param.id);
else if ((param.id > 1000) && (param.id < 1100))
param.avatarData = GameData.getAvatarDataMap().get(param.id - 1000 + 10_000_000);
isRelic = ((param.data != null) && (param.data.getItemType() == ItemType.ITEM_RELIQUARY));
if (!isRelic && !args.isEmpty() && (param.amount == 1)) { // A concession for the people that truly hate [x<amount>].
try {
param.amount = Integer.parseInt(args.remove(0));
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.amount");
throw e;
}
}
}
if (param.amount < 1) param.amount = 1;
if (param.refinement < 1) param.refinement = 1;
if (param.refinement > 5) param.refinement = 5;
if (isRelic) {
// Input 0-20 to match game, instead of 1-21 which is the real level
if (param.lvl < 0) param.lvl = 0;
if (param.lvl > 20) param.lvl = 20;
param.lvl += 1;
if (illegalRelicIds.contains(param.id))
CommandHandler.sendTranslatedMessage(sender, "commands.give.illegal_relic");
} else {
// Suitable for Avatars and Weapons
if (param.lvl < 1) param.lvl = 1;
if (param.lvl > 90) param.lvl = 90;
}
if (!args.isEmpty()) {
if (isRelic) {
try {
parseRelicArgs(param, args);
} catch (IllegalArgumentException e) {
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
CommandHandler.sendTranslatedMessage(sender, "commands.give.usage_relic");
throw e;
}
} else {
sendUsageMessage(sender);
throw new IllegalArgumentException();
}
}
return param;
}
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) { // *No args*
sendUsageMessage(sender);
return;
}
try {
GiveItemParameters param = parseArgs(sender, args);
switch (param.giveAllType) {
case ALL:
giveAll(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case WEAPONS:
giveAllWeapons(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case MATS:
giveAllMats(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case AVATARS:
giveAllAvatars(targetPlayer, param);
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
return;
case NONE:
break;
}
// Check if this is an avatar
if (param.avatarData != null) {
Avatar avatar = makeAvatar(param);
targetPlayer.addAvatar(avatar);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_avatar", param.id, param.lvl, targetPlayer.getUid());
return;
}
// If it's not an avatar, it needs to be a valid item
if (param.data == null) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.itemId");
return;
}
switch (param.data.getItemType()) {
case ITEM_WEAPON:
targetPlayer.getInventory().addItems(makeUnstackableItems(param), ActionReason.SubfieldDrop);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_with_level_and_refinement", param.id, param.lvl, param.refinement, param.amount, targetPlayer.getUid());
return;
case ITEM_RELIQUARY:
targetPlayer.getInventory().addItems(makeArtifacts(param), ActionReason.SubfieldDrop);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_level", param.id, param.lvl, param.amount, targetPlayer.getUid());
return;
default:
targetPlayer.getInventory().addItem(new GameItem(param.data, param.amount), ActionReason.SubfieldDrop);
CommandHandler.sendTranslatedMessage(sender, "commands.give.given", param.amount, param.id, targetPlayer.getUid());
}
} catch (IllegalArgumentException ignored) {
}
}
private enum GiveAllType {
NONE,
ALL,
WEAPONS,
MATS,
AVATARS
}
private static class GiveItemParameters {
public int id;
@Setter
public int lvl = 0;
@Setter
public int amount = 1;
@Setter
public int refinement = 1;
@Setter
public int constellation = -1;
@Setter
public int skillLevel = 1;
public int mainPropId = -1;
public List<Integer> appendPropIdList;
public ItemData data;
public AvatarData avatarData;
public GiveAllType giveAllType = GiveAllType.NONE;
}
} }

View File

@ -19,8 +19,8 @@ public final class HealCommand implements CommandHandler {
targetPlayer.getTeamManager().getActiveTeam().forEach(entity -> { targetPlayer.getTeamManager().getActiveTeam().forEach(entity -> {
boolean isAlive = entity.isAlive(); boolean isAlive = entity.isAlive();
entity.setFightProperty( entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP, FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)
); );
entity.getWorld().broadcastPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); entity.getWorld().broadcastPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
if (!isAlive) { if (!isAlive) {

View File

@ -6,7 +6,8 @@ import emu.grasscutter.command.CommandMap;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;

View File

@ -39,8 +39,8 @@ public final class KillAllCommand implements CommandHandler {
// Separate into list to avoid concurrency issue // Separate into list to avoid concurrency issue
final Scene sceneF = scene; final Scene sceneF = scene;
List<GameEntity> toKill = sceneF.getEntities().values().stream() List<GameEntity> toKill = sceneF.getEntities().values().stream()
.filter(entity -> entity instanceof EntityMonster) .filter(entity -> entity instanceof EntityMonster)
.toList(); .toList();
toKill.forEach(entity -> sceneF.killEntity(entity, 0)); toKill.forEach(entity -> sceneF.killEntity(entity, 0));
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", toKill.size(), scene.getId())); CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", toKill.size(), scene.getId()));
} }

View File

@ -20,8 +20,7 @@ public final class LanguageCommand implements CommandHandler {
String curLangCode = null; String curLangCode = null;
if (sender != null) { if (sender != null) {
curLangCode = Utils.getLanguageCode(sender.getAccount().getLocale()); curLangCode = Utils.getLanguageCode(sender.getAccount().getLocale());
} } else {
else {
curLangCode = Grasscutter.getLanguage().getLanguageCode(); curLangCode = Grasscutter.getLanguage().getLanguageCode();
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.language.current_language", curLangCode)); CommandHandler.sendMessage(sender, translate(sender, "commands.language.current_language", curLangCode));
@ -37,8 +36,7 @@ public final class LanguageCommand implements CommandHandler {
var account = sender.getAccount(); var account = sender.getAccount();
account.setLocale(locale); account.setLocale(locale);
account.save(); account.save();
} } else {
else {
Grasscutter.setLanguage(languageInst); Grasscutter.setLanguage(languageInst);
var config = Grasscutter.getConfig(); var config = Grasscutter.getConfig();
config.language.language = locale; config.language.language = locale;

View File

@ -34,12 +34,12 @@ public final class ListCommand implements CommandHandler {
if (finalNeedUID) { if (finalNeedUID) {
if (sender != null) { if (sender != null) {
playerSet.append(" <color=green>(") playerSet.append(" <color=green>(")
.append(player.getUid()) .append(player.getUid())
.append(")</color>"); .append(")</color>");
} else { } else {
playerSet.append(" (") playerSet.append(" (")
.append(player.getUid()) .append(player.getUid())
.append(")"); .append(")");
} }
} }

View File

@ -2,8 +2,8 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.Command.TargetRequirement; import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;

View File

@ -15,6 +15,6 @@ public final class PositionCommand implements CommandHandler {
Position pos = targetPlayer.getPosition(); Position pos = targetPlayer.getPosition();
Position rot = targetPlayer.getRotation(); Position rot = targetPlayer.getRotation();
CommandHandler.sendTranslatedMessage(sender, "commands.position.success", CommandHandler.sendTranslatedMessage(sender, "commands.position.success",
pos.getX(), pos.getY(), pos.getZ(), rot.getX(), rot.getY(), rot.getZ(), targetPlayer.getSceneId()); pos.getX(), pos.getY(), pos.getZ(), rot.getX(), rot.getY(), rot.getZ(), targetPlayer.getSceneId());
} }
} }

View File

@ -10,10 +10,10 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "quest", @Command(label = "quest",
aliases = {"q"}, aliases = {"q"},
usage = {"(add|finish) [<questId>]"}, usage = {"(add|finish) [<questId>]"},
permission = "player.quest", permission = "player.quest",
permissionTargeted = "player.quest.others") permissionTargeted = "player.quest.others")
public final class QuestCommand implements CommandHandler { public final class QuestCommand implements CommandHandler {
@Override @Override

View File

@ -1,6 +1,5 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;

View File

@ -71,7 +71,6 @@ public final class SendMailCommand implements CommandHandler {
case "stop" -> { case "stop" -> {
mailBeingConstructed.remove(senderId); mailBeingConstructed.remove(senderId);
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_cancel")); CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_cancel"));
return;
} }
case "finish" -> { case "finish" -> {
if (mailBuilder.constructionStage == 3) { if (mailBuilder.constructionStage == 3) {
@ -89,11 +88,9 @@ public final class SendMailCommand implements CommandHandler {
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage, sender))); CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage, sender)));
} }
return;
} }
case "help" -> { case "help" -> {
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage, sender))); CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage, sender)));
return;
} }
default -> { default -> {
switch (mailBuilder.constructionStage) { switch (mailBuilder.constructionStage) {

View File

@ -2,8 +2,8 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.Command.TargetRequirement; import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;

View File

@ -7,7 +7,7 @@ import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
@ -45,8 +45,7 @@ public final class SetConstCommand implements CommandHandler {
if (args.size() > 1 && args.get(1).equalsIgnoreCase("all")) { if (args.size() > 1 && args.get(1).equalsIgnoreCase("all")) {
this.setAllConstellation(targetPlayer, constLevel); this.setAllConstellation(targetPlayer, constLevel);
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.successall", constLevel); CommandHandler.sendTranslatedMessage(sender, "commands.setConst.successall", constLevel);
} } else sendUsageMessage(sender);
else sendUsageMessage(sender);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.level_error"); CommandHandler.sendTranslatedMessage(sender, "commands.setConst.level_error");
} }
@ -69,10 +68,10 @@ public final class SetConstCommand implements CommandHandler {
private void setAllConstellation(Player player, int constLevel) { private void setAllConstellation(Player player, int constLevel) {
player.getAvatars().forEach(avatar -> { player.getAvatars().forEach(avatar -> {
avatar.forceConstellationLevel(constLevel); avatar.forceConstellationLevel(constLevel);
avatar.recalcConstellations(); avatar.recalcConstellations();
avatar.recalcStats(true); avatar.recalcStats(true);
avatar.save(); avatar.save();
}); });
// Just reload scene once, shorter than having to check for each constLevel < currentConstLevel // Just reload scene once, shorter than having to check for each constLevel < currentConstLevel
this.reloadScene(player); this.reloadScene(player);

View File

@ -1,7 +1,5 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import java.util.List;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
@ -9,6 +7,8 @@ import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify; import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify;
import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command( @Command(

View File

@ -1,9 +1,5 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
@ -14,49 +10,14 @@ import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify; import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify;
import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify; import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
import java.util.HashMap;
import java.util.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 { public final class SetPropCommand implements CommandHandler {
static enum PseudoProp { // List of map areas. Unfortunately, there is no readily available source for them in excels or bins.
NONE, 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);
WORLD_LEVEL,
TOWER_LEVEL,
BP_LEVEL,
GOD_MODE,
UNLIMITED_STAMINA,
UNLIMITED_ENERGY,
SET_OPENSTATE,
UNSET_OPENSTATE,
UNLOCK_MAP
}
static class Prop {
String name;
PlayerProperty prop;
PseudoProp pseudoProp;
public Prop(PlayerProperty prop) {
this(prop.toString(), prop, PseudoProp.NONE);
}
public Prop(String name) {
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
}
public Prop(String name, PseudoProp pseudoProp) {
this(name, PlayerProperty.PROP_NONE, pseudoProp);
}
public Prop(String name, PlayerProperty prop) {
this(name, prop, PseudoProp.NONE);
}
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
this.name = name;
this.prop = prop;
this.pseudoProp = pseudoProp;
}
}
Map<String, Prop> props; Map<String, Prop> props;
public SetPropCommand() { public SetPropCommand() {
@ -146,7 +107,8 @@ public final class SetPropCommand implements CommandHandler {
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value); case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value); case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value); case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> 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 SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0); case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
case UNLOCK_MAP -> unlockMap(targetPlayer); case UNLOCK_MAP -> unlockMap(targetPlayer);
@ -185,9 +147,7 @@ public final class SetPropCommand implements CommandHandler {
} }
// Remove records for each floor past our target // Remove records for each floor past our target
for (int floor : floorIds.subList(topFloor, floorIds.size())) { for (int floor : floorIds.subList(topFloor, floorIds.size())) {
if (recordMap.containsKey(floor)) { recordMap.remove(floor);
recordMap.remove(floor);
}
} }
// Six stars required on Floor 8 to unlock Floor 9+ // Six stars required on Floor 8 to unlock Floor 9+
if (topFloor > 8) { if (topFloor > 8) {
@ -230,8 +190,6 @@ public final class SetPropCommand implements CommandHandler {
return true; return true;
} }
// List of map areas. Unfortunately, there is no readily available source for them in excels or bins.
final static private 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);
private boolean unlockMap(Player targetPlayer) { private boolean unlockMap(Player targetPlayer) {
// Unlock. // Unlock.
GameData.getScenePointsPerScene().forEach((sceneId, scenePoints) -> { GameData.getScenePointsPerScene().forEach((sceneId, scenePoints) -> {
@ -248,4 +206,45 @@ public final class SetPropCommand implements CommandHandler {
targetPlayer.sendPacket(new PacketSceneAreaUnlockNotify(playerScene, targetPlayer.getUnlockedSceneAreas(playerScene))); targetPlayer.sendPacket(new PacketSceneAreaUnlockNotify(playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
return true; return true;
} }
enum PseudoProp {
NONE,
WORLD_LEVEL,
TOWER_LEVEL,
BP_LEVEL,
GOD_MODE,
UNLIMITED_STAMINA,
UNLIMITED_ENERGY,
SET_OPENSTATE,
UNSET_OPENSTATE,
UNLOCK_MAP
}
static class Prop {
String name;
PlayerProperty prop;
PseudoProp pseudoProp;
public Prop(PlayerProperty prop) {
this(prop.toString(), prop, PseudoProp.NONE);
}
public Prop(String name) {
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
}
public Prop(String name, PseudoProp pseudoProp) {
this(name, PlayerProperty.PROP_NONE, pseudoProp);
}
public Prop(String name, PlayerProperty prop) {
this(name, prop, PseudoProp.NONE);
}
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
this.name = name;
this.prop = prop;
this.pseudoProp = pseudoProp;
}
}
} }

View File

@ -1,9 +1,5 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
@ -12,6 +8,10 @@ import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Command( @Command(
label = "setStats", label = "setStats",
aliases = {"stats", "stat"}, aliases = {"stats", "stat"},
@ -22,34 +22,7 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
permission = "player.setstats", permission = "player.setstats",
permissionTargeted = "player.setstats.others") permissionTargeted = "player.setstats.others")
public final class SetStatsCommand implements CommandHandler { public final class SetStatsCommand implements CommandHandler {
private static class Stat { private final Map<String, Stat> stats;
String name;
FightProperty prop;
public Stat(FightProperty prop) {
this.name = prop.toString();
this.prop = prop;
}
public Stat(String name, FightProperty prop) {
this.name = name;
this.prop = prop;
}
}
private static enum Action {
ACTION_SET("commands.generic.set_to", "commands.generic.set_for_to"),
ACTION_LOCK("commands.setStats.locked_to", "commands.setStats.locked_for_to"),
ACTION_UNLOCK("commands.setStats.unlocked", "commands.setStats.unlocked_for");
public final String messageKeySelf;
public final String messageKeyOther;
private Action(String messageKeySelf, String messageKeyOther) {
this.messageKeySelf = messageKeySelf;
this.messageKeyOther = messageKeyOther;
}
}
private Map<String, Stat> stats;
public SetStatsCommand() { public SetStatsCommand() {
this.stats = new HashMap<>(); this.stats = new HashMap<>();
@ -86,7 +59,7 @@ public final class SetStatsCommand implements CommandHandler {
public static float parsePercent(String input) throws NumberFormatException { public static float parsePercent(String input) throws NumberFormatException {
if (input.endsWith("%")) { if (input.endsWith("%")) {
return Float.parseFloat(input.substring(0, input.length()-1))/100f; return Float.parseFloat(input.substring(0, input.length() - 1)) / 100f;
} else { } else {
return Float.parseFloat(input); return Float.parseFloat(input);
} }
@ -106,7 +79,10 @@ public final class SetStatsCommand implements CommandHandler {
// Get the action and stat // Get the action and stat
String arg0 = args.remove(0).toLowerCase(); String arg0 = args.remove(0).toLowerCase();
Action action = switch (arg0) { Action action = switch (arg0) {
default -> {statStr = arg0; yield Action.ACTION_SET;} // Implicit set command default -> {
statStr = arg0;
yield Action.ACTION_SET;
} // Implicit set command
case "set" -> Action.ACTION_SET; // Explicit set command case "set" -> Action.ACTION_SET; // Explicit set command
case "lock", "freeze" -> Action.ACTION_LOCK; case "lock", "freeze" -> Action.ACTION_LOCK;
case "unlock", "unfreeze" -> Action.ACTION_UNLOCK; case "unlock", "unfreeze" -> Action.ACTION_UNLOCK;
@ -176,6 +152,33 @@ public final class SetStatsCommand implements CommandHandler {
String uidStr = targetPlayer.getAccount().getId(); String uidStr = targetPlayer.getAccount().getId();
CommandHandler.sendTranslatedMessage(sender, action.messageKeyOther, stat.name, uidStr, valueStr); CommandHandler.sendTranslatedMessage(sender, action.messageKeyOther, stat.name, uidStr, valueStr);
} }
return; }
private enum Action {
ACTION_SET("commands.generic.set_to", "commands.generic.set_for_to"),
ACTION_LOCK("commands.setStats.locked_to", "commands.setStats.locked_for_to"),
ACTION_UNLOCK("commands.setStats.unlocked", "commands.setStats.unlocked_for");
public final String messageKeySelf;
public final String messageKeyOther;
Action(String messageKeySelf, String messageKeyOther) {
this.messageKeySelf = messageKeySelf;
this.messageKeyOther = messageKeyOther;
}
}
private static class Stat {
String name;
FightProperty prop;
public Stat(FightProperty prop) {
this.name = prop.toString();
this.prop = prop;
}
public Stat(String name, FightProperty prop) {
this.name = name;
this.prop = prop;
}
} }
} }

View File

@ -124,8 +124,6 @@ public final class SpawnCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", param.amount, param.id)); CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", param.amount, param.id));
} }
;
private EntityItem createItem(ItemData itemData, SpawnParameters param, Position pos) { private EntityItem createItem(ItemData itemData, SpawnParameters param, Position pos) {
return new EntityItem(param.scene, null, itemData, pos, 1, true); return new EntityItem(param.scene, null, itemData, pos, 1, true);
} }
@ -188,19 +186,32 @@ public final class SpawnCommand implements CommandHandler {
} }
private static class SpawnParameters { private static class SpawnParameters {
@Setter public int id; @Setter
@Setter public int lvl = 1; public int id;
@Setter public int amount = 1; @Setter
@Setter public int blockId = -1; public int lvl = 1;
@Setter public int groupId = -1; @Setter
@Setter public int configId = -1; public int amount = 1;
@Setter public int state = -1; @Setter
@Setter public int hp = -1; public int blockId = -1;
@Setter public int maxHP = -1; @Setter
@Setter public int atk = -1; public int groupId = -1;
@Setter public int def = -1; @Setter
@Setter public int ai = -1; public int configId = -1;
@Setter public Position pos = null; @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; public Scene scene = null;
} }
} }

View File

@ -46,7 +46,6 @@ public final class TalentCommand implements CommandHandler {
switch (cmdSwitch) { switch (cmdSwitch) {
default -> { default -> {
sendUsageMessage(sender); sendUsageMessage(sender);
return;
} }
case "set" -> { case "set" -> {
if (args.size() < 3) { if (args.size() < 3) {

View File

@ -5,12 +5,11 @@ import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp; import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp;
import java.util.List;
import static emu.grasscutter.config.Configuration.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
@Command( @Command(
label = "team", label = "team",
@ -47,7 +46,7 @@ public final class TeamCommand implements CommandHandler {
} }
targetPlayer.getTeamManager().updateTeamEntities( targetPlayer.getTeamManager().updateTeamEntities(
new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo())); new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo()));
} }
private boolean addCommand(Player sender, Player targetPlayer, List<String> args) { private boolean addCommand(Player sender, Player targetPlayer, List<String> args) {
@ -76,7 +75,7 @@ public final class TeamCommand implements CommandHandler {
return false; return false;
} }
for (var avatarId: avatarIds) { for (var avatarId : avatarIds) {
int id = Integer.parseInt(avatarId); int id = Integer.parseInt(avatarId);
if (!addAvatar(sender, targetPlayer, id, index)) if (!addAvatar(sender, targetPlayer, id, index))
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_add_avatar", avatarId); CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_add_avatar", avatarId);
@ -98,7 +97,7 @@ public final class TeamCommand implements CommandHandler {
var metaIndexList = args.get(1).split(","); var metaIndexList = args.get(1).split(",");
var indexes = new HashSet<Integer>(); var indexes = new HashSet<Integer>();
var ignoreList = new ArrayList<Integer>(); var ignoreList = new ArrayList<Integer>();
for (var metaIndex: metaIndexList) { for (var metaIndex : metaIndexList) {
// step 1: parse metaIndex to indexes // step 1: parse metaIndex to indexes
var subIndexes = transformToIndexes(metaIndex, avatarCount); var subIndexes = transformToIndexes(metaIndex, avatarCount);
if (subIndexes == null) { if (subIndexes == null) {
@ -107,7 +106,7 @@ public final class TeamCommand implements CommandHandler {
} }
// step 2: get all of the avatar id through indexes // step 2: get all of the avatar id through indexes
for (var avatarIndex: subIndexes) { for (var avatarIndex : subIndexes) {
try { try {
indexes.add(currentTeamAvatars.get(avatarIndex - 1)); indexes.add(currentTeamAvatars.get(avatarIndex - 1));
} catch (Exception e) { } catch (Exception e) {

View File

@ -36,7 +36,7 @@ public final class TeleportCommand implements CommandHandler {
case 4: case 4:
try { try {
sceneId = Integer.parseInt(args.get(3)); sceneId = Integer.parseInt(args.get(3));
}catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough } // Fallthrough
case 3: case 3:
@ -60,7 +60,7 @@ public final class TeleportCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
} else { } else {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
targetPlayer.getNickname(), x, y, z, sceneId) targetPlayer.getNickname(), x, y, z, sceneId)
); );
} }

View File

@ -1,12 +1,12 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import java.util.List;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List;
@Command( @Command(
label = "unban", label = "unban",
permission = "server.ban", permission = "server.ban",

View File

@ -7,10 +7,10 @@ import emu.grasscutter.Grasscutter.ServerDebugMode;
import emu.grasscutter.Grasscutter.ServerRunMode; import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.utils.JsonUtils; import emu.grasscutter.utils.JsonUtils;
import java.util.Set;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import static emu.grasscutter.Grasscutter.config; import static emu.grasscutter.Grasscutter.config;
@ -18,6 +18,14 @@ import static emu.grasscutter.Grasscutter.config;
* *when your JVM fails* * *when your JVM fails*
*/ */
public class ConfigContainer { public class ConfigContainer {
public Structure folderStructure = new Structure();
public Database databaseInfo = new Database();
public Language language = new Language();
public Account account = new Account();
public Server server = new Server();
// DO NOT. TOUCH. THE VERSION NUMBER.
public int version = version();
private static int version() { private static int version() {
return 4; return 4;
} }
@ -32,7 +40,8 @@ public class ConfigContainer {
Grasscutter.getLogger().info("Updating legacy .."); Grasscutter.getLogger().info("Updating legacy ..");
Grasscutter.saveConfig(null); Grasscutter.saveConfig(null);
} }
} catch (Exception ignored) { } } catch (Exception ignored) {
}
var existing = config.version; var existing = config.version;
var latest = version(); var latest = version();
@ -50,7 +59,8 @@ public class ConfigContainer {
} catch (Exception exception) { } catch (Exception exception) {
Grasscutter.getLogger().error("Failed to update a configuration field.", exception); Grasscutter.getLogger().error("Failed to update a configuration field.", exception);
} }
}); updated.version = version(); });
updated.version = version();
try { // Save configuration & reload. try { // Save configuration & reload.
Grasscutter.saveConfig(updated); Grasscutter.saveConfig(updated);
@ -60,15 +70,6 @@ public class ConfigContainer {
} }
} }
public Structure folderStructure = new Structure();
public Database databaseInfo = new Database();
public Language language = new Language();
public Account account = new Account();
public Server server = new Server();
// DO NOT. TOUCH. THE VERSION NUMBER.
public int version = version();
/* Option containers. */ /* Option containers. */
public static class Database { public static class Database {
@ -174,7 +175,7 @@ public class ConfigContainer {
} }
/* Debug options container, used when jar launch argument is -debug | -debugall and override default values /* Debug options container, used when jar launch argument is -debug | -debugall and override default values
* (see StartupArguments.enableDebug) */ * (see StartupArguments.enableDebug) */
public static class DebugMode { public static class DebugMode {
/* Log level of the main server code (works only with -debug arg) */ /* Log level of the main server code (works only with -debug arg) */
public Level serverLoggerLevel = Level.DEBUG; public Level serverLoggerLevel = Level.DEBUG;
@ -260,16 +261,16 @@ public class ConfigContainer {
public static class Mail { public static class Mail {
public String title = "Welcome to Grasscutter!"; public String title = "Welcome to Grasscutter!";
public String content = """ public String content = """
Hi there!\r Hi there!\r
First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r
\r \r
Check out our:\r Check out our:\r
<type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/> <type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/>
"""; """;
public String sender = "Lawnmower"; public String sender = "Lawnmower";
public emu.grasscutter.game.mail.Mail.MailItem[] items = { public emu.grasscutter.game.mail.Mail.MailItem[] items = {
new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1), new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1),
new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1) new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1)
}; };
} }
} }
@ -292,21 +293,20 @@ public class ConfigContainer {
/* Objects. */ /* Objects. */
public static class Region { public static class Region {
public Region() { }
public Region(
String name, String title,
String address, int port
) {
this.Name = name;
this.Title = title;
this.Ip = address;
this.Port = port;
}
public String Name = "os_usa"; public String Name = "os_usa";
public String Title = "Grasscutter"; public String Title = "Grasscutter";
public String Ip = "127.0.0.1"; public String Ip = "127.0.0.1";
public int Port = 22102; public int Port = 22102;
public Region() {
}
public Region(
String name, String title,
String address, int port
) {
this.Name = name;
this.Title = title;
this.Ip = address;
this.Port = port;
}
} }
} }

View File

@ -10,7 +10,7 @@ import static emu.grasscutter.Grasscutter.config;
/** /**
* A data container for the server's configuration. * A data container for the server's configuration.
* * <p>
* Use `import static emu.grasscutter.Configuration.*;` * Use `import static emu.grasscutter.Configuration.*;`
* to import all configuration constants. * to import all configuration constants.
*/ */
@ -26,26 +26,22 @@ public final class Configuration extends ConfigContainer {
public static final Locale LANGUAGE = config.language.language; public static final Locale LANGUAGE = config.language.language;
public static final Locale FALLBACK_LANGUAGE = config.language.fallback; public static final Locale FALLBACK_LANGUAGE = config.language.fallback;
public static final String DOCUMENT_LANGUAGE = config.language.document; public static final String DOCUMENT_LANGUAGE = config.language.document;
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;
private static final String PACKETS_FOLDER = config.folderStructure.packets;
public static final Server SERVER = config.server; public static final Server SERVER = config.server;
public static final Database DATABASE = config.databaseInfo; public static final Database DATABASE = config.databaseInfo;
public static final Account ACCOUNT = config.account; public static final Account ACCOUNT = config.account;
public static final HTTP HTTP_INFO = config.server.http; public static final HTTP HTTP_INFO = config.server.http;
public static final Game GAME_INFO = config.server.game; public static final Game GAME_INFO = config.server.game;
public static final Dispatch DISPATCH_INFO = config.server.dispatch; public static final Dispatch DISPATCH_INFO = config.server.dispatch;
public static final DebugMode DEBUG_MODE_INFO = config.server.debugMode; public static final DebugMode DEBUG_MODE_INFO = config.server.debugMode;
public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption; public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption;
public static final Policies HTTP_POLICIES = config.server.http.policies; public static final Policies HTTP_POLICIES = config.server.http.policies;
public static final Files HTTP_STATIC_FILES = config.server.http.files; public static final Files HTTP_STATIC_FILES = config.server.http.files;
public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions; public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions;
public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits; public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits;
private static final String DATA_FOLDER = config.folderStructure.data;
private static final String PLUGINS_FOLDER = config.folderStructure.plugins;
private static final String SCRIPTS_FOLDER = config.folderStructure.scripts;
private static final String PACKETS_FOLDER = config.folderStructure.packets;
/* /*
* Utilities * Utilities
@ -91,7 +87,8 @@ public final class Configuration extends ConfigContainer {
/** /**
* Fallback method. * Fallback method.
* @param left Attempt to use. *
* @param left Attempt to use.
* @param right Use if left is undefined. * @param right Use if left is undefined.
* @return Left or right. * @return Left or right.
*/ */
@ -101,7 +98,8 @@ public final class Configuration extends ConfigContainer {
/** /**
* {@link Configuration#lr(Object, Object)} for {@link String}s. * {@link Configuration#lr(Object, Object)} for {@link String}s.
* @param left Attempt to use. *
* @param left Attempt to use.
* @param right Use if left is empty. * @param right Use if left is empty.
* @return Left or right. * @return Left or right.
*/ */
@ -111,7 +109,8 @@ public final class Configuration extends ConfigContainer {
/** /**
* {@link Configuration#lr(Object, Object)} for {@link Integer}s. * {@link Configuration#lr(Object, Object)} for {@link Integer}s.
* @param left Attempt to use. *
* @param left Attempt to use.
* @param right Use if left is 0. * @param right Use if left is 0.
* @return Left or right. * @return Left or right.
*/ */

View File

@ -84,7 +84,7 @@ public class DataLoader {
} }
} }
public static <T1,T2> Map<T1,T2> loadMap(String resourcePath, Class<T1> keyType, Class<T2> valueType) throws IOException { public static <T1, T2> Map<T1, T2> loadMap(String resourcePath, Class<T1> keyType, Class<T2> valueType) throws IOException {
try (InputStreamReader reader = loadReader(resourcePath)) { try (InputStreamReader reader = loadReader(resourcePath)) {
return JsonUtils.loadToMap(reader, keyType, valueType); return JsonUtils.loadToMap(reader, keyType, valueType);
} }
@ -92,7 +92,7 @@ public class DataLoader {
public static <T> List<T> loadTableToList(String resourcePath, Class<T> classType) throws IOException { public static <T> List<T> loadTableToList(String resourcePath, Class<T> classType) throws IOException {
val path = FileUtils.getDataPathTsjJsonTsv(resourcePath); val path = FileUtils.getDataPathTsjJsonTsv(resourcePath);
Grasscutter.getLogger().debug("Loading data table from: "+path); Grasscutter.getLogger().debug("Loading data table from: " + path);
return switch (FileUtils.getFileExtension(path)) { return switch (FileUtils.getFileExtension(path)) {
case "json" -> JsonUtils.loadToList(path, classType); case "json" -> JsonUtils.loadToList(path, classType);
case "tsj" -> TsvUtils.loadTsjToListSetField(path, classType); case "tsj" -> TsvUtils.loadTsjToListSetField(path, classType);

View File

@ -1,116 +1,182 @@
package emu.grasscutter.data; package emu.grasscutter.data;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*; import emu.grasscutter.data.binout.*;
import emu.grasscutter.data.excels.*;
import emu.grasscutter.game.quest.QuestEncryptionKey; import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import emu.grasscutter.data.excels.*; import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.Tolerate; import lombok.experimental.Tolerate;
import java.lang.reflect.Field;
import java.util.*;
public class GameData { public class GameData {
// BinOutputs
@Getter 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<>();
@Deprecated(forRemoval = true) @Getter private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
protected static final Map<String, AbilityData> abilityDataMap = new HashMap<>(); protected static final Map<String, AbilityData> abilityDataMap = new HashMap<>();
protected static final Int2ObjectMap<ScenePointEntry> scenePointEntryMap = new Int2ObjectOpenHashMap<>(); protected static final Int2ObjectMap<ScenePointEntry> scenePointEntryMap = new Int2ObjectOpenHashMap<>();
// BinOutputs
@Getter
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<>();
@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<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<QuestEncryptionKey> questsKeys = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<QuestEncryptionKey> questsKeys = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<SceneNpcBornData> npcBornData = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<SceneNpcBornData> npcBornData = new Int2ObjectOpenHashMap<>();
private static final Map<String, AbilityEmbryoEntry> abilityEmbryos = new HashMap<>(); private static final Map<String, AbilityEmbryoEntry> abilityEmbryos = new HashMap<>();
// ExcelConfigs // ExcelConfigs
@Getter private static final ArrayList<CodexReliquaryData> codexReliquaryArrayList = new ArrayList<>(); @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<>(); @Getter
@Getter private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AchievementGoalData> achievementGoalDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ActivityShopData> activityShopDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataItemIdMap = new Int2ObjectLinkedOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<ActivityShopData> activityShopDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<AvatarData> avatarDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<AvatarFlycloakData> avatarFlycloakDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataItemIdMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarLevelData> avatarLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarData> avatarDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<BlossomRefreshExcelConfigData> blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<BuffData> buffDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarFlycloakData> avatarFlycloakDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarLevelData> avatarLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CookBonusData> cookBonusDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CompoundData> compoundDataMap=new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BlossomRefreshExcelConfigData> blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<ForgeData> forgeDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<BuffData> buffDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<FurnitureMakeConfigData> furnitureMakeConfigDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<GadgetData> gadgetDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<GatherData> gatherDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ItemData> itemDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<MonsterCurveData> monsterCurveDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<MonsterData> monsterDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<MonsterDescribeData> monsterDescribeDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<NpcData> npcDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<OpenStateData> openStateDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<PersonalLineData> personalLineDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<PlayerLevelData> playerLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<QuestData> questDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<ReliquaryAffixData> reliquaryAffixDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CookBonusData> cookBonusDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ReliquaryMainPropData> reliquaryMainPropDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<ReliquarySetData> reliquarySetDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CompoundData> compoundDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<TriggerExcelConfigData> triggerExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<WeaponCurveData> weaponCurveDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<WeaponLevelData> weaponLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<WeaponPromoteData> weaponPromoteDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<WeatherData> weatherDataMap = new Int2ObjectOpenHashMap<>(); @Getter
@Getter private static final Int2ObjectMap<WorldAreaData> worldAreaDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>(); @Getter
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<>();
@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<>();
@Getter
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<ItemData> itemDataMap = new Int2ObjectOpenHashMap<>();
@Getter
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<>();
@Getter
private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<NpcData> npcDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<OpenStateData> openStateDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<PersonalLineData> personalLineDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<PlayerLevelData> playerLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter
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<>();
@Getter
private static final Int2ObjectMap<ReliquaryMainPropData> reliquaryMainPropDataMap = new Int2ObjectOpenHashMap<>();
@Getter
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<>();
@Getter
private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<TriggerExcelConfigData> triggerExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<WeaponCurveData> weaponCurveDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<WeaponLevelData> weaponLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter
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<>();
@Getter
private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<ReliquaryLevelData> reliquaryLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ReliquaryLevelData> reliquaryLevelDataMap = new Int2ObjectOpenHashMap<>();
@ -122,32 +188,70 @@ public class GameData {
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataMap = new Int2ObjectOpenHashMap<>();
// Cache // Cache
@Getter private static final IntList scenePointIdList = new IntArrayList(); @Getter
@Getter private static final List<OpenStateData> openStateList = new ArrayList<>(); private static final IntList scenePointIdList = new IntArrayList();
@Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>(); @Getter
@Getter private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>(); private static final List<OpenStateData> openStateList = new ArrayList<>();
private static Map<Integer, List<Integer>> fetters = new HashMap<>(); @Getter
private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>(); private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
@Getter
private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
protected static Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>(); protected static Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>();
protected static Int2IntMap proudSkillGroupMaxLevels = new Int2IntOpenHashMap(); protected static Int2IntMap proudSkillGroupMaxLevels = new Int2IntOpenHashMap();
protected static Int2ObjectMap<IntSet> avatarSkillLevels = new Int2ObjectOpenHashMap<>(); protected static Int2ObjectMap<IntSet> avatarSkillLevels = new Int2ObjectOpenHashMap<>();
private static final Map<Integer, List<Integer>> fetters = new HashMap<>();
private static final Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>();
// Getters with wrong names, remove later // Getters with wrong names, remove later
@Deprecated(forRemoval = true) public static Int2ObjectMap<CodexReliquaryData> getcodexReliquaryIdMap() {return codexReliquaryDataIdMap;} @Deprecated(forRemoval = true)
@Deprecated(forRemoval = true) public static Int2ObjectMap<DungeonEntryData> getDungeonEntryDatatMap() {return dungeonEntryDataMap;} public static Int2ObjectMap<CodexReliquaryData> getcodexReliquaryIdMap() {
@Deprecated(forRemoval = true) @Tolerate public static ArrayList<CodexReliquaryData> getcodexReliquaryArrayList() {return codexReliquaryArrayList;} return codexReliquaryDataIdMap;
}
@Deprecated(forRemoval = true)
public static Int2ObjectMap<DungeonEntryData> getDungeonEntryDatatMap() {
return dungeonEntryDataMap;
}
@Deprecated(forRemoval = true)
@Tolerate
public static ArrayList<CodexReliquaryData> getcodexReliquaryArrayList() {
return codexReliquaryArrayList;
}
// Getters with different names that stay for now // Getters with different names that stay for now
public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() {return mainQuestData;} public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() {
public static Int2ObjectMap<QuestEncryptionKey> getMainQuestEncryptionMap() {return questsKeys;} return mainQuestData;
public static Int2ObjectMap<SceneNpcBornData> getSceneNpcBornData() {return npcBornData;} }
public static Map<String, AbilityEmbryoEntry> getAbilityEmbryoInfo() {return abilityEmbryos;}
public static Int2ObjectMap<QuestEncryptionKey> getMainQuestEncryptionMap() {
return questsKeys;
}
public static Int2ObjectMap<SceneNpcBornData> getSceneNpcBornData() {
return npcBornData;
}
public static Map<String, AbilityEmbryoEntry> getAbilityEmbryoInfo() {
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);} public static AbilityData getAbilityData(String abilityName) {
public static IntSet getAvatarSkillLevels(int avatarSkillId) {return avatarSkillLevels.get(avatarSkillId);} return abilityDataMap.get(abilityName);
public static IntSet getProudSkillGroupLevels(int proudSkillGroupId) {return proudSkillGroupLevels.get(proudSkillGroupId);} }
public static int getProudSkillGroupMaxLevel(int proudSkillGroupId) {return proudSkillGroupMaxLevels.getOrDefault(proudSkillGroupId, 0);}
public static IntSet getAvatarSkillLevels(int avatarSkillId) {
return avatarSkillLevels.get(avatarSkillId);
}
public static IntSet getProudSkillGroupLevels(int proudSkillGroupId) {
return proudSkillGroupLevels.get(proudSkillGroupId);
}
public static int getProudSkillGroupMaxLevel(int proudSkillGroupId) {
return proudSkillGroupMaxLevels.getOrDefault(proudSkillGroupId, 0);
}
// Multi-keyed getters // Multi-keyed getters
public static AvatarPromoteData getAvatarPromoteData(int promoteId, int promoteLevel) { public static AvatarPromoteData getAvatarPromoteData(int promoteId, int promoteLevel) {
@ -198,7 +302,6 @@ public class GameData {
} }
public static int getWeaponExpRequired(int rankLevel, int level) { public static int getWeaponExpRequired(int rankLevel, int level) {
WeaponLevelData levelData = weaponLevelDataMap.get(level); WeaponLevelData levelData = weaponLevelDataMap.get(level);
if (levelData == null) { if (levelData == null) {

View File

@ -1,11 +1,5 @@
package emu.grasscutter.data; package emu.grasscutter.data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.ResourceLoader.AvatarConfig; import emu.grasscutter.data.ResourceLoader.AvatarConfig;
import emu.grasscutter.data.excels.ReliquaryAffixData; import emu.grasscutter.data.excels.ReliquaryAffixData;
@ -18,16 +12,26 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GameDepot { public class GameDepot {
public static final int[] BLOCK_SIZE = new int[]{50,500};//Scales public static final int[] BLOCK_SIZE = new int[]{50, 500};//Scales
private static Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot = new Int2ObjectOpenHashMap<>();
private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
@Getter @Setter private static Map<String, AvatarConfig> playerAbilities = new HashMap<>(); @Getter
@Getter private static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>(); @Setter
@Getter @Setter private static BlossomConfig blossomConfig; 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;
public static void load() { public static void load() {
for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) { for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) {

View File

@ -1,12 +1,12 @@
package emu.grasscutter.data; package emu.grasscutter.data;
public abstract class GameResource { public abstract class GameResource {
public int getId() { public int getId() {
return 0; return 0;
} }
public void onLoad() { public void onLoad() {
} }
} }

View File

@ -19,10 +19,10 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntArraySet;
import lombok.val; import lombok.val;
import org.reflections.Reflections; import org.reflections.Reflections;
import java.io.*; import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
@ -38,6 +38,7 @@ import static emu.grasscutter.utils.Language.translate;
public class ResourceLoader { public class ResourceLoader {
private static final Set<String> loadedResources = new CopyOnWriteArraySet<>(); private static final Set<String> loadedResources = new CopyOnWriteArraySet<>();
private static boolean loadedAll = false;
// Get a list of all resource classes, sorted by loadPriority // Get a list of all resource classes, sorted by loadPriority
public static List<Class<?>> getResourceDefClasses() { public static List<Class<?>> getResourceDefClasses() {
@ -62,7 +63,7 @@ public class ResourceLoader {
val reflections = new Reflections(ResourceLoader.class.getPackage().getName()); val reflections = new Reflections(ResourceLoader.class.getPackage().getName());
val classes = reflections.getSubTypesOf(GameResource.class); val classes = reflections.getSubTypesOf(GameResource.class);
val priorities = ResourceType.LoadPriority.getInOrder(); val priorities = ResourceType.LoadPriority.getInOrder();
Grasscutter.getLogger().debug("Priorities are "+priorities); Grasscutter.getLogger().debug("Priorities are " + priorities);
val map = new LinkedHashMap<ResourceType.LoadPriority, Set<Class<?>>>(priorities.size()); val map = new LinkedHashMap<ResourceType.LoadPriority, Set<Class<?>>>(priorities.size());
priorities.forEach(p -> map.put(p, new HashSet<>())); priorities.forEach(p -> map.put(p, new HashSet<>()));
@ -76,7 +77,6 @@ public class ResourceLoader {
return List.copyOf(map.values()); return List.copyOf(map.values());
} }
private static boolean loadedAll = false;
public static void loadAll() { public static void loadAll() {
if (loadedAll) return; if (loadedAll) return;
Grasscutter.getLogger().info(translate("messages.status.resources.loading")); Grasscutter.getLogger().info(translate("messages.status.resources.loading"));
@ -134,7 +134,7 @@ public class ResourceLoader {
errors.forEach(pair -> Grasscutter.getLogger().error("Error loading resource file: " + pair.left(), pair.right())); errors.forEach(pair -> Grasscutter.getLogger().error("Error loading resource file: " + pair.left(), pair.right()));
long endTime = System.nanoTime(); long endTime = System.nanoTime();
long ns = (endTime - startTime); //divide by 1000000 to get milliseconds. long ns = (endTime - startTime); //divide by 1000000 to get milliseconds.
Grasscutter.getLogger().debug("Loading resources took "+ns+"ns == "+ns/1000000+"ms"); Grasscutter.getLogger().debug("Loading resources took " + ns + "ns == " + ns / 1000000 + "ms");
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -173,9 +173,6 @@ public class ResourceLoader {
}); });
} }
public class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()
public Map<Integer, PointData> points;
}
private static void loadScenePoints() { private static void loadScenePoints() {
val pattern = Pattern.compile("scene([0-9]+)_point\\.json"); val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
try { try {
@ -210,7 +207,6 @@ public class ResourceLoader {
}); });
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!"); Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!");
return;
} }
} }
@ -234,7 +230,8 @@ public class ResourceLoader {
// Read from cached file if exists // Read from cached file if exists
try { try {
embryoList = JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class); embryoList = JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
} catch (Exception ignored) {} } catch (Exception ignored) {
}
if (embryoList == null) { if (embryoList == null) {
// Load from BinOutput // Load from BinOutput
@ -285,30 +282,26 @@ public class ResourceLoader {
} }
} }
// private static HashSet<String> modifierActionTypes = new HashSet<>();
public static class AbilityConfigData {
public AbilityData Default;
}
private static void loadAbilityModifiers() { private static void loadAbilityModifiers() {
// Load from BinOutput // Load from BinOutput
try (Stream<Path> paths = Files.walk(getResourcePath("BinOutput/Ability/Temp/"))) { try (Stream<Path> paths = Files.walk(getResourcePath("BinOutput/Ability/Temp/"))) {
paths.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".json")).forEach(ResourceLoader::loadAbilityModifiers); paths.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".json")).forEach(ResourceLoader::loadAbilityModifiers);
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers: ", e); Grasscutter.getLogger().error("Error loading ability modifiers: ", e);
return;
} }
// System.out.println("Loaded modifiers, found types:"); // System.out.println("Loaded modifiers, found types:");
// modifierActionTypes.stream().sorted().forEach(s -> System.out.printf("%s, ", s)); // modifierActionTypes.stream().sorted().forEach(s -> System.out.printf("%s, ", s));
// System.out.println("[End]"); // System.out.println("[End]");
} }
private static void loadAbilityModifiers(Path path) { private static void loadAbilityModifiers(Path path) {
try { try {
JsonUtils.loadToList(path, AbilityConfigData.class).forEach(data -> loadAbilityData(data.Default)); JsonUtils.loadToList(path, AbilityConfigData.class).forEach(data -> loadAbilityData(data.Default));
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers from path " + path.toString() + ": ", e); Grasscutter.getLogger().error("Error loading ability modifiers from path " + path.toString() + ": ", e);
return;
} }
} }
private static void loadAbilityData(AbilityData data) { private static void loadAbilityData(AbilityData data) {
GameData.abilityDataMap.put(data.abilityName, data); GameData.abilityDataMap.put(data.abilityName, data);
@ -344,7 +337,8 @@ public class ResourceLoader {
try (InputStreamReader reader = DataLoader.loadReader(name)) { try (InputStreamReader reader = DataLoader.loadReader(name)) {
// Add spawns to group if it already exists in our spawn group map // Add spawns to group if it already exists in our spawn group map
spawnEntryMap.addAll(JsonUtils.loadToList(reader, SpawnGroupEntry.class)); spawnEntryMap.addAll(JsonUtils.loadToList(reader, SpawnGroupEntry.class));
} catch (Exception ignored) {} } catch (Exception ignored) {
}
} }
if (spawnEntryMap.isEmpty()) { if (spawnEntryMap.isEmpty()) {
@ -375,7 +369,8 @@ public class ResourceLoader {
try { try {
list = JsonUtils.loadToList(getDataPath("OpenConfig.json"), OpenConfigEntry.class); list = JsonUtils.loadToList(getDataPath("OpenConfig.json"), OpenConfigEntry.class);
} catch (Exception ignored) {} } catch (Exception ignored) {
}
if (list == null) { if (list == null) {
Map<String, OpenConfigEntry> map = new TreeMap<>(); Map<String, OpenConfigEntry> map = new TreeMap<>();
@ -389,7 +384,6 @@ public class ResourceLoader {
.forEach((name, data) -> map.put(name, new OpenConfigEntry(name, data))); .forEach((name, data) -> map.put(name, new OpenConfigEntry(name, data)));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return;
} }
}); });
} catch (IOException e) { } catch (IOException e) {
@ -431,10 +425,12 @@ public class ResourceLoader {
String path = "QuestEncryptionKeys.json"; String path = "QuestEncryptionKeys.json";
try { try {
JsonUtils.loadToList(getResourcePath(path), QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key)); JsonUtils.loadToList(getResourcePath(path), QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key));
} catch (IOException | NullPointerException ignored) {} } catch (IOException | NullPointerException ignored) {
}
try { try {
DataLoader.loadList(path, QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key)); DataLoader.loadList(path, QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key));
} catch (IOException | NullPointerException ignored) {} } catch (IOException | NullPointerException ignored) {
}
Grasscutter.getLogger().debug("Loaded {} quest keys.", questEncryptionMap.size()); Grasscutter.getLogger().debug("Loaded {} quest keys.", questEncryptionMap.size());
} catch (Exception e) { } catch (Exception e) {
Grasscutter.getLogger().error("Unable to load quest keys.", e); Grasscutter.getLogger().error("Unable to load quest keys.", e);
@ -450,13 +446,11 @@ public class ResourceLoader {
GameData.getScriptSceneDataMap().put(path.getFileName().toString(), JsonUtils.loadToClass(path, ScriptSceneData.class)); GameData.getScriptSceneDataMap().put(path.getFileName().toString(), JsonUtils.loadToClass(path, ScriptSceneData.class));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
return;
} }
}); });
Grasscutter.getLogger().debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas."); Grasscutter.getLogger().debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas.");
} catch (IOException e) { } catch (IOException e) {
Grasscutter.getLogger().debug("ScriptSceneData folder missing or empty."); Grasscutter.getLogger().debug("ScriptSceneData folder missing or empty.");
return;
} }
} }
@ -471,7 +465,8 @@ public class ResourceLoader {
val sceneId = Integer.parseInt(matcher.group(1)); val sceneId = Integer.parseInt(matcher.group(1));
val data = JsonUtils.loadToClass(path, HomeworldDefaultSaveData.class); val data = JsonUtils.loadToClass(path, HomeworldDefaultSaveData.class);
GameData.getHomeworldDefaultSaveData().put(sceneId, data); GameData.getHomeworldDefaultSaveData().put(sceneId, data);
} catch (Exception ignored) {} } catch (Exception ignored) {
}
}); });
Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas."); Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas.");
} catch (IOException e) { } catch (IOException e) {
@ -490,7 +485,8 @@ public class ResourceLoader {
data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint())); data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint()));
GameData.getSceneNpcBornData().put(data.getSceneId(), data); GameData.getSceneNpcBornData().put(data.getSceneId(), data);
} catch (IOException ignored) {} } catch (IOException ignored) {
}
}); });
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas."); Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
} catch (IOException e) { } catch (IOException e) {
@ -505,7 +501,6 @@ public class ResourceLoader {
GameData.getGadgetConfigData().putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class)); GameData.getGadgetConfigData().putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class));
} catch (Exception e) { } catch (Exception e) {
Grasscutter.getLogger().error("failed to load ConfigGadget entries for " + path.toString(), e); Grasscutter.getLogger().error("failed to load ConfigGadget entries for " + path.toString(), e);
return;
} }
}); });
@ -524,15 +519,21 @@ public class ResourceLoader {
} }
} }
// BinOutput configs // private static HashSet<String> modifierActionTypes = new HashSet<>();
public static class AbilityConfigData {
public AbilityData Default;
}
public static class AvatarConfig { public static class AvatarConfig {
@SerializedName(value="abilities", alternate={"targetAbilities"}) @SerializedName(value = "abilities", alternate = {"targetAbilities"})
public ArrayList<AvatarConfigAbility> abilities; public ArrayList<AvatarConfigAbility> abilities;
} }
// BinOutput configs
public static class AvatarConfigAbility { public static class AvatarConfigAbility {
public String abilityName; public String abilityName;
public String toString() { public String toString() {
return abilityName; return abilityName;
} }
@ -546,13 +547,17 @@ public class ResourceLoader {
public String $type; public String $type;
public String abilityName; public String abilityName;
@SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"}) @SerializedName(value = "talentIndex", alternate = {"OJOFFKLNAHN"})
public int talentIndex; public int talentIndex;
@SerializedName(value="skillID", alternate={"overtime"}) @SerializedName(value = "skillID", alternate = {"overtime"})
public int skillID; public int skillID;
@SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"}) @SerializedName(value = "pointDelta", alternate = {"IGEBKIHPOIF"})
public int pointDelta; public int pointDelta;
} }
public class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()
public Map<Integer, PointData> points;
}
} }

View File

@ -5,34 +5,38 @@ import java.lang.annotation.RetentionPolicy;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ResourceType { public @interface ResourceType {
/** Names of the file that this Resource loads from */ /**
String[] name(); * Names of the file that this Resource loads from
*/
/** Load priority - dictates which order to load this resource, with "highest" being loaded first */ String[] name();
LoadPriority loadPriority() default LoadPriority.NORMAL;
public enum LoadPriority {
HIGHEST (4),
HIGH (3),
NORMAL (2),
LOW (1),
LOWEST (0);
private final int value; /**
* Load priority - dictates which order to load this resource, with "highest" being loaded first
LoadPriority(int value) { */
this.value = value; LoadPriority loadPriority() default LoadPriority.NORMAL;
}
enum LoadPriority {
public int value() { HIGHEST(4),
return value; HIGH(3),
} NORMAL(2),
LOW(1),
LOWEST(0);
private final int value;
LoadPriority(int value) {
this.value = value;
}
public static List<LoadPriority> getInOrder() { public static List<LoadPriority> getInOrder() {
return Stream.of(LoadPriority.values()).sorted((x, y) -> y.value() - x.value()).toList(); return Stream.of(LoadPriority.values()).sorted((x, y) -> y.value() - x.value()).toList();
} }
}
public int value() {
return value;
}
}
} }

View File

@ -1,23 +1,23 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
public class AbilityEmbryoEntry { public class AbilityEmbryoEntry {
private String name; private String name;
private String[] abilities; private String[] abilities;
public AbilityEmbryoEntry() {
} public AbilityEmbryoEntry() {
public AbilityEmbryoEntry(String avatarName, String[] array) {
this.name = avatarName;
this.abilities = array;
}
public String getName() { }
return name;
} public AbilityEmbryoEntry(String avatarName, String[] array) {
this.name = avatarName;
public String[] getAbilities() { this.abilities = array;
return abilities; }
}
public String getName() {
return name;
}
public String[] getAbilities() {
return abilities;
}
} }

View File

@ -1,22 +1,35 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import java.io.Serializable;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.common.DynamicFloat; import emu.grasscutter.data.common.DynamicFloat;
import java.io.Serializable;
public class AbilityModifier implements Serializable { public class AbilityModifier implements Serializable {
private static final long serialVersionUID = -2001232313615923575L; private static final long serialVersionUID = -2001232313615923575L;
@SerializedName(value="onAdded", alternate={"KCICDEJLIJD"}) @SerializedName(value = "onAdded", alternate = {"KCICDEJLIJD"})
public AbilityModifierAction[] onAdded; public AbilityModifierAction[] onAdded;
@SerializedName(value="onThinkInterval", alternate={"PBDDACFFPOE"}) @SerializedName(value = "onThinkInterval", alternate = {"PBDDACFFPOE"})
public AbilityModifierAction[] onThinkInterval; public AbilityModifierAction[] onThinkInterval;
public AbilityModifierAction[] onRemoved; public AbilityModifierAction[] onRemoved;
public DynamicFloat duration = DynamicFloat.ZERO; public DynamicFloat duration = DynamicFloat.ZERO;
public static class AbilityModifierAction { public static class AbilityModifierAction {
@SerializedName("$type")
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 { public enum Type {
ActCameraRadialBlur, ActCameraShake, AddAvatarSkillInfo, AddChargeBarValue, ActCameraRadialBlur, ActCameraShake, AddAvatarSkillInfo, AddChargeBarValue,
AddClimateMeter, AddElementDurability, AddGlobalValue, AddGlobalValueToTarget, AddClimateMeter, AddElementDurability, AddGlobalValue, AddGlobalValueToTarget,
@ -71,22 +84,8 @@ public class AbilityModifier implements Serializable {
TriggerSetPassThrough, TriggerSetRenderersEnable, TriggerSetShadowRamp, TriggerSetVisible, TriggerSetPassThrough, TriggerSetRenderersEnable, TriggerSetShadowRamp, TriggerSetVisible,
TriggerTaunt, TriggerThrowEquipPart, TriggerUGCGadgetMove, TryFindBlinkPoint, TriggerTaunt, TriggerThrowEquipPart, TriggerUGCGadgetMove, TryFindBlinkPoint,
TryFindBlinkPointByBorn, TryTriggerPlatformStartMove, TurnDirection, TurnDirectionToPos, TryFindBlinkPointByBorn, TryTriggerPlatformStartMove, TurnDirection, TurnDirectionToPos,
UpdateReactionDamage, UseSkillEliteSet, WidgetSkillStart; UpdateReactionDamage, UseSkillEliteSet, WidgetSkillStart
} }
@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;
} }
//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

View File

@ -1,37 +1,37 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
public class AbilityModifierEntry { public class AbilityModifierEntry {
private String name; // Custom value public List<AbilityModifierAction> onModifierAdded;
public List<AbilityModifierAction> onModifierAdded; public List<AbilityModifierAction> onThinkInterval;
public List<AbilityModifierAction> onThinkInterval; public List<AbilityModifierAction> onRemoved;
public List<AbilityModifierAction> onRemoved; private final String name; // Custom value
public AbilityModifierEntry(String name) {
this.name = name;
this.onModifierAdded = new ArrayList<>();
this.onThinkInterval = new ArrayList<>();
this.onRemoved = new ArrayList<>();
}
public String getName() {
return name;
}
public List<AbilityModifierAction> getOnAdded() { public AbilityModifierEntry(String name) {
return onModifierAdded; this.name = name;
} this.onModifierAdded = new ArrayList<>();
this.onThinkInterval = new ArrayList<>();
this.onRemoved = new ArrayList<>();
}
public List<AbilityModifierAction> getOnThinkInterval() { public String getName() {
return onThinkInterval; return name;
} }
public List<AbilityModifierAction> getOnAdded() {
return onModifierAdded;
}
public List<AbilityModifierAction> getOnThinkInterval() {
return onThinkInterval;
}
public List<AbilityModifierAction> getOnRemoved() {
return onRemoved;
}
public List<AbilityModifierAction> getOnRemoved() {
return onRemoved;
}
} }

View File

@ -1,6 +1,5 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;

View File

@ -27,9 +27,10 @@ public class HomeworldDefaultSaveData {
List<HomeFurniture> doorLists; List<HomeFurniture> doorLists;
@SerializedName("EPGELGEFJFK") @SerializedName("EPGELGEFJFK")
List<HomeFurniture> stairLists; List<HomeFurniture> stairLists;
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public static class HomeBlock{ public static class HomeBlock {
@SerializedName(value = "FGIJCELCGFI", alternate = "PGDPDIDJEEL") @SerializedName(value = "FGIJCELCGFI", alternate = "PGDPDIDJEEL")
int blockId; int blockId;
@ -43,7 +44,7 @@ public class HomeworldDefaultSaveData {
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public static class HomeFurniture{ public static class HomeFurniture {
@SerializedName(value = "ENHNGKJBJAB", alternate = "KMAAJJHPNBA") @SerializedName(value = "ENHNGKJBJAB", alternate = "KMAAJJHPNBA")
int id; int id;

View File

@ -3,6 +3,7 @@ package emu.grasscutter.data.binout;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import emu.grasscutter.game.quest.enums.QuestType; import emu.grasscutter.game.quest.enums.QuestType;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -47,6 +48,7 @@ public class MainQuestData {
public SubQuestData[] getSubQuests() { public SubQuestData[] getSubQuests() {
return subQuests; return subQuests;
} }
public List<TalkData> getTalks() { public List<TalkData> getTalks() {
return talks; return talks;
} }
@ -62,12 +64,15 @@ public class MainQuestData {
} }
@Data @Entity @Data
@Entity
public static class TalkData { public static class TalkData {
private int id; private int id;
private String heroTalk; private String heroTalk;
public TalkData() {} public TalkData() {
}
public TalkData(int id, String heroTalk) { public TalkData(int id, String heroTalk) {
this.id = id; this.id = id;
this.heroTalk = heroTalk; this.heroTalk = heroTalk;

View File

@ -1,72 +1,72 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import emu.grasscutter.data.ResourceLoader.OpenConfigData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import emu.grasscutter.data.ResourceLoader.OpenConfigData;
public class OpenConfigEntry { public class OpenConfigEntry {
private String name; private final String name;
private String[] addAbilities; private String[] addAbilities;
private int extraTalentIndex; private int extraTalentIndex;
private SkillPointModifier[] skillPointModifiers; private SkillPointModifier[] skillPointModifiers;
public OpenConfigEntry(String name, OpenConfigData[] data) { public OpenConfigEntry(String name, OpenConfigData[] data) {
this.name = name; this.name = name;
List<String> abilityList = new ArrayList<>();
List<SkillPointModifier> modList = new ArrayList<>();
for (OpenConfigData entry : data) {
if (entry.$type.contains("AddAbility")) {
abilityList.add(entry.abilityName);
} else if (entry.talentIndex > 0) {
this.extraTalentIndex = entry.talentIndex;
} else if (entry.$type.contains("ModifySkillPoint")) {
modList.add(new SkillPointModifier(entry.skillID, entry.pointDelta));
}
}
if (abilityList.size() > 0) {
this.addAbilities = abilityList.toArray(new String[0]);
}
if (modList.size() > 0) {
this.skillPointModifiers = modList.toArray(new SkillPointModifier[0]);
}
}
public String getName() { List<String> abilityList = new ArrayList<>();
return name; List<SkillPointModifier> modList = new ArrayList<>();
}
public String[] getAddAbilities() { for (OpenConfigData entry : data) {
return addAbilities; if (entry.$type.contains("AddAbility")) {
} abilityList.add(entry.abilityName);
} else if (entry.talentIndex > 0) {
this.extraTalentIndex = entry.talentIndex;
} else if (entry.$type.contains("ModifySkillPoint")) {
modList.add(new SkillPointModifier(entry.skillID, entry.pointDelta));
}
}
public int getExtraTalentIndex() { if (abilityList.size() > 0) {
return extraTalentIndex; this.addAbilities = abilityList.toArray(new String[0]);
} }
public SkillPointModifier[] getSkillPointModifiers() {
return skillPointModifiers;
}
public static class SkillPointModifier { if (modList.size() > 0) {
private int skillId; this.skillPointModifiers = modList.toArray(new SkillPointModifier[0]);
private int delta; }
}
public SkillPointModifier(int skillId, int delta) {
this.skillId = skillId;
this.delta = delta;
}
public int getSkillId() { public String getName() {
return skillId; return name;
} }
public int getDelta() { public String[] getAddAbilities() {
return delta; return addAbilities;
} }
}
public int getExtraTalentIndex() {
return extraTalentIndex;
}
public SkillPointModifier[] getSkillPointModifiers() {
return skillPointModifiers;
}
public static class SkillPointModifier {
private final int skillId;
private final int delta;
public SkillPointModifier(int skillId, int delta) {
this.skillId = skillId;
this.delta = delta;
}
public int getSkillId() {
return skillId;
}
public int getDelta() {
return delta;
}
}
} }

View File

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

View File

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

View File

@ -1,8 +1,6 @@
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.utils.Position;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@ -10,7 +8,7 @@ import java.util.Map;
@Data @Data
public class ScriptSceneData { public class ScriptSceneData {
Map<String,ScriptObject> scriptObjectList; Map<String, ScriptObject> scriptObjectList;
@Data @Data
public static class ScriptObject { public static class ScriptObject {

View File

@ -1,17 +1,19 @@
package emu.grasscutter.data.common; package emu.grasscutter.data.common;
public class CurveInfo { public class CurveInfo {
private String type; private String type;
private String arith; private String arith;
private float value; private float value;
public String getType() { public String getType() {
return type; return type;
} }
public String getArith() {
return arith; public String getArith() {
} return arith;
public float getValue() { }
return value;
} public float getValue() {
return value;
}
} }

View File

@ -1,63 +1,22 @@
package emu.grasscutter.data.common; package emu.grasscutter.data.common;
import java.util.List;
import java.util.Optional;
import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.objects.Object2FloatArrayMap; import it.unimi.dsi.fastutil.objects.Object2FloatArrayMap;
import it.unimi.dsi.fastutil.objects.Object2FloatMap; import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import lombok.val; import lombok.val;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import java.util.List;
import org.luaj.vm2.ast.Str; import java.util.Optional;
public class DynamicFloat { public class DynamicFloat {
public static DynamicFloat ZERO = new DynamicFloat(0f); public static DynamicFloat ZERO = new DynamicFloat(0f);
public static class StackOp {
enum Op { CONSTANT, KEY, ADD, SUB, MUL, DIV, NEXBOOLEAN };
public Op op;
public float fValue;
public String sValue;
public boolean bValue;
public StackOp(String s) {
switch (s.toUpperCase()) {
case "ADD" -> this.op = Op.ADD;
case "SUB" -> this.op = Op.SUB;
case "MUL" -> this.op = Op.MUL;
case "DIV" -> this.op = Op.DIV;
default -> {
this.op = Op.KEY;
this.sValue = s;
}
}
}
public StackOp(boolean b) {
this.op = Op.NEXBOOLEAN;
this.bValue = Boolean.parseBoolean(String.valueOf(b));
}
public StackOp(float f) {
this.op = Op.CONSTANT;
this.fValue = f;
}
}
private List<StackOp> ops; private List<StackOp> ops;
private boolean dynamic = false; private boolean dynamic = false;
private float constant = 0f; private float constant = 0f;
public DynamicFloat(float constant) { public DynamicFloat(float constant) {
this.constant = constant; this.constant = constant;
} }
public String toString(boolean nextBoolean) {
String key = String.valueOf(nextBoolean);
this.ops = List.of(new StackOp(key));
return ops.toString();
}
public DynamicFloat(String key) { public DynamicFloat(String key) {
this.dynamic = true; this.dynamic = true;
this.ops = List.of(new StackOp(key)); this.ops = List.of(new StackOp(key));
@ -73,6 +32,12 @@ public class DynamicFloat {
this.ops = ops; this.ops = ops;
} }
public String toString(boolean nextBoolean) {
String key = String.valueOf(nextBoolean);
this.ops = List.of(new StackOp(key));
return ops.toString();
}
public float get() { public float get() {
return this.get(new Object2FloatArrayMap<String>()); return this.get(new Object2FloatArrayMap<String>());
} }
@ -87,13 +52,46 @@ public class DynamicFloat {
case CONSTANT -> fl.push(op.fValue); case CONSTANT -> fl.push(op.fValue);
case KEY -> fl.push(props.getOrDefault(op.sValue, 0f)); case KEY -> fl.push(props.getOrDefault(op.sValue, 0f));
case ADD -> fl.push(fl.popFloat() + fl.popFloat()); case ADD -> fl.push(fl.popFloat() + fl.popFloat());
case SUB -> 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 MUL -> fl.push(fl.popFloat() * fl.popFloat());
case DIV -> fl.push((1f/fl.popFloat()) * fl.popFloat()); // [f0, f1, f2] -> [f0, f1/f2] case DIV -> fl.push((1f / fl.popFloat()) * fl.popFloat()); // [f0, f1, f2] -> [f0, f1/f2]
case NEXBOOLEAN -> fl.push(props.getOrDefault(Optional.of(op.bValue), 0f)); case NEXBOOLEAN -> fl.push(props.getOrDefault(Optional.of(op.bValue), 0f));
} }
} }
return fl.popFloat(); // well-formed data will always have only one value left at this point return fl.popFloat(); // well-formed data will always have only one value left at this point
} }
public static class StackOp {
public Op op;
public float fValue;
public String sValue;
public boolean bValue;
public StackOp(String s) {
switch (s.toUpperCase()) {
case "ADD" -> this.op = Op.ADD;
case "SUB" -> this.op = Op.SUB;
case "MUL" -> this.op = Op.MUL;
case "DIV" -> this.op = Op.DIV;
default -> {
this.op = Op.KEY;
this.sValue = s;
}
}
}
public StackOp(boolean b) {
this.op = Op.NEXBOOLEAN;
this.bValue = Boolean.parseBoolean(String.valueOf(b));
}
public StackOp(float f) {
this.op = Op.CONSTANT;
this.fValue = f;
}
enum Op {CONSTANT, KEY, ADD, SUB, MUL, DIV, NEXBOOLEAN}
}
} }

View File

@ -3,23 +3,23 @@ package emu.grasscutter.data.common;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
public class FightPropData { public class FightPropData {
private String propType; private String propType;
private FightProperty prop; private FightProperty prop;
private float value; private float value;
public String getPropType() {
return propType;
}
public float getValue() {
return value;
}
public FightProperty getProp() { public String getPropType() {
return prop; return propType;
} }
public void onLoad() { public float getValue() {
this.prop = FightProperty.getPropByName(propType); return value;
} }
}
public FightProperty getProp() {
return prop;
}
public void onLoad() {
this.prop = FightProperty.getPropByName(propType);
}
}

View File

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

View File

@ -1,26 +1,27 @@
package emu.grasscutter.data.common; package emu.grasscutter.data.common;
public class ItemParamStringData { public class ItemParamStringData {
private int id; private int id;
private String count; private String count;
public ItemParamStringData() {} public ItemParamStringData() {
}
public int getId() { public int getId() {
return id; return id;
} }
public String getCount() { public String getCount() {
return count; return count;
} }
public ItemParamData toItemParamData() { public ItemParamData toItemParamData() {
if (count.contains(";")) { if (count.contains(";")) {
String[] split = count.split(";"); String[] split = count.split(";");
count = count.split(";")[split.length - 1]; count = count.split(";")[split.length - 1];
} else if (count.contains(".")) { } else if (count.contains(".")) {
return new ItemParamData(id, (int) Math.ceil(Double.parseDouble(count))); return new ItemParamData(id, (int) Math.ceil(Double.parseDouble(count)));
} }
return new ItemParamData(id, Integer.parseInt(count)); return new ItemParamData(id, Integer.parseInt(count));
} }
} }

View File

@ -1,7 +1,6 @@
package emu.grasscutter.data.common; package emu.grasscutter.data.common;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.DailyDungeonData; import emu.grasscutter.data.excels.DailyDungeonData;
@ -12,18 +11,25 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class PointData { public class PointData {
@Getter @Setter private int id; @Getter
@Setter
private int id;
private String $type; 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; @Getter
private int[] dungeonIds;
@SerializedName(value="dungeonRandomList", alternate={"OIBKFJNBLHO"}) @SerializedName(value = "dungeonRandomList", alternate = {"OIBKFJNBLHO"})
@Getter private int[] dungeonRandomList; @Getter
private int[] dungeonRandomList;
@SerializedName(value="tranSceneId", alternate={"JHBICGBAPIH"}) @SerializedName(value = "tranSceneId", alternate = {"JHBICGBAPIH"})
@Getter @Setter private int tranSceneId; @Getter
@Setter
private int tranSceneId;
public String getType() { public String getType() {
return $type; return $type;

View File

@ -4,12 +4,12 @@ public class PropGrowCurve {
private String type; private String type;
private String growCurve; private String growCurve;
public String getType(){ public String getType() {
return this.type; return this.type;
} }
public String getGrowCurve(){ public String getGrowCurve() {
return this.growCurve; return this.growCurve;
} }
} }

View File

@ -18,7 +18,7 @@ public class AchievementData extends GameResource {
private static final AtomicBoolean isDivided = new AtomicBoolean(); private static final AtomicBoolean isDivided = new AtomicBoolean();
private int goalId; private int goalId;
private int preStageAchievementId; private int preStageAchievementId;
private Set<Integer> groupAchievementIdList = new HashSet<>(); private final Set<Integer> groupAchievementIdList = new HashSet<>();
private boolean isParent; private boolean isParent;
private long titleTextMapHash; private long titleTextMapHash;
private long descTextMapHash; private long descTextMapHash;
@ -29,26 +29,6 @@ public class AchievementData extends GameResource {
private int progress; private int progress;
private boolean isDisuse; private boolean isDisuse;
public boolean hasPreStageAchievement() {
return this.preStageAchievementId != 0;
}
public boolean hasGroupAchievements() {
return !this.groupAchievementIdList.isEmpty();
}
public boolean isUsed() {
return !this.isDisuse;
}
public Set<Integer> getGroupAchievementIdList() {
return this.groupAchievementIdList.stream().collect(Collectors.toUnmodifiableSet());
}
public Set<Integer> getExcludedGroupAchievementIdList() {
return this.groupAchievementIdList.stream().filter(integer -> integer != this.getId()).collect(Collectors.toUnmodifiableSet());
}
public static void divideIntoGroups() { public static void divideIntoGroups() {
if (isDivided.get()) { if (isDivided.get()) {
return; return;
@ -93,4 +73,24 @@ 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() {
return this.preStageAchievementId != 0;
}
public boolean hasGroupAchievements() {
return !this.groupAchievementIdList.isEmpty();
}
public boolean isUsed() {
return !this.isDisuse;
}
public Set<Integer> getGroupAchievementIdList() {
return this.groupAchievementIdList.stream().collect(Collectors.toUnmodifiableSet());
}
public Set<Integer> getExcludedGroupAchievementIdList() {
return this.groupAchievementIdList.stream().filter(integer -> integer != this.getId()).collect(Collectors.toUnmodifiableSet());
}
} }

View File

@ -24,6 +24,7 @@ public class ActivityData extends GameResource {
public int getId() { public int getId() {
return this.activityId; return this.activityId;
} }
@Override @Override
public void onLoad() { public void onLoad() {
this.watcherDataList = watcherId.stream().map(item -> GameData.getActivityWatcherDataMap().get(item.intValue())) this.watcherDataList = watcherId.stream().map(item -> GameData.getActivityWatcherDataMap().get(item.intValue()))

View File

@ -27,7 +27,7 @@ public class ActivityWatcherData extends GameResource {
@Getter @Getter
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public static class WatcherTrigger{ public static class WatcherTrigger {
String triggerType; String triggerType;
List<String> paramList; List<String> paramList;

View File

@ -1,36 +1,36 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.CurveInfo; import emu.grasscutter.data.common.CurveInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
@ResourceType(name = "AvatarCurveExcelConfigData.json") @ResourceType(name = "AvatarCurveExcelConfigData.json")
public class AvatarCurveData extends GameResource { public class AvatarCurveData extends GameResource {
private int level; private int level;
private CurveInfo[] curveInfos; private CurveInfo[] curveInfos;
private Map<String, Float> curveInfoMap; private Map<String, Float> curveInfoMap;
@Override @Override
public int getId() { public int getId() {
return this.level; return this.level;
} }
public int getLevel() { public int getLevel() {
return level; return level;
} }
public Map<String, Float> getCurveInfos() { public Map<String, Float> getCurveInfos() {
return curveInfoMap; return curveInfoMap;
} }
@Override @Override
public void onLoad() { public void onLoad() {
this.curveInfoMap = new HashMap<>(); this.curveInfoMap = new HashMap<>();
Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue())); Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue()));
} }
} }

View File

@ -1,7 +1,5 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
@ -16,26 +14,43 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter; import lombok.Getter;
import java.util.List;
@ResourceType(name = "AvatarExcelConfigData.json", loadPriority = LoadPriority.LOW) @ResourceType(name = "AvatarExcelConfigData.json", loadPriority = LoadPriority.LOW)
public class AvatarData extends GameResource { public class AvatarData extends GameResource {
private String iconName; private String iconName;
@Getter private String bodyType; @Getter
@Getter private String qualityType; private String bodyType;
@Getter private int chargeEfficiency; @Getter
@Getter private int initialWeapon; private String qualityType;
@Getter private WeaponType weaponType; @Getter
@Getter private String imageName; private int chargeEfficiency;
@Getter private int avatarPromoteId; @Getter
@Getter private String cutsceneShow; private int initialWeapon;
@Getter private int skillDepotId; @Getter
@Getter private int staminaRecoverSpeed; private WeaponType weaponType;
@Getter private List<String> candSkillDepotIds; @Getter
@Getter private String avatarIdentityType; private String imageName;
@Getter private List<Integer> avatarPromoteRewardLevelList; @Getter
@Getter private List<Integer> avatarPromoteRewardIdList; private int avatarPromoteId;
@Getter
private String cutsceneShow;
@Getter
private int skillDepotId;
@Getter
private int staminaRecoverSpeed;
@Getter
private List<String> candSkillDepotIds;
@Getter
private String avatarIdentityType;
@Getter
private List<Integer> avatarPromoteRewardLevelList;
@Getter
private List<Integer> avatarPromoteRewardIdList;
@Getter private long nameTextMapHash; @Getter
private long nameTextMapHash;
private float hpBase; private float hpBase;
private float attackBase; private float attackBase;
@ -48,18 +63,24 @@ public class AvatarData extends GameResource {
private int id; private int id;
// Transient // Transient
@Getter private String name; @Getter
private String name;
private Int2ObjectMap<String> growthCurveMap; private Int2ObjectMap<String> growthCurveMap;
private float[] hpGrowthCurve; private float[] hpGrowthCurve;
private float[] attackGrowthCurve; private float[] attackGrowthCurve;
private float[] defenseGrowthCurve; private float[] defenseGrowthCurve;
@Getter private AvatarSkillDepotData skillDepot; @Getter
@Getter private IntList abilities; private AvatarSkillDepotData skillDepot;
@Getter
private IntList abilities;
@Getter private List<Integer> fetters; @Getter
@Getter private int nameCardRewardId; private List<Integer> fetters;
@Getter private int nameCardId; @Getter
private int nameCardRewardId;
@Getter
private int nameCardId;
public float getBaseHp(int level) { public float getBaseHp(int level) {
try { try {
@ -166,4 +187,3 @@ public class AvatarData extends GameResource {
} }
} }
} }

View File

@ -5,19 +5,19 @@ import emu.grasscutter.data.ResourceType;
@ResourceType(name = "AvatarFettersLevelExcelConfigData.json") @ResourceType(name = "AvatarFettersLevelExcelConfigData.json")
public class AvatarFetterLevelData extends GameResource { public class AvatarFetterLevelData extends GameResource {
private int fetterLevel; private int fetterLevel;
private int needExp; private int needExp;
@Override @Override
public int getId() { public int getId() {
return this.fetterLevel; return this.fetterLevel;
} }
public int getLevel() { public int getLevel() {
return fetterLevel; return fetterLevel;
} }
public int getExp() { public int getExp() {
return needExp; return needExp;
} }
} }

View File

@ -5,20 +5,20 @@ import emu.grasscutter.data.ResourceType;
@ResourceType(name = "AvatarFlycloakExcelConfigData.json") @ResourceType(name = "AvatarFlycloakExcelConfigData.json")
public class AvatarFlycloakData extends GameResource { public class AvatarFlycloakData extends GameResource {
private int flycloakId; private int flycloakId;
private long nameTextMapHash; private long nameTextMapHash;
@Override @Override
public int getId() { public int getId() {
return this.flycloakId; return this.flycloakId;
} }
public long getNameTextMapHash() { public long getNameTextMapHash() {
return nameTextMapHash; return nameTextMapHash;
} }
@Override @Override
public void onLoad() { public void onLoad() {
} }
} }

View File

@ -5,19 +5,19 @@ import emu.grasscutter.data.ResourceType;
@ResourceType(name = "AvatarLevelExcelConfigData.json") @ResourceType(name = "AvatarLevelExcelConfigData.json")
public class AvatarLevelData extends GameResource { public class AvatarLevelData extends GameResource {
private int level; private int level;
private int exp; private int exp;
@Override @Override
public int getId() { public int getId() {
return this.level; return this.level;
} }
public int getLevel() { public int getLevel() {
return level; return level;
} }
public int getExp() { public int getExp() {
return exp; return exp;
} }
} }

View File

@ -1,74 +1,75 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.ArrayList;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import java.util.ArrayList;
@ResourceType(name = "AvatarPromoteExcelConfigData.json") @ResourceType(name = "AvatarPromoteExcelConfigData.json")
public class AvatarPromoteData extends GameResource { public class AvatarPromoteData extends GameResource {
private int avatarPromoteId;
private int promoteLevel;
private int scoinCost;
private ItemParamData[] costItems;
private int unlockMaxLevel;
private FightPropData[] addProps;
private int requiredPlayerLevel;
@Override
public int getId() {
return (avatarPromoteId << 8) + promoteLevel;
}
public int getAvatarPromoteId() { private int avatarPromoteId;
return avatarPromoteId; private int promoteLevel;
} private int scoinCost;
private ItemParamData[] costItems;
private int unlockMaxLevel;
private FightPropData[] addProps;
private int requiredPlayerLevel;
public int getPromoteLevel() { @Override
return promoteLevel; public int getId() {
} return (avatarPromoteId << 8) + promoteLevel;
}
public ItemParamData[] getCostItems() { public int getAvatarPromoteId() {
return costItems; return avatarPromoteId;
} }
public int getCoinCost() { public int getPromoteLevel() {
return scoinCost; return promoteLevel;
} }
public FightPropData[] getAddProps() { public ItemParamData[] getCostItems() {
return addProps; return costItems;
} }
public int getUnlockMaxLevel() { public int getCoinCost() {
return unlockMaxLevel; return scoinCost;
} }
public int getRequiredPlayerLevel() { public FightPropData[] getAddProps() {
return requiredPlayerLevel; return addProps;
} }
@Override public int getUnlockMaxLevel() {
public void onLoad() { return unlockMaxLevel;
// Trim item params }
ArrayList<ItemParamData> trim = new ArrayList<>(getAddProps().length);
for (ItemParamData itemParam : getCostItems()) { public int getRequiredPlayerLevel() {
if (itemParam.getId() == 0) { return requiredPlayerLevel;
continue; }
}
trim.add(itemParam); @Override
} public void onLoad() {
this.costItems = trim.toArray(new ItemParamData[trim.size()]); // Trim item params
// Trim fight prop data (just in case) ArrayList<ItemParamData> trim = new ArrayList<>(getAddProps().length);
ArrayList<FightPropData> parsed = new ArrayList<>(getAddProps().length); for (ItemParamData itemParam : getCostItems()) {
for (FightPropData prop : getAddProps()) { if (itemParam.getId() == 0) {
if (prop.getPropType() != null && prop.getValue() != 0f) { continue;
prop.onLoad(); }
parsed.add(prop); trim.add(itemParam);
} }
} this.costItems = trim.toArray(new ItemParamData[trim.size()]);
this.addProps = parsed.toArray(new FightPropData[parsed.size()]); // Trim fight prop data (just in case)
} ArrayList<FightPropData> parsed = new ArrayList<>(getAddProps().length);
for (FightPropData prop : getAddProps()) {
if (prop.getPropType() != null && prop.getValue() != 0f) {
prop.onLoad();
parsed.add(prop);
}
}
this.addProps = parsed.toArray(new FightPropData[parsed.size()]);
}
} }

View File

@ -1,9 +1,5 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
@ -17,6 +13,10 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter; import lombok.Getter;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
@ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH) @ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH)
@Getter @Getter
public class AvatarSkillDepotData extends GameResource { public class AvatarSkillDepotData extends GameResource {
@ -73,14 +73,14 @@ public class AvatarSkillDepotData extends GameResource {
.ifPresent(itemId -> this.talentCostItemId = itemId); .ifPresent(itemId -> this.talentCostItemId = itemId);
} }
public IntStream getSkillsAndEnergySkill() {
return IntStream.concat(this.skills.stream().mapToInt(i -> i), IntStream.of(this.energySkill))
.filter(skillId -> skillId > 0);
}
@Getter @Getter
public static class InherentProudSkillOpens { public static class InherentProudSkillOpens {
private int proudSkillGroupId; private int proudSkillGroupId;
private int needAvatarPromoteLevel; private int needAvatarPromoteLevel;
} }
public IntStream getSkillsAndEnergySkill() {
return IntStream.concat(this.skills.stream().mapToInt(i -> i), IntStream.of(this.energySkill))
.filter(skillId -> skillId > 0);
}
} }

View File

@ -1,15 +1,16 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.ArrayList;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import java.util.ArrayList;
@ResourceType(name = "AvatarTalentExcelConfigData.json", loadPriority = LoadPriority.HIGHEST) @ResourceType(name = "AvatarTalentExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
public class AvatarTalentData extends GameResource { public class AvatarTalentData extends GameResource {
private int talentId; private int talentId;
private int prevTalent; private int prevTalent;
private long nameTextMapHash; private long nameTextMapHash;
private String icon; private String icon;
private int mainCostItemId; private int mainCostItemId;
@ -19,51 +20,51 @@ public class AvatarTalentData extends GameResource {
private float[] paramList; private float[] paramList;
@Override @Override
public int getId(){ public int getId() {
return this.talentId; return this.talentId;
} }
public int PrevTalent() { public int PrevTalent() {
return prevTalent; return prevTalent;
} }
public long getNameTextMapHash() {
return nameTextMapHash;
}
public String getIcon() { public long getNameTextMapHash() {
return icon; return nameTextMapHash;
} }
public int getMainCostItemId() { public String getIcon() {
return mainCostItemId; return icon;
} }
public int getMainCostItemCount() { public int getMainCostItemId() {
return mainCostItemCount; return mainCostItemId;
} }
public String getOpenConfig() { public int getMainCostItemCount() {
return openConfig; return mainCostItemCount;
} }
public FightPropData[] getAddProps() { public String getOpenConfig() {
return addProps; return openConfig;
} }
public float[] getParamList() { public FightPropData[] getAddProps() {
return paramList; return addProps;
} }
@Override public float[] getParamList() {
public void onLoad() { return paramList;
ArrayList<FightPropData> parsed = new ArrayList<FightPropData>(getAddProps().length); }
for (FightPropData prop : getAddProps()) {
if (prop.getPropType() != null || prop.getValue() == 0f) { @Override
prop.onLoad(); public void onLoad() {
parsed.add(prop); ArrayList<FightPropData> parsed = new ArrayList<FightPropData>(getAddProps().length);
} for (FightPropData prop : getAddProps()) {
} if (prop.getPropType() != null || prop.getValue() == 0f) {
this.addProps = parsed.toArray(new FightPropData[parsed.size()]); prop.onLoad();
} parsed.add(prop);
}
}
this.addProps = parsed.toArray(new FightPropData[parsed.size()]);
}
} }

View File

@ -1,9 +1,5 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.BattlePassMissionRefreshType; import emu.grasscutter.game.props.BattlePassMissionRefreshType;
@ -11,6 +7,10 @@ import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus; import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
import lombok.Getter; import lombok.Getter;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"}) @ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
@Getter @Getter
public class BattlePassMissionData extends GameResource { public class BattlePassMissionData extends GameResource {
@ -48,12 +48,6 @@ public class BattlePassMissionData extends GameResource {
} }
} }
@Getter
public static class TriggerConfig {
private WatcherTriggerType triggerType;
private String[] paramList;
}
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() { public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder(); var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
@ -66,4 +60,10 @@ public class BattlePassMissionData extends GameResource {
return protoBuilder.build(); return protoBuilder.build();
} }
@Getter
public static class TriggerConfig {
private WatcherTriggerType triggerType;
private String[] paramList;
}
} }

View File

@ -3,7 +3,6 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import java.util.List; import java.util.List;

View File

@ -1,11 +1,11 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter; import lombok.Getter;
import java.util.List;
@ResourceType(name = "BlossomRefreshExcelConfigData.json") @ResourceType(name = "BlossomRefreshExcelConfigData.json")
@Getter @Getter
public class BlossomRefreshExcelConfigData extends GameResource { public class BlossomRefreshExcelConfigData extends GameResource {

View File

@ -15,16 +15,15 @@ import java.util.Map;
@Setter // TODO: remove on next API break @Setter // TODO: remove on next API break
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class ChapterData extends GameResource { 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) @Getter(onMethod_ = @Override)
int id; int id;
int beginQuestId; int beginQuestId;
int endQuestId; int endQuestId;
int needPlayerLevel; int needPlayerLevel;
// 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<>();
@Override @Override
public void onLoad() { public void onLoad() {
beginQuestChapterMap.put(beginQuestId, this); beginQuestChapterMap.put(beginQuestId, this);

View File

@ -1,7 +1,6 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter; import lombok.Getter;
@ -14,7 +13,7 @@ public class CodexAnimalData extends GameResource {
private String type; private String type;
private int describeId; private int describeId;
private int sortOrder; private int sortOrder;
@SerializedName(value="countType", alternate={"OCCLHPBCDGL"}) @SerializedName(value = "countType", alternate = {"OCCLHPBCDGL"})
private CountType countType; private CountType countType;
public enum CountType { public enum CountType {

View File

@ -34,7 +34,7 @@ public class CodexQuestData extends GameResource {
@Override @Override
public void onLoad() { public void onLoad() {
if(!this.getIsDisuse()) { if (!this.getIsDisuse()) {
GameData.getCodexQuestDataIdMap().put(this.getParentQuestId(), this); GameData.getCodexQuestDataIdMap().put(this.getParentQuestId(), this);
} }
} }

View File

@ -9,15 +9,24 @@ import lombok.Getter;
@ResourceType(name = {"ReliquaryCodexExcelConfigData.json"}) @ResourceType(name = {"ReliquaryCodexExcelConfigData.json"})
public class CodexReliquaryData extends GameResource { public class CodexReliquaryData extends GameResource {
@Getter private int Id; @Getter
@Getter private int suitId; private int Id;
@Getter private int level; @Getter
@Getter private int cupId; private int suitId;
@Getter private int leatherId; @Getter
@Getter private int capId; private int level;
@Getter private int flowerId; @Getter
@Getter private int sandId; private int cupId;
@Getter private int sortOrder; @Getter
private int leatherId;
@Getter
private int capId;
@Getter
private int flowerId;
@Getter
private int sandId;
@Getter
private int sortOrder;
private transient IntCollection ids; private transient IntCollection ids;
public boolean containsId(int id) { public boolean containsId(int id) {
@ -35,11 +44,11 @@ public class CodexReliquaryData extends GameResource {
@Override @Override
public void onLoad() { public void onLoad() {
// Normalize all itemIds to the 0-substat form // Normalize all itemIds to the 0-substat form
cupId = (cupId/10) * 10; cupId = (cupId / 10) * 10;
leatherId = (leatherId/10) * 10; leatherId = (leatherId / 10) * 10;
capId = (capId/10) * 10; capId = (capId / 10) * 10;
flowerId = (flowerId/10) * 10; flowerId = (flowerId / 10) * 10;
sandId = (sandId/10) * 10; sandId = (sandId / 10) * 10;
GameData.getCodexReliquaryArrayList().add(this); GameData.getCodexReliquaryArrayList().add(this);
GameData.getCodexReliquaryDataIdMap().put(getSuitId(), this); GameData.getCodexReliquaryDataIdMap().put(getSuitId(), this);

View File

@ -54,7 +54,7 @@ public class CombineData extends GameResource {
public int getSubCombineType() { public int getSubCombineType() {
return subCombineType; return subCombineType;
} }
public int getResultItemId() { public int getResultItemId() {
return resultItemId; return resultItemId;
} }
@ -80,4 +80,3 @@ public class CombineData extends GameResource {
} }
} }

View File

@ -7,7 +7,7 @@ import lombok.Getter;
import java.util.List; import java.util.List;
@ResourceType(name = {"CompoundExcelConfigData.json"},loadPriority = ResourceType.LoadPriority.LOW) @ResourceType(name = {"CompoundExcelConfigData.json"}, loadPriority = ResourceType.LoadPriority.LOW)
@Getter @Getter
public class CompoundData extends GameResource { public class CompoundData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)

View File

@ -1,11 +1,8 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData;
@ResourceType(name = {"CookBonusExcelConfigData.json"}, loadPriority = LoadPriority.LOW) @ResourceType(name = {"CookBonusExcelConfigData.json"}, loadPriority = LoadPriority.LOW)
public class CookBonusData extends GameResource { public class CookBonusData extends GameResource {
@ -15,9 +12,9 @@ public class CookBonusData extends GameResource {
private int[] complexParamVec; private int[] complexParamVec;
@Override @Override
public int getId() { public int getId() {
return this.avatarId; return this.avatarId;
} }
public int getAvatarId() { public int getAvatarId() {
return avatarId; return avatarId;

View File

@ -1,13 +1,13 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import lombok.Getter; import lombok.Getter;
import java.util.List;
@ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW) @ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW)
@Getter @Getter
public class CookRecipeData extends GameResource { public class CookRecipeData extends GameResource {

View File

@ -1,16 +1,17 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.Calendar;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter; import lombok.Getter;
import java.util.Calendar;
@ResourceType(name = "DailyDungeonConfigData.json") @ResourceType(name = "DailyDungeonConfigData.json")
public class DailyDungeonData extends GameResource { public class DailyDungeonData extends GameResource {
private static final int[] empty = new int[0];
private final Int2ObjectMap<int[]> map;
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int[] monday; private int[] monday;
@ -21,9 +22,6 @@ public class DailyDungeonData extends GameResource {
private int[] saturday; private int[] saturday;
private int[] sunday; private int[] sunday;
private static final int[] empty = new int[0];
private final Int2ObjectMap<int[]> map;
public DailyDungeonData() { public DailyDungeonData() {
this.map = new Int2ObjectOpenHashMap<>(); this.map = new Int2ObjectOpenHashMap<>();
} }

View File

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

View File

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

View File

@ -1,10 +1,11 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.ArrayList;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import java.util.ArrayList;
@ResourceType(name = "EquipAffixExcelConfigData.json") @ResourceType(name = "EquipAffixExcelConfigData.json")
public class EquipAffixData extends GameResource { public class EquipAffixData extends GameResource {

View File

@ -10,9 +10,9 @@ public class FetterCharacterCardData extends GameResource {
private int rewardId; private int rewardId;
@Override @Override
public int getId() { public int getId() {
return avatarId; return avatarId;
} }
public int getRewardId() { public int getRewardId() {
return rewardId; return rewardId;

View File

@ -1,12 +1,12 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.OpenCondData; import emu.grasscutter.data.common.OpenCondData;
import java.util.List;
@ResourceType(name = {"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json", "PhotographExpressionExcelConfigData.json", "PhotographPosenameExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST) @ResourceType(name = {"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json", "PhotographExpressionExcelConfigData.json", "PhotographPosenameExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
public class FetterData extends GameResource { public class FetterData extends GameResource {
private int avatarId; private int avatarId;
@ -14,9 +14,9 @@ public class FetterData extends GameResource {
private List<OpenCondData> openCond; private List<OpenCondData> openCond;
@Override @Override
public int getId() { public int getId() {
return fetterId; return fetterId;
} }
public int getAvatarId() { public int getAvatarId() {
return avatarId; return avatarId;

View File

@ -1,13 +1,13 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import lombok.Getter; import lombok.Getter;
import java.util.List;
@ResourceType(name = {"ForgeExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST) @ResourceType(name = {"ForgeExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
@Getter @Getter
public class ForgeData extends GameResource { public class ForgeData extends GameResource {

View File

@ -31,7 +31,7 @@ public class FurnitureMakeConfigData extends GameResource {
@Override @Override
public void onLoad() { public void onLoad() {
this.materialItems = materialItems.stream() this.materialItems = materialItems.stream()
.filter(x -> x.getId() > 0) .filter(x -> x.getId() > 0)
.toList(); .toList();
} }
} }

View File

@ -5,45 +5,45 @@ import emu.grasscutter.data.ResourceType;
@ResourceType(name = "GatherExcelConfigData.json") @ResourceType(name = "GatherExcelConfigData.json")
public class GatherData extends GameResource { public class GatherData extends GameResource {
private int pointType; private int pointType;
private int id; private int id;
private int gadgetId; private int gadgetId;
private int itemId; private int itemId;
private int cd; // Probably hours private int cd; // Probably hours
private boolean isForbidGuest; private boolean isForbidGuest;
private boolean initDisableInteract; private boolean initDisableInteract;
@Override
public int getId() {
return this.pointType;
}
public int getGatherId() { @Override
return id; public int getId() {
} return this.pointType;
}
public int getGadgetId() { public int getGatherId() {
return gadgetId; return id;
} }
public int getItemId() { public int getGadgetId() {
return itemId; return gadgetId;
} }
public int getCd() { public int getItemId() {
return cd; return itemId;
} }
public boolean isForbidGuest() { public int getCd() {
return isForbidGuest; return cd;
} }
public boolean initDisableInteract() { public boolean isForbidGuest() {
return initDisableInteract; return isForbidGuest;
} }
@Override public boolean initDisableInteract() {
public void onLoad() { return initDisableInteract;
}
} @Override
public void onLoad() {
}
} }

View File

@ -1,33 +1,35 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemUseData; import emu.grasscutter.data.common.ItemUseData;
import emu.grasscutter.game.inventory.*; import emu.grasscutter.game.inventory.EquipType;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.inventory.MaterialType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.ItemUseAction.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
import emu.grasscutter.game.props.ItemUseTarget; import emu.grasscutter.game.props.ItemUseTarget;
import emu.grasscutter.game.props.ItemUseAction.ItemUseAction;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter; import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@ResourceType(name = {"MaterialExcelConfigData.json", @ResourceType(name = {"MaterialExcelConfigData.json",
"WeaponExcelConfigData.json", "WeaponExcelConfigData.json",
"ReliquaryExcelConfigData.json", "ReliquaryExcelConfigData.json",
"HomeWorldFurnitureExcelConfigData.json" "HomeWorldFurnitureExcelConfigData.json"
}) })
@Getter @Getter
public class ItemData extends GameResource { public class ItemData extends GameResource {
// Main // Main
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private int stackLimit = 1; private final int stackLimit = 1;
private int maxUseCount; private int maxUseCount;
private int rankLevel; private int rankLevel;
private String effectName; private String effectName;
@ -39,7 +41,7 @@ public class ItemData extends GameResource {
private int[] destroyReturnMaterialCount; private int[] destroyReturnMaterialCount;
// Enums // Enums
private ItemType itemType = ItemType.ITEM_NONE; private final ItemType itemType = ItemType.ITEM_NONE;
private MaterialType materialType = MaterialType.MATERIAL_NONE; private MaterialType materialType = MaterialType.MATERIAL_NONE;
private EquipType equipType = EquipType.EQUIP_NONE; private EquipType equipType = EquipType.EQUIP_NONE;
private String effectType; private String effectType;
@ -50,10 +52,10 @@ public class ItemData extends GameResource {
private int[] satiationParams; private int[] satiationParams;
// Usable item // Usable item
private ItemUseTarget useTarget = ItemUseTarget.ITEM_USE_TARGET_NONE; private final ItemUseTarget useTarget = ItemUseTarget.ITEM_USE_TARGET_NONE;
private List<ItemUseData> itemUse; private List<ItemUseData> itemUse;
private List<ItemUseAction> itemUseActions; private List<ItemUseAction> itemUseActions;
private boolean useOnGain = false; private final boolean useOnGain = false;
// Relic // Relic
private int mainPropDepotId; private int mainPropDepotId;
@ -82,7 +84,7 @@ public class ItemData extends GameResource {
private List<Integer> furnType; private List<Integer> furnType;
private List<Integer> furnitureGadgetID; private List<Integer> furnitureGadgetID;
@SerializedName(value="roomSceneId", alternate={"BMEPAMCNABE", "DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK", "MFGACDIOHGF"}) @SerializedName(value = "roomSceneId", alternate = {"BMEPAMCNABE", "DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK", "MFGACDIOHGF"})
private int roomSceneId; private int roomSceneId;
// Custom // Custom
@ -128,10 +130,10 @@ public class ItemData extends GameResource {
if (this.itemUse != null && !this.itemUse.isEmpty()) { if (this.itemUse != null && !this.itemUse.isEmpty()) {
this.itemUseActions = this.itemUse.stream() this.itemUseActions = this.itemUse.stream()
.filter(x -> x.getUseOp() != ItemUseOp.ITEM_USE_NONE) .filter(x -> x.getUseOp() != ItemUseOp.ITEM_USE_NONE)
.map(ItemUseAction::fromItemUseData) .map(ItemUseAction::fromItemUseData)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
} }
} }

View File

@ -1,32 +1,32 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.CurveInfo; import emu.grasscutter.data.common.CurveInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
@ResourceType(name = "MonsterCurveExcelConfigData.json") @ResourceType(name = "MonsterCurveExcelConfigData.json")
public class MonsterCurveData extends GameResource { public class MonsterCurveData extends GameResource {
private int level; private int level;
private CurveInfo[] curveInfos; private CurveInfo[] curveInfos;
private Map<String, Float> curveInfoMap;
@Override
public int getId() {
return level;
}
public float getMultByProp(String fightProp) {
return curveInfoMap.getOrDefault(fightProp, 1f);
}
@Override private Map<String, Float> curveInfoMap;
public void onLoad() {
this.curveInfoMap = new HashMap<>(); @Override
Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue())); public int getId() {
} return level;
}
public float getMultByProp(String fightProp) {
return curveInfoMap.getOrDefault(fightProp, 1f);
}
@Override
public void onLoad() {
this.curveInfoMap = new HashMap<>();
Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue()));
}
} }

View File

@ -1,10 +1,6 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List;
import java.util.Set;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
@ -14,6 +10,9 @@ import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.MonsterType; import emu.grasscutter.game.props.MonsterType;
import lombok.Getter; import lombok.Getter;
import java.util.List;
import java.util.Set;
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW) @ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
@Getter @Getter
public class MonsterData extends GameResource { public class MonsterData extends GameResource {

View File

@ -12,24 +12,14 @@ import java.util.List;
public class OpenStateData extends GameResource { public class OpenStateData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
@Getter private boolean defaultState; @Getter
@Getter private boolean allowClientOpen; private boolean defaultState;
@Getter private int systemOpenUiId; @Getter
@Getter private List<OpenStateCond> cond; private boolean allowClientOpen;
@Getter
public static class OpenStateCond { private int systemOpenUiId;
@Getter private OpenStateCondType condType; @Getter
@Getter private int param; private List<OpenStateCond> cond;
@Getter private int param2;
}
public static enum OpenStateCondType {
OPEN_STATE_COND_PLAYER_LEVEL,
OPEN_STATE_COND_QUEST,
OPEN_STATE_OFFERING_LEVEL,
OPEN_STATE_CITY_REPUTATION_LEVEL,
OPEN_STATE_COND_PARENT_QUEST;
}
@Override @Override
public void onLoad() { public void onLoad() {
@ -43,6 +33,23 @@ public class OpenStateData extends GameResource {
this.cond = new ArrayList<>(); this.cond = new ArrayList<>();
} }
} }
public enum OpenStateCondType {
OPEN_STATE_COND_PLAYER_LEVEL,
OPEN_STATE_COND_QUEST,
OPEN_STATE_OFFERING_LEVEL,
OPEN_STATE_CITY_REPUTATION_LEVEL,
OPEN_STATE_COND_PARENT_QUEST
}
public static class OpenStateCond {
@Getter
private OpenStateCondType condType;
@Getter
private int param;
@Getter
private int param2;
}
} }
/* Open state names for documentation: /* Open state names for documentation:

View File

@ -10,7 +10,7 @@ public class PlayerLevelData extends GameResource {
private int level; private int level;
private int exp; private int exp;
private int rewardId; private int rewardId;
private int expeditionLimitAdd = 0; private final int expeditionLimitAdd = 0;
private int unlockWorldLevel; private int unlockWorldLevel;
private long unlockDescTextMapHash; private long unlockDescTextMapHash;

View File

@ -1,8 +1,5 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.ArrayList;
import java.util.List;
import dev.morphia.annotations.Transient; import dev.morphia.annotations.Transient;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
@ -10,23 +7,40 @@ import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import lombok.Getter; import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@ResourceType(name = "ProudSkillExcelConfigData.json") @ResourceType(name = "ProudSkillExcelConfigData.json")
public class ProudSkillData extends GameResource { public class ProudSkillData extends GameResource {
private int proudSkillId; private int proudSkillId;
@Getter private int proudSkillGroupId; @Getter
@Getter private int level; private int proudSkillGroupId;
@Getter private int coinCost; @Getter
@Getter private int breakLevel; private int level;
@Getter private int proudSkillType; @Getter
@Getter private String openConfig; private int coinCost;
@Getter private List<ItemParamData> costItems; @Getter
@Getter private List<String> filterConds; private int breakLevel;
@Getter private List<String> lifeEffectParams; @Getter
@Getter private FightPropData[] addProps; private int proudSkillType;
@Getter private float[] paramList; @Getter
@Getter private long[] paramDescList; private String openConfig;
@Getter private long nameTextMapHash; @Getter
@Transient private Iterable<ItemParamData> totalCostItems; private List<ItemParamData> costItems;
@Getter
private List<String> filterConds;
@Getter
private List<String> lifeEffectParams;
@Getter
private FightPropData[] addProps;
@Getter
private float[] paramList;
@Getter
private long[] paramDescList;
@Getter
private long nameTextMapHash;
@Transient
private Iterable<ItemParamData> totalCostItems;
@Override @Override
public int getId() { public int getId() {

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