diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java index 41e55f056..12f56b38e 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java @@ -1,72 +1,72 @@ -package emu.grasscutter.auth; - -import static emu.grasscutter.config.Configuration.ACCOUNT; -import static emu.grasscutter.utils.Language.translate; - -import emu.grasscutter.Grasscutter; -import emu.grasscutter.auth.DefaultAuthenticators.*; -import emu.grasscutter.game.Account; -import emu.grasscutter.server.http.objects.ComboTokenResJson; -import emu.grasscutter.server.http.objects.LoginResultJson; - -/** - * The default Grasscutter authentication implementation. Allows all users to access any account. - */ -public final class DefaultAuthentication implements AuthenticationSystem { - private final Authenticator passwordAuthenticator; - private final Authenticator tokenAuthenticator = new TokenAuthenticator(); - private final Authenticator sessionKeyAuthenticator = - new SessionKeyAuthenticator(); - private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); - private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); - - public DefaultAuthentication() { - if (ACCOUNT.EXPERIMENTAL_RealPassword) { - passwordAuthenticator = new ExperimentalPasswordAuthenticator(); - } else { - passwordAuthenticator = new PasswordAuthenticator(); - } - } - - @Override - public void createAccount(String username, String password) { - // Unhandled. The default authenticator doesn't store passwords. - } - - @Override - public void resetPassword(String username) { - // Unhandled. The default authenticator doesn't store passwords. - } - - @Override - public Account verifyUser(String details) { - Grasscutter.getLogger() - .info(translate("messages.dispatch.authentication.default_unable_to_verify")); - return null; - } - - @Override - public Authenticator getPasswordAuthenticator() { - return this.passwordAuthenticator; - } - - @Override - public Authenticator getTokenAuthenticator() { - return this.tokenAuthenticator; - } - - @Override - public Authenticator getSessionKeyAuthenticator() { - return this.sessionKeyAuthenticator; - } - - @Override - public ExternalAuthenticator getExternalAuthenticator() { - return this.externalAuthenticator; - } - - @Override - public OAuthAuthenticator getOAuthAuthenticator() { - return this.oAuthAuthenticator; - } -} +package emu.grasscutter.auth; + +import static emu.grasscutter.config.Configuration.ACCOUNT; +import static emu.grasscutter.utils.Language.translate; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.auth.DefaultAuthenticators.*; +import emu.grasscutter.game.Account; +import emu.grasscutter.server.http.objects.ComboTokenResJson; +import emu.grasscutter.server.http.objects.LoginResultJson; + +/** + * The default Grasscutter authentication implementation. Allows all users to access any account. + */ +public final class DefaultAuthentication implements AuthenticationSystem { + private final Authenticator passwordAuthenticator; + private final Authenticator tokenAuthenticator = new TokenAuthenticator(); + private final Authenticator sessionKeyAuthenticator = + new SessionKeyAuthenticator(); + private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); + private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); + + public DefaultAuthentication() { + if (ACCOUNT.EXPERIMENTAL_RealPassword) { + passwordAuthenticator = new ExperimentalPasswordAuthenticator(); + } else { + passwordAuthenticator = new PasswordAuthenticator(); + } + } + + @Override + public void createAccount(String username, String password) { + // Unhandled. The default authenticator doesn't store passwords. + } + + @Override + public void resetPassword(String username) { + // Unhandled. The default authenticator doesn't store passwords. + } + + @Override + public Account verifyUser(String details) { + Grasscutter.getLogger() + .info(translate("messages.dispatch.authentication.default_unable_to_verify")); + return null; + } + + @Override + public Authenticator getPasswordAuthenticator() { + return this.passwordAuthenticator; + } + + @Override + public Authenticator getTokenAuthenticator() { + return this.tokenAuthenticator; + } + + @Override + public Authenticator getSessionKeyAuthenticator() { + return this.sessionKeyAuthenticator; + } + + @Override + public ExternalAuthenticator getExternalAuthenticator() { + return this.externalAuthenticator; + } + + @Override + public OAuthAuthenticator getOAuthAuthenticator() { + return this.oAuthAuthenticator; + } +} diff --git a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java index 4e75ba07a..56ca718a1 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java @@ -1,190 +1,190 @@ -package emu.grasscutter.command.commands; - -import emu.grasscutter.command.Command; -import emu.grasscutter.command.CommandHandler; -import emu.grasscutter.game.avatar.Avatar; -import emu.grasscutter.game.entity.EntityAvatar; -import emu.grasscutter.game.player.Player; -import 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"}, - usage = { - "[set] ", - "(lock|freeze) []", // Can lock to current value - "(unlock|unfreeze) " - }, - permission = "player.setstats", - permissionTargeted = "player.setstats.others") -public final class SetStatsCommand implements CommandHandler { - private final Map stats; - - public SetStatsCommand() { - this.stats = new HashMap<>(); - for (String key : FightProperty.getShortNames()) { - this.stats.put(key, new Stat(FightProperty.getPropByShortName(key))); - } - // Full FightProperty enum that won't be advertised but can be used by devs - // They have a prefix to avoid the "hp" clash - for (FightProperty prop : FightProperty.values()) { - String name = prop.toString().substring(10); // FIGHT_PROP_BASE_HP -> _BASE_HP - String key = name.toLowerCase(); // _BASE_HP -> _base_hp - name = name.substring(1); // _BASE_HP -> BASE_HP - this.stats.put(key, new Stat(name, prop)); - } - - // Compatibility aliases - this.stats.put("mhp", this.stats.get("maxhp")); - this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP - this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK - this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE - this.stats.put( - "atkb", - this.stats.get( - "_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only - // useful for stuff like Bennett's buff. - this.stats.put("eanemo", this.stats.get("anemo%")); - this.stats.put("ecryo", this.stats.get("cryo%")); - this.stats.put("edendro", this.stats.get("dendro%")); - this.stats.put("edend", this.stats.get("dendro%")); - this.stats.put("eelectro", this.stats.get("electro%")); - this.stats.put("eelec", this.stats.get("electro%")); - this.stats.put("ethunder", this.stats.get("electro%")); - this.stats.put("egeo", this.stats.get("geo%")); - this.stats.put("ehydro", this.stats.get("hydro%")); - this.stats.put("epyro", this.stats.get("pyro%")); - this.stats.put("ephys", this.stats.get("phys%")); - } - - public static float parsePercent(String input) throws NumberFormatException { - if (input.endsWith("%")) { - return Float.parseFloat(input.substring(0, input.length() - 1)) / 100f; - } else { - return Float.parseFloat(input); - } - } - - @Override - public void execute(Player sender, Player targetPlayer, List args) { - String statStr = null; - String valueStr; - float value = 0f; - - if (args.size() < 2) { - sendUsageMessage(sender); - return; - } - - // 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 - case "set" -> Action.ACTION_SET; // Explicit set command - case "lock", "freeze" -> Action.ACTION_LOCK; - case "unlock", "unfreeze" -> Action.ACTION_UNLOCK; - }; - if (statStr == null) { - statStr = args.remove(0).toLowerCase(); - } - if (!stats.containsKey(statStr)) { - sendUsageMessage(sender); // Invalid stat or action - return; - } - Stat stat = stats.get(statStr); - EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); - Avatar avatar = entity.getAvatar(); - - // Get the value if the action requires it - try { - switch (action) { - case ACTION_LOCK: - if (args.isEmpty()) { // Lock to current value - value = avatar.getFightProperty(stat.prop); - break; - } // Else fall-through and lock to supplied value - case ACTION_SET: - value = parsePercent(args.remove(0)); - break; - case ACTION_UNLOCK: - break; - } - } catch (NumberFormatException ignored) { - CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.statValue"); - return; - } catch (IndexOutOfBoundsException ignored) { - sendUsageMessage(sender); - return; - } - - if (!args.isEmpty()) { // Leftover arguments! - sendUsageMessage(sender); - return; - } - - switch (action) { - case ACTION_SET: - entity.setFightProperty(stat.prop, value); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop)); - break; - case ACTION_LOCK: - avatar.getFightPropOverrides().put(stat.prop.getId(), value); - avatar.recalcStats(); - break; - case ACTION_UNLOCK: - avatar.getFightPropOverrides().remove(stat.prop.getId()); - avatar.recalcStats(); - break; - } - - // Report action - if (FightProperty.isPercentage(stat.prop)) { - valueStr = String.format("%.1f%%", value * 100f); - } else { - valueStr = String.format("%.0f", value); - } - if (targetPlayer == sender) { - CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr); - } else { - String uidStr = targetPlayer.getAccount().getId(); - CommandHandler.sendTranslatedMessage( - sender, action.messageKeyOther, stat.name, uidStr, valueStr); - } - } - - 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; - } - } -} +package emu.grasscutter.command.commands; + +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.player.Player; +import 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"}, + usage = { + "[set] ", + "(lock|freeze) []", // Can lock to current value + "(unlock|unfreeze) " + }, + permission = "player.setstats", + permissionTargeted = "player.setstats.others") +public final class SetStatsCommand implements CommandHandler { + private final Map stats; + + public SetStatsCommand() { + this.stats = new HashMap<>(); + for (String key : FightProperty.getShortNames()) { + this.stats.put(key, new Stat(FightProperty.getPropByShortName(key))); + } + // Full FightProperty enum that won't be advertised but can be used by devs + // They have a prefix to avoid the "hp" clash + for (FightProperty prop : FightProperty.values()) { + String name = prop.toString().substring(10); // FIGHT_PROP_BASE_HP -> _BASE_HP + String key = name.toLowerCase(); // _BASE_HP -> _base_hp + name = name.substring(1); // _BASE_HP -> BASE_HP + this.stats.put(key, new Stat(name, prop)); + } + + // Compatibility aliases + this.stats.put("mhp", this.stats.get("maxhp")); + this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP + this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK + this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE + this.stats.put( + "atkb", + this.stats.get( + "_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only + // useful for stuff like Bennett's buff. + this.stats.put("eanemo", this.stats.get("anemo%")); + this.stats.put("ecryo", this.stats.get("cryo%")); + this.stats.put("edendro", this.stats.get("dendro%")); + this.stats.put("edend", this.stats.get("dendro%")); + this.stats.put("eelectro", this.stats.get("electro%")); + this.stats.put("eelec", this.stats.get("electro%")); + this.stats.put("ethunder", this.stats.get("electro%")); + this.stats.put("egeo", this.stats.get("geo%")); + this.stats.put("ehydro", this.stats.get("hydro%")); + this.stats.put("epyro", this.stats.get("pyro%")); + this.stats.put("ephys", this.stats.get("phys%")); + } + + public static float parsePercent(String input) throws NumberFormatException { + if (input.endsWith("%")) { + return Float.parseFloat(input.substring(0, input.length() - 1)) / 100f; + } else { + return Float.parseFloat(input); + } + } + + @Override + public void execute(Player sender, Player targetPlayer, List args) { + String statStr = null; + String valueStr; + float value = 0f; + + if (args.size() < 2) { + sendUsageMessage(sender); + return; + } + + // 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 + case "set" -> Action.ACTION_SET; // Explicit set command + case "lock", "freeze" -> Action.ACTION_LOCK; + case "unlock", "unfreeze" -> Action.ACTION_UNLOCK; + }; + if (statStr == null) { + statStr = args.remove(0).toLowerCase(); + } + if (!stats.containsKey(statStr)) { + sendUsageMessage(sender); // Invalid stat or action + return; + } + Stat stat = stats.get(statStr); + EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); + Avatar avatar = entity.getAvatar(); + + // Get the value if the action requires it + try { + switch (action) { + case ACTION_LOCK: + if (args.isEmpty()) { // Lock to current value + value = avatar.getFightProperty(stat.prop); + break; + } // Else fall-through and lock to supplied value + case ACTION_SET: + value = parsePercent(args.remove(0)); + break; + case ACTION_UNLOCK: + break; + } + } catch (NumberFormatException ignored) { + CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.statValue"); + return; + } catch (IndexOutOfBoundsException ignored) { + sendUsageMessage(sender); + return; + } + + if (!args.isEmpty()) { // Leftover arguments! + sendUsageMessage(sender); + return; + } + + switch (action) { + case ACTION_SET: + entity.setFightProperty(stat.prop, value); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop)); + break; + case ACTION_LOCK: + avatar.getFightPropOverrides().put(stat.prop.getId(), value); + avatar.recalcStats(); + break; + case ACTION_UNLOCK: + avatar.getFightPropOverrides().remove(stat.prop.getId()); + avatar.recalcStats(); + break; + } + + // Report action + if (FightProperty.isPercentage(stat.prop)) { + valueStr = String.format("%.1f%%", value * 100f); + } else { + valueStr = String.format("%.0f", value); + } + if (targetPlayer == sender) { + CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr); + } else { + String uidStr = targetPlayer.getAccount().getId(); + CommandHandler.sendTranslatedMessage( + sender, action.messageKeyOther, stat.name, uidStr, valueStr); + } + } + + 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; + } + } +} diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 1107375d8..a11cdb0d7 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -477,8 +477,8 @@ public final class GameData { private static final Int2IntMap trialAvatarIndexIdTrialActivityDataDataMap = new Int2IntOpenHashMap(); - private static final Map> fetters = new HashMap<>(); - private static final Map> shopGoods = new HashMap<>(); + private static Map> fetters = new HashMap<>(); + private static Map> shopGoods = new HashMap<>(); // Getters with different names that stay for now public static Int2ObjectMap getMainQuestDataMap() { diff --git a/src/main/java/emu/grasscutter/data/GameDepot.java b/src/main/java/emu/grasscutter/data/GameDepot.java index 3855912b3..f9e791a71 100644 --- a/src/main/java/emu/grasscutter/data/GameDepot.java +++ b/src/main/java/emu/grasscutter/data/GameDepot.java @@ -19,17 +19,17 @@ import lombok.Setter; public class GameDepot { public static final int[] BLOCK_SIZE = new int[] {50, 500}; // Scales - private static final Int2ObjectMap> relicRandomMainPropDepot = + private static Int2ObjectMap> relicRandomMainPropDepot = new Int2ObjectOpenHashMap<>(); - private static final Int2ObjectMap> relicMainPropDepot = + private static Int2ObjectMap> relicMainPropDepot = new Int2ObjectOpenHashMap<>(); - private static final Int2ObjectMap> relicAffixDepot = + private static Int2ObjectMap> relicAffixDepot = new Int2ObjectOpenHashMap<>(); @Getter @Setter private static Map playerAbilities = new HashMap<>(); @Getter - private static final HashMap> spawnLists = + private static HashMap> spawnLists = new HashMap<>(); @Getter @Setter private static BlossomConfig blossomConfig; diff --git a/src/main/java/emu/grasscutter/data/binout/AbilityModifierEntry.java b/src/main/java/emu/grasscutter/data/binout/AbilityModifierEntry.java index 78d8c7289..37401940f 100644 --- a/src/main/java/emu/grasscutter/data/binout/AbilityModifierEntry.java +++ b/src/main/java/emu/grasscutter/data/binout/AbilityModifierEntry.java @@ -1,35 +1,35 @@ -package emu.grasscutter.data.binout; - -import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; -import java.util.ArrayList; -import java.util.List; - -public class AbilityModifierEntry { - public List onModifierAdded; - public List onThinkInterval; - public List onRemoved; - private final String name; // Custom value - - public AbilityModifierEntry(String name) { - this.name = name; - this.onModifierAdded = new ArrayList<>(); - this.onThinkInterval = new ArrayList<>(); - this.onRemoved = new ArrayList<>(); - } - - public String getName() { - return name; - } - - public List getOnAdded() { - return onModifierAdded; - } - - public List getOnThinkInterval() { - return onThinkInterval; - } - - public List getOnRemoved() { - return onRemoved; - } -} +package emu.grasscutter.data.binout; + +import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; +import java.util.ArrayList; +import java.util.List; + +public class AbilityModifierEntry { + public List onModifierAdded; + public List onThinkInterval; + public List onRemoved; + private final String name; // Custom value + + public AbilityModifierEntry(String name) { + this.name = name; + this.onModifierAdded = new ArrayList<>(); + this.onThinkInterval = new ArrayList<>(); + this.onRemoved = new ArrayList<>(); + } + + public String getName() { + return name; + } + + public List getOnAdded() { + return onModifierAdded; + } + + public List getOnThinkInterval() { + return onThinkInterval; + } + + public List getOnRemoved() { + return onRemoved; + } +} diff --git a/src/main/java/emu/grasscutter/data/binout/OpenConfigEntry.java b/src/main/java/emu/grasscutter/data/binout/OpenConfigEntry.java index fa21fe4c8..f595dc460 100644 --- a/src/main/java/emu/grasscutter/data/binout/OpenConfigEntry.java +++ b/src/main/java/emu/grasscutter/data/binout/OpenConfigEntry.java @@ -1,71 +1,71 @@ -package emu.grasscutter.data.binout; - -import emu.grasscutter.data.ResourceLoader.OpenConfigData; -import java.util.ArrayList; -import java.util.List; - -public class OpenConfigEntry { - private final String name; - private String[] addAbilities; - private int extraTalentIndex; - private SkillPointModifier[] skillPointModifiers; - - public OpenConfigEntry(String name, OpenConfigData[] data) { - this.name = name; - - List abilityList = new ArrayList<>(); - List modList = new ArrayList<>(); - - for (OpenConfigData entry : data) { - if (entry.$type.contains("AddAbility")) { - abilityList.add(entry.abilityName); - } else if (entry.talentIndex > 0) { - this.extraTalentIndex = entry.talentIndex; - } else if (entry.$type.contains("ModifySkillPoint")) { - modList.add(new SkillPointModifier(entry.skillID, entry.pointDelta)); - } - } - - if (abilityList.size() > 0) { - this.addAbilities = abilityList.toArray(new String[0]); - } - - if (modList.size() > 0) { - this.skillPointModifiers = modList.toArray(new SkillPointModifier[0]); - } - } - - public String getName() { - return name; - } - - 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; - } - } -} +package emu.grasscutter.data.binout; + +import emu.grasscutter.data.ResourceLoader.OpenConfigData; +import java.util.ArrayList; +import java.util.List; + +public class OpenConfigEntry { + private final String name; + private String[] addAbilities; + private int extraTalentIndex; + private SkillPointModifier[] skillPointModifiers; + + public OpenConfigEntry(String name, OpenConfigData[] data) { + this.name = name; + + List abilityList = new ArrayList<>(); + List modList = new ArrayList<>(); + + for (OpenConfigData entry : data) { + if (entry.$type.contains("AddAbility")) { + abilityList.add(entry.abilityName); + } else if (entry.talentIndex > 0) { + this.extraTalentIndex = entry.talentIndex; + } else if (entry.$type.contains("ModifySkillPoint")) { + modList.add(new SkillPointModifier(entry.skillID, entry.pointDelta)); + } + } + + if (abilityList.size() > 0) { + this.addAbilities = abilityList.toArray(new String[0]); + } + + if (modList.size() > 0) { + this.skillPointModifiers = modList.toArray(new SkillPointModifier[0]); + } + } + + public String getName() { + return name; + } + + public String[] getAddAbilities() { + return addAbilities; + } + + public int getExtraTalentIndex() { + return extraTalentIndex; + } + + public SkillPointModifier[] getSkillPointModifiers() { + return skillPointModifiers; + } + + public static class SkillPointModifier { + private int skillId; + private int delta; + + public SkillPointModifier(int skillId, int delta) { + this.skillId = skillId; + this.delta = delta; + } + + public int getSkillId() { + return skillId; + } + + public int getDelta() { + return delta; + } + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/ItemData.java b/src/main/java/emu/grasscutter/data/excels/ItemData.java index 75dd5fb9d..3b0edee57 100644 --- a/src/main/java/emu/grasscutter/data/excels/ItemData.java +++ b/src/main/java/emu/grasscutter/data/excels/ItemData.java @@ -31,7 +31,7 @@ public class ItemData extends GameResource { @Getter(onMethod_ = @Override) private int id; - private final int stackLimit = 1; + private int stackLimit = 1; private int maxUseCount; private int rankLevel; private String effectName; @@ -43,7 +43,7 @@ public class ItemData extends GameResource { private int[] destroyReturnMaterialCount; // Enums - private final ItemType itemType = ItemType.ITEM_NONE; + private ItemType itemType = ItemType.ITEM_NONE; private MaterialType materialType = MaterialType.MATERIAL_NONE; private EquipType equipType = EquipType.EQUIP_NONE; private String effectType; diff --git a/src/main/java/emu/grasscutter/data/excels/PlayerLevelData.java b/src/main/java/emu/grasscutter/data/excels/PlayerLevelData.java index 877e09e90..6a0d52e06 100644 --- a/src/main/java/emu/grasscutter/data/excels/PlayerLevelData.java +++ b/src/main/java/emu/grasscutter/data/excels/PlayerLevelData.java @@ -1,21 +1,21 @@ -package emu.grasscutter.data.excels; - -import emu.grasscutter.data.GameResource; -import emu.grasscutter.data.ResourceType; -import lombok.Getter; - -@ResourceType(name = "PlayerLevelExcelConfigData.json") -@Getter -public class PlayerLevelData extends GameResource { - private int level; - private int exp; - private int rewardId; - private final int expeditionLimitAdd = 0; - private int unlockWorldLevel; - private long unlockDescTextMapHash; - - @Override - public int getId() { - return this.level; - } -} +package emu.grasscutter.data.excels; + +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; +import lombok.Getter; + +@ResourceType(name = "PlayerLevelExcelConfigData.json") +@Getter +public class PlayerLevelData extends GameResource { + private int level; + private int exp; + private int rewardId; + private int expeditionLimitAdd = 0; + private int unlockWorldLevel; + private long unlockDescTextMapHash; + + @Override + public int getId() { + return this.level; + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/achievement/AchievementData.java b/src/main/java/emu/grasscutter/data/excels/achievement/AchievementData.java index 24972645e..334bd2dcc 100644 --- a/src/main/java/emu/grasscutter/data/excels/achievement/AchievementData.java +++ b/src/main/java/emu/grasscutter/data/excels/achievement/AchievementData.java @@ -18,7 +18,7 @@ public class AchievementData extends GameResource { private static final AtomicBoolean isDivided = new AtomicBoolean(); private int goalId; private int preStageAchievementId; - private final Set groupAchievementIdList = new HashSet<>(); + private Set groupAchievementIdList = new HashSet<>(); private boolean isParent; private long titleTextMapHash; private long descTextMapHash; diff --git a/src/main/java/emu/grasscutter/game/Account.java b/src/main/java/emu/grasscutter/game/Account.java index c66d630fc..f74e825ea 100644 --- a/src/main/java/emu/grasscutter/game/Account.java +++ b/src/main/java/emu/grasscutter/game/Account.java @@ -26,7 +26,7 @@ public class Account { private String token; private String sessionKey; // Session token for dispatch server - private final List permissions; + private List permissions; private Locale locale; private String banReason; diff --git a/src/main/java/emu/grasscutter/game/ability/HealAbilityManager.java b/src/main/java/emu/grasscutter/game/ability/HealAbilityManager.java index 6db6b3995..0f71d0c27 100644 --- a/src/main/java/emu/grasscutter/game/ability/HealAbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/HealAbilityManager.java @@ -1,214 +1,214 @@ -package emu.grasscutter.game.ability; - -import emu.grasscutter.game.entity.EntityAvatar; -import emu.grasscutter.game.entity.GameEntity; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.FightProperty; -import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; -import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class HealAbilityManager { - ArrayList healDataAvatarList; - private final Player player; - - public HealAbilityManager(Player player) { - this.player = player; - healDataAvatarList = new ArrayList(); - healDataAvatarList.add( - new HealDataAvatar(10000054, "Kokomi", 0) - .addHealData( - "E", - "ElementalArt_Heal_MaxHP_Base_Percentage", - "ElementalArt_Heal_Base_Amount", - false) - .addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false)); - healDataAvatarList.add( - new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true)); - healDataAvatarList.add( - new HealDataAvatar(10000034, "Noel", 2) - .addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true)); - healDataAvatarList.add( - new HealDataAvatar(10000032, "Bennett", 0) - .addHealData("Q", "HealMaxHpRatio", "HealConst", false)); - healDataAvatarList.add( - new HealDataAvatar(10000039, "Diona", 0) - .addHealData("Q", "HealHPRatio", "HealHP_Const", false)); - healDataAvatarList.add( - new HealDataAvatar(10000053, "Sayu", 1) - .addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true) - .addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true)); - healDataAvatarList.add( - new HealDataAvatar(10000014, "Barbara", 0) - .addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true) - .addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true) - .addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true)); - healDataAvatarList.add( - new HealDataAvatar(10000065, "Shinobu", 0) - .addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false)); - healDataAvatarList.add( - new HealDataAvatar(10000035, "Qiqi", 1) - .addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true) - .addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true) - .addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false)); - healDataAvatarList.add( - new HealDataAvatar(10000046, "Hutao", 0) - .addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false)); - } - - public Player getPlayer() { - return this.player; - } - - public void healHandler(AbilityInvokeEntry invoke) throws Exception { - AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData()); - - if (data == null) { - return; - } - - GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId()); - - String modifierString = ""; - if (data.getParentAbilityName() != null) modifierString = data.getParentAbilityName().getStr(); - - if (sourceEntity != null) checkAndHeal(sourceEntity, modifierString); - } - - public void checkAndHeal(GameEntity sourceEntity, String modifierString) { - int fightPropertyType = 0; - float healAmount = 0; - float ratio = 0, base = 0; - float maxHP, curHP, curAttack, curDefense; - Map map = sourceEntity.getMetaOverrideMap(); - - for (int i = 0; i < healDataAvatarList.size(); i++) { - HealDataAvatar healDataAvatar = healDataAvatarList.get(i); - if (modifierString.contains(healDataAvatar.avatarName)) { - fightPropertyType = healDataAvatar.fightPropertyType; - ArrayList healDataList = healDataAvatar.healDataList; - - for (int j = 0; j < healDataList.size(); j++) { - HealData healData = healDataList.get(j); - if (map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) { - if (healData.isString) { - ratio = map.get(healData.sRatio); - base = map.get(healData.sBase); - } else { - ratio = healData.fRatio; - base = healData.fBase; - } - } - - List activeTeam = player.getTeamManager().getActiveTeam(); - List needHealAvatars = new ArrayList(); - int currentIndex = player.getTeamManager().getCurrentCharacterIndex(); - EntityAvatar currentAvatar = activeTeam.get(currentIndex); - if (healData.healAll) { - needHealAvatars = activeTeam; - } else { - needHealAvatars.add(currentAvatar); - } - - EntityAvatar healActionAvatar = null; - for (int k = 0; k < activeTeam.size(); k++) { - EntityAvatar avatar = activeTeam.get(k); - int avatarId = avatar.getAvatar().getAvatarId(); - if (avatarId == healDataAvatar.avatarId) { - healActionAvatar = avatar; - break; - } - } - - if (healActionAvatar != null) { - maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); - curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK); - curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE); - - // Special case for Hu Tao: - if (healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) { - ratio = 0.1555f; - } - - switch (fightPropertyType) { - case 0: - healAmount = ratio * maxHP + base; - break; - case 1: - healAmount = ratio * curAttack + base; - break; - case 2: - healAmount = ratio * curDefense + base; - break; - } - } - - for (int k = 0; k < needHealAvatars.size(); k++) { - EntityAvatar avatar = needHealAvatars.get(k); - avatar.heal(healAmount); - } - } - break; - } - } - } - - private class HealData { - public boolean isString = true; - public String abilityType = ""; // "E" or "Q" - public String sRatio = ""; - public String sBase = ""; - public float fRatio = 0; - public float fBase = 0; - public boolean healAll = false; - - public HealData(String _abilityType, String _sRatio, String _sBase, boolean _healAll) { - abilityType = _abilityType; - isString = true; - sRatio = _sRatio; - sBase = _sBase; - healAll = _healAll; - } - - public HealData( - String _abilityType, String _sRatio, float _fRatio, float _fBase, boolean _healAll) { - abilityType = _abilityType; - isString = false; - sRatio = _sRatio; - fRatio = _fRatio; - fBase = _fBase; - healAll = _healAll; - } - } - - private class HealDataAvatar { - public int avatarId = 0; - public String avatarName = ""; - public int fightPropertyType = 0; // 0: maxHP, 1: curAttack, 2: curDefense - public ArrayList healDataList; - - public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) { - avatarId = _avatarId; - avatarName = _avatarName; - fightPropertyType = _fightPropertyType; - healDataList = new ArrayList(); - } - - public HealDataAvatar addHealData( - String abilityType, String sRatio, String sBase, boolean healAll) { - HealData healData = new HealData(abilityType, sRatio, sBase, healAll); - healDataList.add(healData); - return this; - } - - public HealDataAvatar addHealData( - String abilityType, String sRatio, float fRatio, float fBase, boolean healAll) { - HealData healData = new HealData(abilityType, sRatio, fRatio, fBase, healAll); - healDataList.add(healData); - return this; - } - } -} +package emu.grasscutter.game.ability; + +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; +import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HealAbilityManager { + ArrayList healDataAvatarList; + private Player player; + + public HealAbilityManager(Player player) { + this.player = player; + healDataAvatarList = new ArrayList(); + healDataAvatarList.add( + new HealDataAvatar(10000054, "Kokomi", 0) + .addHealData( + "E", + "ElementalArt_Heal_MaxHP_Base_Percentage", + "ElementalArt_Heal_Base_Amount", + false) + .addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false)); + healDataAvatarList.add( + new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true)); + healDataAvatarList.add( + new HealDataAvatar(10000034, "Noel", 2) + .addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true)); + healDataAvatarList.add( + new HealDataAvatar(10000032, "Bennett", 0) + .addHealData("Q", "HealMaxHpRatio", "HealConst", false)); + healDataAvatarList.add( + new HealDataAvatar(10000039, "Diona", 0) + .addHealData("Q", "HealHPRatio", "HealHP_Const", false)); + healDataAvatarList.add( + new HealDataAvatar(10000053, "Sayu", 1) + .addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true) + .addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true)); + healDataAvatarList.add( + new HealDataAvatar(10000014, "Barbara", 0) + .addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true) + .addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true) + .addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true)); + healDataAvatarList.add( + new HealDataAvatar(10000065, "Shinobu", 0) + .addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false)); + healDataAvatarList.add( + new HealDataAvatar(10000035, "Qiqi", 1) + .addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true) + .addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true) + .addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false)); + healDataAvatarList.add( + new HealDataAvatar(10000046, "Hutao", 0) + .addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false)); + } + + public Player getPlayer() { + return this.player; + } + + public void healHandler(AbilityInvokeEntry invoke) throws Exception { + AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData()); + + if (data == null) { + return; + } + + GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId()); + + String modifierString = ""; + if (data.getParentAbilityName() != null) modifierString = data.getParentAbilityName().getStr(); + + if (sourceEntity != null) checkAndHeal(sourceEntity, modifierString); + } + + public void checkAndHeal(GameEntity sourceEntity, String modifierString) { + int fightPropertyType = 0; + float healAmount = 0; + float ratio = 0, base = 0; + float maxHP, curHP, curAttack, curDefense; + Map map = sourceEntity.getMetaOverrideMap(); + + for (int i = 0; i < healDataAvatarList.size(); i++) { + HealDataAvatar healDataAvatar = healDataAvatarList.get(i); + if (modifierString.contains(healDataAvatar.avatarName)) { + fightPropertyType = healDataAvatar.fightPropertyType; + ArrayList healDataList = healDataAvatar.healDataList; + + for (int j = 0; j < healDataList.size(); j++) { + HealData healData = healDataList.get(j); + if (map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) { + if (healData.isString) { + ratio = map.get(healData.sRatio); + base = map.get(healData.sBase); + } else { + ratio = healData.fRatio; + base = healData.fBase; + } + } + + List activeTeam = player.getTeamManager().getActiveTeam(); + List needHealAvatars = new ArrayList(); + int currentIndex = player.getTeamManager().getCurrentCharacterIndex(); + EntityAvatar currentAvatar = activeTeam.get(currentIndex); + if (healData.healAll) { + needHealAvatars = activeTeam; + } else { + needHealAvatars.add(currentAvatar); + } + + EntityAvatar healActionAvatar = null; + for (int k = 0; k < activeTeam.size(); k++) { + EntityAvatar avatar = activeTeam.get(k); + int avatarId = avatar.getAvatar().getAvatarId(); + if (avatarId == healDataAvatar.avatarId) { + healActionAvatar = avatar; + break; + } + } + + if (healActionAvatar != null) { + maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK); + curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE); + + // Special case for Hu Tao: + if (healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) { + ratio = 0.1555f; + } + + switch (fightPropertyType) { + case 0: + healAmount = ratio * maxHP + base; + break; + case 1: + healAmount = ratio * curAttack + base; + break; + case 2: + healAmount = ratio * curDefense + base; + break; + } + } + + for (int k = 0; k < needHealAvatars.size(); k++) { + EntityAvatar avatar = needHealAvatars.get(k); + avatar.heal(healAmount); + } + } + break; + } + } + } + + private class HealData { + public boolean isString = true; + public String abilityType = ""; // "E" or "Q" + public String sRatio = ""; + public String sBase = ""; + public float fRatio = 0; + public float fBase = 0; + public boolean healAll = false; + + public HealData(String _abilityType, String _sRatio, String _sBase, boolean _healAll) { + abilityType = _abilityType; + isString = true; + sRatio = _sRatio; + sBase = _sBase; + healAll = _healAll; + } + + public HealData( + String _abilityType, String _sRatio, float _fRatio, float _fBase, boolean _healAll) { + abilityType = _abilityType; + isString = false; + sRatio = _sRatio; + fRatio = _fRatio; + fBase = _fBase; + healAll = _healAll; + } + } + + private class HealDataAvatar { + public int avatarId = 0; + public String avatarName = ""; + public int fightPropertyType = 0; // 0: maxHP, 1: curAttack, 2: curDefense + public ArrayList healDataList; + + public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) { + avatarId = _avatarId; + avatarName = _avatarName; + fightPropertyType = _fightPropertyType; + healDataList = new ArrayList(); + } + + public HealDataAvatar addHealData( + String abilityType, String sRatio, String sBase, boolean healAll) { + HealData healData = new HealData(abilityType, sRatio, sBase, healAll); + healDataList.add(healData); + return this; + } + + public HealDataAvatar addHealData( + String abilityType, String sRatio, float fRatio, float fBase, boolean healAll) { + HealData healData = new HealData(abilityType, sRatio, fRatio, fBase, healAll); + healDataList.add(healData); + return this; + } + } +} diff --git a/src/main/java/emu/grasscutter/game/achievement/Achievement.java b/src/main/java/emu/grasscutter/game/achievement/Achievement.java index dac91e063..c52513051 100644 --- a/src/main/java/emu/grasscutter/game/achievement/Achievement.java +++ b/src/main/java/emu/grasscutter/game/achievement/Achievement.java @@ -1,40 +1,40 @@ -package emu.grasscutter.game.achievement; - -import dev.morphia.annotations.Entity; -import emu.grasscutter.net.proto.AchievementOuterClass; -import emu.grasscutter.net.proto.StatusOuterClass; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Getter -public class Achievement { - @Setter private StatusOuterClass.Status status; - private final int id; - private final int totalProgress; - @Setter private int curProgress; - @Setter private int finishTimestampSec; - - public Achievement( - StatusOuterClass.Status status, - int id, - int totalProgress, - int curProgress, - int finishTimestampSec) { - this.status = status; - this.id = id; - this.totalProgress = totalProgress; - this.curProgress = curProgress; - this.finishTimestampSec = finishTimestampSec; - } - - public AchievementOuterClass.Achievement toProto() { - return AchievementOuterClass.Achievement.newBuilder() - .setStatus(this.getStatus()) - .setId(this.getId()) - .setTotalProgress(this.getTotalProgress()) - .setCurProgress(this.getCurProgress()) - .setFinishTimestamp(this.getFinishTimestampSec()) - .build(); - } -} +package emu.grasscutter.game.achievement; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.net.proto.AchievementOuterClass; +import emu.grasscutter.net.proto.StatusOuterClass; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +public class Achievement { + @Setter private StatusOuterClass.Status status; + private int id; + private int totalProgress; + @Setter private int curProgress; + @Setter private int finishTimestampSec; + + public Achievement( + StatusOuterClass.Status status, + int id, + int totalProgress, + int curProgress, + int finishTimestampSec) { + this.status = status; + this.id = id; + this.totalProgress = totalProgress; + this.curProgress = curProgress; + this.finishTimestampSec = finishTimestampSec; + } + + public AchievementOuterClass.Achievement toProto() { + return AchievementOuterClass.Achievement.newBuilder() + .setStatus(this.getStatus()) + .setId(this.getId()) + .setTotalProgress(this.getTotalProgress()) + .setCurProgress(this.getCurProgress()) + .setFinishTimestamp(this.getFinishTimestampSec()) + .build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index 357981913..0b7596565 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -74,13 +74,13 @@ public class Avatar { private List fetters; - private final Map skillLevelMap = new Int2IntArrayMap(7); // Talent levels + private Map skillLevelMap = new Int2IntArrayMap(7); // Talent levels @Transient @Getter - private final Map skillExtraChargeMap = new Int2IntArrayMap(2); // Charges + private Map skillExtraChargeMap = new Int2IntArrayMap(2); // Charges @Transient - private final Map proudSkillBonusMap = + private Map proudSkillBonusMap = new Int2IntArrayMap(2); // Talent bonus levels (from const) @Getter private int skillDepotId; diff --git a/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java index 24e172f50..27453a691 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java @@ -1,122 +1,122 @@ -package emu.grasscutter.game.entity; - -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.PlayerProperty; -import emu.grasscutter.game.world.Scene; -import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; -import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; -import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass; -import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; -import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; -import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; -import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify; -import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; -import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; -import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; -import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; -import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; -import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; -import emu.grasscutter.net.proto.VectorOuterClass.Vector; -import emu.grasscutter.utils.Position; -import emu.grasscutter.utils.ProtoHelper; -import it.unimi.dsi.fastutil.ints.Int2FloatMap; -import lombok.Getter; - -public class EntityClientGadget extends EntityBaseGadget { - @Getter private final Player owner; - - @Getter(onMethod_ = @Override) - private final int gadgetId; - - @Getter private final int campId; - @Getter private final int campType; - @Getter private final int ownerEntityId; - @Getter private final int targetEntityId; - @Getter private final boolean asyncLoad; - - @Getter private final int originalOwnerEntityId; - - public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) { - super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles())); - this.owner = player; - this.id = notify.getEntityId(); - this.gadgetId = notify.getConfigId(); - this.campId = notify.getCampId(); - this.campType = notify.getCampType(); - this.ownerEntityId = notify.getPropOwnerEntityId(); - this.targetEntityId = notify.getTargetEntityId(); - this.asyncLoad = notify.getIsAsyncLoad(); - - GameEntity owner = scene.getEntityById(this.ownerEntityId); - if (owner instanceof EntityClientGadget ownerGadget) { - this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId(); - } else { - this.originalOwnerEntityId = this.ownerEntityId; - } - } - - @Override - public void onDeath(int killerId) { - super.onDeath(killerId); // Invoke super class's onDeath() method. - } - - @Override - public Int2FloatMap getFightProperties() { - return null; - } - - @Override - public SceneEntityInfo toProto() { - EntityAuthorityInfo authority = - EntityAuthorityInfo.newBuilder() - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) - .setAiInfo( - SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) - .setBornPos(Vector.newBuilder()) - .build(); - - SceneEntityInfo.Builder entityInfo = - SceneEntityInfo.newBuilder() - .setEntityId(getId()) - .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) - .setMotionInfo( - MotionInfo.newBuilder() - .setPos(getPosition().toProto()) - .setRot(getRotation().toProto()) - .setSpeed(Vector.newBuilder())) - .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) - .setEntityClientData(EntityClientData.newBuilder()) - .setEntityAuthorityInfo(authority) - .setLifeState(1); - - PropPair pair = - PropPair.newBuilder() - .setType(PlayerProperty.PROP_LEVEL.getId()) - .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) - .build(); - entityInfo.addPropList(pair); - - ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = - ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder() - .setCampId(this.getCampId()) - .setCampType(this.getCampType()) - .setOwnerEntityId(this.getOwnerEntityId()) - .setTargetEntityId(this.getTargetEntityId()) - .setAsyncLoad(this.isAsyncLoad()) - .build(); - - SceneGadgetInfo.Builder gadgetInfo = - SceneGadgetInfo.newBuilder() - .setGadgetId(this.getGadgetId()) - .setOwnerEntityId(this.getOwnerEntityId()) - .setIsEnableInteract(true) - .setClientGadget(clientGadget) - .setPropOwnerEntityId(this.getOwnerEntityId()) - .setAuthorityPeerId(this.getOwner().getPeerId()); - - entityInfo.setGadget(gadgetInfo); - - return entityInfo.build(); - } -} +package emu.grasscutter.game.entity; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; +import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; +import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass; +import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; +import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; +import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; +import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify; +import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; +import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; +import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; +import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; +import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; +import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; +import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.utils.Position; +import emu.grasscutter.utils.ProtoHelper; +import it.unimi.dsi.fastutil.ints.Int2FloatMap; +import lombok.Getter; + +public class EntityClientGadget extends EntityBaseGadget { + @Getter private final Player owner; + + @Getter(onMethod_ = @Override) + private int gadgetId; + + @Getter private int campId; + @Getter private int campType; + @Getter private int ownerEntityId; + @Getter private int targetEntityId; + @Getter private boolean asyncLoad; + + @Getter private int originalOwnerEntityId; + + public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) { + super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles())); + this.owner = player; + this.id = notify.getEntityId(); + this.gadgetId = notify.getConfigId(); + this.campId = notify.getCampId(); + this.campType = notify.getCampType(); + this.ownerEntityId = notify.getPropOwnerEntityId(); + this.targetEntityId = notify.getTargetEntityId(); + this.asyncLoad = notify.getIsAsyncLoad(); + + GameEntity owner = scene.getEntityById(this.ownerEntityId); + if (owner instanceof EntityClientGadget ownerGadget) { + this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId(); + } else { + this.originalOwnerEntityId = this.ownerEntityId; + } + } + + @Override + public void onDeath(int killerId) { + super.onDeath(killerId); // Invoke super class's onDeath() method. + } + + @Override + public Int2FloatMap getFightProperties() { + return null; + } + + @Override + public SceneEntityInfo toProto() { + EntityAuthorityInfo authority = + EntityAuthorityInfo.newBuilder() + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) + .setAiInfo( + SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) + .setBornPos(Vector.newBuilder()) + .build(); + + SceneEntityInfo.Builder entityInfo = + SceneEntityInfo.newBuilder() + .setEntityId(getId()) + .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) + .setMotionInfo( + MotionInfo.newBuilder() + .setPos(getPosition().toProto()) + .setRot(getRotation().toProto()) + .setSpeed(Vector.newBuilder())) + .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) + .setEntityClientData(EntityClientData.newBuilder()) + .setEntityAuthorityInfo(authority) + .setLifeState(1); + + PropPair pair = + PropPair.newBuilder() + .setType(PlayerProperty.PROP_LEVEL.getId()) + .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) + .build(); + entityInfo.addPropList(pair); + + ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = + ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder() + .setCampId(this.getCampId()) + .setCampType(this.getCampType()) + .setOwnerEntityId(this.getOwnerEntityId()) + .setTargetEntityId(this.getTargetEntityId()) + .setAsyncLoad(this.isAsyncLoad()) + .build(); + + SceneGadgetInfo.Builder gadgetInfo = + SceneGadgetInfo.newBuilder() + .setGadgetId(this.getGadgetId()) + .setOwnerEntityId(this.getOwnerEntityId()) + .setIsEnableInteract(true) + .setClientGadget(clientGadget) + .setPropOwnerEntityId(this.getOwnerEntityId()) + .setAuthorityPeerId(this.getOwner().getPeerId()); + + entityInfo.setGadget(gadgetInfo); + + return entityInfo.build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index c80bd2bee..c1f94edcb 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -66,7 +66,7 @@ public class EntityGadget extends EntityBaseGadget { private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap(); @Getter @Setter private SceneGadget metaGadget; - @Nullable @Getter private ConfigEntityGadget configGadget; + @Nullable @Getter ConfigEntityGadget configGadget; @Getter @Setter private BaseRoute routeConfig; @Getter @Setter private int stopValue = 0; // Controller related, inited to zero diff --git a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java index 1992341a0..c86a6aa64 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java @@ -42,7 +42,7 @@ public class EntityVehicle extends EntityBaseGadget { @Getter private final int gadgetId; @Getter @Setter private float curStamina; - @Getter private final List vehicleMembers; + @Getter private List vehicleMembers; @Nullable @Getter private ConfigEntityGadget configGadget; public EntityVehicle( diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java index 24e2f49db..b1bdaeef2 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java @@ -1,352 +1,352 @@ -package emu.grasscutter.game.gacha; - -import static emu.grasscutter.config.Configuration.*; - -import emu.grasscutter.Grasscutter; -import emu.grasscutter.data.common.ItemParamData; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo; -import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo; -import emu.grasscutter.utils.Utils; -import lombok.Getter; - -public class GachaBanner { - // Constants used by the BannerType enum - static final int[][] DEFAULT_WEIGHTS_4 = {{1, 510}, {8, 510}, {10, 10000}}; - static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}}; - static final int[][] DEFAULT_WEIGHTS_5 = {{1, 75}, {73, 150}, {90, 10000}}; - static final int[][] DEFAULT_WEIGHTS_5_CHARACTER = {{1, 80}, {73, 80}, {90, 10000}}; - static final int[][] DEFAULT_WEIGHTS_5_WEAPON = {{1, 100}, {62, 100}, {73, 7800}, {80, 10000}}; - static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_1 = { - 1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, - 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072 - }; // Default avatars - static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = { - 11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, - 14409, 15401, 15402, 15403, 15405 - }; // Default weapons - static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = { - 1003, 1016, 1042, 1035, 1041, 1069 - }; // Default avatars - static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = { - 11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502 - }; // Default weapons - static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback - @Getter int scheduleId = -1; - @Getter int sortId = -1; - @Getter private int gachaType = -1; - @Getter private String prefabPath; - @Getter private String previewPrefabPath; - @Getter private String titlePath; - private int costItemId = 0; - private final int costItemAmount = 1; - private int costItemId10 = 0; - private final int costItemAmount10 = 10; - @Getter private final int beginTime = 0; - @Getter private final int endTime = 1924992000; - @Getter private final int gachaTimesLimit = Integer.MAX_VALUE; - @Getter private final int[] rateUpItems4 = {}; - @Getter private final int[] rateUpItems5 = {}; - // This now handles default values for the fields below - @Getter private final BannerType bannerType = BannerType.STANDARD; - // These don't change between banner types (apart from Standard having three extra 4star avatars) - @Getter - private final int[] fallbackItems3 = { - 11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304 - }; - - @Getter private final int[] fallbackItems4Pool1 = DEFAULT_FALLBACK_ITEMS_4_POOL_1; - @Getter private final int[] fallbackItems4Pool2 = DEFAULT_FALLBACK_ITEMS_4_POOL_2; - // Different banner types have different defaults, see above for default values and the enum for - // which are used where. - @Getter private int[] fallbackItems5Pool1; - @Getter private int[] fallbackItems5Pool2; - private int[][] weights4; - private int[][] weights5; - private int eventChance4 = -1; // Chance to win a featured event item - private int eventChance5 = -1; // Chance to win a featured event item - // - @Getter private final boolean removeC6FromPool = false; - - @Getter - private final boolean autoStripRateUpFromFallback = - true; // Ensures that featured items won't "double dip" into the losing pool - - private final int[][] poolBalanceWeights4 = { - {1, 255}, {17, 255}, {21, 10455} - }; // Used to ensure that players won't go too many rolls without getting something from pool 1 - // (avatar) or pool 2 (weapon) - private final int[][] poolBalanceWeights5 = {{1, 30}, {147, 150}, {181, 10230}}; - @Getter private final int wishMaxProgress = 2; - - // Deprecated fields that were tolerated in early May 2022 but have apparently still being - // circulating in new custom configs - // For now, throw up big scary errors on load telling people that they will be banned outright in - // a future version - @Deprecated private final int[] rateUpItems1 = {}; - @Deprecated private final int[] rateUpItems2 = {}; - @Deprecated private final int eventChance = -1; - @Deprecated private final int costItem = 0; - @Deprecated private final int softPity = -1; - @Deprecated private final int hardPity = -1; - @Deprecated private final int minItemType = -1; - @Deprecated private final int maxItemType = -1; - @Getter private boolean deprecated = false; - @Getter private final boolean disabled = false; - - private void warnDeprecated(String name, String replacement) { - Grasscutter.getLogger() - .error( - "Deprecated field found in Banners config: " - + name - + " was replaced back in early May 2022, use " - + replacement - + " instead. You MUST remove this field from your config."); - this.deprecated = true; - } - - public void onLoad() { - // Handle deprecated configs - if (eventChance != -1) warnDeprecated("eventChance", "eventChance4 & eventChance5"); - if (costItem != 0) warnDeprecated("costItem", "costItemId"); - if (softPity != -1) warnDeprecated("softPity", "weights5"); - if (hardPity != -1) warnDeprecated("hardPity", "weights5"); - if (minItemType != -1) warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]"); - if (maxItemType != -1) warnDeprecated("maxItemType", "fallbackItems[4,5]Pool[1,2]"); - if (rateUpItems1.length > 0) warnDeprecated("rateUpItems1", "rateUpItems5"); - if (rateUpItems2.length > 0) warnDeprecated("rateUpItems2", "rateUpItems4"); - - // Handle default values - if (this.previewPrefabPath != null - && this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath)) - Grasscutter.getLogger() - .error( - "Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\"."); - if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty()) - this.previewPrefabPath = "UI_Tab_" + this.prefabPath; - if (this.gachaType < 0) this.gachaType = this.bannerType.gachaType; - if (this.costItemId == 0) this.costItemId = this.bannerType.costItemId; - if (this.costItemId10 == 0) this.costItemId10 = this.costItemId; - if (this.weights4 == null) this.weights4 = this.bannerType.weights4; - if (this.weights5 == null) this.weights5 = this.bannerType.weights5; - if (this.eventChance4 < 0) this.eventChance4 = this.bannerType.eventChance4; - if (this.eventChance5 < 0) this.eventChance5 = this.bannerType.eventChance5; - if (this.fallbackItems5Pool1 == null) - this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1; - if (this.fallbackItems5Pool2 == null) - this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2; - } - - public ItemParamData getCost(int numRolls) { - return switch (numRolls) { - case 10 -> new ItemParamData(costItemId10, costItemAmount10); - default -> new ItemParamData(costItemId, costItemAmount * numRolls); - }; - } - - @Deprecated - public int getCostItem() { - return costItemId; - } - - public boolean hasEpitomized() { - return bannerType.equals(BannerType.WEAPON); - } - - public int getWeight(int rarity, int pity) { - return switch (rarity) { - case 4 -> Utils.lerp(pity, weights4); - default -> Utils.lerp(pity, weights5); - }; - } - - public int getPoolBalanceWeight(int rarity, int pity) { - return switch (rarity) { - case 4 -> Utils.lerp(pity, poolBalanceWeights4); - default -> Utils.lerp(pity, poolBalanceWeights5); - }; - } - - public int getEventChance(int rarity) { - return switch (rarity) { - case 4 -> eventChance4; - default -> eventChance5; - }; - } - - public GachaInfo toProto(Player player) { - // TODO: use other Nonce/key insteadof session key to ensure the overall security for the player - String sessionKey = player.getAccount().getSessionKey(); - - String record = - "http" - + (HTTP_ENCRYPTION.useInRouting ? "s" : "") - + "://" - + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) - + ":" - + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) - + "/gacha?s=" - + sessionKey - + "&gachaType=" - + gachaType; - String details = - "http" - + (HTTP_ENCRYPTION.useInRouting ? "s" : "") - + "://" - + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) - + ":" - + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) - + "/gacha/details?s=" - + sessionKey - + "&scheduleId=" - + scheduleId; - - // Grasscutter.getLogger().info("record = " + record); - PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this); - int leftGachaTimes = - switch (gachaTimesLimit) { - case Integer.MAX_VALUE -> Integer.MAX_VALUE; - default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0); - }; - GachaInfo.Builder info = - GachaInfo.newBuilder() - .setGachaType(this.getGachaType()) - .setScheduleId(this.getScheduleId()) - .setBeginTime(this.getBeginTime()) - .setEndTime(this.getEndTime()) - .setCostItemId(this.costItemId) - .setCostItemNum(this.costItemAmount) - .setTenCostItemId(this.costItemId10) - .setTenCostItemNum(this.costItemAmount10) - .setGachaPrefabPath(this.getPrefabPath()) - .setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) - .setGachaProbUrl(details) - .setGachaProbUrlOversea(details) - .setGachaRecordUrl(record) - .setGachaRecordUrlOversea(record) - .setLeftGachaTimes(leftGachaTimes) - .setGachaTimesLimit(gachaTimesLimit) - .setGachaSortId(this.getSortId()); - - if (hasEpitomized()) { - info.setWishItemId(gachaInfo.getWishItemId()) - .setWishProgress(gachaInfo.getFailedChosenItemPulls()) - .setWishMaxProgress(this.getWishMaxProgress()); - } - - if (this.getTitlePath() != null) { - info.setTitleTextmap(this.getTitlePath()); - } - - if (this.getRateUpItems5().length > 0) { - GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1); - - for (int id : getRateUpItems5()) { - upInfo.addItemIdList(id); - info.addDisplayUp5ItemList(id); - } - - info.addGachaUpInfoList(upInfo); - } - - if (this.getRateUpItems4().length > 0) { - GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2); - - for (int id : getRateUpItems4()) { - upInfo.addItemIdList(id); - if (info.getDisplayUp4ItemListCount() == 0) { - info.addDisplayUp4ItemList(id); - } - } - - info.addGachaUpInfoList(upInfo); - } - - return info.build(); - } - - public enum BannerType { - STANDARD( - 200, - 224, - DEFAULT_WEIGHTS_4, - DEFAULT_WEIGHTS_5, - 50, - 50, - DEFAULT_FALLBACK_ITEMS_5_POOL_1, - DEFAULT_FALLBACK_ITEMS_5_POOL_2), - BEGINNER( - 100, - 224, - DEFAULT_WEIGHTS_4, - DEFAULT_WEIGHTS_5, - 50, - 50, - DEFAULT_FALLBACK_ITEMS_5_POOL_1, - DEFAULT_FALLBACK_ITEMS_5_POOL_2), - EVENT( - 301, - 223, - DEFAULT_WEIGHTS_4, - DEFAULT_WEIGHTS_5_CHARACTER, - 50, - 50, - DEFAULT_FALLBACK_ITEMS_5_POOL_1, - DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER - CHARACTER( - 301, - 223, - DEFAULT_WEIGHTS_4, - DEFAULT_WEIGHTS_5_CHARACTER, - 50, - 50, - DEFAULT_FALLBACK_ITEMS_5_POOL_1, - EMPTY_POOL), - CHARACTER2( - 400, - 223, - DEFAULT_WEIGHTS_4, - DEFAULT_WEIGHTS_5_CHARACTER, - 50, - 50, - DEFAULT_FALLBACK_ITEMS_5_POOL_1, - EMPTY_POOL), - WEAPON( - 302, - 223, - DEFAULT_WEIGHTS_4_WEAPON, - DEFAULT_WEIGHTS_5_WEAPON, - 75, - 75, - EMPTY_POOL, - DEFAULT_FALLBACK_ITEMS_5_POOL_2); - - public final int gachaType; - public final int costItemId; - public final int[][] weights4; - public final int[][] weights5; - public final int eventChance4; - public final int eventChance5; - public final int[] fallbackItems5Pool1; - public final int[] fallbackItems5Pool2; - - BannerType( - int gachaType, - int costItemId, - int[][] weights4, - int[][] weights5, - int eventChance4, - int eventChance5, - int[] fallbackItems5Pool1, - int[] fallbackItems5Pool2) { - this.gachaType = gachaType; - this.costItemId = costItemId; - this.weights4 = weights4; - this.weights5 = weights5; - this.eventChance4 = eventChance4; - this.eventChance5 = eventChance5; - this.fallbackItems5Pool1 = fallbackItems5Pool1; - this.fallbackItems5Pool2 = fallbackItems5Pool2; - } - } -} +package emu.grasscutter.game.gacha; + +import static emu.grasscutter.config.Configuration.*; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.common.ItemParamData; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo; +import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo; +import emu.grasscutter.utils.Utils; +import lombok.Getter; + +public class GachaBanner { + // Constants used by the BannerType enum + static final int[][] DEFAULT_WEIGHTS_4 = {{1, 510}, {8, 510}, {10, 10000}}; + static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}}; + static final int[][] DEFAULT_WEIGHTS_5 = {{1, 75}, {73, 150}, {90, 10000}}; + static final int[][] DEFAULT_WEIGHTS_5_CHARACTER = {{1, 80}, {73, 80}, {90, 10000}}; + static final int[][] DEFAULT_WEIGHTS_5_WEAPON = {{1, 100}, {62, 100}, {73, 7800}, {80, 10000}}; + static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_1 = { + 1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, + 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072 + }; // Default avatars + static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = { + 11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, + 14409, 15401, 15402, 15403, 15405 + }; // Default weapons + static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = { + 1003, 1016, 1042, 1035, 1041, 1069 + }; // Default avatars + static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = { + 11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502 + }; // Default weapons + static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback + @Getter int scheduleId = -1; + @Getter int sortId = -1; + @Getter private int gachaType = -1; + @Getter private String prefabPath; + @Getter private String previewPrefabPath; + @Getter private String titlePath; + private int costItemId = 0; + private int costItemAmount = 1; + private int costItemId10 = 0; + private int costItemAmount10 = 10; + @Getter private int beginTime = 0; + @Getter private int endTime = 1924992000; + @Getter private int gachaTimesLimit = Integer.MAX_VALUE; + @Getter private int[] rateUpItems4 = {}; + @Getter private int[] rateUpItems5 = {}; + // This now handles default values for the fields below + @Getter private BannerType bannerType = BannerType.STANDARD; + // These don't change between banner types (apart from Standard having three extra 4star avatars) + @Getter + private int[] fallbackItems3 = { + 11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304 + }; + + @Getter private int[] fallbackItems4Pool1 = DEFAULT_FALLBACK_ITEMS_4_POOL_1; + @Getter private int[] fallbackItems4Pool2 = DEFAULT_FALLBACK_ITEMS_4_POOL_2; + // Different banner types have different defaults, see above for default values and the enum for + // which are used where. + @Getter private int[] fallbackItems5Pool1; + @Getter private int[] fallbackItems5Pool2; + private int[][] weights4; + private int[][] weights5; + private int eventChance4 = -1; // Chance to win a featured event item + private int eventChance5 = -1; // Chance to win a featured event item + // + @Getter private boolean removeC6FromPool = false; + + @Getter + private boolean autoStripRateUpFromFallback = + true; // Ensures that featured items won't "double dip" into the losing pool + + private int[][] poolBalanceWeights4 = { + {1, 255}, {17, 255}, {21, 10455} + }; // Used to ensure that players won't go too many rolls without getting something from pool 1 + // (avatar) or pool 2 (weapon) + private int[][] poolBalanceWeights5 = {{1, 30}, {147, 150}, {181, 10230}}; + @Getter private int wishMaxProgress = 2; + + // Deprecated fields that were tolerated in early May 2022 but have apparently still being + // circulating in new custom configs + // For now, throw up big scary errors on load telling people that they will be banned outright in + // a future version + @Deprecated private int[] rateUpItems1 = {}; + @Deprecated private int[] rateUpItems2 = {}; + @Deprecated private int eventChance = -1; + @Deprecated private int costItem = 0; + @Deprecated private int softPity = -1; + @Deprecated private int hardPity = -1; + @Deprecated private int minItemType = -1; + @Deprecated private int maxItemType = -1; + @Getter private boolean deprecated = false; + @Getter private boolean disabled = false; + + private void warnDeprecated(String name, String replacement) { + Grasscutter.getLogger() + .error( + "Deprecated field found in Banners config: " + + name + + " was replaced back in early May 2022, use " + + replacement + + " instead. You MUST remove this field from your config."); + this.deprecated = true; + } + + public void onLoad() { + // Handle deprecated configs + if (eventChance != -1) warnDeprecated("eventChance", "eventChance4 & eventChance5"); + if (costItem != 0) warnDeprecated("costItem", "costItemId"); + if (softPity != -1) warnDeprecated("softPity", "weights5"); + if (hardPity != -1) warnDeprecated("hardPity", "weights5"); + if (minItemType != -1) warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]"); + if (maxItemType != -1) warnDeprecated("maxItemType", "fallbackItems[4,5]Pool[1,2]"); + if (rateUpItems1.length > 0) warnDeprecated("rateUpItems1", "rateUpItems5"); + if (rateUpItems2.length > 0) warnDeprecated("rateUpItems2", "rateUpItems4"); + + // Handle default values + if (this.previewPrefabPath != null + && this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath)) + Grasscutter.getLogger() + .error( + "Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\"."); + if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty()) + this.previewPrefabPath = "UI_Tab_" + this.prefabPath; + if (this.gachaType < 0) this.gachaType = this.bannerType.gachaType; + if (this.costItemId == 0) this.costItemId = this.bannerType.costItemId; + if (this.costItemId10 == 0) this.costItemId10 = this.costItemId; + if (this.weights4 == null) this.weights4 = this.bannerType.weights4; + if (this.weights5 == null) this.weights5 = this.bannerType.weights5; + if (this.eventChance4 < 0) this.eventChance4 = this.bannerType.eventChance4; + if (this.eventChance5 < 0) this.eventChance5 = this.bannerType.eventChance5; + if (this.fallbackItems5Pool1 == null) + this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1; + if (this.fallbackItems5Pool2 == null) + this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2; + } + + public ItemParamData getCost(int numRolls) { + return switch (numRolls) { + case 10 -> new ItemParamData(costItemId10, costItemAmount10); + default -> new ItemParamData(costItemId, costItemAmount * numRolls); + }; + } + + @Deprecated + public int getCostItem() { + return costItemId; + } + + public boolean hasEpitomized() { + return bannerType.equals(BannerType.WEAPON); + } + + public int getWeight(int rarity, int pity) { + return switch (rarity) { + case 4 -> Utils.lerp(pity, weights4); + default -> Utils.lerp(pity, weights5); + }; + } + + public int getPoolBalanceWeight(int rarity, int pity) { + return switch (rarity) { + case 4 -> Utils.lerp(pity, poolBalanceWeights4); + default -> Utils.lerp(pity, poolBalanceWeights5); + }; + } + + public int getEventChance(int rarity) { + return switch (rarity) { + case 4 -> eventChance4; + default -> eventChance5; + }; + } + + public GachaInfo toProto(Player player) { + // TODO: use other Nonce/key insteadof session key to ensure the overall security for the player + String sessionKey = player.getAccount().getSessionKey(); + + String record = + "http" + + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + + "://" + + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + + ":" + + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) + + "/gacha?s=" + + sessionKey + + "&gachaType=" + + gachaType; + String details = + "http" + + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + + "://" + + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + + ":" + + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) + + "/gacha/details?s=" + + sessionKey + + "&scheduleId=" + + scheduleId; + + // Grasscutter.getLogger().info("record = " + record); + PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this); + int leftGachaTimes = + switch (gachaTimesLimit) { + case Integer.MAX_VALUE -> Integer.MAX_VALUE; + default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0); + }; + GachaInfo.Builder info = + GachaInfo.newBuilder() + .setGachaType(this.getGachaType()) + .setScheduleId(this.getScheduleId()) + .setBeginTime(this.getBeginTime()) + .setEndTime(this.getEndTime()) + .setCostItemId(this.costItemId) + .setCostItemNum(this.costItemAmount) + .setTenCostItemId(this.costItemId10) + .setTenCostItemNum(this.costItemAmount10) + .setGachaPrefabPath(this.getPrefabPath()) + .setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) + .setGachaProbUrl(details) + .setGachaProbUrlOversea(details) + .setGachaRecordUrl(record) + .setGachaRecordUrlOversea(record) + .setLeftGachaTimes(leftGachaTimes) + .setGachaTimesLimit(gachaTimesLimit) + .setGachaSortId(this.getSortId()); + + if (hasEpitomized()) { + info.setWishItemId(gachaInfo.getWishItemId()) + .setWishProgress(gachaInfo.getFailedChosenItemPulls()) + .setWishMaxProgress(this.getWishMaxProgress()); + } + + if (this.getTitlePath() != null) { + info.setTitleTextmap(this.getTitlePath()); + } + + if (this.getRateUpItems5().length > 0) { + GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1); + + for (int id : getRateUpItems5()) { + upInfo.addItemIdList(id); + info.addDisplayUp5ItemList(id); + } + + info.addGachaUpInfoList(upInfo); + } + + if (this.getRateUpItems4().length > 0) { + GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2); + + for (int id : getRateUpItems4()) { + upInfo.addItemIdList(id); + if (info.getDisplayUp4ItemListCount() == 0) { + info.addDisplayUp4ItemList(id); + } + } + + info.addGachaUpInfoList(upInfo); + } + + return info.build(); + } + + public enum BannerType { + STANDARD( + 200, + 224, + DEFAULT_WEIGHTS_4, + DEFAULT_WEIGHTS_5, + 50, + 50, + DEFAULT_FALLBACK_ITEMS_5_POOL_1, + DEFAULT_FALLBACK_ITEMS_5_POOL_2), + BEGINNER( + 100, + 224, + DEFAULT_WEIGHTS_4, + DEFAULT_WEIGHTS_5, + 50, + 50, + DEFAULT_FALLBACK_ITEMS_5_POOL_1, + DEFAULT_FALLBACK_ITEMS_5_POOL_2), + EVENT( + 301, + 223, + DEFAULT_WEIGHTS_4, + DEFAULT_WEIGHTS_5_CHARACTER, + 50, + 50, + DEFAULT_FALLBACK_ITEMS_5_POOL_1, + DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER + CHARACTER( + 301, + 223, + DEFAULT_WEIGHTS_4, + DEFAULT_WEIGHTS_5_CHARACTER, + 50, + 50, + DEFAULT_FALLBACK_ITEMS_5_POOL_1, + EMPTY_POOL), + CHARACTER2( + 400, + 223, + DEFAULT_WEIGHTS_4, + DEFAULT_WEIGHTS_5_CHARACTER, + 50, + 50, + DEFAULT_FALLBACK_ITEMS_5_POOL_1, + EMPTY_POOL), + WEAPON( + 302, + 223, + DEFAULT_WEIGHTS_4_WEAPON, + DEFAULT_WEIGHTS_5_WEAPON, + 75, + 75, + EMPTY_POOL, + DEFAULT_FALLBACK_ITEMS_5_POOL_2); + + public final int gachaType; + public final int costItemId; + public final int[][] weights4; + public final int[][] weights5; + public final int eventChance4; + public final int eventChance5; + public final int[] fallbackItems5Pool1; + public final int[] fallbackItems5Pool2; + + BannerType( + int gachaType, + int costItemId, + int[][] weights4, + int[][] weights5, + int eventChance4, + int eventChance5, + int[] fallbackItems5Pool1, + int[] fallbackItems5Pool2) { + this.gachaType = gachaType; + this.costItemId = costItemId; + this.weights4 = weights4; + this.weights5 = weights5; + this.eventChance4 = eventChance4; + this.eventChance5 = eventChance5; + this.fallbackItems5Pool1 = fallbackItems5Pool1; + this.fallbackItems5Pool2 = fallbackItems5Pool2; + } + } +} diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMark.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMark.java index 75eabbfb8..a3a65ab9e 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMark.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMark.java @@ -1,62 +1,62 @@ -package emu.grasscutter.game.managers.mapmark; - -import dev.morphia.annotations.Entity; -import emu.grasscutter.net.proto.MapMarkFromTypeOuterClass.MapMarkFromType; -import emu.grasscutter.net.proto.MapMarkPointOuterClass.MapMarkPoint; -import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; -import emu.grasscutter.utils.Position; - -@Entity -public class MapMark { - private int sceneId; - private String name; - private Position position; - private final MapMarkPointType mapMarkPointType; - private int monsterId; - private final MapMarkFromType mapMarkFromType; - private int questId; - - @Deprecated // Morhpia - public MapMark() { - this.mapMarkPointType = MapMarkPointType.MAP_MARK_POINT_TYPE_MONSTER; - this.mapMarkFromType = MapMarkFromType.MAP_MARK_FROM_TYPE_MONSTER; - } - - public MapMark(MapMarkPoint mapMarkPoint) { - this.sceneId = mapMarkPoint.getSceneId(); - this.name = mapMarkPoint.getName(); - this.position = new Position(mapMarkPoint.getPos()); - this.mapMarkPointType = mapMarkPoint.getPointType(); - this.monsterId = mapMarkPoint.getMonsterId(); - this.mapMarkFromType = mapMarkPoint.getFromType(); - this.questId = mapMarkPoint.getQuestId(); - } - - public int getSceneId() { - return this.sceneId; - } - - public String getName() { - return this.name; - } - - public Position getPosition() { - return this.position; - } - - public MapMarkPointType getMapMarkPointType() { - return this.mapMarkPointType; - } - - public int getMonsterId() { - return this.monsterId; - } - - public MapMarkFromType getMapMarkFromType() { - return this.mapMarkFromType; - } - - public int getQuestId() { - return this.questId; - } -} +package emu.grasscutter.game.managers.mapmark; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.net.proto.MapMarkFromTypeOuterClass.MapMarkFromType; +import emu.grasscutter.net.proto.MapMarkPointOuterClass.MapMarkPoint; +import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; +import emu.grasscutter.utils.Position; + +@Entity +public class MapMark { + private int sceneId; + private String name; + private Position position; + private MapMarkPointType mapMarkPointType; + private int monsterId; + private MapMarkFromType mapMarkFromType; + private int questId; + + @Deprecated // Morhpia + public MapMark() { + this.mapMarkPointType = MapMarkPointType.MAP_MARK_POINT_TYPE_MONSTER; + this.mapMarkFromType = MapMarkFromType.MAP_MARK_FROM_TYPE_MONSTER; + } + + public MapMark(MapMarkPoint mapMarkPoint) { + this.sceneId = mapMarkPoint.getSceneId(); + this.name = mapMarkPoint.getName(); + this.position = new Position(mapMarkPoint.getPos()); + this.mapMarkPointType = mapMarkPoint.getPointType(); + this.monsterId = mapMarkPoint.getMonsterId(); + this.mapMarkFromType = mapMarkPoint.getFromType(); + this.questId = mapMarkPoint.getQuestId(); + } + + public int getSceneId() { + return this.sceneId; + } + + public String getName() { + return this.name; + } + + public Position getPosition() { + return this.position; + } + + public MapMarkPointType getMapMarkPointType() { + return this.mapMarkPointType; + } + + public int getMonsterId() { + return this.monsterId; + } + + public MapMarkFromType getMapMarkFromType() { + return this.mapMarkFromType; + } + + public int getQuestId() { + return this.questId; + } +} diff --git a/src/main/java/emu/grasscutter/game/player/PlayerCodex.java b/src/main/java/emu/grasscutter/game/player/PlayerCodex.java index 54787ffaf..bedc5edee 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerCodex.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerCodex.java @@ -17,14 +17,14 @@ public class PlayerCodex { @Transient private Player player; // itemId is not codexId! - @Getter private final Set unlockedWeapon; - @Getter private final Map unlockedAnimal; - @Getter private final Set unlockedMaterial; - @Getter private final Set unlockedBook; - @Getter private final Set unlockedTip; - @Getter private final Set unlockedView; + @Getter private Set unlockedWeapon; + @Getter private Map unlockedAnimal; + @Getter private Set unlockedMaterial; + @Getter private Set unlockedBook; + @Getter private Set unlockedTip; + @Getter private Set unlockedView; @Getter private Set unlockedReliquary; - @Getter private final Set unlockedReliquarySuitCodex; + @Getter private Set unlockedReliquarySuitCodex; public PlayerCodex() { this.unlockedWeapon = new HashSet<>(); diff --git a/src/main/java/emu/grasscutter/game/player/TeamInfo.java b/src/main/java/emu/grasscutter/game/player/TeamInfo.java index ca29f66be..fad4ee4c6 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamInfo.java +++ b/src/main/java/emu/grasscutter/game/player/TeamInfo.java @@ -11,7 +11,7 @@ import java.util.List; @Entity public final class TeamInfo { private String name; - private final List avatars; + private List avatars; public TeamInfo() { this.name = ""; diff --git a/src/main/java/emu/grasscutter/game/props/FightProperty.java b/src/main/java/emu/grasscutter/game/props/FightProperty.java index bd67b01c1..e6d25242b 100644 --- a/src/main/java/emu/grasscutter/game/props/FightProperty.java +++ b/src/main/java/emu/grasscutter/game/props/FightProperty.java @@ -1,263 +1,263 @@ -package emu.grasscutter.game.props; - -import static java.util.Map.entry; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Stream; -import lombok.Getter; - -public enum FightProperty { - FIGHT_PROP_NONE(0), - FIGHT_PROP_BASE_HP(1), - FIGHT_PROP_HP(2), - FIGHT_PROP_HP_PERCENT(3), - FIGHT_PROP_BASE_ATTACK(4), - FIGHT_PROP_ATTACK(5), - FIGHT_PROP_ATTACK_PERCENT(6), - FIGHT_PROP_BASE_DEFENSE(7), - FIGHT_PROP_DEFENSE(8), - FIGHT_PROP_DEFENSE_PERCENT(9), - FIGHT_PROP_BASE_SPEED(10), - FIGHT_PROP_SPEED_PERCENT(11), - FIGHT_PROP_HP_MP_PERCENT(12), - FIGHT_PROP_ATTACK_MP_PERCENT(13), - FIGHT_PROP_CRITICAL(20), - FIGHT_PROP_ANTI_CRITICAL(21), - FIGHT_PROP_CRITICAL_HURT(22), - FIGHT_PROP_CHARGE_EFFICIENCY(23), - FIGHT_PROP_ADD_HURT(24), - FIGHT_PROP_SUB_HURT(25), - FIGHT_PROP_HEAL_ADD(26), - FIGHT_PROP_HEALED_ADD(27), - FIGHT_PROP_ELEMENT_MASTERY(28), - FIGHT_PROP_PHYSICAL_SUB_HURT(29), - FIGHT_PROP_PHYSICAL_ADD_HURT(30), - FIGHT_PROP_DEFENCE_IGNORE_RATIO(31), - FIGHT_PROP_DEFENCE_IGNORE_DELTA(32), - FIGHT_PROP_FIRE_ADD_HURT(40), - FIGHT_PROP_ELEC_ADD_HURT(41), - FIGHT_PROP_WATER_ADD_HURT(42), - FIGHT_PROP_GRASS_ADD_HURT(43), - FIGHT_PROP_WIND_ADD_HURT(44), - FIGHT_PROP_ROCK_ADD_HURT(45), - FIGHT_PROP_ICE_ADD_HURT(46), - FIGHT_PROP_HIT_HEAD_ADD_HURT(47), - FIGHT_PROP_FIRE_SUB_HURT(50), - FIGHT_PROP_ELEC_SUB_HURT(51), - FIGHT_PROP_WATER_SUB_HURT(52), - FIGHT_PROP_GRASS_SUB_HURT(53), - FIGHT_PROP_WIND_SUB_HURT(54), - FIGHT_PROP_ROCK_SUB_HURT(55), - FIGHT_PROP_ICE_SUB_HURT(56), - FIGHT_PROP_EFFECT_HIT(60), - FIGHT_PROP_EFFECT_RESIST(61), - FIGHT_PROP_FREEZE_RESIST(62), - FIGHT_PROP_TORPOR_RESIST(63), - FIGHT_PROP_DIZZY_RESIST(64), - FIGHT_PROP_FREEZE_SHORTEN(65), - FIGHT_PROP_TORPOR_SHORTEN(66), - FIGHT_PROP_DIZZY_SHORTEN(67), - FIGHT_PROP_MAX_FIRE_ENERGY(70), - FIGHT_PROP_MAX_ELEC_ENERGY(71), - FIGHT_PROP_MAX_WATER_ENERGY(72), - FIGHT_PROP_MAX_GRASS_ENERGY(73), - FIGHT_PROP_MAX_WIND_ENERGY(74), - FIGHT_PROP_MAX_ICE_ENERGY(75), - FIGHT_PROP_MAX_ROCK_ENERGY(76), - FIGHT_PROP_SKILL_CD_MINUS_RATIO(80), - FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81), - FIGHT_PROP_CUR_FIRE_ENERGY(1000), - FIGHT_PROP_CUR_ELEC_ENERGY(1001), - FIGHT_PROP_CUR_WATER_ENERGY(1002), - FIGHT_PROP_CUR_GRASS_ENERGY(1003), - FIGHT_PROP_CUR_WIND_ENERGY(1004), - FIGHT_PROP_CUR_ICE_ENERGY(1005), - FIGHT_PROP_CUR_ROCK_ENERGY(1006), - FIGHT_PROP_CUR_HP(1010), - FIGHT_PROP_MAX_HP(2000), - FIGHT_PROP_CUR_ATTACK(2001), - FIGHT_PROP_CUR_DEFENSE(2002), - FIGHT_PROP_CUR_SPEED(2003), - FIGHT_PROP_NONEXTRA_ATTACK(3000), - FIGHT_PROP_NONEXTRA_DEFENSE(3001), - FIGHT_PROP_NONEXTRA_CRITICAL(3002), - FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003), - FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004), - FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005), - FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006), - FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007), - FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008), - FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009), - FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010), - FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011), - FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012), - FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013), - FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014), - FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015), - FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016), - FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017), - FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018), - FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019), - FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020), - FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021), - FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022), - FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023), - FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024); - - public static final int[] fightProps = - new int[] { - 1, 4, 7, 20, 21, 22, 23, 26, 27, 28, 29, 30, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, - 55, 56, 2000, 2001, 2002, 2003, 1010 - }; - private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); - private static final Map stringMap = new HashMap<>(); - // This was originally for relic properties so some names might not be applicable for e.g. - // setstats - private static final Map shortNameMap = - Map.ofEntries( - // Normal relic stats - entry("hp", FIGHT_PROP_HP), - entry("atk", FIGHT_PROP_ATTACK), - entry("def", FIGHT_PROP_DEFENSE), - entry("hp%", FIGHT_PROP_HP_PERCENT), - entry("atk%", FIGHT_PROP_ATTACK_PERCENT), - entry("def%", FIGHT_PROP_DEFENSE_PERCENT), - entry("em", FIGHT_PROP_ELEMENT_MASTERY), - entry("er", FIGHT_PROP_CHARGE_EFFICIENCY), - entry("hb", FIGHT_PROP_HEAL_ADD), - entry("heal", FIGHT_PROP_HEAL_ADD), - entry("cd", FIGHT_PROP_CRITICAL_HURT), - entry("cdmg", FIGHT_PROP_CRITICAL_HURT), - entry("cr", FIGHT_PROP_CRITICAL), - entry("crate", FIGHT_PROP_CRITICAL), - entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT), - entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT), - entry("geo%", FIGHT_PROP_ROCK_ADD_HURT), - entry("anemo%", FIGHT_PROP_WIND_ADD_HURT), - entry("hydro%", FIGHT_PROP_WATER_ADD_HURT), - entry("cryo%", FIGHT_PROP_ICE_ADD_HURT), - entry("electro%", FIGHT_PROP_ELEC_ADD_HURT), - entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT), - // Other stats - entry("maxhp", FIGHT_PROP_MAX_HP), - entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks - entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO), - entry("heali", FIGHT_PROP_HEALED_ADD), - entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO), - entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO), - entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks - entry("resanemo", FIGHT_PROP_WIND_SUB_HURT), - entry("rescryo", FIGHT_PROP_ICE_SUB_HURT), - entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT), - entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT), - entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT), - entry("reshydro", FIGHT_PROP_WATER_SUB_HURT), - entry("respyro", FIGHT_PROP_FIRE_SUB_HURT), - entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)); - private static final List flatProps = - Arrays.asList( - FIGHT_PROP_BASE_HP, - FIGHT_PROP_HP, - FIGHT_PROP_BASE_ATTACK, - FIGHT_PROP_ATTACK, - FIGHT_PROP_BASE_DEFENSE, - FIGHT_PROP_DEFENSE, - FIGHT_PROP_HEALED_ADD, - FIGHT_PROP_CUR_FIRE_ENERGY, - FIGHT_PROP_CUR_ELEC_ENERGY, - FIGHT_PROP_CUR_WATER_ENERGY, - FIGHT_PROP_CUR_GRASS_ENERGY, - FIGHT_PROP_CUR_WIND_ENERGY, - FIGHT_PROP_CUR_ICE_ENERGY, - FIGHT_PROP_CUR_ROCK_ENERGY, - FIGHT_PROP_CUR_HP, - FIGHT_PROP_MAX_HP, - FIGHT_PROP_CUR_ATTACK, - FIGHT_PROP_CUR_DEFENSE); - private static final Map compoundProperties = - Map.ofEntries( - entry( - FIGHT_PROP_MAX_HP, - new CompoundProperty( - FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)), - entry( - FIGHT_PROP_CUR_ATTACK, - new CompoundProperty( - FIGHT_PROP_CUR_ATTACK, - FIGHT_PROP_BASE_ATTACK, - FIGHT_PROP_ATTACK_PERCENT, - FIGHT_PROP_ATTACK)), - entry( - FIGHT_PROP_CUR_DEFENSE, - new CompoundProperty( - FIGHT_PROP_CUR_DEFENSE, - FIGHT_PROP_BASE_DEFENSE, - FIGHT_PROP_DEFENSE_PERCENT, - FIGHT_PROP_DEFENSE))); - - static { - Stream.of(values()) - .forEach( - e -> { - map.put(e.getId(), e); - stringMap.put(e.name(), e); - }); - } - - private final int id; - - FightProperty(int id) { - this.id = id; - } - - public static FightProperty getPropById(int value) { - return map.getOrDefault(value, FIGHT_PROP_NONE); - } - - public static FightProperty getPropByName(String name) { - return stringMap.getOrDefault(name, FIGHT_PROP_NONE); - } - - public static FightProperty getPropByShortName(String name) { - return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE); - } - - public static Set getShortNames() { - return shortNameMap.keySet(); - } - - public static CompoundProperty getCompoundProperty(FightProperty result) { - return compoundProperties.get(result); - } - - public static void forEachCompoundProperty(Consumer consumer) { - compoundProperties.values().forEach(consumer); - } - - public static boolean isPercentage(FightProperty prop) { - return !flatProps.contains(prop); - } - - public int getId() { - return id; - } - - @Getter - public static class CompoundProperty { - private final FightProperty result; - private final FightProperty base; - private final FightProperty percent; - private final FightProperty flat; - - public CompoundProperty( - FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) { - this.result = result; - this.base = base; - this.percent = percent; - this.flat = flat; - } - } -} +package emu.grasscutter.game.props; + +import static java.util.Map.entry; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Stream; +import lombok.Getter; + +public enum FightProperty { + FIGHT_PROP_NONE(0), + FIGHT_PROP_BASE_HP(1), + FIGHT_PROP_HP(2), + FIGHT_PROP_HP_PERCENT(3), + FIGHT_PROP_BASE_ATTACK(4), + FIGHT_PROP_ATTACK(5), + FIGHT_PROP_ATTACK_PERCENT(6), + FIGHT_PROP_BASE_DEFENSE(7), + FIGHT_PROP_DEFENSE(8), + FIGHT_PROP_DEFENSE_PERCENT(9), + FIGHT_PROP_BASE_SPEED(10), + FIGHT_PROP_SPEED_PERCENT(11), + FIGHT_PROP_HP_MP_PERCENT(12), + FIGHT_PROP_ATTACK_MP_PERCENT(13), + FIGHT_PROP_CRITICAL(20), + FIGHT_PROP_ANTI_CRITICAL(21), + FIGHT_PROP_CRITICAL_HURT(22), + FIGHT_PROP_CHARGE_EFFICIENCY(23), + FIGHT_PROP_ADD_HURT(24), + FIGHT_PROP_SUB_HURT(25), + FIGHT_PROP_HEAL_ADD(26), + FIGHT_PROP_HEALED_ADD(27), + FIGHT_PROP_ELEMENT_MASTERY(28), + FIGHT_PROP_PHYSICAL_SUB_HURT(29), + FIGHT_PROP_PHYSICAL_ADD_HURT(30), + FIGHT_PROP_DEFENCE_IGNORE_RATIO(31), + FIGHT_PROP_DEFENCE_IGNORE_DELTA(32), + FIGHT_PROP_FIRE_ADD_HURT(40), + FIGHT_PROP_ELEC_ADD_HURT(41), + FIGHT_PROP_WATER_ADD_HURT(42), + FIGHT_PROP_GRASS_ADD_HURT(43), + FIGHT_PROP_WIND_ADD_HURT(44), + FIGHT_PROP_ROCK_ADD_HURT(45), + FIGHT_PROP_ICE_ADD_HURT(46), + FIGHT_PROP_HIT_HEAD_ADD_HURT(47), + FIGHT_PROP_FIRE_SUB_HURT(50), + FIGHT_PROP_ELEC_SUB_HURT(51), + FIGHT_PROP_WATER_SUB_HURT(52), + FIGHT_PROP_GRASS_SUB_HURT(53), + FIGHT_PROP_WIND_SUB_HURT(54), + FIGHT_PROP_ROCK_SUB_HURT(55), + FIGHT_PROP_ICE_SUB_HURT(56), + FIGHT_PROP_EFFECT_HIT(60), + FIGHT_PROP_EFFECT_RESIST(61), + FIGHT_PROP_FREEZE_RESIST(62), + FIGHT_PROP_TORPOR_RESIST(63), + FIGHT_PROP_DIZZY_RESIST(64), + FIGHT_PROP_FREEZE_SHORTEN(65), + FIGHT_PROP_TORPOR_SHORTEN(66), + FIGHT_PROP_DIZZY_SHORTEN(67), + FIGHT_PROP_MAX_FIRE_ENERGY(70), + FIGHT_PROP_MAX_ELEC_ENERGY(71), + FIGHT_PROP_MAX_WATER_ENERGY(72), + FIGHT_PROP_MAX_GRASS_ENERGY(73), + FIGHT_PROP_MAX_WIND_ENERGY(74), + FIGHT_PROP_MAX_ICE_ENERGY(75), + FIGHT_PROP_MAX_ROCK_ENERGY(76), + FIGHT_PROP_SKILL_CD_MINUS_RATIO(80), + FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81), + FIGHT_PROP_CUR_FIRE_ENERGY(1000), + FIGHT_PROP_CUR_ELEC_ENERGY(1001), + FIGHT_PROP_CUR_WATER_ENERGY(1002), + FIGHT_PROP_CUR_GRASS_ENERGY(1003), + FIGHT_PROP_CUR_WIND_ENERGY(1004), + FIGHT_PROP_CUR_ICE_ENERGY(1005), + FIGHT_PROP_CUR_ROCK_ENERGY(1006), + FIGHT_PROP_CUR_HP(1010), + FIGHT_PROP_MAX_HP(2000), + FIGHT_PROP_CUR_ATTACK(2001), + FIGHT_PROP_CUR_DEFENSE(2002), + FIGHT_PROP_CUR_SPEED(2003), + FIGHT_PROP_NONEXTRA_ATTACK(3000), + FIGHT_PROP_NONEXTRA_DEFENSE(3001), + FIGHT_PROP_NONEXTRA_CRITICAL(3002), + FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003), + FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004), + FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005), + FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006), + FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007), + FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008), + FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009), + FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010), + FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011), + FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012), + FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013), + FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014), + FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015), + FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016), + FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017), + FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018), + FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019), + FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020), + FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021), + FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022), + FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023), + FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024); + + public static final int[] fightProps = + new int[] { + 1, 4, 7, 20, 21, 22, 23, 26, 27, 28, 29, 30, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, + 55, 56, 2000, 2001, 2002, 2003, 1010 + }; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); + // This was originally for relic properties so some names might not be applicable for e.g. + // setstats + private static final Map shortNameMap = + Map.ofEntries( + // Normal relic stats + entry("hp", FIGHT_PROP_HP), + entry("atk", FIGHT_PROP_ATTACK), + entry("def", FIGHT_PROP_DEFENSE), + entry("hp%", FIGHT_PROP_HP_PERCENT), + entry("atk%", FIGHT_PROP_ATTACK_PERCENT), + entry("def%", FIGHT_PROP_DEFENSE_PERCENT), + entry("em", FIGHT_PROP_ELEMENT_MASTERY), + entry("er", FIGHT_PROP_CHARGE_EFFICIENCY), + entry("hb", FIGHT_PROP_HEAL_ADD), + entry("heal", FIGHT_PROP_HEAL_ADD), + entry("cd", FIGHT_PROP_CRITICAL_HURT), + entry("cdmg", FIGHT_PROP_CRITICAL_HURT), + entry("cr", FIGHT_PROP_CRITICAL), + entry("crate", FIGHT_PROP_CRITICAL), + entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT), + entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT), + entry("geo%", FIGHT_PROP_ROCK_ADD_HURT), + entry("anemo%", FIGHT_PROP_WIND_ADD_HURT), + entry("hydro%", FIGHT_PROP_WATER_ADD_HURT), + entry("cryo%", FIGHT_PROP_ICE_ADD_HURT), + entry("electro%", FIGHT_PROP_ELEC_ADD_HURT), + entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT), + // Other stats + entry("maxhp", FIGHT_PROP_MAX_HP), + entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks + entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO), + entry("heali", FIGHT_PROP_HEALED_ADD), + entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO), + entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO), + entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks + entry("resanemo", FIGHT_PROP_WIND_SUB_HURT), + entry("rescryo", FIGHT_PROP_ICE_SUB_HURT), + entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT), + entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT), + entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT), + entry("reshydro", FIGHT_PROP_WATER_SUB_HURT), + entry("respyro", FIGHT_PROP_FIRE_SUB_HURT), + entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)); + private static final List flatProps = + Arrays.asList( + FIGHT_PROP_BASE_HP, + FIGHT_PROP_HP, + FIGHT_PROP_BASE_ATTACK, + FIGHT_PROP_ATTACK, + FIGHT_PROP_BASE_DEFENSE, + FIGHT_PROP_DEFENSE, + FIGHT_PROP_HEALED_ADD, + FIGHT_PROP_CUR_FIRE_ENERGY, + FIGHT_PROP_CUR_ELEC_ENERGY, + FIGHT_PROP_CUR_WATER_ENERGY, + FIGHT_PROP_CUR_GRASS_ENERGY, + FIGHT_PROP_CUR_WIND_ENERGY, + FIGHT_PROP_CUR_ICE_ENERGY, + FIGHT_PROP_CUR_ROCK_ENERGY, + FIGHT_PROP_CUR_HP, + FIGHT_PROP_MAX_HP, + FIGHT_PROP_CUR_ATTACK, + FIGHT_PROP_CUR_DEFENSE); + private static final Map compoundProperties = + Map.ofEntries( + entry( + FIGHT_PROP_MAX_HP, + new CompoundProperty( + FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)), + entry( + FIGHT_PROP_CUR_ATTACK, + new CompoundProperty( + FIGHT_PROP_CUR_ATTACK, + FIGHT_PROP_BASE_ATTACK, + FIGHT_PROP_ATTACK_PERCENT, + FIGHT_PROP_ATTACK)), + entry( + FIGHT_PROP_CUR_DEFENSE, + new CompoundProperty( + FIGHT_PROP_CUR_DEFENSE, + FIGHT_PROP_BASE_DEFENSE, + FIGHT_PROP_DEFENSE_PERCENT, + FIGHT_PROP_DEFENSE))); + + static { + Stream.of(values()) + .forEach( + e -> { + map.put(e.getId(), e); + stringMap.put(e.name(), e); + }); + } + + private final int id; + + FightProperty(int id) { + this.id = id; + } + + public static FightProperty getPropById(int value) { + return map.getOrDefault(value, FIGHT_PROP_NONE); + } + + public static FightProperty getPropByName(String name) { + return stringMap.getOrDefault(name, FIGHT_PROP_NONE); + } + + public static FightProperty getPropByShortName(String name) { + return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE); + } + + public static Set getShortNames() { + return shortNameMap.keySet(); + } + + public static CompoundProperty getCompoundProperty(FightProperty result) { + return compoundProperties.get(result); + } + + public static void forEachCompoundProperty(Consumer consumer) { + compoundProperties.values().forEach(consumer); + } + + public static boolean isPercentage(FightProperty prop) { + return !flatProps.contains(prop); + } + + public int getId() { + return id; + } + + @Getter + public static class CompoundProperty { + private final FightProperty result; + private final FightProperty base; + private final FightProperty percent; + private final FightProperty flat; + + public CompoundProperty( + FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) { + this.result = result; + this.base = base; + this.percent = percent; + this.flat = flat; + } + } +} diff --git a/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseAddCurHp.java b/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseAddCurHp.java index 84c036506..ac9f84ee8 100644 --- a/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseAddCurHp.java +++ b/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseAddCurHp.java @@ -1,22 +1,22 @@ -package emu.grasscutter.game.props.ItemUseAction; - -import emu.grasscutter.game.props.ItemUseOp; - -public class ItemUseAddCurHp extends ItemUseInt { - private final String icon; - - public ItemUseAddCurHp(String[] useParam) { - super(useParam); - this.icon = useParam[1]; - } - - @Override - public ItemUseOp getItemUseOp() { - return ItemUseOp.ITEM_USE_ADD_CUR_HP; - } - - @Override - public boolean useItem(UseItemParams params) { - return (params.targetAvatar.getAsEntity().heal(params.count * this.i) > 0.01); - } -} +package emu.grasscutter.game.props.ItemUseAction; + +import emu.grasscutter.game.props.ItemUseOp; + +public class ItemUseAddCurHp extends ItemUseInt { + private final String icon; + + public ItemUseAddCurHp(String[] useParam) { + super(useParam); + this.icon = useParam[1]; + } + + @Override + public ItemUseOp getItemUseOp() { + return ItemUseOp.ITEM_USE_ADD_CUR_HP; + } + + @Override + public boolean useItem(UseItemParams params) { + return (params.targetAvatar.getAsEntity().heal(params.count * this.i) > 0.01); + } +} diff --git a/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseChestSelectItem.java b/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseChestSelectItem.java index ee9f8b4bb..863877de5 100644 --- a/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseChestSelectItem.java +++ b/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseChestSelectItem.java @@ -1,38 +1,38 @@ -package emu.grasscutter.game.props.ItemUseAction; - -import emu.grasscutter.game.props.ItemUseOp; - -public class ItemUseChestSelectItem extends ItemUseSelectItems { - private final int[] optionItemCounts; - - public ItemUseChestSelectItem(String[] useParam) { - String[] options = useParam[0].split(","); - this.optionItemIds = new int[options.length]; - this.optionItemCounts = new int[options.length]; - for (int i = 0; i < options.length; i++) { - String[] optionParts = options[i].split(":"); - try { - this.optionItemIds[i] = Integer.parseInt(optionParts[0]); - } catch (NumberFormatException ignored) { - this.optionItemIds[i] = INVALID; - } - try { - this.optionItemCounts[i] = Integer.parseInt(optionParts[1]); - } catch (NumberFormatException ignored) { - this.optionItemCounts[i] = INVALID; - } - } - } - - @Override - public ItemUseOp getItemUseOp() { - return ItemUseOp.ITEM_USE_CHEST_SELECT_ITEM; - } - - @Override - protected int getItemCount(int index) { - if ((optionItemCounts == null) || (index < 0) || (index > optionItemCounts.length)) - return INVALID; - return this.optionItemCounts[index]; - } -} +package emu.grasscutter.game.props.ItemUseAction; + +import emu.grasscutter.game.props.ItemUseOp; + +public class ItemUseChestSelectItem extends ItemUseSelectItems { + private final int[] optionItemCounts; + + public ItemUseChestSelectItem(String[] useParam) { + String[] options = useParam[0].split(","); + this.optionItemIds = new int[options.length]; + this.optionItemCounts = new int[options.length]; + for (int i = 0; i < options.length; i++) { + String[] optionParts = options[i].split(":"); + try { + this.optionItemIds[i] = Integer.parseInt(optionParts[0]); + } catch (NumberFormatException ignored) { + this.optionItemIds[i] = INVALID; + } + try { + this.optionItemCounts[i] = Integer.parseInt(optionParts[1]); + } catch (NumberFormatException ignored) { + this.optionItemCounts[i] = INVALID; + } + } + } + + @Override + public ItemUseOp getItemUseOp() { + return ItemUseOp.ITEM_USE_CHEST_SELECT_ITEM; + } + + @Override + protected int getItemCount(int index) { + if ((optionItemCounts == null) || (index < 0) || (index > optionItemCounts.length)) + return INVALID; + return this.optionItemCounts[index]; + } +} diff --git a/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java b/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java index 05fee5110..c08f33193 100644 --- a/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java +++ b/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java @@ -1,97 +1,97 @@ -package emu.grasscutter.game.world; - -import emu.grasscutter.data.GameDepot; -import emu.grasscutter.utils.Position; -import java.util.List; -import java.util.Objects; -import lombok.Getter; -import lombok.Setter; - -public class SpawnDataEntry { - @Getter @Setter private transient SpawnGroupEntry group; - @Getter private int monsterId; - @Getter private int gadgetId; - @Getter private int configId; - @Getter private int level; - @Getter private int poseId; - @Getter private int gatherItemId; - @Getter private int gadgetState; - @Getter private Position pos; - @Getter private Position rot; - - public GridBlockId getBlockId() { - int scale = GridBlockId.getScale(gadgetId); - return new GridBlockId( - group.sceneId, - scale, - (int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]), - (int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale])); - } - - public static class SpawnGroupEntry { - @Getter private int sceneId; - @Getter private int groupId; - @Getter private int blockId; - @Getter @Setter private List spawns; - } - - public static class GridBlockId { - @Getter private final int sceneId; - @Getter private final int scale; - @Getter private final int x; - @Getter private final int z; - - public GridBlockId(int sceneId, int scale, int x, int z) { - this.sceneId = sceneId; - this.scale = scale; - this.x = x; - this.z = z; - } - - public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) { - GridBlockId[] results = new GridBlockId[5 * 5 * GameDepot.BLOCK_SIZE.length]; - int t = 0; - for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) { - int x = ((int) (pos.getX() / GameDepot.BLOCK_SIZE[scale])); - int z = ((int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale])); - for (int i = x - 2; i < x + 3; i++) { - for (int j = z - 2; j < z + 3; j++) { - results[t++] = new GridBlockId(sceneId, scale, i, j); - } - } - } - return results; - } - - public static int getScale(int gadgetId) { - return 0; // you should implement here,this is index of GameDepot.BLOCK_SIZE - } - - @Override - public String toString() { - return "SpawnDataEntryScaledPoint{" - + "sceneId=" - + sceneId - + ", scale=" - + scale - + ", x=" - + x - + ", z=" - + z - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - GridBlockId that = (GridBlockId) o; - return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z; - } - - @Override - public int hashCode() { - return Objects.hash(sceneId, scale, x, z); - } - } -} +package emu.grasscutter.game.world; + +import emu.grasscutter.data.GameDepot; +import emu.grasscutter.utils.Position; +import java.util.List; +import java.util.Objects; +import lombok.Getter; +import lombok.Setter; + +public class SpawnDataEntry { + @Getter @Setter private transient SpawnGroupEntry group; + @Getter private int monsterId; + @Getter private int gadgetId; + @Getter private int configId; + @Getter private int level; + @Getter private int poseId; + @Getter private int gatherItemId; + @Getter private int gadgetState; + @Getter private Position pos; + @Getter private Position rot; + + public GridBlockId getBlockId() { + int scale = GridBlockId.getScale(gadgetId); + return new GridBlockId( + group.sceneId, + scale, + (int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]), + (int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale])); + } + + public static class SpawnGroupEntry { + @Getter private int sceneId; + @Getter private int groupId; + @Getter private int blockId; + @Getter @Setter private List spawns; + } + + public static class GridBlockId { + @Getter private int sceneId; + @Getter private int scale; + @Getter private int x; + @Getter private int z; + + public GridBlockId(int sceneId, int scale, int x, int z) { + this.sceneId = sceneId; + this.scale = scale; + this.x = x; + this.z = z; + } + + public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) { + GridBlockId[] results = new GridBlockId[5 * 5 * GameDepot.BLOCK_SIZE.length]; + int t = 0; + for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) { + int x = ((int) (pos.getX() / GameDepot.BLOCK_SIZE[scale])); + int z = ((int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale])); + for (int i = x - 2; i < x + 3; i++) { + for (int j = z - 2; j < z + 3; j++) { + results[t++] = new GridBlockId(sceneId, scale, i, j); + } + } + } + return results; + } + + public static int getScale(int gadgetId) { + return 0; // you should implement here,this is index of GameDepot.BLOCK_SIZE + } + + @Override + public String toString() { + return "SpawnDataEntryScaledPoint{" + + "sceneId=" + + sceneId + + ", scale=" + + scale + + ", x=" + + x + + ", z=" + + z + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GridBlockId that = (GridBlockId) o; + return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z; + } + + @Override + public int hashCode() { + return Objects.hash(sceneId, scale, x, z); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 81a57edda..73551850d 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -37,12 +37,12 @@ public class World implements Iterable { @Getter private final List players; @Getter private final Int2ObjectMap scenes; - @Getter private final int levelEntityId; + @Getter private int levelEntityId; private int nextEntityId = 0; private int nextPeerId = 0; private int worldLevel; - private final boolean isMultiplayer; + private boolean isMultiplayer; private long lastUpdateTime; @Getter private int tickCount = 0; diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java index 45b052a30..f3aece27a 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java @@ -36,10 +36,10 @@ public class ScriptLoader { @Getter private static ScriptLib scriptLib; @Getter private static LuaValue scriptLibLua; /** suggest GC to remove it if the memory is less */ - private static final Map> scriptsCache = + private static Map> scriptsCache = new ConcurrentHashMap<>(); /** sceneId - SceneMeta */ - private static final Map> sceneMetaCache = + private static Map> sceneMetaCache = new ConcurrentHashMap<>(); public static synchronized void init() throws Exception { diff --git a/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java b/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java index 1ec9c35b9..02f0da8ae 100644 --- a/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java +++ b/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java @@ -1,26 +1,26 @@ -package emu.grasscutter.server.http.documentation; - -import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE; - -import emu.grasscutter.tools.Tools; -import emu.grasscutter.utils.Language; -import io.javalin.http.ContentType; -import io.javalin.http.Context; -import java.util.List; - -final class GachaMappingRequestHandler implements DocumentationHandler { - private final List gachaJsons; - - GachaMappingRequestHandler() { - this.gachaJsons = Tools.createGachaMappingJsons(); - } - - @Override - public void handle(Context ctx) { - final int langIdx = - Language.TextStrings.MAP_LANGUAGES.getOrDefault( - DOCUMENT_LANGUAGE, - 0); // TODO: This should really be based off the client language somehow - ctx.contentType(ContentType.APPLICATION_JSON).result(gachaJsons.get(langIdx)); - } -} +package emu.grasscutter.server.http.documentation; + +import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE; + +import emu.grasscutter.tools.Tools; +import emu.grasscutter.utils.Language; +import io.javalin.http.ContentType; +import io.javalin.http.Context; +import java.util.List; + +final class GachaMappingRequestHandler implements DocumentationHandler { + private final List gachaJsons; + + GachaMappingRequestHandler() { + this.gachaJsons = Tools.createGachaMappingJsons(); + } + + @Override + public void handle(Context ctx) { + final int langIdx = + Language.TextStrings.MAP_LANGUAGES.getOrDefault( + DOCUMENT_LANGUAGE, + 0); // TODO: This should really be based off the client language somehow + ctx.contentType(ContentType.APPLICATION_JSON).result(gachaJsons.get(langIdx)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java index 384c22583..97a2e9bef 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java @@ -1,48 +1,48 @@ -package emu.grasscutter.server.packet.send; - -import emu.grasscutter.net.packet.BasePacket; -import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; -import emu.grasscutter.net.proto.PrivateChatNotifyOuterClass.PrivateChatNotify; - -public class PacketPrivateChatNotify extends BasePacket { - private final ChatInfo info; - - public PacketPrivateChatNotify(int senderId, int recvId, String message) { - super(PacketOpcodes.PrivateChatNotify); - - ChatInfo info = - ChatInfo.newBuilder() - .setTime((int) (System.currentTimeMillis() / 1000)) - .setUid(senderId) - .setToUid(recvId) - .setText(message) - .build(); - this.info = info; - - PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build(); - - this.setData(proto); - } - - public PacketPrivateChatNotify(int senderId, int recvId, int emote) { - super(PacketOpcodes.PrivateChatNotify); - - ChatInfo info = - ChatInfo.newBuilder() - .setTime((int) (System.currentTimeMillis() / 1000)) - .setUid(senderId) - .setToUid(recvId) - .setIcon(emote) - .build(); - this.info = info; - - PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build(); - - this.setData(proto); - } - - public ChatInfo getChatInfo() { - return this.info; - } -} +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; +import emu.grasscutter.net.proto.PrivateChatNotifyOuterClass.PrivateChatNotify; + +public class PacketPrivateChatNotify extends BasePacket { + private final ChatInfo info; + + public PacketPrivateChatNotify(int senderId, int recvId, String message) { + super(PacketOpcodes.PrivateChatNotify); + + ChatInfo info = + ChatInfo.newBuilder() + .setTime((int) (System.currentTimeMillis() / 1000)) + .setUid(senderId) + .setToUid(recvId) + .setText(message) + .build(); + this.info = info; + + PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build(); + + this.setData(proto); + } + + public PacketPrivateChatNotify(int senderId, int recvId, int emote) { + super(PacketOpcodes.PrivateChatNotify); + + ChatInfo info = + ChatInfo.newBuilder() + .setTime((int) (System.currentTimeMillis() / 1000)) + .setUid(senderId) + .setToUid(recvId) + .setIcon(emote) + .build(); + this.info = info; + + PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build(); + + this.setData(proto); + } + + public ChatInfo getChatInfo() { + return this.info; + } +} diff --git a/src/main/java/emu/grasscutter/utils/TsvUtils.java b/src/main/java/emu/grasscutter/utils/TsvUtils.java index 4212ecb98..221d65ea9 100644 --- a/src/main/java/emu/grasscutter/utils/TsvUtils.java +++ b/src/main/java/emu/grasscutter/utils/TsvUtils.java @@ -57,7 +57,7 @@ public class TsvUtils { private static final Function parseLong = value -> (long) Double.parseDouble(value); // Long::parseLong; private static final Map, Function> enumTypeParsers = new HashMap<>(); - private static final Map> primitiveTypeParsers = + private final static Map> primitiveTypeParsers = Map.ofEntries( Map.entry(String.class, parseString), Map.entry(Integer.class, parseInt), @@ -72,7 +72,7 @@ public class TsvUtils { Map.entry(boolean.class, Boolean::parseBoolean)); private static final Map> typeParsers = new HashMap<>(primitiveTypeParsers); - private static final Map, Map> cachedClassFieldMaps = + private final static Map, Map> cachedClassFieldMaps = new HashMap<>(); @SuppressWarnings("unchecked")