Merge remote-tracking branch 'origin/unstable-quests' into unstable-quests

This commit is contained in:
KingRainbow44 2023-05-07 17:57:24 -04:00
commit 4f1136ce2d
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
29 changed files with 1702 additions and 1702 deletions

View File

@ -1,72 +1,72 @@
package emu.grasscutter.auth; package emu.grasscutter.auth;
import static emu.grasscutter.config.Configuration.ACCOUNT; import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.auth.DefaultAuthenticators.*; import emu.grasscutter.auth.DefaultAuthenticators.*;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.server.http.objects.ComboTokenResJson; import emu.grasscutter.server.http.objects.ComboTokenResJson;
import emu.grasscutter.server.http.objects.LoginResultJson; import emu.grasscutter.server.http.objects.LoginResultJson;
/** /**
* The default Grasscutter authentication implementation. Allows all users to access any account. * The default Grasscutter authentication implementation. Allows all users to access any account.
*/ */
public final class DefaultAuthentication implements AuthenticationSystem { public final class DefaultAuthentication implements AuthenticationSystem {
private final Authenticator<LoginResultJson> passwordAuthenticator; private final Authenticator<LoginResultJson> passwordAuthenticator;
private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator(); private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator();
private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator = private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator =
new SessionKeyAuthenticator(); new SessionKeyAuthenticator();
private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication();
private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
public DefaultAuthentication() { public DefaultAuthentication() {
if (ACCOUNT.EXPERIMENTAL_RealPassword) { if (ACCOUNT.EXPERIMENTAL_RealPassword) {
passwordAuthenticator = new ExperimentalPasswordAuthenticator(); passwordAuthenticator = new ExperimentalPasswordAuthenticator();
} else { } else {
passwordAuthenticator = new PasswordAuthenticator(); passwordAuthenticator = new PasswordAuthenticator();
} }
} }
@Override @Override
public void createAccount(String username, String password) { public void createAccount(String username, String password) {
// Unhandled. The default authenticator doesn't store passwords. // Unhandled. The default authenticator doesn't store passwords.
} }
@Override @Override
public void resetPassword(String username) { public void resetPassword(String username) {
// Unhandled. The default authenticator doesn't store passwords. // Unhandled. The default authenticator doesn't store passwords.
} }
@Override @Override
public Account verifyUser(String details) { public Account verifyUser(String details) {
Grasscutter.getLogger() Grasscutter.getLogger()
.info(translate("messages.dispatch.authentication.default_unable_to_verify")); .info(translate("messages.dispatch.authentication.default_unable_to_verify"));
return null; return null;
} }
@Override @Override
public Authenticator<LoginResultJson> getPasswordAuthenticator() { public Authenticator<LoginResultJson> getPasswordAuthenticator() {
return this.passwordAuthenticator; return this.passwordAuthenticator;
} }
@Override @Override
public Authenticator<LoginResultJson> getTokenAuthenticator() { public Authenticator<LoginResultJson> getTokenAuthenticator() {
return this.tokenAuthenticator; return this.tokenAuthenticator;
} }
@Override @Override
public Authenticator<ComboTokenResJson> getSessionKeyAuthenticator() { public Authenticator<ComboTokenResJson> getSessionKeyAuthenticator() {
return this.sessionKeyAuthenticator; return this.sessionKeyAuthenticator;
} }
@Override @Override
public ExternalAuthenticator getExternalAuthenticator() { public ExternalAuthenticator getExternalAuthenticator() {
return this.externalAuthenticator; return this.externalAuthenticator;
} }
@Override @Override
public OAuthAuthenticator getOAuthAuthenticator() { public OAuthAuthenticator getOAuthAuthenticator() {
return this.oAuthAuthenticator; return this.oAuthAuthenticator;
} }
} }

View File

@ -1,190 +1,190 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Command( @Command(
label = "setStats", label = "setStats",
aliases = {"stats", "stat"}, aliases = {"stats", "stat"},
usage = { usage = {
"[set] <stat> <value>", "[set] <stat> <value>",
"(lock|freeze) <stat> [<value>]", // Can lock to current value "(lock|freeze) <stat> [<value>]", // Can lock to current value
"(unlock|unfreeze) <stat>" "(unlock|unfreeze) <stat>"
}, },
permission = "player.setstats", permission = "player.setstats",
permissionTargeted = "player.setstats.others") permissionTargeted = "player.setstats.others")
public final class SetStatsCommand implements CommandHandler { public final class SetStatsCommand implements CommandHandler {
private final Map<String, Stat> stats; private final Map<String, Stat> stats;
public SetStatsCommand() { public SetStatsCommand() {
this.stats = new HashMap<>(); this.stats = new HashMap<>();
for (String key : FightProperty.getShortNames()) { for (String key : FightProperty.getShortNames()) {
this.stats.put(key, new Stat(FightProperty.getPropByShortName(key))); this.stats.put(key, new Stat(FightProperty.getPropByShortName(key)));
} }
// Full FightProperty enum that won't be advertised but can be used by devs // Full FightProperty enum that won't be advertised but can be used by devs
// They have a prefix to avoid the "hp" clash // They have a prefix to avoid the "hp" clash
for (FightProperty prop : FightProperty.values()) { for (FightProperty prop : FightProperty.values()) {
String name = prop.toString().substring(10); // FIGHT_PROP_BASE_HP -> _BASE_HP String name = prop.toString().substring(10); // FIGHT_PROP_BASE_HP -> _BASE_HP
String key = name.toLowerCase(); // _BASE_HP -> _base_hp String key = name.toLowerCase(); // _BASE_HP -> _base_hp
name = name.substring(1); // _BASE_HP -> BASE_HP name = name.substring(1); // _BASE_HP -> BASE_HP
this.stats.put(key, new Stat(name, prop)); this.stats.put(key, new Stat(name, prop));
} }
// Compatibility aliases // Compatibility aliases
this.stats.put("mhp", this.stats.get("maxhp")); this.stats.put("mhp", this.stats.get("maxhp"));
this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP
this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK
this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE
this.stats.put( this.stats.put(
"atkb", "atkb",
this.stats.get( this.stats.get(
"_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only "_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only
// useful for stuff like Bennett's buff. // useful for stuff like Bennett's buff.
this.stats.put("eanemo", this.stats.get("anemo%")); this.stats.put("eanemo", this.stats.get("anemo%"));
this.stats.put("ecryo", this.stats.get("cryo%")); this.stats.put("ecryo", this.stats.get("cryo%"));
this.stats.put("edendro", this.stats.get("dendro%")); this.stats.put("edendro", this.stats.get("dendro%"));
this.stats.put("edend", this.stats.get("dendro%")); this.stats.put("edend", this.stats.get("dendro%"));
this.stats.put("eelectro", this.stats.get("electro%")); this.stats.put("eelectro", this.stats.get("electro%"));
this.stats.put("eelec", this.stats.get("electro%")); this.stats.put("eelec", this.stats.get("electro%"));
this.stats.put("ethunder", this.stats.get("electro%")); this.stats.put("ethunder", this.stats.get("electro%"));
this.stats.put("egeo", this.stats.get("geo%")); this.stats.put("egeo", this.stats.get("geo%"));
this.stats.put("ehydro", this.stats.get("hydro%")); this.stats.put("ehydro", this.stats.get("hydro%"));
this.stats.put("epyro", this.stats.get("pyro%")); this.stats.put("epyro", this.stats.get("pyro%"));
this.stats.put("ephys", this.stats.get("phys%")); this.stats.put("ephys", this.stats.get("phys%"));
} }
public static float parsePercent(String input) throws NumberFormatException { public static float parsePercent(String input) throws NumberFormatException {
if (input.endsWith("%")) { if (input.endsWith("%")) {
return Float.parseFloat(input.substring(0, input.length() - 1)) / 100f; return Float.parseFloat(input.substring(0, input.length() - 1)) / 100f;
} else { } else {
return Float.parseFloat(input); return Float.parseFloat(input);
} }
} }
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
String statStr = null; String statStr = null;
String valueStr; String valueStr;
float value = 0f; float value = 0f;
if (args.size() < 2) { if (args.size() < 2) {
sendUsageMessage(sender); sendUsageMessage(sender);
return; return;
} }
// Get the action and stat // Get the action and stat
String arg0 = args.remove(0).toLowerCase(); String arg0 = args.remove(0).toLowerCase();
Action action = Action action =
switch (arg0) { switch (arg0) {
default -> { default -> {
statStr = arg0; statStr = arg0;
yield Action.ACTION_SET; yield Action.ACTION_SET;
} // Implicit set command } // Implicit set command
case "set" -> Action.ACTION_SET; // Explicit set command case "set" -> Action.ACTION_SET; // Explicit set command
case "lock", "freeze" -> Action.ACTION_LOCK; case "lock", "freeze" -> Action.ACTION_LOCK;
case "unlock", "unfreeze" -> Action.ACTION_UNLOCK; case "unlock", "unfreeze" -> Action.ACTION_UNLOCK;
}; };
if (statStr == null) { if (statStr == null) {
statStr = args.remove(0).toLowerCase(); statStr = args.remove(0).toLowerCase();
} }
if (!stats.containsKey(statStr)) { if (!stats.containsKey(statStr)) {
sendUsageMessage(sender); // Invalid stat or action sendUsageMessage(sender); // Invalid stat or action
return; return;
} }
Stat stat = stats.get(statStr); Stat stat = stats.get(statStr);
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
Avatar avatar = entity.getAvatar(); Avatar avatar = entity.getAvatar();
// Get the value if the action requires it // Get the value if the action requires it
try { try {
switch (action) { switch (action) {
case ACTION_LOCK: case ACTION_LOCK:
if (args.isEmpty()) { // Lock to current value if (args.isEmpty()) { // Lock to current value
value = avatar.getFightProperty(stat.prop); value = avatar.getFightProperty(stat.prop);
break; break;
} // Else fall-through and lock to supplied value } // Else fall-through and lock to supplied value
case ACTION_SET: case ACTION_SET:
value = parsePercent(args.remove(0)); value = parsePercent(args.remove(0));
break; break;
case ACTION_UNLOCK: case ACTION_UNLOCK:
break; break;
} }
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.statValue"); CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.statValue");
return; return;
} catch (IndexOutOfBoundsException ignored) { } catch (IndexOutOfBoundsException ignored) {
sendUsageMessage(sender); sendUsageMessage(sender);
return; return;
} }
if (!args.isEmpty()) { // Leftover arguments! if (!args.isEmpty()) { // Leftover arguments!
sendUsageMessage(sender); sendUsageMessage(sender);
return; return;
} }
switch (action) { switch (action) {
case ACTION_SET: case ACTION_SET:
entity.setFightProperty(stat.prop, value); entity.setFightProperty(stat.prop, value);
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop)); entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop));
break; break;
case ACTION_LOCK: case ACTION_LOCK:
avatar.getFightPropOverrides().put(stat.prop.getId(), value); avatar.getFightPropOverrides().put(stat.prop.getId(), value);
avatar.recalcStats(); avatar.recalcStats();
break; break;
case ACTION_UNLOCK: case ACTION_UNLOCK:
avatar.getFightPropOverrides().remove(stat.prop.getId()); avatar.getFightPropOverrides().remove(stat.prop.getId());
avatar.recalcStats(); avatar.recalcStats();
break; break;
} }
// Report action // Report action
if (FightProperty.isPercentage(stat.prop)) { if (FightProperty.isPercentage(stat.prop)) {
valueStr = String.format("%.1f%%", value * 100f); valueStr = String.format("%.1f%%", value * 100f);
} else { } else {
valueStr = String.format("%.0f", value); valueStr = String.format("%.0f", value);
} }
if (targetPlayer == sender) { if (targetPlayer == sender) {
CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr); CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr);
} else { } else {
String uidStr = targetPlayer.getAccount().getId(); String uidStr = targetPlayer.getAccount().getId();
CommandHandler.sendTranslatedMessage( CommandHandler.sendTranslatedMessage(
sender, action.messageKeyOther, stat.name, uidStr, valueStr); sender, action.messageKeyOther, stat.name, uidStr, valueStr);
} }
} }
private enum Action { private enum Action {
ACTION_SET("commands.generic.set_to", "commands.generic.set_for_to"), ACTION_SET("commands.generic.set_to", "commands.generic.set_for_to"),
ACTION_LOCK("commands.setStats.locked_to", "commands.setStats.locked_for_to"), ACTION_LOCK("commands.setStats.locked_to", "commands.setStats.locked_for_to"),
ACTION_UNLOCK("commands.setStats.unlocked", "commands.setStats.unlocked_for"); ACTION_UNLOCK("commands.setStats.unlocked", "commands.setStats.unlocked_for");
public final String messageKeySelf; public final String messageKeySelf;
public final String messageKeyOther; public final String messageKeyOther;
Action(String messageKeySelf, String messageKeyOther) { Action(String messageKeySelf, String messageKeyOther) {
this.messageKeySelf = messageKeySelf; this.messageKeySelf = messageKeySelf;
this.messageKeyOther = messageKeyOther; this.messageKeyOther = messageKeyOther;
} }
} }
private static class Stat { private static class Stat {
String name; String name;
FightProperty prop; FightProperty prop;
public Stat(FightProperty prop) { public Stat(FightProperty prop) {
this.name = prop.toString(); this.name = prop.toString();
this.prop = prop; this.prop = prop;
} }
public Stat(String name, FightProperty prop) { public Stat(String name, FightProperty prop) {
this.name = name; this.name = name;
this.prop = prop; this.prop = prop;
} }
} }
} }

