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;
import java.util.Arrays;
import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils;
public final class GameConstants {
public static String VERSION = "3.5.0";
import java.util.Arrays;
public final class GameConstants {
public static final int DEFAULT_TEAMS = 4;
public static final int MAX_TEAMS = 10;
public static final int MAIN_CHARACTER_MALE = 10000005;
public static final int MAIN_CHARACTER_FEMALE = 10000007;
public static final Position START_POSITION = new Position(2747, 194, -1719);
public static final int MAX_FRIENDS = 60;
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 BATTLE_PASS_MAX_LEVEL = 50;
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_LEVEL_PRICE = 150;
public static final int BATTLE_PASS_CURRENT_INDEX = 2;
// Default entity ability hashes.
public static final String[] DEFAULT_ABILITY_STRINGS = {
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
@ -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_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.Logger;
import emu.grasscutter.auth.AuthenticationSystem;
import emu.grasscutter.auth.DefaultAuthentication;
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.LogHandler;
import emu.grasscutter.tools.Tools;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.Language;
import emu.grasscutter.utils.StartupArguments;
import emu.grasscutter.utils.Utils;
import emu.grasscutter.utils.*;
import lombok.Getter;
import lombok.Setter;
import org.jline.reader.EndOfFileException;
@ -41,34 +36,47 @@ import org.reflections.Reflections;
import org.slf4j.LoggerFactory;
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 static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.utils.Language.translate;
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");
@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");
@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 {
// Declare logback configuration.
@ -265,7 +273,7 @@ public final class Grasscutter {
public static void updateDayOfWeek() {
Calendar calendar = Calendar.getInstance();
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() {

View File

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

View File

@ -1,17 +1,20 @@
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.
*
* @param <T> The response object type. Should be {@link LoginResultJson} or {@link ComboTokenResJson}
*/
public interface Authenticator<T> {
/**
* Attempt to authenticate the client with the provided credentials.
*
* @param request The authentication request wrapped in a {@link AuthenticationSystem.AuthenticationRequest} object.
* @return The result of the login in an object.
*/
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.
*/
public final class DefaultAuthentication implements AuthenticationSystem {
private Authenticator<LoginResultJson> passwordAuthenticator;
private Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator();
private Authenticator<ComboTokenResJson> sessionKeyAuthenticator = new SessionKeyAuthenticator();
private ExternalAuthenticator externalAuthenticator = new ExternalAuthentication();
private OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
private final Authenticator<LoginResultJson> passwordAuthenticator;
private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator();
private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator = new SessionKeyAuthenticator();
private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication();
private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
public DefaultAuthentication() {
if (ACCOUNT.EXPERIMENTAL_RealPassword) {

View File

@ -5,7 +5,8 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
import emu.grasscutter.database.DatabaseHelper;
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.Utils;
@ -15,7 +16,7 @@ import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
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;
/**

View File

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

View File

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

View File

@ -15,13 +15,14 @@ public @interface Command {
String permissionTargeted() default "";
public enum TargetRequirement {
TargetRequirement targetRequirement() default TargetRequirement.ONLINE;
boolean threading() default false;
enum TargetRequirement {
NONE, // targetPlayer is not required
OFFLINE, // targetPlayer must be offline
PLAYER, // targetPlayer can be online or offline
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.game.player.Player;
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.StringJoiner;
import static emu.grasscutter.utils.Language.translate;
public interface CommandHandler {
/**
@ -52,7 +51,8 @@ public interface CommandHandler {
String target = switch (annotation.targetRequirement()) {
case NONE -> "";
case OFFLINE -> "@<UID> "; // TODO: make translation keys for offline and online players
case ONLINE -> (player == null) ? "@<UID> " : "[@<UID>] "; // TODO: make translation keys for offline and online players
case ONLINE ->
(player == null) ? "@<UID> " : "[@<UID>] "; // TODO: make translation keys for offline and online players
case PLAYER -> (player == null) ? "@<UID> " : "[@<UID>] ";
};
String[] usages = annotation.usage();
@ -81,8 +81,9 @@ public interface CommandHandler {
/**
* Called when a player/console invokes a 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) {
}

View File

@ -5,23 +5,20 @@ import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.reflections.Reflections;
import java.net.IDN;
import java.util.*;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.config.Configuration.SERVER;
@SuppressWarnings({"UnusedReturnValue", "unused"})
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> aliases = new TreeMap<>();
private final Map<String, Command> annotations = new TreeMap<>();
private final Object2IntMap<String> targetPlayerIds = new Object2IntOpenHashMap<>();
private static final int INVALID_UID = Integer.MIN_VALUE;
private static final String consoleId = "console";
public CommandMap() {
this(false);
@ -35,6 +32,20 @@ public final class CommandMap {
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.
*
@ -52,11 +63,9 @@ public final class CommandMap {
this.commands.put(label, command);
// Register aliases.
if (annotation.aliases().length > 0) {
for (String alias : annotation.aliases()) {
this.aliases.put(alias, command);
this.annotations.put(alias, annotation);
}
for (String alias : annotation.aliases()) {
this.aliases.put(alias, command);
this.annotations.put(alias, annotation);
}
return this;
}
@ -78,11 +87,9 @@ public final class CommandMap {
this.commands.remove(label);
// Unregister aliases.
if (annotation.aliases().length > 0) {
for (String alias : annotation.aliases()) {
this.aliases.remove(alias);
this.annotations.remove(alias);
}
for (String alias : annotation.aliases()) {
this.aliases.remove(alias);
this.annotations.remove(alias);
}
return this;
@ -124,20 +131,6 @@ public final class CommandMap {
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) {
// Top priority: If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) {

View File

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

View File

@ -3,6 +3,7 @@ package emu.grasscutter.command;
import emu.grasscutter.game.player.Player;
public interface PermissionHandler {
public boolean EnablePermissionCommand();
public boolean checkPermission(Player player, Player targetPlayer, String permissionNode, String permissionNodeTargeted);
boolean EnablePermissionCommand();
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;
String password = "";
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) {
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
if (args.size() < 3) {
CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires a password argument");
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));
} catch (NumberFormatException ignored) {
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, "Usage: account create <username> <password> [uid]");
}
@ -81,7 +81,7 @@ public final class AccountCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.exists"));
return;
} else {
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) {
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
account.setPassword(BCrypt.withDefaults().hashToString(12, password.toCharArray()));
}
account.addPermission("*");
@ -103,7 +103,7 @@ public final class AccountCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.delete"));
return;
case "resetpass":
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) {
if (!Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage(sender, "resetpass requires EXPERIMENTAL_RealPassword to be true.");
return;
}
@ -127,7 +127,6 @@ public final class AccountCommand implements CommandHandler {
toUpdate.setPassword(BCrypt.withDefaults().hashToString(12, args.get(2).toCharArray()));
toUpdate.save();
CommandHandler.sendMessage(sender, "Password Updated.");
return;
}
}

View File

@ -21,71 +21,6 @@ import java.util.concurrent.atomic.AtomicInteger;
targetRequirement = Command.TargetRequirement.PLAYER,
threading = true)
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) {
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());
}
@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;
import java.util.List;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.game.GameSession;
import java.util.List;
@Command(
label = "ban",
usage = {"[<time> [<reason>]]"},

View File

@ -29,28 +29,22 @@ public final class ClearCommand implements CommandHandler {
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) {
return playerInventory.getItems().values().stream()
.filter(item -> item.getItemType() == type)
.filter(item -> item.getItemData().getRankLevel() <= param.rank)
.filter(item -> !item.isLocked() && !item.isEquipped());
.filter(item -> item.getItemType() == type)
.filter(item -> item.getItemData().getRankLevel() <= param.rank)
.filter(item -> !item.isLocked() && !item.isEquipped());
}
private Stream<GameItem> getWeapons(Inventory playerInventory, ClearItemParameters param) {
return getOther(ItemType.ITEM_WEAPON, playerInventory, param)
.filter(item -> item.getLevel() <= param.lvl)
.filter(item -> item.getRefinement() < param.refinement);
.filter(item -> item.getLevel() <= param.lvl)
.filter(item -> item.getRefinement() < param.refinement);
}
private Stream<GameItem> getRelics(Inventory playerInventory, ClearItemParameters param) {
return getOther(ItemType.ITEM_RELIQUARY, playerInventory, param)
.filter(item -> item.getLevel() <= param.lvl + 1);
.filter(item -> item.getLevel() <= param.lvl + 1);
}
@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.GameDepot;
import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.data.excels.AvatarSkillDepotData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.data.excels.ReliquaryAffixData;
import emu.grasscutter.data.excels.ReliquaryMainPropData;
@ -36,14 +35,6 @@ import static emu.grasscutter.command.CommandHelpers.*;
permissionTargeted = "player.give.others",
threading = true)
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(
Map.entry(lvlRegex, GiveItemParameters::setLvl),
Map.entry(refineRegex, GiveItemParameters::setRefinement),
@ -51,168 +42,18 @@ public final class GiveCommand implements CommandHandler {
Map.entry(constellationRegex, GiveItemParameters::setConstellation),
Map.entry(skillLevelRegex, GiveItemParameters::setSkillLevel)
);
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;
}
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 final SparseSet illegalWeaponIds = new SparseSet("""
10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509,
13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
""");
private static final SparseSet illegalRelicIds = new SparseSet("""
20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554
""");
private static final SparseSet illegalItemIds = new SparseSet("""
100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000,
105001, 105004, 106000-107000, 107011, 108000, 109000-110000,
115000-130000, 200200-200899, 220050, 220054
""");
private static Avatar makeAvatar(GiveItemParameters param) {
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) {
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()) {
int id = avatarData.getId();
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);
item.setLevel(param.lvl);
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
item.setMainPropId(param.mainPropId);
if (param.appendPropIdList != null) {
@ -431,18 +273,176 @@ public final class GiveCommand implements CommandHandler {
giveAllWeapons(player, param);
}
private static final SparseSet illegalWeaponIds = new SparseSet("""
10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509,
13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
""");
private GiveItemParameters parseArgs(Player sender, List<String> args) throws IllegalArgumentException {
GiveItemParameters param = new GiveItemParameters();
private static final SparseSet illegalRelicIds = new SparseSet("""
20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554
""");
// Extract any tagged arguments (e.g. "lv90", "x100", "r5")
parseIntParameters(args, param, intCommandHandlers);
private static final SparseSet illegalItemIds = new SparseSet("""
100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000,
105001, 105004, 106000-107000, 107011, 108000, 109000-110000,
115000-130000, 200200-200899, 220050, 220054
""");
// 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());
}
} 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 -> {
boolean isAlive = entity.isAlive();
entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)
FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)
);
entity.getWorld().broadcastPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
if (!isAlive) {

View File

@ -6,7 +6,8 @@ import emu.grasscutter.command.CommandMap;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
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
final Scene sceneF = scene;
List<GameEntity> toKill = sceneF.getEntities().values().stream()
.filter(entity -> entity instanceof EntityMonster)
.toList();
.filter(entity -> entity instanceof EntityMonster)
.toList();
toKill.forEach(entity -> sceneF.killEntity(entity, 0));
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", toKill.size(), scene.getId()));
}

View File

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

View File

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

View File

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

View File

@ -15,6 +15,6 @@ public final class PositionCommand implements CommandHandler {
Position pos = targetPlayer.getPosition();
Position rot = targetPlayer.getRotation();
CommandHandler.sendTranslatedMessage(sender, "commands.position.success",
pos.getX(), pos.getY(), pos.getZ(), rot.getX(), rot.getY(), rot.getZ(), targetPlayer.getSceneId());
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;
@Command(label = "quest",
aliases = {"q"},
usage = {"(add|finish) [<questId>]"},
permission = "player.quest",
permissionTargeted = "player.quest.others")
aliases = {"q"},
usage = {"(add|finish) [<questId>]"},
permission = "player.quest",
permissionTargeted = "player.quest.others")
public final class QuestCommand implements CommandHandler {
@Override

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,5 @@
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.CommandHandler;
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.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")
public final class SetPropCommand implements CommandHandler {
static 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;
}
}
// List of map areas. Unfortunately, there is no readily available source for them in excels or bins.
private static final List<Integer> sceneAreas = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403);
Map<String, Prop> props;
public SetPropCommand() {
@ -146,7 +107,8 @@ public final class SetPropCommand implements CommandHandler {
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool(sender, targetPlayer, prop.pseudoProp, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY ->
this.setBool(sender, targetPlayer, prop.pseudoProp, value);
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
case UNLOCK_MAP -> unlockMap(targetPlayer);
@ -185,9 +147,7 @@ public final class SetPropCommand implements CommandHandler {
}
// Remove records for each floor past our target
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+
if (topFloor > 8) {
@ -230,8 +190,6 @@ public final class SetPropCommand implements CommandHandler {
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) {
// Unlock.
GameData.getScenePointsPerScene().forEach((sceneId, scenePoints) -> {
@ -248,4 +206,45 @@ public final class SetPropCommand implements CommandHandler {
targetPlayer.sendPacket(new PacketSceneAreaUnlockNotify(playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
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;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
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.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Command(
label = "setStats",
aliases = {"stats", "stat"},
@ -22,34 +22,7 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
permission = "player.setstats",
permissionTargeted = "player.setstats.others")
public final class SetStatsCommand implements CommandHandler {
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;
}
}
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;
private final Map<String, Stat> stats;
public SetStatsCommand() {
this.stats = new HashMap<>();
@ -86,7 +59,7 @@ public final class SetStatsCommand implements CommandHandler {
public static float parsePercent(String input) throws NumberFormatException {
if (input.endsWith("%")) {
return Float.parseFloat(input.substring(0, input.length()-1))/100f;
return Float.parseFloat(input.substring(0, input.length() - 1)) / 100f;
} else {
return Float.parseFloat(input);
}
@ -106,7 +79,10 @@ public final class SetStatsCommand implements CommandHandler {
// Get the action and stat
String arg0 = args.remove(0).toLowerCase();
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 "lock", "freeze" -> Action.ACTION_LOCK;
case "unlock", "unfreeze" -> Action.ACTION_UNLOCK;
@ -176,6 +152,33 @@ public final class SetStatsCommand implements CommandHandler {
String uidStr = targetPlayer.getAccount().getId();
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));
}
;
private EntityItem createItem(ItemData itemData, SpawnParameters param, Position pos) {
return new EntityItem(param.scene, null, itemData, pos, 1, true);
}
@ -188,19 +186,32 @@ public final class SpawnCommand implements CommandHandler {
}
private static class SpawnParameters {
@Setter public int id;
@Setter public int lvl = 1;
@Setter public int amount = 1;
@Setter public int blockId = -1;
@Setter public int groupId = -1;
@Setter public int configId = -1;
@Setter public int state = -1;
@Setter public int hp = -1;
@Setter public int maxHP = -1;
@Setter public int atk = -1;
@Setter public int def = -1;
@Setter public int ai = -1;
@Setter public Position pos = null;
@Setter
public int id;
@Setter
public int lvl = 1;
@Setter
public int amount = 1;
@Setter
public int blockId = -1;
@Setter
public int groupId = -1;
@Setter
public int configId = -1;
@Setter
public int state = -1;
@Setter
public int hp = -1;
@Setter
public int maxHP = -1;
@Setter
public int atk = -1;
@Setter
public int def = -1;
@Setter
public int ai = -1;
@Setter
public Position pos = null;
public Scene scene = null;
}
}

View File

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

View File

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

View File

@ -36,7 +36,7 @@ public final class TeleportCommand implements CommandHandler {
case 4:
try {
sceneId = Integer.parseInt(args.get(3));
}catch (NumberFormatException ignored) {
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
} // Fallthrough
case 3:
@ -60,7 +60,7 @@ public final class TeleportCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
} else {
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;
import java.util.List;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import java.util.List;
@Command(
label = "unban",
permission = "server.ban",

View File

@ -7,10 +7,10 @@ import emu.grasscutter.Grasscutter.ServerDebugMode;
import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.utils.JsonUtils;
import java.util.Set;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Locale;
import java.util.Set;
import static emu.grasscutter.Grasscutter.config;
@ -18,6 +18,14 @@ import static emu.grasscutter.Grasscutter.config;
* *when your JVM fails*
*/
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() {
return 4;
}
@ -32,7 +40,8 @@ public class ConfigContainer {
Grasscutter.getLogger().info("Updating legacy ..");
Grasscutter.saveConfig(null);
}
} catch (Exception ignored) { }
} catch (Exception ignored) {
}
var existing = config.version;
var latest = version();
@ -50,7 +59,8 @@ public class ConfigContainer {
} catch (Exception exception) {
Grasscutter.getLogger().error("Failed to update a configuration field.", exception);
}
}); updated.version = version();
});
updated.version = version();
try { // Save configuration & reload.
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. */
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
* (see StartupArguments.enableDebug) */
* (see StartupArguments.enableDebug) */
public static class DebugMode {
/* Log level of the main server code (works only with -debug arg) */
public Level serverLoggerLevel = Level.DEBUG;
@ -260,16 +261,16 @@ public class ConfigContainer {
public static class Mail {
public String title = "Welcome to Grasscutter!";
public String content = """
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
\r
Check out our:\r
<type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/>
""";
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
\r
Check out our:\r
<type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/>
""";
public String sender = "Lawnmower";
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(201, 99999, 1)
new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1),
new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1)
};
}
}
@ -292,21 +293,20 @@ public class ConfigContainer {
/* Objects. */
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 Title = "Grasscutter";
public String Ip = "127.0.0.1";
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.
*
* <p>
* Use `import static emu.grasscutter.Configuration.*;`
* 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 FALLBACK_LANGUAGE = config.language.fallback;
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 Database DATABASE = config.databaseInfo;
public static final Account ACCOUNT = config.account;
public static final HTTP HTTP_INFO = config.server.http;
public static final Game GAME_INFO = config.server.game;
public static final Dispatch DISPATCH_INFO = config.server.dispatch;
public static final DebugMode DEBUG_MODE_INFO = config.server.debugMode;
public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption;
public static final Policies HTTP_POLICIES = config.server.http.policies;
public static final Files HTTP_STATIC_FILES = config.server.http.files;
public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions;
public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits;
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
@ -91,7 +87,8 @@ public final class Configuration extends ConfigContainer {
/**
* Fallback method.
* @param left Attempt to use.
*
* @param left Attempt to use.
* @param right Use if left is undefined.
* @return Left or right.
*/
@ -101,7 +98,8 @@ public final class Configuration extends ConfigContainer {
/**
* {@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.
* @return Left or right.
*/
@ -111,7 +109,8 @@ public final class Configuration extends ConfigContainer {
/**
* {@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.
* @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)) {
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 {
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)) {
case "json" -> JsonUtils.loadToList(path, classType);
case "tsj" -> TsvUtils.loadTsjToListSetField(path, classType);

View File

@ -1,116 +1,182 @@
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.data.binout.*;
import emu.grasscutter.data.excels.*;
import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.utils.Utils;
import emu.grasscutter.data.excels.*;
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 it.unimi.dsi.fastutil.ints.*;
import lombok.Getter;
import lombok.experimental.Tolerate;
import java.lang.reflect.Field;
import java.util.*;
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 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<QuestEncryptionKey> questsKeys = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<SceneNpcBornData> npcBornData = new Int2ObjectOpenHashMap<>();
private static final Map<String, AbilityEmbryoEntry> abilityEmbryos = new HashMap<>();
// 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<>();
@Getter private static final Int2ObjectMap<AchievementGoalData> achievementGoalDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ActivityShopData> activityShopDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataItemIdMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarData> avatarDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarFlycloakData> avatarFlycloakDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarLevelData> avatarLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<BlossomRefreshExcelConfigData> blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<BuffData> buffDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CookBonusData> cookBonusDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<CompoundData> compoundDataMap=new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = 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<>();
@Getter
private static final Int2ObjectMap<AchievementGoalData> achievementGoalDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<ActivityShopData> activityShopDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataItemIdMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarData> avatarDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarFlycloakData> avatarFlycloakDataMap = new Int2ObjectLinkedOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarLevelData> avatarLevelDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<BlossomRefreshExcelConfigData> blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<BuffData> buffDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CookBonusData> cookBonusDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<CompoundData> compoundDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = 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<FetterData> fetterDataMap = 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<>();
// Cache
@Getter private static final IntList scenePointIdList = new IntArrayList();
@Getter private static final List<OpenStateData> openStateList = new ArrayList<>();
@Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
@Getter private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>();
@Getter
private static final IntList scenePointIdList = new IntArrayList();
@Getter
private static final List<OpenStateData> openStateList = new ArrayList<>();
@Getter
private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
@Getter
private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
protected static Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>();
protected static Int2IntMap proudSkillGroupMaxLevels = new Int2IntOpenHashMap();
protected static Int2ObjectMap<IntSet> avatarSkillLevels = new Int2ObjectOpenHashMap<>();
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
@Deprecated(forRemoval = true) public static Int2ObjectMap<CodexReliquaryData> getcodexReliquaryIdMap() {return codexReliquaryDataIdMap;}
@Deprecated(forRemoval = true) public static Int2ObjectMap<DungeonEntryData> getDungeonEntryDatatMap() {return dungeonEntryDataMap;}
@Deprecated(forRemoval = true) @Tolerate public static ArrayList<CodexReliquaryData> getcodexReliquaryArrayList() {return codexReliquaryArrayList;}
@Deprecated(forRemoval = true)
public static Int2ObjectMap<CodexReliquaryData> getcodexReliquaryIdMap() {
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
public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() {return mainQuestData;}
public static Int2ObjectMap<QuestEncryptionKey> getMainQuestEncryptionMap() {return questsKeys;}
public static Int2ObjectMap<SceneNpcBornData> getSceneNpcBornData() {return npcBornData;}
public static Map<String, AbilityEmbryoEntry> getAbilityEmbryoInfo() {return abilityEmbryos;}
public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() {
return mainQuestData;
}
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.
public static AbilityData getAbilityData(String abilityName) {return abilityDataMap.get(abilityName);}
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);}
public static AbilityData getAbilityData(String abilityName) {
return abilityDataMap.get(abilityName);
}
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
public static AvatarPromoteData getAvatarPromoteData(int promoteId, int promoteLevel) {
@ -198,7 +302,6 @@ public class GameData {
}
public static int getWeaponExpRequired(int rankLevel, int level) {
WeaponLevelData levelData = weaponLevelDataMap.get(level);
if (levelData == null) {

View File

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

View File

@ -1,12 +1,12 @@
package emu.grasscutter.data;
public abstract class GameResource {
public int getId() {
return 0;
}
public void onLoad() {
}
public int getId() {
return 0;
}
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.IntArraySet;
import lombok.val;
import org.reflections.Reflections;
import java.io.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@ -38,6 +38,7 @@ import static emu.grasscutter.utils.Language.translate;
public class ResourceLoader {
private static final Set<String> loadedResources = new CopyOnWriteArraySet<>();
private static boolean loadedAll = false;
// Get a list of all resource classes, sorted by loadPriority
public static List<Class<?>> getResourceDefClasses() {
@ -62,7 +63,7 @@ public class ResourceLoader {
val reflections = new Reflections(ResourceLoader.class.getPackage().getName());
val classes = reflections.getSubTypesOf(GameResource.class);
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());
priorities.forEach(p -> map.put(p, new HashSet<>()));
@ -76,7 +77,6 @@ public class ResourceLoader {
return List.copyOf(map.values());
}
private static boolean loadedAll = false;
public static void loadAll() {
if (loadedAll) return;
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()));
long endTime = System.nanoTime();
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")
@ -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() {
val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
try {
@ -210,7 +207,6 @@ public class ResourceLoader {
});
} catch (IOException e) {
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
try {
embryoList = JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
if (embryoList == null) {
// 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() {
// Load from BinOutput
try (Stream<Path> paths = Files.walk(getResourcePath("BinOutput/Ability/Temp/"))) {
paths.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".json")).forEach(ResourceLoader::loadAbilityModifiers);
} catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers: ", e);
return;
}
// System.out.println("Loaded modifiers, found types:");
// modifierActionTypes.stream().sorted().forEach(s -> System.out.printf("%s, ", s));
// System.out.println("[End]");
}
private static void loadAbilityModifiers(Path path) {
try {
JsonUtils.loadToList(path, AbilityConfigData.class).forEach(data -> loadAbilityData(data.Default));
} catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers from path " + path.toString() + ": ", e);
return;
}
}
private static void loadAbilityData(AbilityData data) {
GameData.abilityDataMap.put(data.abilityName, data);
@ -344,7 +337,8 @@ public class ResourceLoader {
try (InputStreamReader reader = DataLoader.loadReader(name)) {
// Add spawns to group if it already exists in our spawn group map
spawnEntryMap.addAll(JsonUtils.loadToList(reader, SpawnGroupEntry.class));
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
}
if (spawnEntryMap.isEmpty()) {
@ -375,7 +369,8 @@ public class ResourceLoader {
try {
list = JsonUtils.loadToList(getDataPath("OpenConfig.json"), OpenConfigEntry.class);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
if (list == null) {
Map<String, OpenConfigEntry> map = new TreeMap<>();
@ -389,7 +384,6 @@ public class ResourceLoader {
.forEach((name, data) -> map.put(name, new OpenConfigEntry(name, data)));
} catch (Exception e) {
e.printStackTrace();
return;
}
});
} catch (IOException e) {
@ -431,10 +425,12 @@ public class ResourceLoader {
String path = "QuestEncryptionKeys.json";
try {
JsonUtils.loadToList(getResourcePath(path), QuestEncryptionKey.class).forEach(key -> questEncryptionMap.put(key.getMainQuestId(), key));
} catch (IOException | NullPointerException ignored) {}
} catch (IOException | NullPointerException ignored) {
}
try {
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());
} catch (Exception 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));
} catch (IOException e) {
e.printStackTrace();
return;
}
});
Grasscutter.getLogger().debug("Loaded " + GameData.getScriptSceneDataMap().size() + " ScriptSceneDatas.");
} catch (IOException e) {
Grasscutter.getLogger().debug("ScriptSceneData folder missing or empty.");
return;
}
}
@ -471,7 +465,8 @@ public class ResourceLoader {
val sceneId = Integer.parseInt(matcher.group(1));
val data = JsonUtils.loadToClass(path, HomeworldDefaultSaveData.class);
GameData.getHomeworldDefaultSaveData().put(sceneId, data);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
});
Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas.");
} catch (IOException e) {
@ -490,7 +485,8 @@ public class ResourceLoader {
data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint()));
GameData.getSceneNpcBornData().put(data.getSceneId(), data);
} catch (IOException ignored) {}
} catch (IOException ignored) {
}
});
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
} catch (IOException e) {
@ -505,7 +501,6 @@ public class ResourceLoader {
GameData.getGadgetConfigData().putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class));
} catch (Exception e) {
Grasscutter.getLogger().error("failed to load ConfigGadget entries for " + path.toString(), e);
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 {
@SerializedName(value="abilities", alternate={"targetAbilities"})
@SerializedName(value = "abilities", alternate = {"targetAbilities"})
public ArrayList<AvatarConfigAbility> abilities;
}
// BinOutput configs
public static class AvatarConfigAbility {
public String abilityName;
public String toString() {
return abilityName;
}
@ -546,13 +547,17 @@ public class ResourceLoader {
public String $type;
public String abilityName;
@SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"})
@SerializedName(value = "talentIndex", alternate = {"OJOFFKLNAHN"})
public int talentIndex;
@SerializedName(value="skillID", alternate={"overtime"})
@SerializedName(value = "skillID", alternate = {"overtime"})
public int skillID;
@SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"})
@SerializedName(value = "pointDelta", alternate = {"IGEBKIHPOIF"})
public int pointDelta;
}
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.stream.Stream;
@Retention(RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResourceType {
/** Names of the file that this Resource loads from */
String[] name();
/** Load priority - dictates which order to load this resource, with "highest" being loaded first */
LoadPriority loadPriority() default LoadPriority.NORMAL;
public enum LoadPriority {
HIGHEST (4),
HIGH (3),
NORMAL (2),
LOW (1),
LOWEST (0);
/**
* Names of the file that this Resource loads from
*/
String[] name();
private final int value;
LoadPriority(int value) {
this.value = value;
}
public int value() {
return value;
}
/**
* Load priority - dictates which order to load this resource, with "highest" being loaded first
*/
LoadPriority loadPriority() default LoadPriority.NORMAL;
enum LoadPriority {
HIGHEST(4),
HIGH(3),
NORMAL(2),
LOW(1),
LOWEST(0);
private final int value;
LoadPriority(int value) {
this.value = value;
}
public static List<LoadPriority> getInOrder() {
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;
public class AbilityEmbryoEntry {
private String name;
private String[] abilities;
public AbilityEmbryoEntry() {
private String name;
private String[] abilities;
}
public AbilityEmbryoEntry(String avatarName, String[] array) {
this.name = avatarName;
this.abilities = array;
}
public AbilityEmbryoEntry() {
public String getName() {
return name;
}
public String[] getAbilities() {
return abilities;
}
}
public AbilityEmbryoEntry(String avatarName, String[] array) {
this.name = avatarName;
this.abilities = array;
}
public String getName() {
return name;
}
public String[] getAbilities() {
return abilities;
}
}

View File

@ -1,22 +1,35 @@
package emu.grasscutter.data.binout;
import java.io.Serializable;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.common.DynamicFloat;
import java.io.Serializable;
public class AbilityModifier implements Serializable {
private static final long serialVersionUID = -2001232313615923575L;
@SerializedName(value="onAdded", alternate={"KCICDEJLIJD"})
@SerializedName(value = "onAdded", alternate = {"KCICDEJLIJD"})
public AbilityModifierAction[] onAdded;
@SerializedName(value="onThinkInterval", alternate={"PBDDACFFPOE"})
@SerializedName(value = "onThinkInterval", alternate = {"PBDDACFFPOE"})
public AbilityModifierAction[] onThinkInterval;
public AbilityModifierAction[] onRemoved;
public DynamicFloat duration = DynamicFloat.ZERO;
public static class AbilityModifierAction {
@SerializedName("$type")
public Type type;
public String target;
@SerializedName(value = "amount", alternate = "PDLLIFICICJ")
public DynamicFloat amount = DynamicFloat.ZERO;
public DynamicFloat amountByCasterAttackRatio = DynamicFloat.ZERO;
public DynamicFloat amountByCasterCurrentHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByCasterMaxHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByGetDamage = DynamicFloat.ZERO;
public DynamicFloat amountByTargetCurrentHPRatio = DynamicFloat.ZERO;
public DynamicFloat amountByTargetMaxHPRatio = DynamicFloat.ZERO;
@SerializedName(value = "ignoreAbilityProperty", alternate = "HHFGADCJJDI")
public boolean ignoreAbilityProperty;
public String modifierName;
public enum Type {
ActCameraRadialBlur, ActCameraShake, AddAvatarSkillInfo, AddChargeBarValue,
AddClimateMeter, AddElementDurability, AddGlobalValue, AddGlobalValueToTarget,
@ -71,22 +84,8 @@ public class AbilityModifier implements Serializable {
TriggerSetPassThrough, TriggerSetRenderersEnable, TriggerSetShadowRamp, TriggerSetVisible,
TriggerTaunt, TriggerThrowEquipPart, TriggerUGCGadgetMove, TryFindBlinkPoint,
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

View File

@ -1,37 +1,37 @@
package emu.grasscutter.data.binout;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
public class AbilityModifierEntry {
private String name; // Custom value
public List<AbilityModifierAction> onModifierAdded;
public List<AbilityModifierAction> onThinkInterval;
public List<AbilityModifierAction> onRemoved;
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> onModifierAdded;
public List<AbilityModifierAction> onThinkInterval;
public List<AbilityModifierAction> onRemoved;
private final String name; // Custom value
public List<AbilityModifierAction> getOnAdded() {
return onModifierAdded;
}
public AbilityModifierEntry(String name) {
this.name = name;
this.onModifierAdded = new ArrayList<>();
this.onThinkInterval = new ArrayList<>();
this.onRemoved = new ArrayList<>();
}
public List<AbilityModifierAction> getOnThinkInterval() {
return onThinkInterval;
}
public String getName() {
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;
import com.google.gson.annotations.SerializedName;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;

View File

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

View File

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

View File

@ -1,72 +1,72 @@
package emu.grasscutter.data.binout;
import emu.grasscutter.data.ResourceLoader.OpenConfigData;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.data.ResourceLoader.OpenConfigData;
public class OpenConfigEntry {
private String name;
private String[] addAbilities;
private int extraTalentIndex;
private SkillPointModifier[] skillPointModifiers;
private final String name;
private String[] addAbilities;
private int extraTalentIndex;
private SkillPointModifier[] skillPointModifiers;
public OpenConfigEntry(String name, OpenConfigData[] data) {
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 OpenConfigEntry(String name, OpenConfigData[] data) {
this.name = name;
public String getName() {
return name;
}
List<String> abilityList = new ArrayList<>();
List<SkillPointModifier> modList = new ArrayList<>();
public String[] getAddAbilities() {
return addAbilities;
}
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));
}
}
public int getExtraTalentIndex() {
return extraTalentIndex;
}
public SkillPointModifier[] getSkillPointModifiers() {
return skillPointModifiers;
}
if (abilityList.size() > 0) {
this.addAbilities = abilityList.toArray(new String[0]);
}
public static class SkillPointModifier {
private int skillId;
private int delta;
public SkillPointModifier(int skillId, int delta) {
this.skillId = skillId;
this.delta = delta;
}
if (modList.size() > 0) {
this.skillPointModifiers = modList.toArray(new SkillPointModifier[0]);
}
}
public int getSkillId() {
return skillId;
}
public String getName() {
return name;
}
public int getDelta() {
return delta;
}
}
public String[] getAddAbilities() {
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;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.utils.Position;
import lombok.AccessLevel;
import lombok.Data;
@ -7,26 +8,24 @@ import lombok.experimental.FieldDefaults;
import java.util.List;
import com.google.gson.annotations.SerializedName;
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SceneNpcBornEntry {
@SerializedName(value="id", alternate={"_id", "ID"})
@SerializedName(value = "id", alternate = {"_id", "ID"})
int id;
@SerializedName(value="configId", alternate={"_configId"})
@SerializedName(value = "configId", alternate = {"_configId"})
int configId;
@SerializedName(value="pos", alternate={"_pos"})
@SerializedName(value = "pos", alternate = {"_pos"})
Position pos;
@SerializedName(value="rot", alternate={"_rot"})
@SerializedName(value = "rot", alternate = {"_rot"})
Position rot;
@SerializedName(value="groupId", alternate={"_groupId"})
@SerializedName(value = "groupId", alternate = {"_groupId"})
int groupId;
@SerializedName(value="suiteIdList", alternate={"_suiteIdList"})
@SerializedName(value = "suiteIdList", alternate = {"_suiteIdList"})
List<Integer> suiteIdList;
}

View File

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

View File

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

View File

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

View File

@ -1,63 +1,22 @@
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.objects.Object2FloatArrayMap;
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import lombok.val;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.luaj.vm2.ast.Str;
import java.util.List;
import java.util.Optional;
public class DynamicFloat {
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 boolean dynamic = false;
private float constant = 0f;
public DynamicFloat(float 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) {
this.dynamic = true;
this.ops = List.of(new StackOp(key));
@ -73,6 +32,12 @@ public class DynamicFloat {
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() {
return this.get(new Object2FloatArrayMap<String>());
}
@ -87,13 +52,46 @@ public class DynamicFloat {
case CONSTANT -> fl.push(op.fValue);
case KEY -> fl.push(props.getOrDefault(op.sValue, 0f));
case ADD -> fl.push(fl.popFloat() + fl.popFloat());
case SUB -> fl.push(-fl.popFloat() + fl.popFloat()); // [f0, f1, f2] -> [f0, f1-f2] (opposite of RPN order)
case SUB ->
fl.push(-fl.popFloat() + fl.popFloat()); // [f0, f1, f2] -> [f0, f1-f2] (opposite of RPN order)
case MUL -> fl.push(fl.popFloat() * fl.popFloat());
case DIV -> fl.push((1f/fl.popFloat()) * fl.popFloat()); // [f0, f1, f2] -> [f0, f1/f2]
case NEXBOOLEAN -> fl.push(props.getOrDefault(Optional.of(op.bValue), 0f));
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));
}
}
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;
public class FightPropData {
private String propType;
private FightProperty prop;
private String propType;
private FightProperty prop;
private float value;
public String getPropType() {
return propType;
}
public float getValue() {
return value;
}
public FightProperty getProp() {
return prop;
}
public String getPropType() {
return propType;
}
public void onLoad() {
this.prop = FightProperty.getPropByName(propType);
}
}
public float getValue() {
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
public class ItemParamData {
@SerializedName(value="id", alternate={"itemId"})
@SerializedName(value = "id", alternate = {"itemId"})
private int id;
@SerializedName(value="count", alternate={"itemCount"})
@SerializedName(value = "count", alternate = {"itemCount"})
private int count;
public ItemParamData() {}
public ItemParamData() {
}
public ItemParamData(int id, int count) {
this.id = id;

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ public class AchievementData extends GameResource {
private static final AtomicBoolean isDivided = new AtomicBoolean();
private int goalId;
private int preStageAchievementId;
private Set<Integer> groupAchievementIdList = new HashSet<>();
private final Set<Integer> groupAchievementIdList = new HashSet<>();
private boolean isParent;
private long titleTextMapHash;
private long descTextMapHash;
@ -29,26 +29,6 @@ public class AchievementData extends GameResource {
private int progress;
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() {
if (isDivided.get()) {
return;
@ -93,4 +73,24 @@ public class AchievementData extends GameResource {
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() {
return this.activityId;
}
@Override
public void onLoad() {
this.watcherDataList = watcherId.stream().map(item -> GameData.getActivityWatcherDataMap().get(item.intValue()))

View File

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

View File

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

View File

@ -1,7 +1,5 @@
package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ -16,26 +14,43 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import java.util.List;
@ResourceType(name = "AvatarExcelConfigData.json", loadPriority = LoadPriority.LOW)
public class AvatarData extends GameResource {
private String iconName;
@Getter private String bodyType;
@Getter private String qualityType;
@Getter private int chargeEfficiency;
@Getter private int initialWeapon;
@Getter private WeaponType weaponType;
@Getter private String imageName;
@Getter 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 String bodyType;
@Getter
private String qualityType;
@Getter
private int chargeEfficiency;
@Getter
private int initialWeapon;
@Getter
private WeaponType weaponType;
@Getter
private String imageName;
@Getter
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 attackBase;
@ -48,18 +63,24 @@ public class AvatarData extends GameResource {
private int id;
// Transient
@Getter private String name;
@Getter
private String name;
private Int2ObjectMap<String> growthCurveMap;
private float[] hpGrowthCurve;
private float[] attackGrowthCurve;
private float[] defenseGrowthCurve;
@Getter private AvatarSkillDepotData skillDepot;
@Getter private IntList abilities;
@Getter
private AvatarSkillDepotData skillDepot;
@Getter
private IntList abilities;
@Getter private List<Integer> fetters;
@Getter private int nameCardRewardId;
@Getter private int nameCardId;
@Getter
private List<Integer> fetters;
@Getter
private int nameCardRewardId;
@Getter
private int nameCardId;
public float getBaseHp(int level) {
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")
public class AvatarFetterLevelData extends GameResource {
private int fetterLevel;
private int needExp;
@Override
public int getId() {
return this.fetterLevel;
}
public int getLevel() {
return fetterLevel;
}
public int getExp() {
return needExp;
}
private int fetterLevel;
private int needExp;
@Override
public int getId() {
return this.fetterLevel;
}
public int getLevel() {
return fetterLevel;
}
public int getExp() {
return needExp;
}
}

View File

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

View File

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

View File

@ -1,74 +1,75 @@
package emu.grasscutter.data.excels;
import java.util.ArrayList;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData;
import java.util.ArrayList;
@ResourceType(name = "AvatarPromoteExcelConfigData.json")
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() {
return avatarPromoteId;
}
private int avatarPromoteId;
private int promoteLevel;
private int scoinCost;
private ItemParamData[] costItems;
private int unlockMaxLevel;
private FightPropData[] addProps;
private int requiredPlayerLevel;
public int getPromoteLevel() {
return promoteLevel;
}
@Override
public int getId() {
return (avatarPromoteId << 8) + promoteLevel;
}
public ItemParamData[] getCostItems() {
return costItems;
}
public int getAvatarPromoteId() {
return avatarPromoteId;
}
public int getCoinCost() {
return scoinCost;
}
public int getPromoteLevel() {
return promoteLevel;
}
public FightPropData[] getAddProps() {
return addProps;
}
public ItemParamData[] getCostItems() {
return costItems;
}
public int getUnlockMaxLevel() {
return unlockMaxLevel;
}
public int getCoinCost() {
return scoinCost;
}
public int getRequiredPlayerLevel() {
return requiredPlayerLevel;
}
public FightPropData[] getAddProps() {
return addProps;
}
@Override
public void onLoad() {
// Trim item params
ArrayList<ItemParamData> trim = new ArrayList<>(getAddProps().length);
for (ItemParamData itemParam : getCostItems()) {
if (itemParam.getId() == 0) {
continue;
}
trim.add(itemParam);
}
this.costItems = trim.toArray(new ItemParamData[trim.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()]);
}
public int getUnlockMaxLevel() {
return unlockMaxLevel;
}
public int getRequiredPlayerLevel() {
return requiredPlayerLevel;
}
@Override
public void onLoad() {
// Trim item params
ArrayList<ItemParamData> trim = new ArrayList<>(getAddProps().length);
for (ItemParamData itemParam : getCostItems()) {
if (itemParam.getId() == 0) {
continue;
}
trim.add(itemParam);
}
this.costItems = trim.toArray(new ItemParamData[trim.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;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.GameResource;
@ -17,6 +13,10 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
@ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH)
@Getter
public class AvatarSkillDepotData extends GameResource {
@ -73,14 +73,14 @@ public class AvatarSkillDepotData extends GameResource {
.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
public static class InherentProudSkillOpens {
private int proudSkillGroupId;
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;
import java.util.ArrayList;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.FightPropData;
import java.util.ArrayList;
@ResourceType(name = "AvatarTalentExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
public class AvatarTalentData extends GameResource {
private int talentId;
private int prevTalent;
private int talentId;
private int prevTalent;
private long nameTextMapHash;
private String icon;
private int mainCostItemId;
@ -19,51 +20,51 @@ public class AvatarTalentData extends GameResource {
private float[] paramList;
@Override
public int getId(){
public int getId() {
return this.talentId;
}
public int PrevTalent() {
return prevTalent;
}
public long getNameTextMapHash() {
return nameTextMapHash;
}
return prevTalent;
}
public String getIcon() {
return icon;
}
public long getNameTextMapHash() {
return nameTextMapHash;
}
public int getMainCostItemId() {
return mainCostItemId;
}
public String getIcon() {
return icon;
}
public int getMainCostItemCount() {
return mainCostItemCount;
}
public int getMainCostItemId() {
return mainCostItemId;
}
public String getOpenConfig() {
return openConfig;
}
public int getMainCostItemCount() {
return mainCostItemCount;
}
public FightPropData[] getAddProps() {
return addProps;
}
public String getOpenConfig() {
return openConfig;
}
public float[] getParamList() {
return paramList;
}
public FightPropData[] getAddProps() {
return addProps;
}
@Override
public void onLoad() {
ArrayList<FightPropData> parsed = new ArrayList<FightPropData>(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()]);
}
public float[] getParamList() {
return paramList;
}
@Override
public void onLoad() {
ArrayList<FightPropData> parsed = new ArrayList<FightPropData>(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;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
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 lombok.Getter;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
@Getter
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() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
@ -66,4 +60,10 @@ public class BattlePassMissionData extends GameResource {
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.ResourceType;
import lombok.Getter;
import lombok.Setter;
import java.util.List;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,12 @@
package emu.grasscutter.data.excels;
import java.util.List;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority;
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)
public class FetterData extends GameResource {
private int avatarId;
@ -14,9 +14,9 @@ public class FetterData extends GameResource {
private List<OpenCondData> openCond;
@Override
public int getId() {
return fetterId;
}
public int getId() {
return fetterId;
}
public int getAvatarId() {
return avatarId;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,32 +1,32 @@
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.ResourceType;
import emu.grasscutter.data.common.CurveInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
@ResourceType(name = "MonsterCurveExcelConfigData.json")
public class MonsterCurveData extends GameResource {
private int level;
private int level;
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
public void onLoad() {
this.curveInfoMap = new HashMap<>();
Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue()));
}
private Map<String, Float> curveInfoMap;
@Override
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;
import java.util.List;
import java.util.Set;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ -14,6 +10,9 @@ import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.MonsterType;
import lombok.Getter;
import java.util.List;
import java.util.Set;
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
@Getter
public class MonsterData extends GameResource {

View File

@ -12,24 +12,14 @@ import java.util.List;
public class OpenStateData extends GameResource {
@Getter(onMethod_ = @Override)
private int id;
@Getter private boolean defaultState;
@Getter private boolean allowClientOpen;
@Getter private int systemOpenUiId;
@Getter private List<OpenStateCond> cond;
public static class OpenStateCond {
@Getter private OpenStateCondType condType;
@Getter private int param;
@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;
}
@Getter
private boolean defaultState;
@Getter
private boolean allowClientOpen;
@Getter
private int systemOpenUiId;
@Getter
private List<OpenStateCond> cond;
@Override
public void onLoad() {
@ -43,6 +33,23 @@ public class OpenStateData extends GameResource {
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:

View File

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

View File

@ -1,8 +1,5 @@
package emu.grasscutter.data.excels;
import java.util.ArrayList;
import java.util.List;
import dev.morphia.annotations.Transient;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ -10,23 +7,40 @@ import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@ResourceType(name = "ProudSkillExcelConfigData.json")
public class ProudSkillData extends GameResource {
private int proudSkillId;
@Getter private int proudSkillGroupId;
@Getter private int level;
@Getter private int coinCost;
@Getter private int breakLevel;
@Getter private int proudSkillType;
@Getter private String openConfig;
@Getter 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;
@Getter
private int proudSkillGroupId;
@Getter
private int level;
@Getter
private int coinCost;
@Getter
private int breakLevel;
@Getter
private int proudSkillType;
@Getter
private String openConfig;
@Getter
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
public int getId() {

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