View File

@ -477,8 +477,8 @@ public final class GameData {
private static final Int2IntMap trialAvatarIndexIdTrialActivityDataDataMap = private static final Int2IntMap trialAvatarIndexIdTrialActivityDataDataMap =
new Int2IntOpenHashMap(); new Int2IntOpenHashMap();
private static final Map<Integer, List<Integer>> fetters = new HashMap<>(); private static Map<Integer, List<Integer>> fetters = new HashMap<>();
private static final Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>(); private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>();
// Getters with different names that stay for now // Getters with different names that stay for now
public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() { public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() {

View File

@ -19,17 +19,17 @@ import lombok.Setter;
public class GameDepot { public class GameDepot {
public static final int[] BLOCK_SIZE = new int[] {50, 500}; // Scales public static final int[] BLOCK_SIZE = new int[] {50, 500}; // Scales
private static final Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot = private static Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
@Getter @Setter private static Map<String, AvatarConfig> playerAbilities = new HashMap<>(); @Getter @Setter private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
@Getter @Getter
private static final HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = private static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists =
new HashMap<>(); new HashMap<>();
@Getter @Setter private static BlossomConfig blossomConfig; @Getter @Setter private static BlossomConfig blossomConfig;

View File

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

View File

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

View File

@ -31,7 +31,7 @@ public class ItemData extends GameResource {
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private int id; private int id;
private final int stackLimit = 1; private int stackLimit = 1;
private int maxUseCount; private int maxUseCount;
private int rankLevel; private int rankLevel;
private String effectName; private String effectName;
@ -43,7 +43,7 @@ public class ItemData extends GameResource {
private int[] destroyReturnMaterialCount; private int[] destroyReturnMaterialCount;
// Enums // Enums
private final ItemType itemType = ItemType.ITEM_NONE; private ItemType itemType = ItemType.ITEM_NONE;
private MaterialType materialType = MaterialType.MATERIAL_NONE; private MaterialType materialType = MaterialType.MATERIAL_NONE;
private EquipType equipType = EquipType.EQUIP_NONE; private EquipType equipType = EquipType.EQUIP_NONE;
private String effectType; private String effectType;

View File

@ -1,21 +1,21 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter; import lombok.Getter;
@ResourceType(name = "PlayerLevelExcelConfigData.json") @ResourceType(name = "PlayerLevelExcelConfigData.json")
@Getter @Getter
public class PlayerLevelData extends GameResource { public class PlayerLevelData extends GameResource {
private int level; private int level;
private int exp; private int exp;
private int rewardId; private int rewardId;
private final int expeditionLimitAdd = 0; private int expeditionLimitAdd = 0;
private int unlockWorldLevel; private int unlockWorldLevel;
private long unlockDescTextMapHash; private long unlockDescTextMapHash;
@Override @Override
public int getId() { public int getId() {
return this.level; return this.level;
} }
} }

View File

@ -18,7 +18,7 @@ public class AchievementData extends GameResource {
private static final AtomicBoolean isDivided = new AtomicBoolean(); private static final AtomicBoolean isDivided = new AtomicBoolean();
private int goalId; private int goalId;
private int preStageAchievementId; private int preStageAchievementId;
private final Set<Integer> groupAchievementIdList = new HashSet<>(); private Set<Integer> groupAchievementIdList = new HashSet<>();
private boolean isParent; private boolean isParent;
private long titleTextMapHash; private long titleTextMapHash;
private long descTextMapHash; private long descTextMapHash;

View File

@ -26,7 +26,7 @@ public class Account {
private String token; private String token;
private String sessionKey; // Session token for dispatch server private String sessionKey; // Session token for dispatch server
private final List<String> permissions; private List<String> permissions;
private Locale locale; private Locale locale;
private String banReason; private String banReason;

View File

@ -1,214 +1,214 @@
package emu.grasscutter.game.ability; package emu.grasscutter.game.ability;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange; import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class HealAbilityManager { public class HealAbilityManager {
ArrayList<HealDataAvatar> healDataAvatarList; ArrayList<HealDataAvatar> healDataAvatarList;
private final Player player; private Player player;
public HealAbilityManager(Player player) { public HealAbilityManager(Player player) {
this.player = player; this.player = player;
healDataAvatarList = new ArrayList(); healDataAvatarList = new ArrayList();
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000054, "Kokomi", 0) new HealDataAvatar(10000054, "Kokomi", 0)
.addHealData( .addHealData(
"E", "E",
"ElementalArt_Heal_MaxHP_Base_Percentage", "ElementalArt_Heal_MaxHP_Base_Percentage",
"ElementalArt_Heal_Base_Amount", "ElementalArt_Heal_Base_Amount",
false) false)
.addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false)); .addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true)); new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000034, "Noel", 2) new HealDataAvatar(10000034, "Noel", 2)
.addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true)); .addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000032, "Bennett", 0) new HealDataAvatar(10000032, "Bennett", 0)
.addHealData("Q", "HealMaxHpRatio", "HealConst", false)); .addHealData("Q", "HealMaxHpRatio", "HealConst", false));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000039, "Diona", 0) new HealDataAvatar(10000039, "Diona", 0)
.addHealData("Q", "HealHPRatio", "HealHP_Const", false)); .addHealData("Q", "HealHPRatio", "HealHP_Const", false));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000053, "Sayu", 1) new HealDataAvatar(10000053, "Sayu", 1)
.addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true) .addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true)
.addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true)); .addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000014, "Barbara", 0) new HealDataAvatar(10000014, "Barbara", 0)
.addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true) .addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true)
.addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true) .addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true)
.addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true)); .addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000065, "Shinobu", 0) new HealDataAvatar(10000065, "Shinobu", 0)
.addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false)); .addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000035, "Qiqi", 1) new HealDataAvatar(10000035, "Qiqi", 1)
.addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true) .addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true)
.addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true) .addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true)
.addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false)); .addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false));
healDataAvatarList.add( healDataAvatarList.add(
new HealDataAvatar(10000046, "Hutao", 0) new HealDataAvatar(10000046, "Hutao", 0)
.addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false)); .addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false));
} }
public Player getPlayer() { public Player getPlayer() {
return this.player; return this.player;
} }
public void healHandler(AbilityInvokeEntry invoke) throws Exception { public void healHandler(AbilityInvokeEntry invoke) throws Exception {
AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData()); AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData());
if (data == null) { if (data == null) {
return; return;
} }
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId()); GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
String modifierString = ""; String modifierString = "";
if (data.getParentAbilityName() != null) modifierString = data.getParentAbilityName().getStr(); if (data.getParentAbilityName() != null) modifierString = data.getParentAbilityName().getStr();
if (sourceEntity != null) checkAndHeal(sourceEntity, modifierString); if (sourceEntity != null) checkAndHeal(sourceEntity, modifierString);
} }
public void checkAndHeal(GameEntity sourceEntity, String modifierString) { public void checkAndHeal(GameEntity sourceEntity, String modifierString) {
int fightPropertyType = 0; int fightPropertyType = 0;
float healAmount = 0; float healAmount = 0;
float ratio = 0, base = 0; float ratio = 0, base = 0;
float maxHP, curHP, curAttack, curDefense; float maxHP, curHP, curAttack, curDefense;
Map<String, Float> map = sourceEntity.getMetaOverrideMap(); Map<String, Float> map = sourceEntity.getMetaOverrideMap();
for (int i = 0; i < healDataAvatarList.size(); i++) { for (int i = 0; i < healDataAvatarList.size(); i++) {
HealDataAvatar healDataAvatar = healDataAvatarList.get(i); HealDataAvatar healDataAvatar = healDataAvatarList.get(i);
if (modifierString.contains(healDataAvatar.avatarName)) { if (modifierString.contains(healDataAvatar.avatarName)) {
fightPropertyType = healDataAvatar.fightPropertyType; fightPropertyType = healDataAvatar.fightPropertyType;
ArrayList<HealData> healDataList = healDataAvatar.healDataList; ArrayList<HealData> healDataList = healDataAvatar.healDataList;
for (int j = 0; j < healDataList.size(); j++) { for (int j = 0; j < healDataList.size(); j++) {
HealData healData = healDataList.get(j); HealData healData = healDataList.get(j);
if (map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) { if (map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) {
if (healData.isString) { if (healData.isString) {
ratio = map.get(healData.sRatio); ratio = map.get(healData.sRatio);
base = map.get(healData.sBase); base = map.get(healData.sBase);
} else { } else {
ratio = healData.fRatio; ratio = healData.fRatio;
base = healData.fBase; base = healData.fBase;
} }
} }
List<EntityAvatar> activeTeam = player.getTeamManager().getActiveTeam(); List<EntityAvatar> activeTeam = player.getTeamManager().getActiveTeam();
List<EntityAvatar> needHealAvatars = new ArrayList(); List<EntityAvatar> needHealAvatars = new ArrayList();
int currentIndex = player.getTeamManager().getCurrentCharacterIndex(); int currentIndex = player.getTeamManager().getCurrentCharacterIndex();
EntityAvatar currentAvatar = activeTeam.get(currentIndex); EntityAvatar currentAvatar = activeTeam.get(currentIndex);
if (healData.healAll) { if (healData.healAll) {
needHealAvatars = activeTeam; needHealAvatars = activeTeam;
} else { } else {
needHealAvatars.add(currentAvatar); needHealAvatars.add(currentAvatar);
} }
EntityAvatar healActionAvatar = null; EntityAvatar healActionAvatar = null;
for (int k = 0; k < activeTeam.size(); k++) { for (int k = 0; k < activeTeam.size(); k++) {
EntityAvatar avatar = activeTeam.get(k); EntityAvatar avatar = activeTeam.get(k);
int avatarId = avatar.getAvatar().getAvatarId(); int avatarId = avatar.getAvatar().getAvatarId();
if (avatarId == healDataAvatar.avatarId) { if (avatarId == healDataAvatar.avatarId) {
healActionAvatar = avatar; healActionAvatar = avatar;
break; break;
} }
} }
if (healActionAvatar != null) { if (healActionAvatar != null) {
maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK); curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK);
curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE); curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE);
// Special case for Hu Tao: // Special case for Hu Tao:
if (healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) { if (healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) {
ratio = 0.1555f; ratio = 0.1555f;
} }
switch (fightPropertyType) { switch (fightPropertyType) {
case 0: case 0:
healAmount = ratio * maxHP + base; healAmount = ratio * maxHP + base;
break; break;
case 1: case 1:
healAmount = ratio * curAttack + base; healAmount = ratio * curAttack + base;
break; break;
case 2: case 2:
healAmount = ratio * curDefense + base; healAmount = ratio * curDefense + base;
break; break;
} }
} }
for (int k = 0; k < needHealAvatars.size(); k++) { for (int k = 0; k < needHealAvatars.size(); k++) {
EntityAvatar avatar = needHealAvatars.get(k); EntityAvatar avatar = needHealAvatars.get(k);
avatar.heal(healAmount); avatar.heal(healAmount);
} }
} }
break; break;
} }
} }
} }
private class HealData { private class HealData {
public boolean isString = true; public boolean isString = true;
public String abilityType = ""; // "E" or "Q" public String abilityType = ""; // "E" or "Q"
public String sRatio = ""; public String sRatio = "";
public String sBase = ""; public String sBase = "";
public float fRatio = 0; public float fRatio = 0;
public float fBase = 0; public float fBase = 0;
public boolean healAll = false; public boolean healAll = false;
public HealData(String _abilityType, String _sRatio, String _sBase, boolean _healAll) { public HealData(String _abilityType, String _sRatio, String _sBase, boolean _healAll) {
abilityType = _abilityType; abilityType = _abilityType;
isString = true; isString = true;
sRatio = _sRatio; sRatio = _sRatio;
sBase = _sBase; sBase = _sBase;
healAll = _healAll; healAll = _healAll;
} }
public HealData( public HealData(
String _abilityType, String _sRatio, float _fRatio, float _fBase, boolean _healAll) { String _abilityType, String _sRatio, float _fRatio, float _fBase, boolean _healAll) {
abilityType = _abilityType; abilityType = _abilityType;
isString = false; isString = false;
sRatio = _sRatio; sRatio = _sRatio;
fRatio = _fRatio; fRatio = _fRatio;
fBase = _fBase; fBase = _fBase;
healAll = _healAll; healAll = _healAll;
} }
} }
private class HealDataAvatar { private class HealDataAvatar {
public int avatarId = 0; public int avatarId = 0;
public String avatarName = ""; public String avatarName = "";
public int fightPropertyType = 0; // 0: maxHP, 1: curAttack, 2: curDefense public int fightPropertyType = 0; // 0: maxHP, 1: curAttack, 2: curDefense
public ArrayList<HealData> healDataList; public ArrayList<HealData> healDataList;
public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) { public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) {
avatarId = _avatarId; avatarId = _avatarId;
avatarName = _avatarName; avatarName = _avatarName;
fightPropertyType = _fightPropertyType; fightPropertyType = _fightPropertyType;
healDataList = new ArrayList(); healDataList = new ArrayList();
} }
public HealDataAvatar addHealData( public HealDataAvatar addHealData(
String abilityType, String sRatio, String sBase, boolean healAll) { String abilityType, String sRatio, String sBase, boolean healAll) {
HealData healData = new HealData(abilityType, sRatio, sBase, healAll); HealData healData = new HealData(abilityType, sRatio, sBase, healAll);
healDataList.add(healData); healDataList.add(healData);
return this; return this;
} }
public HealDataAvatar addHealData( public HealDataAvatar addHealData(
String abilityType, String sRatio, float fRatio, float fBase, boolean healAll) { String abilityType, String sRatio, float fRatio, float fBase, boolean healAll) {
HealData healData = new HealData(abilityType, sRatio, fRatio, fBase, healAll); HealData healData = new HealData(abilityType, sRatio, fRatio, fBase, healAll);
healDataList.add(healData); healDataList.add(healData);
return this; return this;
} }
} }
} }

View File

@ -1,40 +1,40 @@
package emu.grasscutter.game.achievement; package emu.grasscutter.game.achievement;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import emu.grasscutter.net.proto.AchievementOuterClass; import emu.grasscutter.net.proto.AchievementOuterClass;
import emu.grasscutter.net.proto.StatusOuterClass; import emu.grasscutter.net.proto.StatusOuterClass;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@Entity @Entity
@Getter @Getter
public class Achievement { public class Achievement {
@Setter private StatusOuterClass.Status status; @Setter private StatusOuterClass.Status status;
private final int id; private int id;
private final int totalProgress; private int totalProgress;
@Setter private int curProgress; @Setter private int curProgress;
@Setter private int finishTimestampSec; @Setter private int finishTimestampSec;
public Achievement( public Achievement(
StatusOuterClass.Status status, StatusOuterClass.Status status,
int id, int id,
int totalProgress, int totalProgress,
int curProgress, int curProgress,
int finishTimestampSec) { int finishTimestampSec) {
this.status = status; this.status = status;
this.id = id; this.id = id;
this.totalProgress = totalProgress; this.totalProgress = totalProgress;
this.curProgress = curProgress; this.curProgress = curProgress;
this.finishTimestampSec = finishTimestampSec; this.finishTimestampSec = finishTimestampSec;
} }
public AchievementOuterClass.Achievement toProto() { public AchievementOuterClass.Achievement toProto() {
return AchievementOuterClass.Achievement.newBuilder() return AchievementOuterClass.Achievement.newBuilder()
.setStatus(this.getStatus()) .setStatus(this.getStatus())
.setId(this.getId()) .setId(this.getId())
.setTotalProgress(this.getTotalProgress()) .setTotalProgress(this.getTotalProgress())
.setCurProgress(this.getCurProgress()) .setCurProgress(this.getCurProgress())
.setFinishTimestamp(this.getFinishTimestampSec()) .setFinishTimestamp(this.getFinishTimestampSec())
.build(); .build();
} }
} }

View File

@ -74,13 +74,13 @@ public class Avatar {
private List<Integer> fetters; private List<Integer> fetters;
private final Map<Integer, Integer> skillLevelMap = new Int2IntArrayMap(7); // Talent levels private Map<Integer, Integer> skillLevelMap = new Int2IntArrayMap(7); // Talent levels
@Transient @Getter @Transient @Getter
private final Map<Integer, Integer> skillExtraChargeMap = new Int2IntArrayMap(2); // Charges private Map<Integer, Integer> skillExtraChargeMap = new Int2IntArrayMap(2); // Charges
@Transient @Transient
private final Map<Integer, Integer> proudSkillBonusMap = private Map<Integer, Integer> proudSkillBonusMap =
new Int2IntArrayMap(2); // Talent bonus levels (from const) new Int2IntArrayMap(2); // Talent bonus levels (from const)
@Getter private int skillDepotId; @Getter private int skillDepotId;

View File

@ -1,122 +1,122 @@
package emu.grasscutter.game.entity; package emu.grasscutter.game.entity;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass; import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify; import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify;
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.net.proto.VectorOuterClass.Vector;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter; import lombok.Getter;
public class EntityClientGadget extends EntityBaseGadget { public class EntityClientGadget extends EntityBaseGadget {
@Getter private final Player owner; @Getter private final Player owner;
@Getter(onMethod_ = @Override) @Getter(onMethod_ = @Override)
private final int gadgetId; private int gadgetId;
@Getter private final int campId; @Getter private int campId;
@Getter private final int campType; @Getter private int campType;
@Getter private final int ownerEntityId; @Getter private int ownerEntityId;
@Getter private final int targetEntityId; @Getter private int targetEntityId;
@Getter private final boolean asyncLoad; @Getter private boolean asyncLoad;
@Getter private final int originalOwnerEntityId; @Getter private int originalOwnerEntityId;
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) { public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles())); super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles()));
this.owner = player; this.owner = player;
this.id = notify.getEntityId(); this.id = notify.getEntityId();
this.gadgetId = notify.getConfigId(); this.gadgetId = notify.getConfigId();
this.campId = notify.getCampId(); this.campId = notify.getCampId();
this.campType = notify.getCampType(); this.campType = notify.getCampType();
this.ownerEntityId = notify.getPropOwnerEntityId(); this.ownerEntityId = notify.getPropOwnerEntityId();
this.targetEntityId = notify.getTargetEntityId(); this.targetEntityId = notify.getTargetEntityId();
this.asyncLoad = notify.getIsAsyncLoad(); this.asyncLoad = notify.getIsAsyncLoad();
GameEntity owner = scene.getEntityById(this.ownerEntityId); GameEntity owner = scene.getEntityById(this.ownerEntityId);
if (owner instanceof EntityClientGadget ownerGadget) { if (owner instanceof EntityClientGadget ownerGadget) {
this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId(); this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId();
} else { } else {
this.originalOwnerEntityId = this.ownerEntityId; this.originalOwnerEntityId = this.ownerEntityId;
} }
} }
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method. super.onDeath(killerId); // Invoke super class's onDeath() method.
} }
@Override @Override
public Int2FloatMap getFightProperties() { public Int2FloatMap getFightProperties() {
return null; return null;
} }
@Override @Override
public SceneEntityInfo toProto() { public SceneEntityInfo toProto() {
EntityAuthorityInfo authority = EntityAuthorityInfo authority =
EntityAuthorityInfo.newBuilder() EntityAuthorityInfo.newBuilder()
.setAbilityInfo(AbilitySyncStateInfo.newBuilder()) .setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
.setAiInfo( .setAiInfo(
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
.setBornPos(Vector.newBuilder()) .setBornPos(Vector.newBuilder())
.build(); .build();
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.Builder entityInfo =
SceneEntityInfo.newBuilder() SceneEntityInfo.newBuilder()
.setEntityId(getId()) .setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
.setMotionInfo( .setMotionInfo(
MotionInfo.newBuilder() MotionInfo.newBuilder()
.setPos(getPosition().toProto()) .setPos(getPosition().toProto())
.setRot(getRotation().toProto()) .setRot(getRotation().toProto())
.setSpeed(Vector.newBuilder())) .setSpeed(Vector.newBuilder()))
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientData.newBuilder()) .setEntityClientData(EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority) .setEntityAuthorityInfo(authority)
.setLifeState(1); .setLifeState(1);
PropPair pair = PropPair pair =
PropPair.newBuilder() PropPair.newBuilder()
.setType(PlayerProperty.PROP_LEVEL.getId()) .setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
.build(); .build();
entityInfo.addPropList(pair); entityInfo.addPropList(pair);
ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget =
ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder() ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder()
.setCampId(this.getCampId()) .setCampId(this.getCampId())
.setCampType(this.getCampType()) .setCampType(this.getCampType())
.setOwnerEntityId(this.getOwnerEntityId()) .setOwnerEntityId(this.getOwnerEntityId())
.setTargetEntityId(this.getTargetEntityId()) .setTargetEntityId(this.getTargetEntityId())
.setAsyncLoad(this.isAsyncLoad()) .setAsyncLoad(this.isAsyncLoad())
.build(); .build();
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.Builder gadgetInfo =
SceneGadgetInfo.newBuilder() SceneGadgetInfo.newBuilder()
.setGadgetId(this.getGadgetId()) .setGadgetId(this.getGadgetId())
.setOwnerEntityId(this.getOwnerEntityId()) .setOwnerEntityId(this.getOwnerEntityId())
.setIsEnableInteract(true) .setIsEnableInteract(true)
.setClientGadget(clientGadget) .setClientGadget(clientGadget)
.setPropOwnerEntityId(this.getOwnerEntityId()) .setPropOwnerEntityId(this.getOwnerEntityId())
.setAuthorityPeerId(this.getOwner().getPeerId()); .setAuthorityPeerId(this.getOwner().getPeerId());
entityInfo.setGadget(gadgetInfo); entityInfo.setGadget(gadgetInfo);
return entityInfo.build(); return entityInfo.build();
} }
} }

View File

@ -66,7 +66,7 @@ public class EntityGadget extends EntityBaseGadget {
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap(); private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
@Getter @Setter private SceneGadget metaGadget; @Getter @Setter private SceneGadget metaGadget;
@Nullable @Getter private ConfigEntityGadget configGadget; @Nullable @Getter ConfigEntityGadget configGadget;
@Getter @Setter private BaseRoute routeConfig; @Getter @Setter private BaseRoute routeConfig;
@Getter @Setter private int stopValue = 0; // Controller related, inited to zero @Getter @Setter private int stopValue = 0; // Controller related, inited to zero

View File

@ -42,7 +42,7 @@ public class EntityVehicle extends EntityBaseGadget {
@Getter private final int gadgetId; @Getter private final int gadgetId;
@Getter @Setter private float curStamina; @Getter @Setter private float curStamina;
@Getter private final List<VehicleMember> vehicleMembers; @Getter private List<VehicleMember> vehicleMembers;
@Nullable @Getter private ConfigEntityGadget configGadget; @Nullable @Getter private ConfigEntityGadget configGadget;
public EntityVehicle( public EntityVehicle(

View File

@ -1,352 +1,352 @@
package emu.grasscutter.game.gacha; package emu.grasscutter.game.gacha;
import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.config.Configuration.*;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo; import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo; import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import lombok.Getter; import lombok.Getter;
public class GachaBanner { public class GachaBanner {
// Constants used by the BannerType enum // Constants used by the BannerType enum
static final int[][] DEFAULT_WEIGHTS_4 = {{1, 510}, {8, 510}, {10, 10000}}; 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_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 = {{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_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_WEIGHTS_5_WEAPON = {{1, 100}, {62, 100}, {73, 7800}, {80, 10000}};
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_1 = { 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, 1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053,
1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072
}; // Default avatars }; // Default avatars
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = { static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = {
11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403,
14409, 15401, 15402, 15403, 15405 14409, 15401, 15402, 15403, 15405
}; // Default weapons }; // Default weapons
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = { static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = {
1003, 1016, 1042, 1035, 1041, 1069 1003, 1016, 1042, 1035, 1041, 1069
}; // Default avatars }; // Default avatars
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = { static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = {
11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502 11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502
}; // Default weapons }; // Default weapons
static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback
@Getter int scheduleId = -1; @Getter int scheduleId = -1;
@Getter int sortId = -1; @Getter int sortId = -1;
@Getter private int gachaType = -1; @Getter private int gachaType = -1;
@Getter private String prefabPath; @Getter private String prefabPath;
@Getter private String previewPrefabPath; @Getter private String previewPrefabPath;
@Getter private String titlePath; @Getter private String titlePath;
private int costItemId = 0; private int costItemId = 0;
private final int costItemAmount = 1; private int costItemAmount = 1;
private int costItemId10 = 0; private int costItemId10 = 0;
private final int costItemAmount10 = 10; private int costItemAmount10 = 10;
@Getter private final int beginTime = 0; @Getter private int beginTime = 0;
@Getter private final int endTime = 1924992000; @Getter private int endTime = 1924992000;
@Getter private final int gachaTimesLimit = Integer.MAX_VALUE; @Getter private int gachaTimesLimit = Integer.MAX_VALUE;
@Getter private final int[] rateUpItems4 = {}; @Getter private int[] rateUpItems4 = {};
@Getter private final int[] rateUpItems5 = {}; @Getter private int[] rateUpItems5 = {};
// This now handles default values for the fields below // This now handles default values for the fields below
@Getter private final BannerType bannerType = BannerType.STANDARD; @Getter private BannerType bannerType = BannerType.STANDARD;
// These don't change between banner types (apart from Standard having three extra 4star avatars) // These don't change between banner types (apart from Standard having three extra 4star avatars)
@Getter @Getter
private final int[] fallbackItems3 = { private int[] fallbackItems3 = {
11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304 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 int[] fallbackItems4Pool1 = DEFAULT_FALLBACK_ITEMS_4_POOL_1;
@Getter private final int[] fallbackItems4Pool2 = DEFAULT_FALLBACK_ITEMS_4_POOL_2; @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 // Different banner types have different defaults, see above for default values and the enum for
// which are used where. // which are used where.
@Getter private int[] fallbackItems5Pool1; @Getter private int[] fallbackItems5Pool1;
@Getter private int[] fallbackItems5Pool2; @Getter private int[] fallbackItems5Pool2;
private int[][] weights4; private int[][] weights4;
private int[][] weights5; private int[][] weights5;
private int eventChance4 = -1; // Chance to win a featured event item private int eventChance4 = -1; // Chance to win a featured event item
private int eventChance5 = -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 boolean removeC6FromPool = false;
@Getter @Getter
private final boolean autoStripRateUpFromFallback = private boolean autoStripRateUpFromFallback =
true; // Ensures that featured items won't "double dip" into the losing pool true; // Ensures that featured items won't "double dip" into the losing pool
private final int[][] poolBalanceWeights4 = { private int[][] poolBalanceWeights4 = {
{1, 255}, {17, 255}, {21, 10455} {1, 255}, {17, 255}, {21, 10455}
}; // Used to ensure that players won't go too many rolls without getting something from pool 1 }; // Used to ensure that players won't go too many rolls without getting something from pool 1
// (avatar) or pool 2 (weapon) // (avatar) or pool 2 (weapon)
private final int[][] poolBalanceWeights5 = {{1, 30}, {147, 150}, {181, 10230}}; private int[][] poolBalanceWeights5 = {{1, 30}, {147, 150}, {181, 10230}};
@Getter private final int wishMaxProgress = 2; @Getter private int wishMaxProgress = 2;
// Deprecated fields that were tolerated in early May 2022 but have apparently still being // Deprecated fields that were tolerated in early May 2022 but have apparently still being
// circulating in new custom configs // circulating in new custom configs
// For now, throw up big scary errors on load telling people that they will be banned outright in // For now, throw up big scary errors on load telling people that they will be banned outright in
// a future version // a future version
@Deprecated private final int[] rateUpItems1 = {}; @Deprecated private int[] rateUpItems1 = {};
@Deprecated private final int[] rateUpItems2 = {}; @Deprecated private int[] rateUpItems2 = {};
@Deprecated private final int eventChance = -1; @Deprecated private int eventChance = -1;
@Deprecated private final int costItem = 0; @Deprecated private int costItem = 0;
@Deprecated private final int softPity = -1; @Deprecated private int softPity = -1;
@Deprecated private final int hardPity = -1; @Deprecated private int hardPity = -1;
@Deprecated private final int minItemType = -1; @Deprecated private int minItemType = -1;
@Deprecated private final int maxItemType = -1; @Deprecated private int maxItemType = -1;
@Getter private boolean deprecated = false; @Getter private boolean deprecated = false;
@Getter private final boolean disabled = false; @Getter private boolean disabled = false;
private void warnDeprecated(String name, String replacement) { private void warnDeprecated(String name, String replacement) {
Grasscutter.getLogger() Grasscutter.getLogger()
.error( .error(
"Deprecated field found in Banners config: " "Deprecated field found in Banners config: "
+ name + name
+ " was replaced back in early May 2022, use " + " was replaced back in early May 2022, use "
+ replacement + replacement
+ " instead. You MUST remove this field from your config."); + " instead. You MUST remove this field from your config.");
this.deprecated = true; this.deprecated = true;
} }
public void onLoad() { public void onLoad() {
// Handle deprecated configs // Handle deprecated configs
if (eventChance != -1) warnDeprecated("eventChance", "eventChance4 & eventChance5"); if (eventChance != -1) warnDeprecated("eventChance", "eventChance4 & eventChance5");
if (costItem != 0) warnDeprecated("costItem", "costItemId"); if (costItem != 0) warnDeprecated("costItem", "costItemId");
if (softPity != -1) warnDeprecated("softPity", "weights5"); if (softPity != -1) warnDeprecated("softPity", "weights5");
if (hardPity != -1) warnDeprecated("hardPity", "weights5"); if (hardPity != -1) warnDeprecated("hardPity", "weights5");
if (minItemType != -1) warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]"); if (minItemType != -1) warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]");
if (maxItemType != -1) warnDeprecated("maxItemType", "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 (rateUpItems1.length > 0) warnDeprecated("rateUpItems1", "rateUpItems5");
if (rateUpItems2.length > 0) warnDeprecated("rateUpItems2", "rateUpItems4"); if (rateUpItems2.length > 0) warnDeprecated("rateUpItems2", "rateUpItems4");
// Handle default values // Handle default values
if (this.previewPrefabPath != null if (this.previewPrefabPath != null
&& this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath)) && this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath))
Grasscutter.getLogger() Grasscutter.getLogger()
.error( .error(
"Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\"."); "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()) if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty())
this.previewPrefabPath = "UI_Tab_" + this.prefabPath; this.previewPrefabPath = "UI_Tab_" + this.prefabPath;
if (this.gachaType < 0) this.gachaType = this.bannerType.gachaType; if (this.gachaType < 0) this.gachaType = this.bannerType.gachaType;
if (this.costItemId == 0) this.costItemId = this.bannerType.costItemId; if (this.costItemId == 0) this.costItemId = this.bannerType.costItemId;
if (this.costItemId10 == 0) this.costItemId10 = this.costItemId; if (this.costItemId10 == 0) this.costItemId10 = this.costItemId;
if (this.weights4 == null) this.weights4 = this.bannerType.weights4; if (this.weights4 == null) this.weights4 = this.bannerType.weights4;
if (this.weights5 == null) this.weights5 = this.bannerType.weights5; if (this.weights5 == null) this.weights5 = this.bannerType.weights5;
if (this.eventChance4 < 0) this.eventChance4 = this.bannerType.eventChance4; if (this.eventChance4 < 0) this.eventChance4 = this.bannerType.eventChance4;
if (this.eventChance5 < 0) this.eventChance5 = this.bannerType.eventChance5; if (this.eventChance5 < 0) this.eventChance5 = this.bannerType.eventChance5;
if (this.fallbackItems5Pool1 == null) if (this.fallbackItems5Pool1 == null)
this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1; this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1;
if (this.fallbackItems5Pool2 == null) if (this.fallbackItems5Pool2 == null)
this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2; this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2;
} }
public ItemParamData getCost(int numRolls) { public ItemParamData getCost(int numRolls) {
return switch (numRolls) { return switch (numRolls) {
case 10 -> new ItemParamData(costItemId10, costItemAmount10); case 10 -> new ItemParamData(costItemId10, costItemAmount10);
default -> new ItemParamData(costItemId, costItemAmount * numRolls); default -> new ItemParamData(costItemId, costItemAmount * numRolls);
}; };
} }
@Deprecated @Deprecated
public int getCostItem() { public int getCostItem() {
return costItemId; return costItemId;
} }
public boolean hasEpitomized() { public boolean hasEpitomized() {
return bannerType.equals(BannerType.WEAPON); return bannerType.equals(BannerType.WEAPON);
} }
public int getWeight(int rarity, int pity) { public int getWeight(int rarity, int pity) {
return switch (rarity) { return switch (rarity) {
case 4 -> Utils.lerp(pity, weights4); case 4 -> Utils.lerp(pity, weights4);
default -> Utils.lerp(pity, weights5); default -> Utils.lerp(pity, weights5);
}; };
} }
public int getPoolBalanceWeight(int rarity, int pity) { public int getPoolBalanceWeight(int rarity, int pity) {
return switch (rarity) { return switch (rarity) {
case 4 -> Utils.lerp(pity, poolBalanceWeights4); case 4 -> Utils.lerp(pity, poolBalanceWeights4);
default -> Utils.lerp(pity, poolBalanceWeights5); default -> Utils.lerp(pity, poolBalanceWeights5);
}; };
} }
public int getEventChance(int rarity) { public int getEventChance(int rarity) {
return switch (rarity) { return switch (rarity) {
case 4 -> eventChance4; case 4 -> eventChance4;
default -> eventChance5; default -> eventChance5;
}; };
} }
public GachaInfo toProto(Player player) { public GachaInfo toProto(Player player) {
// TODO: use other Nonce/key insteadof session key to ensure the overall security for the player // TODO: use other Nonce/key insteadof session key to ensure the overall security for the player
String sessionKey = player.getAccount().getSessionKey(); String sessionKey = player.getAccount().getSessionKey();
String record = String record =
"http" "http"
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "") + (HTTP_ENCRYPTION.useInRouting ? "s" : "")
+ "://" + "://"
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
+ ":" + ":"
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
+ "/gacha?s=" + "/gacha?s="
+ sessionKey + sessionKey
+ "&gachaType=" + "&gachaType="
+ gachaType; + gachaType;
String details = String details =
"http" "http"
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "") + (HTTP_ENCRYPTION.useInRouting ? "s" : "")
+ "://" + "://"
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
+ ":" + ":"
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
+ "/gacha/details?s=" + "/gacha/details?s="
+ sessionKey + sessionKey
+ "&scheduleId=" + "&scheduleId="
+ scheduleId; + scheduleId;
// Grasscutter.getLogger().info("record = " + record); // Grasscutter.getLogger().info("record = " + record);
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this); PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
int leftGachaTimes = int leftGachaTimes =
switch (gachaTimesLimit) { switch (gachaTimesLimit) {
case Integer.MAX_VALUE -> Integer.MAX_VALUE; case Integer.MAX_VALUE -> Integer.MAX_VALUE;
default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0); default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0);
}; };
GachaInfo.Builder info = GachaInfo.Builder info =
GachaInfo.newBuilder() GachaInfo.newBuilder()
.setGachaType(this.getGachaType()) .setGachaType(this.getGachaType())
.setScheduleId(this.getScheduleId()) .setScheduleId(this.getScheduleId())
.setBeginTime(this.getBeginTime()) .setBeginTime(this.getBeginTime())
.setEndTime(this.getEndTime()) .setEndTime(this.getEndTime())
.setCostItemId(this.costItemId) .setCostItemId(this.costItemId)
.setCostItemNum(this.costItemAmount) .setCostItemNum(this.costItemAmount)
.setTenCostItemId(this.costItemId10) .setTenCostItemId(this.costItemId10)
.setTenCostItemNum(this.costItemAmount10) .setTenCostItemNum(this.costItemAmount10)
.setGachaPrefabPath(this.getPrefabPath()) .setGachaPrefabPath(this.getPrefabPath())
.setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) .setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
.setGachaProbUrl(details) .setGachaProbUrl(details)
.setGachaProbUrlOversea(details) .setGachaProbUrlOversea(details)
.setGachaRecordUrl(record) .setGachaRecordUrl(record)
.setGachaRecordUrlOversea(record) .setGachaRecordUrlOversea(record)
.setLeftGachaTimes(leftGachaTimes) .setLeftGachaTimes(leftGachaTimes)
.setGachaTimesLimit(gachaTimesLimit) .setGachaTimesLimit(gachaTimesLimit)
.setGachaSortId(this.getSortId()); .setGachaSortId(this.getSortId());
if (hasEpitomized()) { if (hasEpitomized()) {
info.setWishItemId(gachaInfo.getWishItemId()) info.setWishItemId(gachaInfo.getWishItemId())
.setWishProgress(gachaInfo.getFailedChosenItemPulls()) .setWishProgress(gachaInfo.getFailedChosenItemPulls())
.setWishMaxProgress(this.getWishMaxProgress()); .setWishMaxProgress(this.getWishMaxProgress());
} }
if (this.getTitlePath() != null) { if (this.getTitlePath() != null) {
info.setTitleTextmap(this.getTitlePath()); info.setTitleTextmap(this.getTitlePath());
} }
if (this.getRateUpItems5().length > 0) { if (this.getRateUpItems5().length > 0) {
GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1); GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1);
for (int id : getRateUpItems5()) { for (int id : getRateUpItems5()) {
upInfo.addItemIdList(id); upInfo.addItemIdList(id);
info.addDisplayUp5ItemList(id); info.addDisplayUp5ItemList(id);
} }
info.addGachaUpInfoList(upInfo); info.addGachaUpInfoList(upInfo);
} }
if (this.getRateUpItems4().length > 0) { if (this.getRateUpItems4().length > 0) {
GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2); GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2);
for (int id : getRateUpItems4()) { for (int id : getRateUpItems4()) {
upInfo.addItemIdList(id); upInfo.addItemIdList(id);
if (info.getDisplayUp4ItemListCount() == 0) { if (info.getDisplayUp4ItemListCount() == 0) {
info.addDisplayUp4ItemList(id); info.addDisplayUp4ItemList(id);
} }
} }
info.addGachaUpInfoList(upInfo); info.addGachaUpInfoList(upInfo);
} }
return info.build(); return info.build();
} }
public enum BannerType { public enum BannerType {
STANDARD( STANDARD(
200, 200,
224, 224,
DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_4,
DEFAULT_WEIGHTS_5, DEFAULT_WEIGHTS_5,
50, 50,
50, 50,
DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_1,
DEFAULT_FALLBACK_ITEMS_5_POOL_2), DEFAULT_FALLBACK_ITEMS_5_POOL_2),
BEGINNER( BEGINNER(
100, 100,
224, 224,
DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_4,
DEFAULT_WEIGHTS_5, DEFAULT_WEIGHTS_5,
50, 50,
50, 50,
DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_1,
DEFAULT_FALLBACK_ITEMS_5_POOL_2), DEFAULT_FALLBACK_ITEMS_5_POOL_2),
EVENT( EVENT(
301, 301,
223, 223,
DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_4,
DEFAULT_WEIGHTS_5_CHARACTER, DEFAULT_WEIGHTS_5_CHARACTER,
50, 50,
50, 50,
DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_1,
DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER
CHARACTER( CHARACTER(
301, 301,
223, 223,
DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_4,
DEFAULT_WEIGHTS_5_CHARACTER, DEFAULT_WEIGHTS_5_CHARACTER,
50, 50,
50, 50,
DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_1,
EMPTY_POOL), EMPTY_POOL),
CHARACTER2( CHARACTER2(
400, 400,
223, 223,
DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_4,
DEFAULT_WEIGHTS_5_CHARACTER, DEFAULT_WEIGHTS_5_CHARACTER,
50, 50,
50, 50,
DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_1,
EMPTY_POOL), EMPTY_POOL),
WEAPON( WEAPON(
302, 302,
223, 223,
DEFAULT_WEIGHTS_4_WEAPON, DEFAULT_WEIGHTS_4_WEAPON,
DEFAULT_WEIGHTS_5_WEAPON, DEFAULT_WEIGHTS_5_WEAPON,
75, 75,
75, 75,
EMPTY_POOL, EMPTY_POOL,
DEFAULT_FALLBACK_ITEMS_5_POOL_2); DEFAULT_FALLBACK_ITEMS_5_POOL_2);
public final int gachaType; public final int gachaType;
public final int costItemId; public final int costItemId;
public final int[][] weights4; public final int[][] weights4;
public final int[][] weights5; public final int[][] weights5;
public final int eventChance4; public final int eventChance4;
public final int eventChance5; public final int eventChance5;
public final int[] fallbackItems5Pool1; public final int[] fallbackItems5Pool1;
public final int[] fallbackItems5Pool2; public final int[] fallbackItems5Pool2;
BannerType( BannerType(
int gachaType, int gachaType,
int costItemId, int costItemId,
int[][] weights4, int[][] weights4,
int[][] weights5, int[][] weights5,
int eventChance4, int eventChance4,
int eventChance5, int eventChance5,
int[] fallbackItems5Pool1, int[] fallbackItems5Pool1,
int[] fallbackItems5Pool2) { int[] fallbackItems5Pool2) {
this.gachaType = gachaType; this.gachaType = gachaType;
this.costItemId = costItemId; this.costItemId = costItemId;
this.weights4 = weights4; this.weights4 = weights4;
this.weights5 = weights5; this.weights5 = weights5;
this.eventChance4 = eventChance4; this.eventChance4 = eventChance4;
this.eventChance5 = eventChance5; this.eventChance5 = eventChance5;
this.fallbackItems5Pool1 = fallbackItems5Pool1; this.fallbackItems5Pool1 = fallbackItems5Pool1;
this.fallbackItems5Pool2 = fallbackItems5Pool2; this.fallbackItems5Pool2 = fallbackItems5Pool2;
} }
} }
} }

View File

@ -1,62 +1,62 @@
package emu.grasscutter.game.managers.mapmark; package emu.grasscutter.game.managers.mapmark;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import emu.grasscutter.net.proto.MapMarkFromTypeOuterClass.MapMarkFromType; import emu.grasscutter.net.proto.MapMarkFromTypeOuterClass.MapMarkFromType;
import emu.grasscutter.net.proto.MapMarkPointOuterClass.MapMarkPoint; import emu.grasscutter.net.proto.MapMarkPointOuterClass.MapMarkPoint;
import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
@Entity @Entity
public class MapMark { public class MapMark {
private int sceneId; private int sceneId;
private String name; private String name;
private Position position; private Position position;
private final MapMarkPointType mapMarkPointType; private MapMarkPointType mapMarkPointType;
private int monsterId; private int monsterId;
private final MapMarkFromType mapMarkFromType; private MapMarkFromType mapMarkFromType;
private int questId; private int questId;
@Deprecated // Morhpia @Deprecated // Morhpia
public MapMark() { public MapMark() {
this.mapMarkPointType = MapMarkPointType.MAP_MARK_POINT_TYPE_MONSTER; this.mapMarkPointType = MapMarkPointType.MAP_MARK_POINT_TYPE_MONSTER;
this.mapMarkFromType = MapMarkFromType.MAP_MARK_FROM_TYPE_MONSTER; this.mapMarkFromType = MapMarkFromType.MAP_MARK_FROM_TYPE_MONSTER;
} }
public MapMark(MapMarkPoint mapMarkPoint) { public MapMark(MapMarkPoint mapMarkPoint) {
this.sceneId = mapMarkPoint.getSceneId(); this.sceneId = mapMarkPoint.getSceneId();
this.name = mapMarkPoint.getName(); this.name = mapMarkPoint.getName();
this.position = new Position(mapMarkPoint.getPos()); this.position = new Position(mapMarkPoint.getPos());
this.mapMarkPointType = mapMarkPoint.getPointType(); this.mapMarkPointType = mapMarkPoint.getPointType();
this.monsterId = mapMarkPoint.getMonsterId(); this.monsterId = mapMarkPoint.getMonsterId();
this.mapMarkFromType = mapMarkPoint.getFromType(); this.mapMarkFromType = mapMarkPoint.getFromType();
this.questId = mapMarkPoint.getQuestId(); this.questId = mapMarkPoint.getQuestId();
} }
public int getSceneId() { public int getSceneId() {
return this.sceneId; return this.sceneId;
} }
public String getName() { public String getName() {
return this.name; return this.name;
} }
public Position getPosition() { public Position getPosition() {
return this.position; return this.position;
} }
public MapMarkPointType getMapMarkPointType() { public MapMarkPointType getMapMarkPointType() {
return this.mapMarkPointType; return this.mapMarkPointType;
} }
public int getMonsterId() { public int getMonsterId() {
return this.monsterId; return this.monsterId;
} }
public MapMarkFromType getMapMarkFromType() { public MapMarkFromType getMapMarkFromType() {
return this.mapMarkFromType; return this.mapMarkFromType;
} }
public int getQuestId() { public int getQuestId() {
return this.questId; return this.questId;
} }
} }

View File

@ -17,14 +17,14 @@ public class PlayerCodex {
@Transient private Player player; @Transient private Player player;
// itemId is not codexId! // itemId is not codexId!
@Getter private final Set<Integer> unlockedWeapon; @Getter private Set<Integer> unlockedWeapon;
@Getter private final Map<Integer, Integer> unlockedAnimal; @Getter private Map<Integer, Integer> unlockedAnimal;
@Getter private final Set<Integer> unlockedMaterial; @Getter private Set<Integer> unlockedMaterial;
@Getter private final Set<Integer> unlockedBook; @Getter private Set<Integer> unlockedBook;
@Getter private final Set<Integer> unlockedTip; @Getter private Set<Integer> unlockedTip;
@Getter private final Set<Integer> unlockedView; @Getter private Set<Integer> unlockedView;
@Getter private Set<Integer> unlockedReliquary; @Getter private Set<Integer> unlockedReliquary;
@Getter private final Set<Integer> unlockedReliquarySuitCodex; @Getter private Set<Integer> unlockedReliquarySuitCodex;
public PlayerCodex() { public PlayerCodex() {
this.unlockedWeapon = new HashSet<>(); this.unlockedWeapon = new HashSet<>();

View File

@ -11,7 +11,7 @@ import java.util.List;
@Entity @Entity
public final class TeamInfo { public final class TeamInfo {
private String name; private String name;
private final List<Integer> avatars; private List<Integer> avatars;
public TeamInfo() { public TeamInfo() {
this.name = ""; this.name = "";

View File

@ -1,263 +1,263 @@
package emu.grasscutter.game.props; package emu.grasscutter.game.props;
import static java.util.Map.entry; import static java.util.Map.entry;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
import lombok.Getter; import lombok.Getter;
public enum FightProperty { public enum FightProperty {
FIGHT_PROP_NONE(0), FIGHT_PROP_NONE(0),
FIGHT_PROP_BASE_HP(1), FIGHT_PROP_BASE_HP(1),
FIGHT_PROP_HP(2), FIGHT_PROP_HP(2),
FIGHT_PROP_HP_PERCENT(3), FIGHT_PROP_HP_PERCENT(3),
FIGHT_PROP_BASE_ATTACK(4), FIGHT_PROP_BASE_ATTACK(4),
FIGHT_PROP_ATTACK(5), FIGHT_PROP_ATTACK(5),
FIGHT_PROP_ATTACK_PERCENT(6), FIGHT_PROP_ATTACK_PERCENT(6),
FIGHT_PROP_BASE_DEFENSE(7), FIGHT_PROP_BASE_DEFENSE(7),
FIGHT_PROP_DEFENSE(8), FIGHT_PROP_DEFENSE(8),
FIGHT_PROP_DEFENSE_PERCENT(9), FIGHT_PROP_DEFENSE_PERCENT(9),
FIGHT_PROP_BASE_SPEED(10), FIGHT_PROP_BASE_SPEED(10),
FIGHT_PROP_SPEED_PERCENT(11), FIGHT_PROP_SPEED_PERCENT(11),
FIGHT_PROP_HP_MP_PERCENT(12), FIGHT_PROP_HP_MP_PERCENT(12),
FIGHT_PROP_ATTACK_MP_PERCENT(13), FIGHT_PROP_ATTACK_MP_PERCENT(13),
FIGHT_PROP_CRITICAL(20), FIGHT_PROP_CRITICAL(20),
FIGHT_PROP_ANTI_CRITICAL(21), FIGHT_PROP_ANTI_CRITICAL(21),
FIGHT_PROP_CRITICAL_HURT(22), FIGHT_PROP_CRITICAL_HURT(22),
FIGHT_PROP_CHARGE_EFFICIENCY(23), FIGHT_PROP_CHARGE_EFFICIENCY(23),
FIGHT_PROP_ADD_HURT(24), FIGHT_PROP_ADD_HURT(24),
FIGHT_PROP_SUB_HURT(25), FIGHT_PROP_SUB_HURT(25),
FIGHT_PROP_HEAL_ADD(26), FIGHT_PROP_HEAL_ADD(26),
FIGHT_PROP_HEALED_ADD(27), FIGHT_PROP_HEALED_ADD(27),
FIGHT_PROP_ELEMENT_MASTERY(28), FIGHT_PROP_ELEMENT_MASTERY(28),
FIGHT_PROP_PHYSICAL_SUB_HURT(29), FIGHT_PROP_PHYSICAL_SUB_HURT(29),
FIGHT_PROP_PHYSICAL_ADD_HURT(30), FIGHT_PROP_PHYSICAL_ADD_HURT(30),
FIGHT_PROP_DEFENCE_IGNORE_RATIO(31), FIGHT_PROP_DEFENCE_IGNORE_RATIO(31),
FIGHT_PROP_DEFENCE_IGNORE_DELTA(32), FIGHT_PROP_DEFENCE_IGNORE_DELTA(32),
FIGHT_PROP_FIRE_ADD_HURT(40), FIGHT_PROP_FIRE_ADD_HURT(40),
FIGHT_PROP_ELEC_ADD_HURT(41), FIGHT_PROP_ELEC_ADD_HURT(41),
FIGHT_PROP_WATER_ADD_HURT(42), FIGHT_PROP_WATER_ADD_HURT(42),
FIGHT_PROP_GRASS_ADD_HURT(43), FIGHT_PROP_GRASS_ADD_HURT(43),
FIGHT_PROP_WIND_ADD_HURT(44), FIGHT_PROP_WIND_ADD_HURT(44),
FIGHT_PROP_ROCK_ADD_HURT(45), FIGHT_PROP_ROCK_ADD_HURT(45),
FIGHT_PROP_ICE_ADD_HURT(46), FIGHT_PROP_ICE_ADD_HURT(46),
FIGHT_PROP_HIT_HEAD_ADD_HURT(47), FIGHT_PROP_HIT_HEAD_ADD_HURT(47),
FIGHT_PROP_FIRE_SUB_HURT(50), FIGHT_PROP_FIRE_SUB_HURT(50),
FIGHT_PROP_ELEC_SUB_HURT(51), FIGHT_PROP_ELEC_SUB_HURT(51),
FIGHT_PROP_WATER_SUB_HURT(52), FIGHT_PROP_WATER_SUB_HURT(52),
FIGHT_PROP_GRASS_SUB_HURT(53), FIGHT_PROP_GRASS_SUB_HURT(53),
FIGHT_PROP_WIND_SUB_HURT(54), FIGHT_PROP_WIND_SUB_HURT(54),
FIGHT_PROP_ROCK_SUB_HURT(55), FIGHT_PROP_ROCK_SUB_HURT(55),
FIGHT_PROP_ICE_SUB_HURT(56), FIGHT_PROP_ICE_SUB_HURT(56),
FIGHT_PROP_EFFECT_HIT(60), FIGHT_PROP_EFFECT_HIT(60),
FIGHT_PROP_EFFECT_RESIST(61), FIGHT_PROP_EFFECT_RESIST(61),
FIGHT_PROP_FREEZE_RESIST(62), FIGHT_PROP_FREEZE_RESIST(62),
FIGHT_PROP_TORPOR_RESIST(63), FIGHT_PROP_TORPOR_RESIST(63),
FIGHT_PROP_DIZZY_RESIST(64), FIGHT_PROP_DIZZY_RESIST(64),
FIGHT_PROP_FREEZE_SHORTEN(65), FIGHT_PROP_FREEZE_SHORTEN(65),
FIGHT_PROP_TORPOR_SHORTEN(66), FIGHT_PROP_TORPOR_SHORTEN(66),
FIGHT_PROP_DIZZY_SHORTEN(67), FIGHT_PROP_DIZZY_SHORTEN(67),
FIGHT_PROP_MAX_FIRE_ENERGY(70), FIGHT_PROP_MAX_FIRE_ENERGY(70),
FIGHT_PROP_MAX_ELEC_ENERGY(71), FIGHT_PROP_MAX_ELEC_ENERGY(71),
FIGHT_PROP_MAX_WATER_ENERGY(72), FIGHT_PROP_MAX_WATER_ENERGY(72),
FIGHT_PROP_MAX_GRASS_ENERGY(73), FIGHT_PROP_MAX_GRASS_ENERGY(73),
FIGHT_PROP_MAX_WIND_ENERGY(74), FIGHT_PROP_MAX_WIND_ENERGY(74),
FIGHT_PROP_MAX_ICE_ENERGY(75), FIGHT_PROP_MAX_ICE_ENERGY(75),
FIGHT_PROP_MAX_ROCK_ENERGY(76), FIGHT_PROP_MAX_ROCK_ENERGY(76),
FIGHT_PROP_SKILL_CD_MINUS_RATIO(80), FIGHT_PROP_SKILL_CD_MINUS_RATIO(80),
FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81), FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81),
FIGHT_PROP_CUR_FIRE_ENERGY(1000), FIGHT_PROP_CUR_FIRE_ENERGY(1000),
FIGHT_PROP_CUR_ELEC_ENERGY(1001), FIGHT_PROP_CUR_ELEC_ENERGY(1001),
FIGHT_PROP_CUR_WATER_ENERGY(1002), FIGHT_PROP_CUR_WATER_ENERGY(1002),
FIGHT_PROP_CUR_GRASS_ENERGY(1003), FIGHT_PROP_CUR_GRASS_ENERGY(1003),
FIGHT_PROP_CUR_WIND_ENERGY(1004), FIGHT_PROP_CUR_WIND_ENERGY(1004),
FIGHT_PROP_CUR_ICE_ENERGY(1005), FIGHT_PROP_CUR_ICE_ENERGY(1005),
FIGHT_PROP_CUR_ROCK_ENERGY(1006), FIGHT_PROP_CUR_ROCK_ENERGY(1006),
FIGHT_PROP_CUR_HP(1010), FIGHT_PROP_CUR_HP(1010),
FIGHT_PROP_MAX_HP(2000), FIGHT_PROP_MAX_HP(2000),
FIGHT_PROP_CUR_ATTACK(2001), FIGHT_PROP_CUR_ATTACK(2001),
FIGHT_PROP_CUR_DEFENSE(2002), FIGHT_PROP_CUR_DEFENSE(2002),
FIGHT_PROP_CUR_SPEED(2003), FIGHT_PROP_CUR_SPEED(2003),
FIGHT_PROP_NONEXTRA_ATTACK(3000), FIGHT_PROP_NONEXTRA_ATTACK(3000),
FIGHT_PROP_NONEXTRA_DEFENSE(3001), FIGHT_PROP_NONEXTRA_DEFENSE(3001),
FIGHT_PROP_NONEXTRA_CRITICAL(3002), FIGHT_PROP_NONEXTRA_CRITICAL(3002),
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003), FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003),
FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004), FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004),
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005), FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005),
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006), FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006),
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007), FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007),
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008), FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008),
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009), FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009),
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010), FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010),
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011), FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011),
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012), FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012),
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013), FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013),
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014), FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014),
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015), FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015),
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016), FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016),
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017), FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017),
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018), FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018),
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019), FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019),
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020), FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020),
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021), FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021),
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022), FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022),
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023), FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023),
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024); FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024);
public static final int[] fightProps = public static final int[] fightProps =
new int[] { 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, 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 55, 56, 2000, 2001, 2002, 2003, 1010
}; };
private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, FightProperty> stringMap = new HashMap<>(); private static final Map<String, FightProperty> stringMap = new HashMap<>();
// This was originally for relic properties so some names might not be applicable for e.g. // This was originally for relic properties so some names might not be applicable for e.g.
// setstats // setstats
private static final Map<String, FightProperty> shortNameMap = private static final Map<String, FightProperty> shortNameMap =
Map.ofEntries( Map.ofEntries(
// Normal relic stats // Normal relic stats
entry("hp", FIGHT_PROP_HP), entry("hp", FIGHT_PROP_HP),
entry("atk", FIGHT_PROP_ATTACK), entry("atk", FIGHT_PROP_ATTACK),
entry("def", FIGHT_PROP_DEFENSE), entry("def", FIGHT_PROP_DEFENSE),
entry("hp%", FIGHT_PROP_HP_PERCENT), entry("hp%", FIGHT_PROP_HP_PERCENT),
entry("atk%", FIGHT_PROP_ATTACK_PERCENT), entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
entry("def%", FIGHT_PROP_DEFENSE_PERCENT), entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
entry("em", FIGHT_PROP_ELEMENT_MASTERY), entry("em", FIGHT_PROP_ELEMENT_MASTERY),
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY), entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
entry("hb", FIGHT_PROP_HEAL_ADD), entry("hb", FIGHT_PROP_HEAL_ADD),
entry("heal", FIGHT_PROP_HEAL_ADD), entry("heal", FIGHT_PROP_HEAL_ADD),
entry("cd", FIGHT_PROP_CRITICAL_HURT), entry("cd", FIGHT_PROP_CRITICAL_HURT),
entry("cdmg", FIGHT_PROP_CRITICAL_HURT), entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
entry("cr", FIGHT_PROP_CRITICAL), entry("cr", FIGHT_PROP_CRITICAL),
entry("crate", FIGHT_PROP_CRITICAL), entry("crate", FIGHT_PROP_CRITICAL),
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT), entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT), entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT), entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT), entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT), entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT), entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT), entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT), entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
// Other stats // Other stats
entry("maxhp", FIGHT_PROP_MAX_HP), entry("maxhp", FIGHT_PROP_MAX_HP),
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO), entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO),
entry("heali", FIGHT_PROP_HEALED_ADD), entry("heali", FIGHT_PROP_HEALED_ADD),
entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO), entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO),
entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO), entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO),
entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks
entry("resanemo", FIGHT_PROP_WIND_SUB_HURT), entry("resanemo", FIGHT_PROP_WIND_SUB_HURT),
entry("rescryo", FIGHT_PROP_ICE_SUB_HURT), entry("rescryo", FIGHT_PROP_ICE_SUB_HURT),
entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT), entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT),
entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT), entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT),
entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT), entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT),
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT), entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT), entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)); entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT));
private static final List<FightProperty> flatProps = private static final List<FightProperty> flatProps =
Arrays.asList( Arrays.asList(
FIGHT_PROP_BASE_HP, FIGHT_PROP_BASE_HP,
FIGHT_PROP_HP, FIGHT_PROP_HP,
FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_BASE_ATTACK,
FIGHT_PROP_ATTACK, FIGHT_PROP_ATTACK,
FIGHT_PROP_BASE_DEFENSE, FIGHT_PROP_BASE_DEFENSE,
FIGHT_PROP_DEFENSE, FIGHT_PROP_DEFENSE,
FIGHT_PROP_HEALED_ADD, FIGHT_PROP_HEALED_ADD,
FIGHT_PROP_CUR_FIRE_ENERGY, FIGHT_PROP_CUR_FIRE_ENERGY,
FIGHT_PROP_CUR_ELEC_ENERGY, FIGHT_PROP_CUR_ELEC_ENERGY,
FIGHT_PROP_CUR_WATER_ENERGY, FIGHT_PROP_CUR_WATER_ENERGY,
FIGHT_PROP_CUR_GRASS_ENERGY, FIGHT_PROP_CUR_GRASS_ENERGY,
FIGHT_PROP_CUR_WIND_ENERGY, FIGHT_PROP_CUR_WIND_ENERGY,
FIGHT_PROP_CUR_ICE_ENERGY, FIGHT_PROP_CUR_ICE_ENERGY,
FIGHT_PROP_CUR_ROCK_ENERGY, FIGHT_PROP_CUR_ROCK_ENERGY,
FIGHT_PROP_CUR_HP, FIGHT_PROP_CUR_HP,
FIGHT_PROP_MAX_HP, FIGHT_PROP_MAX_HP,
FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_ATTACK,
FIGHT_PROP_CUR_DEFENSE); FIGHT_PROP_CUR_DEFENSE);
private static final Map<FightProperty, CompoundProperty> compoundProperties = private static final Map<FightProperty, CompoundProperty> compoundProperties =
Map.ofEntries( Map.ofEntries(
entry( entry(
FIGHT_PROP_MAX_HP, FIGHT_PROP_MAX_HP,
new CompoundProperty( new CompoundProperty(
FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)), FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)),
entry( entry(
FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_ATTACK,
new CompoundProperty( new CompoundProperty(
FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_ATTACK,
FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_BASE_ATTACK,
FIGHT_PROP_ATTACK_PERCENT, FIGHT_PROP_ATTACK_PERCENT,
FIGHT_PROP_ATTACK)), FIGHT_PROP_ATTACK)),
entry( entry(
FIGHT_PROP_CUR_DEFENSE, FIGHT_PROP_CUR_DEFENSE,
new CompoundProperty( new CompoundProperty(
FIGHT_PROP_CUR_DEFENSE, FIGHT_PROP_CUR_DEFENSE,
FIGHT_PROP_BASE_DEFENSE, FIGHT_PROP_BASE_DEFENSE,
FIGHT_PROP_DEFENSE_PERCENT, FIGHT_PROP_DEFENSE_PERCENT,
FIGHT_PROP_DEFENSE))); FIGHT_PROP_DEFENSE)));
static { static {
Stream.of(values()) Stream.of(values())
.forEach( .forEach(
e -> { e -> {
map.put(e.getId(), e); map.put(e.getId(), e);
stringMap.put(e.name(), e); stringMap.put(e.name(), e);
}); });
} }
private final int id; private final int id;
FightProperty(int id) { FightProperty(int id) {
this.id = id; this.id = id;
} }
public static FightProperty getPropById(int value) { public static FightProperty getPropById(int value) {
return map.getOrDefault(value, FIGHT_PROP_NONE); return map.getOrDefault(value, FIGHT_PROP_NONE);
} }
public static FightProperty getPropByName(String name) { public static FightProperty getPropByName(String name) {
return stringMap.getOrDefault(name, FIGHT_PROP_NONE); return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
} }
public static FightProperty getPropByShortName(String name) { public static FightProperty getPropByShortName(String name) {
return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE); return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE);
} }
public static Set<String> getShortNames() { public static Set<String> getShortNames() {
return shortNameMap.keySet(); return shortNameMap.keySet();
} }
public static CompoundProperty getCompoundProperty(FightProperty result) { public static CompoundProperty getCompoundProperty(FightProperty result) {
return compoundProperties.get(result); return compoundProperties.get(result);
} }
public static void forEachCompoundProperty(Consumer<CompoundProperty> consumer) { public static void forEachCompoundProperty(Consumer<CompoundProperty> consumer) {
compoundProperties.values().forEach(consumer); compoundProperties.values().forEach(consumer);
} }
public static boolean isPercentage(FightProperty prop) { public static boolean isPercentage(FightProperty prop) {
return !flatProps.contains(prop); return !flatProps.contains(prop);
} }
public int getId() { public int getId() {
return id; return id;
} }
@Getter @Getter
public static class CompoundProperty { public static class CompoundProperty {
private final FightProperty result; private final FightProperty result;
private final FightProperty base; private final FightProperty base;
private final FightProperty percent; private final FightProperty percent;
private final FightProperty flat; private final FightProperty flat;
public CompoundProperty( public CompoundProperty(
FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) { FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) {
this.result = result; this.result = result;
this.base = base; this.base = base;
this.percent = percent; this.percent = percent;
this.flat = flat; this.flat = flat;
} }
} }
} }

View File

@ -1,22 +1,22 @@
package emu.grasscutter.game.props.ItemUseAction; package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
public class ItemUseAddCurHp extends ItemUseInt { public class ItemUseAddCurHp extends ItemUseInt {
private final String icon; private final String icon;
public ItemUseAddCurHp(String[] useParam) { public ItemUseAddCurHp(String[] useParam) {
super(useParam); super(useParam);
this.icon = useParam[1]; this.icon = useParam[1];
} }
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_ADD_CUR_HP; return ItemUseOp.ITEM_USE_ADD_CUR_HP;
} }
@Override @Override
public boolean useItem(UseItemParams params) { public boolean useItem(UseItemParams params) {
return (params.targetAvatar.getAsEntity().heal(params.count * this.i) > 0.01); return (params.targetAvatar.getAsEntity().heal(params.count * this.i) > 0.01);
} }
} }

View File

@ -1,38 +1,38 @@
package emu.grasscutter.game.props.ItemUseAction; package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
public class ItemUseChestSelectItem extends ItemUseSelectItems { public class ItemUseChestSelectItem extends ItemUseSelectItems {
private final int[] optionItemCounts; private final int[] optionItemCounts;
public ItemUseChestSelectItem(String[] useParam) { public ItemUseChestSelectItem(String[] useParam) {
String[] options = useParam[0].split(","); String[] options = useParam[0].split(",");
this.optionItemIds = new int[options.length]; this.optionItemIds = new int[options.length];
this.optionItemCounts = new int[options.length]; this.optionItemCounts = new int[options.length];
for (int i = 0; i < options.length; i++) { for (int i = 0; i < options.length; i++) {
String[] optionParts = options[i].split(":"); String[] optionParts = options[i].split(":");
try { try {
this.optionItemIds[i] = Integer.parseInt(optionParts[0]); this.optionItemIds[i] = Integer.parseInt(optionParts[0]);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
this.optionItemIds[i] = INVALID; this.optionItemIds[i] = INVALID;
} }
try { try {
this.optionItemCounts[i] = Integer.parseInt(optionParts[1]); this.optionItemCounts[i] = Integer.parseInt(optionParts[1]);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
this.optionItemCounts[i] = INVALID; this.optionItemCounts[i] = INVALID;
} }
} }
} }
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_CHEST_SELECT_ITEM; return ItemUseOp.ITEM_USE_CHEST_SELECT_ITEM;
} }
@Override @Override
protected int getItemCount(int index) { protected int getItemCount(int index) {
if ((optionItemCounts == null) || (index < 0) || (index > optionItemCounts.length)) if ((optionItemCounts == null) || (index < 0) || (index > optionItemCounts.length))
return INVALID; return INVALID;
return this.optionItemCounts[index]; return this.optionItemCounts[index];
} }
} }

View File

@ -1,97 +1,97 @@
package emu.grasscutter.game.world; package emu.grasscutter.game.world;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class SpawnDataEntry { public class SpawnDataEntry {
@Getter @Setter private transient SpawnGroupEntry group; @Getter @Setter private transient SpawnGroupEntry group;
@Getter private int monsterId; @Getter private int monsterId;
@Getter private int gadgetId; @Getter private int gadgetId;
@Getter private int configId; @Getter private int configId;
@Getter private int level; @Getter private int level;
@Getter private int poseId; @Getter private int poseId;
@Getter private int gatherItemId; @Getter private int gatherItemId;
@Getter private int gadgetState; @Getter private int gadgetState;
@Getter private Position pos; @Getter private Position pos;
@Getter private Position rot; @Getter private Position rot;
public GridBlockId getBlockId() { public GridBlockId getBlockId() {
int scale = GridBlockId.getScale(gadgetId); int scale = GridBlockId.getScale(gadgetId);
return new GridBlockId( return new GridBlockId(
group.sceneId, group.sceneId,
scale, scale,
(int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]), (int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]),
(int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale])); (int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale]));
} }
public static class SpawnGroupEntry { public static class SpawnGroupEntry {
@Getter private int sceneId; @Getter private int sceneId;
@Getter private int groupId; @Getter private int groupId;
@Getter private int blockId; @Getter private int blockId;
@Getter @Setter private List<SpawnDataEntry> spawns; @Getter @Setter private List<SpawnDataEntry> spawns;
} }
public static class GridBlockId { public static class GridBlockId {
@Getter private final int sceneId; @Getter private int sceneId;
@Getter private final int scale; @Getter private int scale;
@Getter private final int x; @Getter private int x;
@Getter private final int z; @Getter private int z;
public GridBlockId(int sceneId, int scale, int x, int z) { public GridBlockId(int sceneId, int scale, int x, int z) {
this.sceneId = sceneId; this.sceneId = sceneId;
this.scale = scale; this.scale = scale;
this.x = x; this.x = x;
this.z = z; this.z = z;
} }
public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) { public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) {
GridBlockId[] results = new GridBlockId[5 * 5 * GameDepot.BLOCK_SIZE.length]; GridBlockId[] results = new GridBlockId[5 * 5 * GameDepot.BLOCK_SIZE.length];
int t = 0; int t = 0;
for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) { for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) {
int x = ((int) (pos.getX() / GameDepot.BLOCK_SIZE[scale])); int x = ((int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]));
int z = ((int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale])); int z = ((int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale]));
for (int i = x - 2; i < x + 3; i++) { for (int i = x - 2; i < x + 3; i++) {
for (int j = z - 2; j < z + 3; j++) { for (int j = z - 2; j < z + 3; j++) {
results[t++] = new GridBlockId(sceneId, scale, i, j); results[t++] = new GridBlockId(sceneId, scale, i, j);
} }
} }
} }
return results; return results;
} }
public static int getScale(int gadgetId) { public static int getScale(int gadgetId) {
return 0; // you should implement here,this is index of GameDepot.BLOCK_SIZE return 0; // you should implement here,this is index of GameDepot.BLOCK_SIZE
} }
@Override @Override
public String toString() { public String toString() {
return "SpawnDataEntryScaledPoint{" return "SpawnDataEntryScaledPoint{"
+ "sceneId=" + "sceneId="
+ sceneId + sceneId
+ ", scale=" + ", scale="
+ scale + scale
+ ", x=" + ", x="
+ x + x
+ ", z=" + ", z="
+ z + z
+ '}'; + '}';
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
GridBlockId that = (GridBlockId) o; GridBlockId that = (GridBlockId) o;
return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z; return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(sceneId, scale, x, z); return Objects.hash(sceneId, scale, x, z);
} }
} }
} }

View File

@ -37,12 +37,12 @@ public class World implements Iterable<Player> {
@Getter private final List<Player> players; @Getter private final List<Player> players;
@Getter private final Int2ObjectMap<Scene> scenes; @Getter private final Int2ObjectMap<Scene> scenes;
@Getter private final int levelEntityId; @Getter private int levelEntityId;
private int nextEntityId = 0; private int nextEntityId = 0;
private int nextPeerId = 0; private int nextPeerId = 0;
private int worldLevel; private int worldLevel;
private final boolean isMultiplayer; private boolean isMultiplayer;
private long lastUpdateTime; private long lastUpdateTime;
@Getter private int tickCount = 0; @Getter private int tickCount = 0;

View File

@ -36,10 +36,10 @@ public class ScriptLoader {
@Getter private static ScriptLib scriptLib; @Getter private static ScriptLib scriptLib;
@Getter private static LuaValue scriptLibLua; @Getter private static LuaValue scriptLibLua;
/** suggest GC to remove it if the memory is less */ /** suggest GC to remove it if the memory is less */
private static final Map<String, SoftReference<CompiledScript>> scriptsCache = private static Map<String, SoftReference<CompiledScript>> scriptsCache =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
/** sceneId - SceneMeta */ /** sceneId - SceneMeta */
private static final Map<Integer, SoftReference<SceneMeta>> sceneMetaCache = private static Map<Integer, SoftReference<SceneMeta>> sceneMetaCache =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
public static synchronized void init() throws Exception { public static synchronized void init() throws Exception {

View File

@ -1,26 +1,26 @@
package emu.grasscutter.server.http.documentation; package emu.grasscutter.server.http.documentation;
import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE; import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE;
import emu.grasscutter.tools.Tools; import emu.grasscutter.tools.Tools;
import emu.grasscutter.utils.Language; import emu.grasscutter.utils.Language;
import io.javalin.http.ContentType; import io.javalin.http.ContentType;
import io.javalin.http.Context; import io.javalin.http.Context;
import java.util.List; import java.util.List;
final class GachaMappingRequestHandler implements DocumentationHandler { final class GachaMappingRequestHandler implements DocumentationHandler {
private final List<String> gachaJsons; private final List<String> gachaJsons;
GachaMappingRequestHandler() { GachaMappingRequestHandler() {
this.gachaJsons = Tools.createGachaMappingJsons(); this.gachaJsons = Tools.createGachaMappingJsons();
} }
@Override @Override
public void handle(Context ctx) { public void handle(Context ctx) {
final int langIdx = final int langIdx =
Language.TextStrings.MAP_LANGUAGES.getOrDefault( Language.TextStrings.MAP_LANGUAGES.getOrDefault(
DOCUMENT_LANGUAGE, DOCUMENT_LANGUAGE,
0); // TODO: This should really be based off the client language somehow 0); // TODO: This should really be based off the client language somehow
ctx.contentType(ContentType.APPLICATION_JSON).result(gachaJsons.get(langIdx)); ctx.contentType(ContentType.APPLICATION_JSON).result(gachaJsons.get(langIdx));
} }
} }

View File

@ -1,48 +1,48 @@
package emu.grasscutter.server.packet.send; package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo;
import emu.grasscutter.net.proto.PrivateChatNotifyOuterClass.PrivateChatNotify; import emu.grasscutter.net.proto.PrivateChatNotifyOuterClass.PrivateChatNotify;
public class PacketPrivateChatNotify extends BasePacket { public class PacketPrivateChatNotify extends BasePacket {
private final ChatInfo info; private final ChatInfo info;
public PacketPrivateChatNotify(int senderId, int recvId, String message) { public PacketPrivateChatNotify(int senderId, int recvId, String message) {
super(PacketOpcodes.PrivateChatNotify); super(PacketOpcodes.PrivateChatNotify);
ChatInfo info = ChatInfo info =
ChatInfo.newBuilder() ChatInfo.newBuilder()
.setTime((int) (System.currentTimeMillis() / 1000)) .setTime((int) (System.currentTimeMillis() / 1000))
.setUid(senderId) .setUid(senderId)
.setToUid(recvId) .setToUid(recvId)
.setText(message) .setText(message)
.build(); .build();
this.info = info; this.info = info;
PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build(); PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build();
this.setData(proto); this.setData(proto);
} }
public PacketPrivateChatNotify(int senderId, int recvId, int emote) { public PacketPrivateChatNotify(int senderId, int recvId, int emote) {
super(PacketOpcodes.PrivateChatNotify); super(PacketOpcodes.PrivateChatNotify);
ChatInfo info = ChatInfo info =
ChatInfo.newBuilder() ChatInfo.newBuilder()
.setTime((int) (System.currentTimeMillis() / 1000)) .setTime((int) (System.currentTimeMillis() / 1000))
.setUid(senderId) .setUid(senderId)
.setToUid(recvId) .setToUid(recvId)
.setIcon(emote) .setIcon(emote)
.build(); .build();
this.info = info; this.info = info;
PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build(); PrivateChatNotify proto = PrivateChatNotify.newBuilder().setChatInfo(info).build();
this.setData(proto); this.setData(proto);
} }
public ChatInfo getChatInfo() { public ChatInfo getChatInfo() {
return this.info; return this.info;
} }
} }

View File

@ -57,7 +57,7 @@ public class TsvUtils {
private static final Function<String, Object> parseLong = private static final Function<String, Object> parseLong =
value -> (long) Double.parseDouble(value); // Long::parseLong; value -> (long) Double.parseDouble(value); // Long::parseLong;
private static final Map<Class<?>, Function<String, Object>> enumTypeParsers = new HashMap<>(); private static final Map<Class<?>, Function<String, Object>> enumTypeParsers = new HashMap<>();
private static final Map<Type, Function<String, Object>> primitiveTypeParsers = private final static Map<Type, Function<String, Object>> primitiveTypeParsers =
Map.ofEntries( Map.ofEntries(
Map.entry(String.class, parseString), Map.entry(String.class, parseString),
Map.entry(Integer.class, parseInt), Map.entry(Integer.class, parseInt),
@ -72,7 +72,7 @@ public class TsvUtils {
Map.entry(boolean.class, Boolean::parseBoolean)); Map.entry(boolean.class, Boolean::parseBoolean));
private static final Map<Type, Function<String, Object>> typeParsers = private static final Map<Type, Function<String, Object>> typeParsers =
new HashMap<>(primitiveTypeParsers); new HashMap<>(primitiveTypeParsers);
private static final Map<Class<?>, Map<String, FieldParser>> cachedClassFieldMaps = private final static Map<Class<?>, Map<String, FieldParser>> cachedClassFieldMaps =
new HashMap<>(); new HashMap<>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")