mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2026-03-25 17:12:49 +01:00
Revert final's added by 15e2f3ca34 (#2144)
* Revert final's added by 15e2f3ca34
* Apply suggestions from code review
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
* Apply suggestions from code review
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
---------
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
This commit is contained in:
@@ -26,7 +26,7 @@ public class Account {
|
||||
|
||||
private String token;
|
||||
private String sessionKey; // Session token for dispatch server
|
||||
private final List<String> permissions;
|
||||
private List<String> permissions;
|
||||
private Locale locale;
|
||||
|
||||
private String banReason;
|
||||
|
||||
@@ -1,214 +1,214 @@
|
||||
package emu.grasscutter.game.ability;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HealAbilityManager {
|
||||
ArrayList<HealDataAvatar> healDataAvatarList;
|
||||
private final Player player;
|
||||
|
||||
public HealAbilityManager(Player player) {
|
||||
this.player = player;
|
||||
healDataAvatarList = new ArrayList();
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000054, "Kokomi", 0)
|
||||
.addHealData(
|
||||
"E",
|
||||
"ElementalArt_Heal_MaxHP_Base_Percentage",
|
||||
"ElementalArt_Heal_Base_Amount",
|
||||
false)
|
||||
.addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000034, "Noel", 2)
|
||||
.addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000032, "Bennett", 0)
|
||||
.addHealData("Q", "HealMaxHpRatio", "HealConst", false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000039, "Diona", 0)
|
||||
.addHealData("Q", "HealHPRatio", "HealHP_Const", false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000053, "Sayu", 1)
|
||||
.addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true)
|
||||
.addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000014, "Barbara", 0)
|
||||
.addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true)
|
||||
.addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true)
|
||||
.addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000065, "Shinobu", 0)
|
||||
.addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000035, "Qiqi", 1)
|
||||
.addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true)
|
||||
.addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true)
|
||||
.addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000046, "Hutao", 0)
|
||||
.addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false));
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void healHandler(AbilityInvokeEntry invoke) throws Exception {
|
||||
AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData());
|
||||
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
|
||||
|
||||
String modifierString = "";
|
||||
if (data.getParentAbilityName() != null) modifierString = data.getParentAbilityName().getStr();
|
||||
|
||||
if (sourceEntity != null) checkAndHeal(sourceEntity, modifierString);
|
||||
}
|
||||
|
||||
public void checkAndHeal(GameEntity sourceEntity, String modifierString) {
|
||||
int fightPropertyType = 0;
|
||||
float healAmount = 0;
|
||||
float ratio = 0, base = 0;
|
||||
float maxHP, curHP, curAttack, curDefense;
|
||||
Map<String, Float> map = sourceEntity.getMetaOverrideMap();
|
||||
|
||||
for (int i = 0; i < healDataAvatarList.size(); i++) {
|
||||
HealDataAvatar healDataAvatar = healDataAvatarList.get(i);
|
||||
if (modifierString.contains(healDataAvatar.avatarName)) {
|
||||
fightPropertyType = healDataAvatar.fightPropertyType;
|
||||
ArrayList<HealData> healDataList = healDataAvatar.healDataList;
|
||||
|
||||
for (int j = 0; j < healDataList.size(); j++) {
|
||||
HealData healData = healDataList.get(j);
|
||||
if (map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) {
|
||||
if (healData.isString) {
|
||||
ratio = map.get(healData.sRatio);
|
||||
base = map.get(healData.sBase);
|
||||
} else {
|
||||
ratio = healData.fRatio;
|
||||
base = healData.fBase;
|
||||
}
|
||||
}
|
||||
|
||||
List<EntityAvatar> activeTeam = player.getTeamManager().getActiveTeam();
|
||||
List<EntityAvatar> needHealAvatars = new ArrayList();
|
||||
int currentIndex = player.getTeamManager().getCurrentCharacterIndex();
|
||||
EntityAvatar currentAvatar = activeTeam.get(currentIndex);
|
||||
if (healData.healAll) {
|
||||
needHealAvatars = activeTeam;
|
||||
} else {
|
||||
needHealAvatars.add(currentAvatar);
|
||||
}
|
||||
|
||||
EntityAvatar healActionAvatar = null;
|
||||
for (int k = 0; k < activeTeam.size(); k++) {
|
||||
EntityAvatar avatar = activeTeam.get(k);
|
||||
int avatarId = avatar.getAvatar().getAvatarId();
|
||||
if (avatarId == healDataAvatar.avatarId) {
|
||||
healActionAvatar = avatar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (healActionAvatar != null) {
|
||||
maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK);
|
||||
curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE);
|
||||
|
||||
// Special case for Hu Tao:
|
||||
if (healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) {
|
||||
ratio = 0.1555f;
|
||||
}
|
||||
|
||||
switch (fightPropertyType) {
|
||||
case 0:
|
||||
healAmount = ratio * maxHP + base;
|
||||
break;
|
||||
case 1:
|
||||
healAmount = ratio * curAttack + base;
|
||||
break;
|
||||
case 2:
|
||||
healAmount = ratio * curDefense + base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < needHealAvatars.size(); k++) {
|
||||
EntityAvatar avatar = needHealAvatars.get(k);
|
||||
avatar.heal(healAmount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HealData {
|
||||
public boolean isString = true;
|
||||
public String abilityType = ""; // "E" or "Q"
|
||||
public String sRatio = "";
|
||||
public String sBase = "";
|
||||
public float fRatio = 0;
|
||||
public float fBase = 0;
|
||||
public boolean healAll = false;
|
||||
|
||||
public HealData(String _abilityType, String _sRatio, String _sBase, boolean _healAll) {
|
||||
abilityType = _abilityType;
|
||||
isString = true;
|
||||
sRatio = _sRatio;
|
||||
sBase = _sBase;
|
||||
healAll = _healAll;
|
||||
}
|
||||
|
||||
public HealData(
|
||||
String _abilityType, String _sRatio, float _fRatio, float _fBase, boolean _healAll) {
|
||||
abilityType = _abilityType;
|
||||
isString = false;
|
||||
sRatio = _sRatio;
|
||||
fRatio = _fRatio;
|
||||
fBase = _fBase;
|
||||
healAll = _healAll;
|
||||
}
|
||||
}
|
||||
|
||||
private class HealDataAvatar {
|
||||
public int avatarId = 0;
|
||||
public String avatarName = "";
|
||||
public int fightPropertyType = 0; // 0: maxHP, 1: curAttack, 2: curDefense
|
||||
public ArrayList<HealData> healDataList;
|
||||
|
||||
public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) {
|
||||
avatarId = _avatarId;
|
||||
avatarName = _avatarName;
|
||||
fightPropertyType = _fightPropertyType;
|
||||
healDataList = new ArrayList();
|
||||
}
|
||||
|
||||
public HealDataAvatar addHealData(
|
||||
String abilityType, String sRatio, String sBase, boolean healAll) {
|
||||
HealData healData = new HealData(abilityType, sRatio, sBase, healAll);
|
||||
healDataList.add(healData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HealDataAvatar addHealData(
|
||||
String abilityType, String sRatio, float fRatio, float fBase, boolean healAll) {
|
||||
HealData healData = new HealData(abilityType, sRatio, fRatio, fBase, healAll);
|
||||
healDataList.add(healData);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.ability;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HealAbilityManager {
|
||||
ArrayList<HealDataAvatar> healDataAvatarList;
|
||||
private Player player;
|
||||
|
||||
public HealAbilityManager(Player player) {
|
||||
this.player = player;
|
||||
healDataAvatarList = new ArrayList();
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000054, "Kokomi", 0)
|
||||
.addHealData(
|
||||
"E",
|
||||
"ElementalArt_Heal_MaxHP_Base_Percentage",
|
||||
"ElementalArt_Heal_Base_Amount",
|
||||
false)
|
||||
.addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000034, "Noel", 2)
|
||||
.addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000032, "Bennett", 0)
|
||||
.addHealData("Q", "HealMaxHpRatio", "HealConst", false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000039, "Diona", 0)
|
||||
.addHealData("Q", "HealHPRatio", "HealHP_Const", false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000053, "Sayu", 1)
|
||||
.addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true)
|
||||
.addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000014, "Barbara", 0)
|
||||
.addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true)
|
||||
.addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true)
|
||||
.addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000065, "Shinobu", 0)
|
||||
.addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000035, "Qiqi", 1)
|
||||
.addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true)
|
||||
.addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true)
|
||||
.addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false));
|
||||
healDataAvatarList.add(
|
||||
new HealDataAvatar(10000046, "Hutao", 0)
|
||||
.addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false));
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void healHandler(AbilityInvokeEntry invoke) throws Exception {
|
||||
AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData());
|
||||
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
|
||||
|
||||
String modifierString = "";
|
||||
if (data.getParentAbilityName() != null) modifierString = data.getParentAbilityName().getStr();
|
||||
|
||||
if (sourceEntity != null) checkAndHeal(sourceEntity, modifierString);
|
||||
}
|
||||
|
||||
public void checkAndHeal(GameEntity sourceEntity, String modifierString) {
|
||||
int fightPropertyType = 0;
|
||||
float healAmount = 0;
|
||||
float ratio = 0, base = 0;
|
||||
float maxHP, curHP, curAttack, curDefense;
|
||||
Map<String, Float> map = sourceEntity.getMetaOverrideMap();
|
||||
|
||||
for (int i = 0; i < healDataAvatarList.size(); i++) {
|
||||
HealDataAvatar healDataAvatar = healDataAvatarList.get(i);
|
||||
if (modifierString.contains(healDataAvatar.avatarName)) {
|
||||
fightPropertyType = healDataAvatar.fightPropertyType;
|
||||
ArrayList<HealData> healDataList = healDataAvatar.healDataList;
|
||||
|
||||
for (int j = 0; j < healDataList.size(); j++) {
|
||||
HealData healData = healDataList.get(j);
|
||||
if (map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) {
|
||||
if (healData.isString) {
|
||||
ratio = map.get(healData.sRatio);
|
||||
base = map.get(healData.sBase);
|
||||
} else {
|
||||
ratio = healData.fRatio;
|
||||
base = healData.fBase;
|
||||
}
|
||||
}
|
||||
|
||||
List<EntityAvatar> activeTeam = player.getTeamManager().getActiveTeam();
|
||||
List<EntityAvatar> needHealAvatars = new ArrayList();
|
||||
int currentIndex = player.getTeamManager().getCurrentCharacterIndex();
|
||||
EntityAvatar currentAvatar = activeTeam.get(currentIndex);
|
||||
if (healData.healAll) {
|
||||
needHealAvatars = activeTeam;
|
||||
} else {
|
||||
needHealAvatars.add(currentAvatar);
|
||||
}
|
||||
|
||||
EntityAvatar healActionAvatar = null;
|
||||
for (int k = 0; k < activeTeam.size(); k++) {
|
||||
EntityAvatar avatar = activeTeam.get(k);
|
||||
int avatarId = avatar.getAvatar().getAvatarId();
|
||||
if (avatarId == healDataAvatar.avatarId) {
|
||||
healActionAvatar = avatar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (healActionAvatar != null) {
|
||||
maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK);
|
||||
curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE);
|
||||
|
||||
// Special case for Hu Tao:
|
||||
if (healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) {
|
||||
ratio = 0.1555f;
|
||||
}
|
||||
|
||||
switch (fightPropertyType) {
|
||||
case 0:
|
||||
healAmount = ratio * maxHP + base;
|
||||
break;
|
||||
case 1:
|
||||
healAmount = ratio * curAttack + base;
|
||||
break;
|
||||
case 2:
|
||||
healAmount = ratio * curDefense + base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < needHealAvatars.size(); k++) {
|
||||
EntityAvatar avatar = needHealAvatars.get(k);
|
||||
avatar.heal(healAmount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HealData {
|
||||
public boolean isString = true;
|
||||
public String abilityType = ""; // "E" or "Q"
|
||||
public String sRatio = "";
|
||||
public String sBase = "";
|
||||
public float fRatio = 0;
|
||||
public float fBase = 0;
|
||||
public boolean healAll = false;
|
||||
|
||||
public HealData(String _abilityType, String _sRatio, String _sBase, boolean _healAll) {
|
||||
abilityType = _abilityType;
|
||||
isString = true;
|
||||
sRatio = _sRatio;
|
||||
sBase = _sBase;
|
||||
healAll = _healAll;
|
||||
}
|
||||
|
||||
public HealData(
|
||||
String _abilityType, String _sRatio, float _fRatio, float _fBase, boolean _healAll) {
|
||||
abilityType = _abilityType;
|
||||
isString = false;
|
||||
sRatio = _sRatio;
|
||||
fRatio = _fRatio;
|
||||
fBase = _fBase;
|
||||
healAll = _healAll;
|
||||
}
|
||||
}
|
||||
|
||||
private class HealDataAvatar {
|
||||
public int avatarId = 0;
|
||||
public String avatarName = "";
|
||||
public int fightPropertyType = 0; // 0: maxHP, 1: curAttack, 2: curDefense
|
||||
public ArrayList<HealData> healDataList;
|
||||
|
||||
public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) {
|
||||
avatarId = _avatarId;
|
||||
avatarName = _avatarName;
|
||||
fightPropertyType = _fightPropertyType;
|
||||
healDataList = new ArrayList();
|
||||
}
|
||||
|
||||
public HealDataAvatar addHealData(
|
||||
String abilityType, String sRatio, String sBase, boolean healAll) {
|
||||
HealData healData = new HealData(abilityType, sRatio, sBase, healAll);
|
||||
healDataList.add(healData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HealDataAvatar addHealData(
|
||||
String abilityType, String sRatio, float fRatio, float fBase, boolean healAll) {
|
||||
HealData healData = new HealData(abilityType, sRatio, fRatio, fBase, healAll);
|
||||
healDataList.add(healData);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
package emu.grasscutter.game.achievement;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.net.proto.AchievementOuterClass;
|
||||
import emu.grasscutter.net.proto.StatusOuterClass;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
public class Achievement {
|
||||
@Setter private StatusOuterClass.Status status;
|
||||
private final int id;
|
||||
private final int totalProgress;
|
||||
@Setter private int curProgress;
|
||||
@Setter private int finishTimestampSec;
|
||||
|
||||
public Achievement(
|
||||
StatusOuterClass.Status status,
|
||||
int id,
|
||||
int totalProgress,
|
||||
int curProgress,
|
||||
int finishTimestampSec) {
|
||||
this.status = status;
|
||||
this.id = id;
|
||||
this.totalProgress = totalProgress;
|
||||
this.curProgress = curProgress;
|
||||
this.finishTimestampSec = finishTimestampSec;
|
||||
}
|
||||
|
||||
public AchievementOuterClass.Achievement toProto() {
|
||||
return AchievementOuterClass.Achievement.newBuilder()
|
||||
.setStatus(this.getStatus())
|
||||
.setId(this.getId())
|
||||
.setTotalProgress(this.getTotalProgress())
|
||||
.setCurProgress(this.getCurProgress())
|
||||
.setFinishTimestamp(this.getFinishTimestampSec())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.achievement;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.net.proto.AchievementOuterClass;
|
||||
import emu.grasscutter.net.proto.StatusOuterClass;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
public class Achievement {
|
||||
@Setter private StatusOuterClass.Status status;
|
||||
private int id;
|
||||
private int totalProgress;
|
||||
@Setter private int curProgress;
|
||||
@Setter private int finishTimestampSec;
|
||||
|
||||
public Achievement(
|
||||
StatusOuterClass.Status status,
|
||||
int id,
|
||||
int totalProgress,
|
||||
int curProgress,
|
||||
int finishTimestampSec) {
|
||||
this.status = status;
|
||||
this.id = id;
|
||||
this.totalProgress = totalProgress;
|
||||
this.curProgress = curProgress;
|
||||
this.finishTimestampSec = finishTimestampSec;
|
||||
}
|
||||
|
||||
public AchievementOuterClass.Achievement toProto() {
|
||||
return AchievementOuterClass.Achievement.newBuilder()
|
||||
.setStatus(this.getStatus())
|
||||
.setId(this.getId())
|
||||
.setTotalProgress(this.getTotalProgress())
|
||||
.setCurProgress(this.getCurProgress())
|
||||
.setFinishTimestamp(this.getFinishTimestampSec())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,13 +74,13 @@ public class Avatar {
|
||||
|
||||
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
|
||||
private final Map<Integer, Integer> skillExtraChargeMap = new Int2IntArrayMap(2); // Charges
|
||||
private Map<Integer, Integer> skillExtraChargeMap = new Int2IntArrayMap(2); // Charges
|
||||
|
||||
@Transient
|
||||
private final Map<Integer, Integer> proudSkillBonusMap =
|
||||
private Map<Integer, Integer> proudSkillBonusMap =
|
||||
new Int2IntArrayMap(2); // Talent bonus levels (from const)
|
||||
|
||||
@Getter private int skillDepotId;
|
||||
|
||||
@@ -1,122 +1,122 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public class EntityClientGadget extends EntityBaseGadget {
|
||||
@Getter private final Player owner;
|
||||
|
||||
@Getter(onMethod_ = @Override)
|
||||
private final int gadgetId;
|
||||
|
||||
@Getter private final int campId;
|
||||
@Getter private final int campType;
|
||||
@Getter private final int ownerEntityId;
|
||||
@Getter private final int targetEntityId;
|
||||
@Getter private final boolean asyncLoad;
|
||||
|
||||
@Getter private final int originalOwnerEntityId;
|
||||
|
||||
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
|
||||
super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles()));
|
||||
this.owner = player;
|
||||
this.id = notify.getEntityId();
|
||||
this.gadgetId = notify.getConfigId();
|
||||
this.campId = notify.getCampId();
|
||||
this.campType = notify.getCampType();
|
||||
this.ownerEntityId = notify.getPropOwnerEntityId();
|
||||
this.targetEntityId = notify.getTargetEntityId();
|
||||
this.asyncLoad = notify.getIsAsyncLoad();
|
||||
|
||||
GameEntity owner = scene.getEntityById(this.ownerEntityId);
|
||||
if (owner instanceof EntityClientGadget ownerGadget) {
|
||||
this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId();
|
||||
} else {
|
||||
this.originalOwnerEntityId = this.ownerEntityId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatMap getFightProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority =
|
||||
EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(
|
||||
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo =
|
||||
SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(
|
||||
MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
.setRot(getRotation().toProto())
|
||||
.setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair =
|
||||
PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget =
|
||||
ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder()
|
||||
.setCampId(this.getCampId())
|
||||
.setCampType(this.getCampType())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setTargetEntityId(this.getTargetEntityId())
|
||||
.setAsyncLoad(this.isAsyncLoad())
|
||||
.build();
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo =
|
||||
SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setIsEnableInteract(true)
|
||||
.setClientGadget(clientGadget)
|
||||
.setPropOwnerEntityId(this.getOwnerEntityId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId());
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public class EntityClientGadget extends EntityBaseGadget {
|
||||
@Getter private final Player owner;
|
||||
|
||||
@Getter(onMethod_ = @Override)
|
||||
private int gadgetId;
|
||||
|
||||
@Getter private int campId;
|
||||
@Getter private int campType;
|
||||
@Getter private int ownerEntityId;
|
||||
@Getter private int targetEntityId;
|
||||
@Getter private boolean asyncLoad;
|
||||
|
||||
@Getter private int originalOwnerEntityId;
|
||||
|
||||
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
|
||||
super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles()));
|
||||
this.owner = player;
|
||||
this.id = notify.getEntityId();
|
||||
this.gadgetId = notify.getConfigId();
|
||||
this.campId = notify.getCampId();
|
||||
this.campType = notify.getCampType();
|
||||
this.ownerEntityId = notify.getPropOwnerEntityId();
|
||||
this.targetEntityId = notify.getTargetEntityId();
|
||||
this.asyncLoad = notify.getIsAsyncLoad();
|
||||
|
||||
GameEntity owner = scene.getEntityById(this.ownerEntityId);
|
||||
if (owner instanceof EntityClientGadget ownerGadget) {
|
||||
this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId();
|
||||
} else {
|
||||
this.originalOwnerEntityId = this.ownerEntityId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatMap getFightProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority =
|
||||
EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(
|
||||
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo =
|
||||
SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(
|
||||
MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
.setRot(getRotation().toProto())
|
||||
.setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair =
|
||||
PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget =
|
||||
ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder()
|
||||
.setCampId(this.getCampId())
|
||||
.setCampType(this.getCampType())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setTargetEntityId(this.getTargetEntityId())
|
||||
.setAsyncLoad(this.isAsyncLoad())
|
||||
.build();
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo =
|
||||
SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setIsEnableInteract(true)
|
||||
.setClientGadget(clientGadget)
|
||||
.setPropOwnerEntityId(this.getOwnerEntityId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId());
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
|
||||
|
||||
@Getter @Setter private SceneGadget metaGadget;
|
||||
@Nullable @Getter private ConfigEntityGadget configGadget;
|
||||
@Nullable @Getter ConfigEntityGadget configGadget;
|
||||
@Getter @Setter private BaseRoute routeConfig;
|
||||
|
||||
@Getter @Setter private int stopValue = 0; // Controller related, inited to zero
|
||||
|
||||
@@ -42,7 +42,7 @@ public class EntityVehicle extends EntityBaseGadget {
|
||||
@Getter private final int gadgetId;
|
||||
|
||||
@Getter @Setter private float curStamina;
|
||||
@Getter private final List<VehicleMember> vehicleMembers;
|
||||
@Getter private List<VehicleMember> vehicleMembers;
|
||||
@Nullable @Getter private ConfigEntityGadget configGadget;
|
||||
|
||||
public EntityVehicle(
|
||||
|
||||
@@ -1,352 +1,352 @@
|
||||
package emu.grasscutter.game.gacha;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
||||
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import lombok.Getter;
|
||||
|
||||
public class GachaBanner {
|
||||
// Constants used by the BannerType enum
|
||||
static final int[][] DEFAULT_WEIGHTS_4 = {{1, 510}, {8, 510}, {10, 10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5 = {{1, 75}, {73, 150}, {90, 10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5_CHARACTER = {{1, 80}, {73, 80}, {90, 10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5_WEAPON = {{1, 100}, {62, 100}, {73, 7800}, {80, 10000}};
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_1 = {
|
||||
1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053,
|
||||
1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072
|
||||
}; // Default avatars
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = {
|
||||
11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403,
|
||||
14409, 15401, 15402, 15403, 15405
|
||||
}; // Default weapons
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = {
|
||||
1003, 1016, 1042, 1035, 1041, 1069
|
||||
}; // Default avatars
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = {
|
||||
11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502
|
||||
}; // Default weapons
|
||||
static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback
|
||||
@Getter int scheduleId = -1;
|
||||
@Getter int sortId = -1;
|
||||
@Getter private int gachaType = -1;
|
||||
@Getter private String prefabPath;
|
||||
@Getter private String previewPrefabPath;
|
||||
@Getter private String titlePath;
|
||||
private int costItemId = 0;
|
||||
private final int costItemAmount = 1;
|
||||
private int costItemId10 = 0;
|
||||
private final int costItemAmount10 = 10;
|
||||
@Getter private final int beginTime = 0;
|
||||
@Getter private final int endTime = 1924992000;
|
||||
@Getter private final int gachaTimesLimit = Integer.MAX_VALUE;
|
||||
@Getter private final int[] rateUpItems4 = {};
|
||||
@Getter private final int[] rateUpItems5 = {};
|
||||
// This now handles default values for the fields below
|
||||
@Getter private final BannerType bannerType = BannerType.STANDARD;
|
||||
// These don't change between banner types (apart from Standard having three extra 4star avatars)
|
||||
@Getter
|
||||
private final int[] fallbackItems3 = {
|
||||
11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304
|
||||
};
|
||||
|
||||
@Getter private final int[] fallbackItems4Pool1 = DEFAULT_FALLBACK_ITEMS_4_POOL_1;
|
||||
@Getter private final int[] fallbackItems4Pool2 = DEFAULT_FALLBACK_ITEMS_4_POOL_2;
|
||||
// Different banner types have different defaults, see above for default values and the enum for
|
||||
// which are used where.
|
||||
@Getter private int[] fallbackItems5Pool1;
|
||||
@Getter private int[] fallbackItems5Pool2;
|
||||
private int[][] weights4;
|
||||
private int[][] weights5;
|
||||
private int eventChance4 = -1; // Chance to win a featured event item
|
||||
private int eventChance5 = -1; // Chance to win a featured event item
|
||||
//
|
||||
@Getter private final boolean removeC6FromPool = false;
|
||||
|
||||
@Getter
|
||||
private final boolean autoStripRateUpFromFallback =
|
||||
true; // Ensures that featured items won't "double dip" into the losing pool
|
||||
|
||||
private final int[][] poolBalanceWeights4 = {
|
||||
{1, 255}, {17, 255}, {21, 10455}
|
||||
}; // Used to ensure that players won't go too many rolls without getting something from pool 1
|
||||
// (avatar) or pool 2 (weapon)
|
||||
private final int[][] poolBalanceWeights5 = {{1, 30}, {147, 150}, {181, 10230}};
|
||||
@Getter private final int wishMaxProgress = 2;
|
||||
|
||||
// Deprecated fields that were tolerated in early May 2022 but have apparently still being
|
||||
// circulating in new custom configs
|
||||
// For now, throw up big scary errors on load telling people that they will be banned outright in
|
||||
// a future version
|
||||
@Deprecated private final int[] rateUpItems1 = {};
|
||||
@Deprecated private final int[] rateUpItems2 = {};
|
||||
@Deprecated private final int eventChance = -1;
|
||||
@Deprecated private final int costItem = 0;
|
||||
@Deprecated private final int softPity = -1;
|
||||
@Deprecated private final int hardPity = -1;
|
||||
@Deprecated private final int minItemType = -1;
|
||||
@Deprecated private final int maxItemType = -1;
|
||||
@Getter private boolean deprecated = false;
|
||||
@Getter private final boolean disabled = false;
|
||||
|
||||
private void warnDeprecated(String name, String replacement) {
|
||||
Grasscutter.getLogger()
|
||||
.error(
|
||||
"Deprecated field found in Banners config: "
|
||||
+ name
|
||||
+ " was replaced back in early May 2022, use "
|
||||
+ replacement
|
||||
+ " instead. You MUST remove this field from your config.");
|
||||
this.deprecated = true;
|
||||
}
|
||||
|
||||
public void onLoad() {
|
||||
// Handle deprecated configs
|
||||
if (eventChance != -1) warnDeprecated("eventChance", "eventChance4 & eventChance5");
|
||||
if (costItem != 0) warnDeprecated("costItem", "costItemId");
|
||||
if (softPity != -1) warnDeprecated("softPity", "weights5");
|
||||
if (hardPity != -1) warnDeprecated("hardPity", "weights5");
|
||||
if (minItemType != -1) warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]");
|
||||
if (maxItemType != -1) warnDeprecated("maxItemType", "fallbackItems[4,5]Pool[1,2]");
|
||||
if (rateUpItems1.length > 0) warnDeprecated("rateUpItems1", "rateUpItems5");
|
||||
if (rateUpItems2.length > 0) warnDeprecated("rateUpItems2", "rateUpItems4");
|
||||
|
||||
// Handle default values
|
||||
if (this.previewPrefabPath != null
|
||||
&& this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath))
|
||||
Grasscutter.getLogger()
|
||||
.error(
|
||||
"Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\".");
|
||||
if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty())
|
||||
this.previewPrefabPath = "UI_Tab_" + this.prefabPath;
|
||||
if (this.gachaType < 0) this.gachaType = this.bannerType.gachaType;
|
||||
if (this.costItemId == 0) this.costItemId = this.bannerType.costItemId;
|
||||
if (this.costItemId10 == 0) this.costItemId10 = this.costItemId;
|
||||
if (this.weights4 == null) this.weights4 = this.bannerType.weights4;
|
||||
if (this.weights5 == null) this.weights5 = this.bannerType.weights5;
|
||||
if (this.eventChance4 < 0) this.eventChance4 = this.bannerType.eventChance4;
|
||||
if (this.eventChance5 < 0) this.eventChance5 = this.bannerType.eventChance5;
|
||||
if (this.fallbackItems5Pool1 == null)
|
||||
this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1;
|
||||
if (this.fallbackItems5Pool2 == null)
|
||||
this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2;
|
||||
}
|
||||
|
||||
public ItemParamData getCost(int numRolls) {
|
||||
return switch (numRolls) {
|
||||
case 10 -> new ItemParamData(costItemId10, costItemAmount10);
|
||||
default -> new ItemParamData(costItemId, costItemAmount * numRolls);
|
||||
};
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getCostItem() {
|
||||
return costItemId;
|
||||
}
|
||||
|
||||
public boolean hasEpitomized() {
|
||||
return bannerType.equals(BannerType.WEAPON);
|
||||
}
|
||||
|
||||
public int getWeight(int rarity, int pity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> Utils.lerp(pity, weights4);
|
||||
default -> Utils.lerp(pity, weights5);
|
||||
};
|
||||
}
|
||||
|
||||
public int getPoolBalanceWeight(int rarity, int pity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> Utils.lerp(pity, poolBalanceWeights4);
|
||||
default -> Utils.lerp(pity, poolBalanceWeights5);
|
||||
};
|
||||
}
|
||||
|
||||
public int getEventChance(int rarity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> eventChance4;
|
||||
default -> eventChance5;
|
||||
};
|
||||
}
|
||||
|
||||
public GachaInfo toProto(Player player) {
|
||||
// TODO: use other Nonce/key insteadof session key to ensure the overall security for the player
|
||||
String sessionKey = player.getAccount().getSessionKey();
|
||||
|
||||
String record =
|
||||
"http"
|
||||
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "")
|
||||
+ "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
|
||||
+ ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
|
||||
+ "/gacha?s="
|
||||
+ sessionKey
|
||||
+ "&gachaType="
|
||||
+ gachaType;
|
||||
String details =
|
||||
"http"
|
||||
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "")
|
||||
+ "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
|
||||
+ ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
|
||||
+ "/gacha/details?s="
|
||||
+ sessionKey
|
||||
+ "&scheduleId="
|
||||
+ scheduleId;
|
||||
|
||||
// Grasscutter.getLogger().info("record = " + record);
|
||||
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
|
||||
int leftGachaTimes =
|
||||
switch (gachaTimesLimit) {
|
||||
case Integer.MAX_VALUE -> Integer.MAX_VALUE;
|
||||
default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0);
|
||||
};
|
||||
GachaInfo.Builder info =
|
||||
GachaInfo.newBuilder()
|
||||
.setGachaType(this.getGachaType())
|
||||
.setScheduleId(this.getScheduleId())
|
||||
.setBeginTime(this.getBeginTime())
|
||||
.setEndTime(this.getEndTime())
|
||||
.setCostItemId(this.costItemId)
|
||||
.setCostItemNum(this.costItemAmount)
|
||||
.setTenCostItemId(this.costItemId10)
|
||||
.setTenCostItemNum(this.costItemAmount10)
|
||||
.setGachaPrefabPath(this.getPrefabPath())
|
||||
.setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
|
||||
.setGachaProbUrl(details)
|
||||
.setGachaProbUrlOversea(details)
|
||||
.setGachaRecordUrl(record)
|
||||
.setGachaRecordUrlOversea(record)
|
||||
.setLeftGachaTimes(leftGachaTimes)
|
||||
.setGachaTimesLimit(gachaTimesLimit)
|
||||
.setGachaSortId(this.getSortId());
|
||||
|
||||
if (hasEpitomized()) {
|
||||
info.setWishItemId(gachaInfo.getWishItemId())
|
||||
.setWishProgress(gachaInfo.getFailedChosenItemPulls())
|
||||
.setWishMaxProgress(this.getWishMaxProgress());
|
||||
}
|
||||
|
||||
if (this.getTitlePath() != null) {
|
||||
info.setTitleTextmap(this.getTitlePath());
|
||||
}
|
||||
|
||||
if (this.getRateUpItems5().length > 0) {
|
||||
GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1);
|
||||
|
||||
for (int id : getRateUpItems5()) {
|
||||
upInfo.addItemIdList(id);
|
||||
info.addDisplayUp5ItemList(id);
|
||||
}
|
||||
|
||||
info.addGachaUpInfoList(upInfo);
|
||||
}
|
||||
|
||||
if (this.getRateUpItems4().length > 0) {
|
||||
GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2);
|
||||
|
||||
for (int id : getRateUpItems4()) {
|
||||
upInfo.addItemIdList(id);
|
||||
if (info.getDisplayUp4ItemListCount() == 0) {
|
||||
info.addDisplayUp4ItemList(id);
|
||||
}
|
||||
}
|
||||
|
||||
info.addGachaUpInfoList(upInfo);
|
||||
}
|
||||
|
||||
return info.build();
|
||||
}
|
||||
|
||||
public enum BannerType {
|
||||
STANDARD(
|
||||
200,
|
||||
224,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2),
|
||||
BEGINNER(
|
||||
100,
|
||||
224,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2),
|
||||
EVENT(
|
||||
301,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5_CHARACTER,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER
|
||||
CHARACTER(
|
||||
301,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5_CHARACTER,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
EMPTY_POOL),
|
||||
CHARACTER2(
|
||||
400,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5_CHARACTER,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
EMPTY_POOL),
|
||||
WEAPON(
|
||||
302,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4_WEAPON,
|
||||
DEFAULT_WEIGHTS_5_WEAPON,
|
||||
75,
|
||||
75,
|
||||
EMPTY_POOL,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2);
|
||||
|
||||
public final int gachaType;
|
||||
public final int costItemId;
|
||||
public final int[][] weights4;
|
||||
public final int[][] weights5;
|
||||
public final int eventChance4;
|
||||
public final int eventChance5;
|
||||
public final int[] fallbackItems5Pool1;
|
||||
public final int[] fallbackItems5Pool2;
|
||||
|
||||
BannerType(
|
||||
int gachaType,
|
||||
int costItemId,
|
||||
int[][] weights4,
|
||||
int[][] weights5,
|
||||
int eventChance4,
|
||||
int eventChance5,
|
||||
int[] fallbackItems5Pool1,
|
||||
int[] fallbackItems5Pool2) {
|
||||
this.gachaType = gachaType;
|
||||
this.costItemId = costItemId;
|
||||
this.weights4 = weights4;
|
||||
this.weights5 = weights5;
|
||||
this.eventChance4 = eventChance4;
|
||||
this.eventChance5 = eventChance5;
|
||||
this.fallbackItems5Pool1 = fallbackItems5Pool1;
|
||||
this.fallbackItems5Pool2 = fallbackItems5Pool2;
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.gacha;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
||||
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import lombok.Getter;
|
||||
|
||||
public class GachaBanner {
|
||||
// Constants used by the BannerType enum
|
||||
static final int[][] DEFAULT_WEIGHTS_4 = {{1, 510}, {8, 510}, {10, 10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5 = {{1, 75}, {73, 150}, {90, 10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5_CHARACTER = {{1, 80}, {73, 80}, {90, 10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5_WEAPON = {{1, 100}, {62, 100}, {73, 7800}, {80, 10000}};
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_1 = {
|
||||
1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053,
|
||||
1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072
|
||||
}; // Default avatars
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = {
|
||||
11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403,
|
||||
14409, 15401, 15402, 15403, 15405
|
||||
}; // Default weapons
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = {
|
||||
1003, 1016, 1042, 1035, 1041, 1069
|
||||
}; // Default avatars
|
||||
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = {
|
||||
11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502
|
||||
}; // Default weapons
|
||||
static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback
|
||||
@Getter int scheduleId = -1;
|
||||
@Getter int sortId = -1;
|
||||
@Getter private int gachaType = -1;
|
||||
@Getter private String prefabPath;
|
||||
@Getter private String previewPrefabPath;
|
||||
@Getter private String titlePath;
|
||||
private int costItemId = 0;
|
||||
private int costItemAmount = 1;
|
||||
private int costItemId10 = 0;
|
||||
private int costItemAmount10 = 10;
|
||||
@Getter private int beginTime = 0;
|
||||
@Getter private int endTime = 1924992000;
|
||||
@Getter private int gachaTimesLimit = Integer.MAX_VALUE;
|
||||
@Getter private int[] rateUpItems4 = {};
|
||||
@Getter private int[] rateUpItems5 = {};
|
||||
// This now handles default values for the fields below
|
||||
@Getter private BannerType bannerType = BannerType.STANDARD;
|
||||
// These don't change between banner types (apart from Standard having three extra 4star avatars)
|
||||
@Getter
|
||||
private int[] fallbackItems3 = {
|
||||
11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304
|
||||
};
|
||||
|
||||
@Getter private int[] fallbackItems4Pool1 = DEFAULT_FALLBACK_ITEMS_4_POOL_1;
|
||||
@Getter private int[] fallbackItems4Pool2 = DEFAULT_FALLBACK_ITEMS_4_POOL_2;
|
||||
// Different banner types have different defaults, see above for default values and the enum for
|
||||
// which are used where.
|
||||
@Getter private int[] fallbackItems5Pool1;
|
||||
@Getter private int[] fallbackItems5Pool2;
|
||||
private int[][] weights4;
|
||||
private int[][] weights5;
|
||||
private int eventChance4 = -1; // Chance to win a featured event item
|
||||
private int eventChance5 = -1; // Chance to win a featured event item
|
||||
//
|
||||
@Getter private boolean removeC6FromPool = false;
|
||||
|
||||
@Getter
|
||||
private boolean autoStripRateUpFromFallback =
|
||||
true; // Ensures that featured items won't "double dip" into the losing pool
|
||||
|
||||
private int[][] poolBalanceWeights4 = {
|
||||
{1, 255}, {17, 255}, {21, 10455}
|
||||
}; // Used to ensure that players won't go too many rolls without getting something from pool 1
|
||||
// (avatar) or pool 2 (weapon)
|
||||
private int[][] poolBalanceWeights5 = {{1, 30}, {147, 150}, {181, 10230}};
|
||||
@Getter private int wishMaxProgress = 2;
|
||||
|
||||
// Deprecated fields that were tolerated in early May 2022 but have apparently still being
|
||||
// circulating in new custom configs
|
||||
// For now, throw up big scary errors on load telling people that they will be banned outright in
|
||||
// a future version
|
||||
@Deprecated private int[] rateUpItems1 = {};
|
||||
@Deprecated private int[] rateUpItems2 = {};
|
||||
@Deprecated private int eventChance = -1;
|
||||
@Deprecated private int costItem = 0;
|
||||
@Deprecated private int softPity = -1;
|
||||
@Deprecated private int hardPity = -1;
|
||||
@Deprecated private int minItemType = -1;
|
||||
@Deprecated private int maxItemType = -1;
|
||||
@Getter private boolean deprecated = false;
|
||||
@Getter private boolean disabled = false;
|
||||
|
||||
private void warnDeprecated(String name, String replacement) {
|
||||
Grasscutter.getLogger()
|
||||
.error(
|
||||
"Deprecated field found in Banners config: "
|
||||
+ name
|
||||
+ " was replaced back in early May 2022, use "
|
||||
+ replacement
|
||||
+ " instead. You MUST remove this field from your config.");
|
||||
this.deprecated = true;
|
||||
}
|
||||
|
||||
public void onLoad() {
|
||||
// Handle deprecated configs
|
||||
if (eventChance != -1) warnDeprecated("eventChance", "eventChance4 & eventChance5");
|
||||
if (costItem != 0) warnDeprecated("costItem", "costItemId");
|
||||
if (softPity != -1) warnDeprecated("softPity", "weights5");
|
||||
if (hardPity != -1) warnDeprecated("hardPity", "weights5");
|
||||
if (minItemType != -1) warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]");
|
||||
if (maxItemType != -1) warnDeprecated("maxItemType", "fallbackItems[4,5]Pool[1,2]");
|
||||
if (rateUpItems1.length > 0) warnDeprecated("rateUpItems1", "rateUpItems5");
|
||||
if (rateUpItems2.length > 0) warnDeprecated("rateUpItems2", "rateUpItems4");
|
||||
|
||||
// Handle default values
|
||||
if (this.previewPrefabPath != null
|
||||
&& this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath))
|
||||
Grasscutter.getLogger()
|
||||
.error(
|
||||
"Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\".");
|
||||
if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty())
|
||||
this.previewPrefabPath = "UI_Tab_" + this.prefabPath;
|
||||
if (this.gachaType < 0) this.gachaType = this.bannerType.gachaType;
|
||||
if (this.costItemId == 0) this.costItemId = this.bannerType.costItemId;
|
||||
if (this.costItemId10 == 0) this.costItemId10 = this.costItemId;
|
||||
if (this.weights4 == null) this.weights4 = this.bannerType.weights4;
|
||||
if (this.weights5 == null) this.weights5 = this.bannerType.weights5;
|
||||
if (this.eventChance4 < 0) this.eventChance4 = this.bannerType.eventChance4;
|
||||
if (this.eventChance5 < 0) this.eventChance5 = this.bannerType.eventChance5;
|
||||
if (this.fallbackItems5Pool1 == null)
|
||||
this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1;
|
||||
if (this.fallbackItems5Pool2 == null)
|
||||
this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2;
|
||||
}
|
||||
|
||||
public ItemParamData getCost(int numRolls) {
|
||||
return switch (numRolls) {
|
||||
case 10 -> new ItemParamData(costItemId10, costItemAmount10);
|
||||
default -> new ItemParamData(costItemId, costItemAmount * numRolls);
|
||||
};
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getCostItem() {
|
||||
return costItemId;
|
||||
}
|
||||
|
||||
public boolean hasEpitomized() {
|
||||
return bannerType.equals(BannerType.WEAPON);
|
||||
}
|
||||
|
||||
public int getWeight(int rarity, int pity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> Utils.lerp(pity, weights4);
|
||||
default -> Utils.lerp(pity, weights5);
|
||||
};
|
||||
}
|
||||
|
||||
public int getPoolBalanceWeight(int rarity, int pity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> Utils.lerp(pity, poolBalanceWeights4);
|
||||
default -> Utils.lerp(pity, poolBalanceWeights5);
|
||||
};
|
||||
}
|
||||
|
||||
public int getEventChance(int rarity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> eventChance4;
|
||||
default -> eventChance5;
|
||||
};
|
||||
}
|
||||
|
||||
public GachaInfo toProto(Player player) {
|
||||
// TODO: use other Nonce/key insteadof session key to ensure the overall security for the player
|
||||
String sessionKey = player.getAccount().getSessionKey();
|
||||
|
||||
String record =
|
||||
"http"
|
||||
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "")
|
||||
+ "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
|
||||
+ ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
|
||||
+ "/gacha?s="
|
||||
+ sessionKey
|
||||
+ "&gachaType="
|
||||
+ gachaType;
|
||||
String details =
|
||||
"http"
|
||||
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "")
|
||||
+ "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
|
||||
+ ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
|
||||
+ "/gacha/details?s="
|
||||
+ sessionKey
|
||||
+ "&scheduleId="
|
||||
+ scheduleId;
|
||||
|
||||
// Grasscutter.getLogger().info("record = " + record);
|
||||
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
|
||||
int leftGachaTimes =
|
||||
switch (gachaTimesLimit) {
|
||||
case Integer.MAX_VALUE -> Integer.MAX_VALUE;
|
||||
default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0);
|
||||
};
|
||||
GachaInfo.Builder info =
|
||||
GachaInfo.newBuilder()
|
||||
.setGachaType(this.getGachaType())
|
||||
.setScheduleId(this.getScheduleId())
|
||||
.setBeginTime(this.getBeginTime())
|
||||
.setEndTime(this.getEndTime())
|
||||
.setCostItemId(this.costItemId)
|
||||
.setCostItemNum(this.costItemAmount)
|
||||
.setTenCostItemId(this.costItemId10)
|
||||
.setTenCostItemNum(this.costItemAmount10)
|
||||
.setGachaPrefabPath(this.getPrefabPath())
|
||||
.setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
|
||||
.setGachaProbUrl(details)
|
||||
.setGachaProbUrlOversea(details)
|
||||
.setGachaRecordUrl(record)
|
||||
.setGachaRecordUrlOversea(record)
|
||||
.setLeftGachaTimes(leftGachaTimes)
|
||||
.setGachaTimesLimit(gachaTimesLimit)
|
||||
.setGachaSortId(this.getSortId());
|
||||
|
||||
if (hasEpitomized()) {
|
||||
info.setWishItemId(gachaInfo.getWishItemId())
|
||||
.setWishProgress(gachaInfo.getFailedChosenItemPulls())
|
||||
.setWishMaxProgress(this.getWishMaxProgress());
|
||||
}
|
||||
|
||||
if (this.getTitlePath() != null) {
|
||||
info.setTitleTextmap(this.getTitlePath());
|
||||
}
|
||||
|
||||
if (this.getRateUpItems5().length > 0) {
|
||||
GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1);
|
||||
|
||||
for (int id : getRateUpItems5()) {
|
||||
upInfo.addItemIdList(id);
|
||||
info.addDisplayUp5ItemList(id);
|
||||
}
|
||||
|
||||
info.addGachaUpInfoList(upInfo);
|
||||
}
|
||||
|
||||
if (this.getRateUpItems4().length > 0) {
|
||||
GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2);
|
||||
|
||||
for (int id : getRateUpItems4()) {
|
||||
upInfo.addItemIdList(id);
|
||||
if (info.getDisplayUp4ItemListCount() == 0) {
|
||||
info.addDisplayUp4ItemList(id);
|
||||
}
|
||||
}
|
||||
|
||||
info.addGachaUpInfoList(upInfo);
|
||||
}
|
||||
|
||||
return info.build();
|
||||
}
|
||||
|
||||
public enum BannerType {
|
||||
STANDARD(
|
||||
200,
|
||||
224,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2),
|
||||
BEGINNER(
|
||||
100,
|
||||
224,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2),
|
||||
EVENT(
|
||||
301,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5_CHARACTER,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER
|
||||
CHARACTER(
|
||||
301,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5_CHARACTER,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
EMPTY_POOL),
|
||||
CHARACTER2(
|
||||
400,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4,
|
||||
DEFAULT_WEIGHTS_5_CHARACTER,
|
||||
50,
|
||||
50,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_1,
|
||||
EMPTY_POOL),
|
||||
WEAPON(
|
||||
302,
|
||||
223,
|
||||
DEFAULT_WEIGHTS_4_WEAPON,
|
||||
DEFAULT_WEIGHTS_5_WEAPON,
|
||||
75,
|
||||
75,
|
||||
EMPTY_POOL,
|
||||
DEFAULT_FALLBACK_ITEMS_5_POOL_2);
|
||||
|
||||
public final int gachaType;
|
||||
public final int costItemId;
|
||||
public final int[][] weights4;
|
||||
public final int[][] weights5;
|
||||
public final int eventChance4;
|
||||
public final int eventChance5;
|
||||
public final int[] fallbackItems5Pool1;
|
||||
public final int[] fallbackItems5Pool2;
|
||||
|
||||
BannerType(
|
||||
int gachaType,
|
||||
int costItemId,
|
||||
int[][] weights4,
|
||||
int[][] weights5,
|
||||
int eventChance4,
|
||||
int eventChance5,
|
||||
int[] fallbackItems5Pool1,
|
||||
int[] fallbackItems5Pool2) {
|
||||
this.gachaType = gachaType;
|
||||
this.costItemId = costItemId;
|
||||
this.weights4 = weights4;
|
||||
this.weights5 = weights5;
|
||||
this.eventChance4 = eventChance4;
|
||||
this.eventChance5 = eventChance5;
|
||||
this.fallbackItems5Pool1 = fallbackItems5Pool1;
|
||||
this.fallbackItems5Pool2 = fallbackItems5Pool2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
package emu.grasscutter.game.managers.mapmark;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.net.proto.MapMarkFromTypeOuterClass.MapMarkFromType;
|
||||
import emu.grasscutter.net.proto.MapMarkPointOuterClass.MapMarkPoint;
|
||||
import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
@Entity
|
||||
public class MapMark {
|
||||
private int sceneId;
|
||||
private String name;
|
||||
private Position position;
|
||||
private final MapMarkPointType mapMarkPointType;
|
||||
private int monsterId;
|
||||
private final MapMarkFromType mapMarkFromType;
|
||||
private int questId;
|
||||
|
||||
@Deprecated // Morhpia
|
||||
public MapMark() {
|
||||
this.mapMarkPointType = MapMarkPointType.MAP_MARK_POINT_TYPE_MONSTER;
|
||||
this.mapMarkFromType = MapMarkFromType.MAP_MARK_FROM_TYPE_MONSTER;
|
||||
}
|
||||
|
||||
public MapMark(MapMarkPoint mapMarkPoint) {
|
||||
this.sceneId = mapMarkPoint.getSceneId();
|
||||
this.name = mapMarkPoint.getName();
|
||||
this.position = new Position(mapMarkPoint.getPos());
|
||||
this.mapMarkPointType = mapMarkPoint.getPointType();
|
||||
this.monsterId = mapMarkPoint.getMonsterId();
|
||||
this.mapMarkFromType = mapMarkPoint.getFromType();
|
||||
this.questId = mapMarkPoint.getQuestId();
|
||||
}
|
||||
|
||||
public int getSceneId() {
|
||||
return this.sceneId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public MapMarkPointType getMapMarkPointType() {
|
||||
return this.mapMarkPointType;
|
||||
}
|
||||
|
||||
public int getMonsterId() {
|
||||
return this.monsterId;
|
||||
}
|
||||
|
||||
public MapMarkFromType getMapMarkFromType() {
|
||||
return this.mapMarkFromType;
|
||||
}
|
||||
|
||||
public int getQuestId() {
|
||||
return this.questId;
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.managers.mapmark;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.net.proto.MapMarkFromTypeOuterClass.MapMarkFromType;
|
||||
import emu.grasscutter.net.proto.MapMarkPointOuterClass.MapMarkPoint;
|
||||
import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
@Entity
|
||||
public class MapMark {
|
||||
private int sceneId;
|
||||
private String name;
|
||||
private Position position;
|
||||
private MapMarkPointType mapMarkPointType;
|
||||
private int monsterId;
|
||||
private MapMarkFromType mapMarkFromType;
|
||||
private int questId;
|
||||
|
||||
@Deprecated // Morhpia
|
||||
public MapMark() {
|
||||
this.mapMarkPointType = MapMarkPointType.MAP_MARK_POINT_TYPE_MONSTER;
|
||||
this.mapMarkFromType = MapMarkFromType.MAP_MARK_FROM_TYPE_MONSTER;
|
||||
}
|
||||
|
||||
public MapMark(MapMarkPoint mapMarkPoint) {
|
||||
this.sceneId = mapMarkPoint.getSceneId();
|
||||
this.name = mapMarkPoint.getName();
|
||||
this.position = new Position(mapMarkPoint.getPos());
|
||||
this.mapMarkPointType = mapMarkPoint.getPointType();
|
||||
this.monsterId = mapMarkPoint.getMonsterId();
|
||||
this.mapMarkFromType = mapMarkPoint.getFromType();
|
||||
this.questId = mapMarkPoint.getQuestId();
|
||||
}
|
||||
|
||||
public int getSceneId() {
|
||||
return this.sceneId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public MapMarkPointType getMapMarkPointType() {
|
||||
return this.mapMarkPointType;
|
||||
}
|
||||
|
||||
public int getMonsterId() {
|
||||
return this.monsterId;
|
||||
}
|
||||
|
||||
public MapMarkFromType getMapMarkFromType() {
|
||||
return this.mapMarkFromType;
|
||||
}
|
||||
|
||||
public int getQuestId() {
|
||||
return this.questId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ public class PlayerCodex {
|
||||
@Transient private Player player;
|
||||
|
||||
// itemId is not codexId!
|
||||
@Getter private final Set<Integer> unlockedWeapon;
|
||||
@Getter private final Map<Integer, Integer> unlockedAnimal;
|
||||
@Getter private final Set<Integer> unlockedMaterial;
|
||||
@Getter private final Set<Integer> unlockedBook;
|
||||
@Getter private final Set<Integer> unlockedTip;
|
||||
@Getter private final Set<Integer> unlockedView;
|
||||
@Getter private Set<Integer> unlockedWeapon;
|
||||
@Getter private Map<Integer, Integer> unlockedAnimal;
|
||||
@Getter private Set<Integer> unlockedMaterial;
|
||||
@Getter private Set<Integer> unlockedBook;
|
||||
@Getter private Set<Integer> unlockedTip;
|
||||
@Getter private Set<Integer> unlockedView;
|
||||
@Getter private Set<Integer> unlockedReliquary;
|
||||
@Getter private final Set<Integer> unlockedReliquarySuitCodex;
|
||||
@Getter private Set<Integer> unlockedReliquarySuitCodex;
|
||||
|
||||
public PlayerCodex() {
|
||||
this.unlockedWeapon = new HashSet<>();
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.util.List;
|
||||
@Entity
|
||||
public final class TeamInfo {
|
||||
private String name;
|
||||
private final List<Integer> avatars;
|
||||
private List<Integer> avatars;
|
||||
|
||||
public TeamInfo() {
|
||||
this.name = "";
|
||||
|
||||
@@ -1,263 +1,263 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum FightProperty {
|
||||
FIGHT_PROP_NONE(0),
|
||||
FIGHT_PROP_BASE_HP(1),
|
||||
FIGHT_PROP_HP(2),
|
||||
FIGHT_PROP_HP_PERCENT(3),
|
||||
FIGHT_PROP_BASE_ATTACK(4),
|
||||
FIGHT_PROP_ATTACK(5),
|
||||
FIGHT_PROP_ATTACK_PERCENT(6),
|
||||
FIGHT_PROP_BASE_DEFENSE(7),
|
||||
FIGHT_PROP_DEFENSE(8),
|
||||
FIGHT_PROP_DEFENSE_PERCENT(9),
|
||||
FIGHT_PROP_BASE_SPEED(10),
|
||||
FIGHT_PROP_SPEED_PERCENT(11),
|
||||
FIGHT_PROP_HP_MP_PERCENT(12),
|
||||
FIGHT_PROP_ATTACK_MP_PERCENT(13),
|
||||
FIGHT_PROP_CRITICAL(20),
|
||||
FIGHT_PROP_ANTI_CRITICAL(21),
|
||||
FIGHT_PROP_CRITICAL_HURT(22),
|
||||
FIGHT_PROP_CHARGE_EFFICIENCY(23),
|
||||
FIGHT_PROP_ADD_HURT(24),
|
||||
FIGHT_PROP_SUB_HURT(25),
|
||||
FIGHT_PROP_HEAL_ADD(26),
|
||||
FIGHT_PROP_HEALED_ADD(27),
|
||||
FIGHT_PROP_ELEMENT_MASTERY(28),
|
||||
FIGHT_PROP_PHYSICAL_SUB_HURT(29),
|
||||
FIGHT_PROP_PHYSICAL_ADD_HURT(30),
|
||||
FIGHT_PROP_DEFENCE_IGNORE_RATIO(31),
|
||||
FIGHT_PROP_DEFENCE_IGNORE_DELTA(32),
|
||||
FIGHT_PROP_FIRE_ADD_HURT(40),
|
||||
FIGHT_PROP_ELEC_ADD_HURT(41),
|
||||
FIGHT_PROP_WATER_ADD_HURT(42),
|
||||
FIGHT_PROP_GRASS_ADD_HURT(43),
|
||||
FIGHT_PROP_WIND_ADD_HURT(44),
|
||||
FIGHT_PROP_ROCK_ADD_HURT(45),
|
||||
FIGHT_PROP_ICE_ADD_HURT(46),
|
||||
FIGHT_PROP_HIT_HEAD_ADD_HURT(47),
|
||||
FIGHT_PROP_FIRE_SUB_HURT(50),
|
||||
FIGHT_PROP_ELEC_SUB_HURT(51),
|
||||
FIGHT_PROP_WATER_SUB_HURT(52),
|
||||
FIGHT_PROP_GRASS_SUB_HURT(53),
|
||||
FIGHT_PROP_WIND_SUB_HURT(54),
|
||||
FIGHT_PROP_ROCK_SUB_HURT(55),
|
||||
FIGHT_PROP_ICE_SUB_HURT(56),
|
||||
FIGHT_PROP_EFFECT_HIT(60),
|
||||
FIGHT_PROP_EFFECT_RESIST(61),
|
||||
FIGHT_PROP_FREEZE_RESIST(62),
|
||||
FIGHT_PROP_TORPOR_RESIST(63),
|
||||
FIGHT_PROP_DIZZY_RESIST(64),
|
||||
FIGHT_PROP_FREEZE_SHORTEN(65),
|
||||
FIGHT_PROP_TORPOR_SHORTEN(66),
|
||||
FIGHT_PROP_DIZZY_SHORTEN(67),
|
||||
FIGHT_PROP_MAX_FIRE_ENERGY(70),
|
||||
FIGHT_PROP_MAX_ELEC_ENERGY(71),
|
||||
FIGHT_PROP_MAX_WATER_ENERGY(72),
|
||||
FIGHT_PROP_MAX_GRASS_ENERGY(73),
|
||||
FIGHT_PROP_MAX_WIND_ENERGY(74),
|
||||
FIGHT_PROP_MAX_ICE_ENERGY(75),
|
||||
FIGHT_PROP_MAX_ROCK_ENERGY(76),
|
||||
FIGHT_PROP_SKILL_CD_MINUS_RATIO(80),
|
||||
FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81),
|
||||
FIGHT_PROP_CUR_FIRE_ENERGY(1000),
|
||||
FIGHT_PROP_CUR_ELEC_ENERGY(1001),
|
||||
FIGHT_PROP_CUR_WATER_ENERGY(1002),
|
||||
FIGHT_PROP_CUR_GRASS_ENERGY(1003),
|
||||
FIGHT_PROP_CUR_WIND_ENERGY(1004),
|
||||
FIGHT_PROP_CUR_ICE_ENERGY(1005),
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY(1006),
|
||||
FIGHT_PROP_CUR_HP(1010),
|
||||
FIGHT_PROP_MAX_HP(2000),
|
||||
FIGHT_PROP_CUR_ATTACK(2001),
|
||||
FIGHT_PROP_CUR_DEFENSE(2002),
|
||||
FIGHT_PROP_CUR_SPEED(2003),
|
||||
FIGHT_PROP_NONEXTRA_ATTACK(3000),
|
||||
FIGHT_PROP_NONEXTRA_DEFENSE(3001),
|
||||
FIGHT_PROP_NONEXTRA_CRITICAL(3002),
|
||||
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003),
|
||||
FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004),
|
||||
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005),
|
||||
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006),
|
||||
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007),
|
||||
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008),
|
||||
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009),
|
||||
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010),
|
||||
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011),
|
||||
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012),
|
||||
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013),
|
||||
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014),
|
||||
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015),
|
||||
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016),
|
||||
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017),
|
||||
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018),
|
||||
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019),
|
||||
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020),
|
||||
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021),
|
||||
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022),
|
||||
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023),
|
||||
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024);
|
||||
|
||||
public static final int[] fightProps =
|
||||
new int[] {
|
||||
1, 4, 7, 20, 21, 22, 23, 26, 27, 28, 29, 30, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54,
|
||||
55, 56, 2000, 2001, 2002, 2003, 1010
|
||||
};
|
||||
private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
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.
|
||||
// setstats
|
||||
private static final Map<String, FightProperty> shortNameMap =
|
||||
Map.ofEntries(
|
||||
// Normal relic stats
|
||||
entry("hp", FIGHT_PROP_HP),
|
||||
entry("atk", FIGHT_PROP_ATTACK),
|
||||
entry("def", FIGHT_PROP_DEFENSE),
|
||||
entry("hp%", FIGHT_PROP_HP_PERCENT),
|
||||
entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
|
||||
entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
|
||||
entry("em", FIGHT_PROP_ELEMENT_MASTERY),
|
||||
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
entry("hb", FIGHT_PROP_HEAL_ADD),
|
||||
entry("heal", FIGHT_PROP_HEAL_ADD),
|
||||
entry("cd", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cr", FIGHT_PROP_CRITICAL),
|
||||
entry("crate", FIGHT_PROP_CRITICAL),
|
||||
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
|
||||
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
|
||||
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
|
||||
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
|
||||
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
|
||||
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
|
||||
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
|
||||
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
|
||||
// Other stats
|
||||
entry("maxhp", FIGHT_PROP_MAX_HP),
|
||||
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
|
||||
entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO),
|
||||
entry("heali", FIGHT_PROP_HEALED_ADD),
|
||||
entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO),
|
||||
entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO),
|
||||
entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks
|
||||
entry("resanemo", FIGHT_PROP_WIND_SUB_HURT),
|
||||
entry("rescryo", FIGHT_PROP_ICE_SUB_HURT),
|
||||
entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT),
|
||||
entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT),
|
||||
entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT),
|
||||
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
|
||||
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
|
||||
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT));
|
||||
private static final List<FightProperty> flatProps =
|
||||
Arrays.asList(
|
||||
FIGHT_PROP_BASE_HP,
|
||||
FIGHT_PROP_HP,
|
||||
FIGHT_PROP_BASE_ATTACK,
|
||||
FIGHT_PROP_ATTACK,
|
||||
FIGHT_PROP_BASE_DEFENSE,
|
||||
FIGHT_PROP_DEFENSE,
|
||||
FIGHT_PROP_HEALED_ADD,
|
||||
FIGHT_PROP_CUR_FIRE_ENERGY,
|
||||
FIGHT_PROP_CUR_ELEC_ENERGY,
|
||||
FIGHT_PROP_CUR_WATER_ENERGY,
|
||||
FIGHT_PROP_CUR_GRASS_ENERGY,
|
||||
FIGHT_PROP_CUR_WIND_ENERGY,
|
||||
FIGHT_PROP_CUR_ICE_ENERGY,
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY,
|
||||
FIGHT_PROP_CUR_HP,
|
||||
FIGHT_PROP_MAX_HP,
|
||||
FIGHT_PROP_CUR_ATTACK,
|
||||
FIGHT_PROP_CUR_DEFENSE);
|
||||
private static final Map<FightProperty, CompoundProperty> compoundProperties =
|
||||
Map.ofEntries(
|
||||
entry(
|
||||
FIGHT_PROP_MAX_HP,
|
||||
new CompoundProperty(
|
||||
FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)),
|
||||
entry(
|
||||
FIGHT_PROP_CUR_ATTACK,
|
||||
new CompoundProperty(
|
||||
FIGHT_PROP_CUR_ATTACK,
|
||||
FIGHT_PROP_BASE_ATTACK,
|
||||
FIGHT_PROP_ATTACK_PERCENT,
|
||||
FIGHT_PROP_ATTACK)),
|
||||
entry(
|
||||
FIGHT_PROP_CUR_DEFENSE,
|
||||
new CompoundProperty(
|
||||
FIGHT_PROP_CUR_DEFENSE,
|
||||
FIGHT_PROP_BASE_DEFENSE,
|
||||
FIGHT_PROP_DEFENSE_PERCENT,
|
||||
FIGHT_PROP_DEFENSE)));
|
||||
|
||||
static {
|
||||
Stream.of(values())
|
||||
.forEach(
|
||||
e -> {
|
||||
map.put(e.getId(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private final int id;
|
||||
|
||||
FightProperty(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static FightProperty getPropById(int value) {
|
||||
return map.getOrDefault(value, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByName(String name) {
|
||||
return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByShortName(String name) {
|
||||
return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static Set<String> getShortNames() {
|
||||
return shortNameMap.keySet();
|
||||
}
|
||||
|
||||
public static CompoundProperty getCompoundProperty(FightProperty result) {
|
||||
return compoundProperties.get(result);
|
||||
}
|
||||
|
||||
public static void forEachCompoundProperty(Consumer<CompoundProperty> consumer) {
|
||||
compoundProperties.values().forEach(consumer);
|
||||
}
|
||||
|
||||
public static boolean isPercentage(FightProperty prop) {
|
||||
return !flatProps.contains(prop);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class CompoundProperty {
|
||||
private final FightProperty result;
|
||||
private final FightProperty base;
|
||||
private final FightProperty percent;
|
||||
private final FightProperty flat;
|
||||
|
||||
public CompoundProperty(
|
||||
FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) {
|
||||
this.result = result;
|
||||
this.base = base;
|
||||
this.percent = percent;
|
||||
this.flat = flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum FightProperty {
|
||||
FIGHT_PROP_NONE(0),
|
||||
FIGHT_PROP_BASE_HP(1),
|
||||
FIGHT_PROP_HP(2),
|
||||
FIGHT_PROP_HP_PERCENT(3),
|
||||
FIGHT_PROP_BASE_ATTACK(4),
|
||||
FIGHT_PROP_ATTACK(5),
|
||||
FIGHT_PROP_ATTACK_PERCENT(6),
|
||||
FIGHT_PROP_BASE_DEFENSE(7),
|
||||
FIGHT_PROP_DEFENSE(8),
|
||||
FIGHT_PROP_DEFENSE_PERCENT(9),
|
||||
FIGHT_PROP_BASE_SPEED(10),
|
||||
FIGHT_PROP_SPEED_PERCENT(11),
|
||||
FIGHT_PROP_HP_MP_PERCENT(12),
|
||||
FIGHT_PROP_ATTACK_MP_PERCENT(13),
|
||||
FIGHT_PROP_CRITICAL(20),
|
||||
FIGHT_PROP_ANTI_CRITICAL(21),
|
||||
FIGHT_PROP_CRITICAL_HURT(22),
|
||||
FIGHT_PROP_CHARGE_EFFICIENCY(23),
|
||||
FIGHT_PROP_ADD_HURT(24),
|
||||
FIGHT_PROP_SUB_HURT(25),
|
||||
FIGHT_PROP_HEAL_ADD(26),
|
||||
FIGHT_PROP_HEALED_ADD(27),
|
||||
FIGHT_PROP_ELEMENT_MASTERY(28),
|
||||
FIGHT_PROP_PHYSICAL_SUB_HURT(29),
|
||||
FIGHT_PROP_PHYSICAL_ADD_HURT(30),
|
||||
FIGHT_PROP_DEFENCE_IGNORE_RATIO(31),
|
||||
FIGHT_PROP_DEFENCE_IGNORE_DELTA(32),
|
||||
FIGHT_PROP_FIRE_ADD_HURT(40),
|
||||
FIGHT_PROP_ELEC_ADD_HURT(41),
|
||||
FIGHT_PROP_WATER_ADD_HURT(42),
|
||||
FIGHT_PROP_GRASS_ADD_HURT(43),
|
||||
FIGHT_PROP_WIND_ADD_HURT(44),
|
||||
FIGHT_PROP_ROCK_ADD_HURT(45),
|
||||
FIGHT_PROP_ICE_ADD_HURT(46),
|
||||
FIGHT_PROP_HIT_HEAD_ADD_HURT(47),
|
||||
FIGHT_PROP_FIRE_SUB_HURT(50),
|
||||
FIGHT_PROP_ELEC_SUB_HURT(51),
|
||||
FIGHT_PROP_WATER_SUB_HURT(52),
|
||||
FIGHT_PROP_GRASS_SUB_HURT(53),
|
||||
FIGHT_PROP_WIND_SUB_HURT(54),
|
||||
FIGHT_PROP_ROCK_SUB_HURT(55),
|
||||
FIGHT_PROP_ICE_SUB_HURT(56),
|
||||
FIGHT_PROP_EFFECT_HIT(60),
|
||||
FIGHT_PROP_EFFECT_RESIST(61),
|
||||
FIGHT_PROP_FREEZE_RESIST(62),
|
||||
FIGHT_PROP_TORPOR_RESIST(63),
|
||||
FIGHT_PROP_DIZZY_RESIST(64),
|
||||
FIGHT_PROP_FREEZE_SHORTEN(65),
|
||||
FIGHT_PROP_TORPOR_SHORTEN(66),
|
||||
FIGHT_PROP_DIZZY_SHORTEN(67),
|
||||
FIGHT_PROP_MAX_FIRE_ENERGY(70),
|
||||
FIGHT_PROP_MAX_ELEC_ENERGY(71),
|
||||
FIGHT_PROP_MAX_WATER_ENERGY(72),
|
||||
FIGHT_PROP_MAX_GRASS_ENERGY(73),
|
||||
FIGHT_PROP_MAX_WIND_ENERGY(74),
|
||||
FIGHT_PROP_MAX_ICE_ENERGY(75),
|
||||
FIGHT_PROP_MAX_ROCK_ENERGY(76),
|
||||
FIGHT_PROP_SKILL_CD_MINUS_RATIO(80),
|
||||
FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81),
|
||||
FIGHT_PROP_CUR_FIRE_ENERGY(1000),
|
||||
FIGHT_PROP_CUR_ELEC_ENERGY(1001),
|
||||
FIGHT_PROP_CUR_WATER_ENERGY(1002),
|
||||
FIGHT_PROP_CUR_GRASS_ENERGY(1003),
|
||||
FIGHT_PROP_CUR_WIND_ENERGY(1004),
|
||||
FIGHT_PROP_CUR_ICE_ENERGY(1005),
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY(1006),
|
||||
FIGHT_PROP_CUR_HP(1010),
|
||||
FIGHT_PROP_MAX_HP(2000),
|
||||
FIGHT_PROP_CUR_ATTACK(2001),
|
||||
FIGHT_PROP_CUR_DEFENSE(2002),
|
||||
FIGHT_PROP_CUR_SPEED(2003),
|
||||
FIGHT_PROP_NONEXTRA_ATTACK(3000),
|
||||
FIGHT_PROP_NONEXTRA_DEFENSE(3001),
|
||||
FIGHT_PROP_NONEXTRA_CRITICAL(3002),
|
||||
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003),
|
||||
FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004),
|
||||
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005),
|
||||
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006),
|
||||
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007),
|
||||
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008),
|
||||
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009),
|
||||
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010),
|
||||
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011),
|
||||
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012),
|
||||
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013),
|
||||
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014),
|
||||
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015),
|
||||
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016),
|
||||
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017),
|
||||
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018),
|
||||
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019),
|
||||
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020),
|
||||
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021),
|
||||
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022),
|
||||
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023),
|
||||
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024);
|
||||
|
||||
public static final int[] fightProps =
|
||||
new int[] {
|
||||
1, 4, 7, 20, 21, 22, 23, 26, 27, 28, 29, 30, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54,
|
||||
55, 56, 2000, 2001, 2002, 2003, 1010
|
||||
};
|
||||
private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
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.
|
||||
// setstats
|
||||
private static final Map<String, FightProperty> shortNameMap =
|
||||
Map.ofEntries(
|
||||
// Normal relic stats
|
||||
entry("hp", FIGHT_PROP_HP),
|
||||
entry("atk", FIGHT_PROP_ATTACK),
|
||||
entry("def", FIGHT_PROP_DEFENSE),
|
||||
entry("hp%", FIGHT_PROP_HP_PERCENT),
|
||||
entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
|
||||
entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
|
||||
entry("em", FIGHT_PROP_ELEMENT_MASTERY),
|
||||
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
entry("hb", FIGHT_PROP_HEAL_ADD),
|
||||
entry("heal", FIGHT_PROP_HEAL_ADD),
|
||||
entry("cd", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cr", FIGHT_PROP_CRITICAL),
|
||||
entry("crate", FIGHT_PROP_CRITICAL),
|
||||
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
|
||||
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
|
||||
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
|
||||
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
|
||||
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
|
||||
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
|
||||
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
|
||||
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
|
||||
// Other stats
|
||||
entry("maxhp", FIGHT_PROP_MAX_HP),
|
||||
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
|
||||
entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO),
|
||||
entry("heali", FIGHT_PROP_HEALED_ADD),
|
||||
entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO),
|
||||
entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO),
|
||||
entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks
|
||||
entry("resanemo", FIGHT_PROP_WIND_SUB_HURT),
|
||||
entry("rescryo", FIGHT_PROP_ICE_SUB_HURT),
|
||||
entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT),
|
||||
entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT),
|
||||
entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT),
|
||||
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
|
||||
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
|
||||
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT));
|
||||
private static final List<FightProperty> flatProps =
|
||||
Arrays.asList(
|
||||
FIGHT_PROP_BASE_HP,
|
||||
FIGHT_PROP_HP,
|
||||
FIGHT_PROP_BASE_ATTACK,
|
||||
FIGHT_PROP_ATTACK,
|
||||
FIGHT_PROP_BASE_DEFENSE,
|
||||
FIGHT_PROP_DEFENSE,
|
||||
FIGHT_PROP_HEALED_ADD,
|
||||
FIGHT_PROP_CUR_FIRE_ENERGY,
|
||||
FIGHT_PROP_CUR_ELEC_ENERGY,
|
||||
FIGHT_PROP_CUR_WATER_ENERGY,
|
||||
FIGHT_PROP_CUR_GRASS_ENERGY,
|
||||
FIGHT_PROP_CUR_WIND_ENERGY,
|
||||
FIGHT_PROP_CUR_ICE_ENERGY,
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY,
|
||||
FIGHT_PROP_CUR_HP,
|
||||
FIGHT_PROP_MAX_HP,
|
||||
FIGHT_PROP_CUR_ATTACK,
|
||||
FIGHT_PROP_CUR_DEFENSE);
|
||||
private static final Map<FightProperty, CompoundProperty> compoundProperties =
|
||||
Map.ofEntries(
|
||||
entry(
|
||||
FIGHT_PROP_MAX_HP,
|
||||
new CompoundProperty(
|
||||
FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)),
|
||||
entry(
|
||||
FIGHT_PROP_CUR_ATTACK,
|
||||
new CompoundProperty(
|
||||
FIGHT_PROP_CUR_ATTACK,
|
||||
FIGHT_PROP_BASE_ATTACK,
|
||||
FIGHT_PROP_ATTACK_PERCENT,
|
||||
FIGHT_PROP_ATTACK)),
|
||||
entry(
|
||||
FIGHT_PROP_CUR_DEFENSE,
|
||||
new CompoundProperty(
|
||||
FIGHT_PROP_CUR_DEFENSE,
|
||||
FIGHT_PROP_BASE_DEFENSE,
|
||||
FIGHT_PROP_DEFENSE_PERCENT,
|
||||
FIGHT_PROP_DEFENSE)));
|
||||
|
||||
static {
|
||||
Stream.of(values())
|
||||
.forEach(
|
||||
e -> {
|
||||
map.put(e.getId(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private final int id;
|
||||
|
||||
FightProperty(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static FightProperty getPropById(int value) {
|
||||
return map.getOrDefault(value, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByName(String name) {
|
||||
return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByShortName(String name) {
|
||||
return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static Set<String> getShortNames() {
|
||||
return shortNameMap.keySet();
|
||||
}
|
||||
|
||||
public static CompoundProperty getCompoundProperty(FightProperty result) {
|
||||
return compoundProperties.get(result);
|
||||
}
|
||||
|
||||
public static void forEachCompoundProperty(Consumer<CompoundProperty> consumer) {
|
||||
compoundProperties.values().forEach(consumer);
|
||||
}
|
||||
|
||||
public static boolean isPercentage(FightProperty prop) {
|
||||
return !flatProps.contains(prop);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class CompoundProperty {
|
||||
private final FightProperty result;
|
||||
private final FightProperty base;
|
||||
private final FightProperty percent;
|
||||
private final FightProperty flat;
|
||||
|
||||
public CompoundProperty(
|
||||
FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) {
|
||||
this.result = result;
|
||||
this.base = base;
|
||||
this.percent = percent;
|
||||
this.flat = flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
import emu.grasscutter.game.props.ItemUseOp;
|
||||
|
||||
public class ItemUseAddCurHp extends ItemUseInt {
|
||||
private final String icon;
|
||||
|
||||
public ItemUseAddCurHp(String[] useParam) {
|
||||
super(useParam);
|
||||
this.icon = useParam[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_ADD_CUR_HP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useItem(UseItemParams params) {
|
||||
return (params.targetAvatar.getAsEntity().heal(params.count * this.i) > 0.01);
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
import emu.grasscutter.game.props.ItemUseOp;
|
||||
|
||||
public class ItemUseAddCurHp extends ItemUseInt {
|
||||
private final String icon;
|
||||
|
||||
public ItemUseAddCurHp(String[] useParam) {
|
||||
super(useParam);
|
||||
this.icon = useParam[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_ADD_CUR_HP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useItem(UseItemParams params) {
|
||||
return (params.targetAvatar.getAsEntity().heal(params.count * this.i) > 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
import emu.grasscutter.game.props.ItemUseOp;
|
||||
|
||||
public class ItemUseChestSelectItem extends ItemUseSelectItems {
|
||||
private final int[] optionItemCounts;
|
||||
|
||||
public ItemUseChestSelectItem(String[] useParam) {
|
||||
String[] options = useParam[0].split(",");
|
||||
this.optionItemIds = new int[options.length];
|
||||
this.optionItemCounts = new int[options.length];
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
String[] optionParts = options[i].split(":");
|
||||
try {
|
||||
this.optionItemIds[i] = Integer.parseInt(optionParts[0]);
|
||||
} catch (NumberFormatException ignored) {
|
||||
this.optionItemIds[i] = INVALID;
|
||||
}
|
||||
try {
|
||||
this.optionItemCounts[i] = Integer.parseInt(optionParts[1]);
|
||||
} catch (NumberFormatException ignored) {
|
||||
this.optionItemCounts[i] = INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_CHEST_SELECT_ITEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getItemCount(int index) {
|
||||
if ((optionItemCounts == null) || (index < 0) || (index > optionItemCounts.length))
|
||||
return INVALID;
|
||||
return this.optionItemCounts[index];
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
import emu.grasscutter.game.props.ItemUseOp;
|
||||
|
||||
public class ItemUseChestSelectItem extends ItemUseSelectItems {
|
||||
private final int[] optionItemCounts;
|
||||
|
||||
public ItemUseChestSelectItem(String[] useParam) {
|
||||
String[] options = useParam[0].split(",");
|
||||
this.optionItemIds = new int[options.length];
|
||||
this.optionItemCounts = new int[options.length];
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
String[] optionParts = options[i].split(":");
|
||||
try {
|
||||
this.optionItemIds[i] = Integer.parseInt(optionParts[0]);
|
||||
} catch (NumberFormatException ignored) {
|
||||
this.optionItemIds[i] = INVALID;
|
||||
}
|
||||
try {
|
||||
this.optionItemCounts[i] = Integer.parseInt(optionParts[1]);
|
||||
} catch (NumberFormatException ignored) {
|
||||
this.optionItemCounts[i] = INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_CHEST_SELECT_ITEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getItemCount(int index) {
|
||||
if ((optionItemCounts == null) || (index < 0) || (index > optionItemCounts.length))
|
||||
return INVALID;
|
||||
return this.optionItemCounts[index];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
package emu.grasscutter.game.world;
|
||||
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class SpawnDataEntry {
|
||||
@Getter @Setter private transient SpawnGroupEntry group;
|
||||
@Getter private int monsterId;
|
||||
@Getter private int gadgetId;
|
||||
@Getter private int configId;
|
||||
@Getter private int level;
|
||||
@Getter private int poseId;
|
||||
@Getter private int gatherItemId;
|
||||
@Getter private int gadgetState;
|
||||
@Getter private Position pos;
|
||||
@Getter private Position rot;
|
||||
|
||||
public GridBlockId getBlockId() {
|
||||
int scale = GridBlockId.getScale(gadgetId);
|
||||
return new GridBlockId(
|
||||
group.sceneId,
|
||||
scale,
|
||||
(int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]),
|
||||
(int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale]));
|
||||
}
|
||||
|
||||
public static class SpawnGroupEntry {
|
||||
@Getter private int sceneId;
|
||||
@Getter private int groupId;
|
||||
@Getter private int blockId;
|
||||
@Getter @Setter private List<SpawnDataEntry> spawns;
|
||||
}
|
||||
|
||||
public static class GridBlockId {
|
||||
@Getter private final int sceneId;
|
||||
@Getter private final int scale;
|
||||
@Getter private final int x;
|
||||
@Getter private final int z;
|
||||
|
||||
public GridBlockId(int sceneId, int scale, int x, int z) {
|
||||
this.sceneId = sceneId;
|
||||
this.scale = scale;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) {
|
||||
GridBlockId[] results = new GridBlockId[5 * 5 * GameDepot.BLOCK_SIZE.length];
|
||||
int t = 0;
|
||||
for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) {
|
||||
int x = ((int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]));
|
||||
int z = ((int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale]));
|
||||
for (int i = x - 2; i < x + 3; i++) {
|
||||
for (int j = z - 2; j < z + 3; j++) {
|
||||
results[t++] = new GridBlockId(sceneId, scale, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public static int getScale(int gadgetId) {
|
||||
return 0; // you should implement here,this is index of GameDepot.BLOCK_SIZE
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SpawnDataEntryScaledPoint{"
|
||||
+ "sceneId="
|
||||
+ sceneId
|
||||
+ ", scale="
|
||||
+ scale
|
||||
+ ", x="
|
||||
+ x
|
||||
+ ", z="
|
||||
+ z
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
GridBlockId that = (GridBlockId) o;
|
||||
return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(sceneId, scale, x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.world;
|
||||
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class SpawnDataEntry {
|
||||
@Getter @Setter private transient SpawnGroupEntry group;
|
||||
@Getter private int monsterId;
|
||||
@Getter private int gadgetId;
|
||||
@Getter private int configId;
|
||||
@Getter private int level;
|
||||
@Getter private int poseId;
|
||||
@Getter private int gatherItemId;
|
||||
@Getter private int gadgetState;
|
||||
@Getter private Position pos;
|
||||
@Getter private Position rot;
|
||||
|
||||
public GridBlockId getBlockId() {
|
||||
int scale = GridBlockId.getScale(gadgetId);
|
||||
return new GridBlockId(
|
||||
group.sceneId,
|
||||
scale,
|
||||
(int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]),
|
||||
(int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale]));
|
||||
}
|
||||
|
||||
public static class SpawnGroupEntry {
|
||||
@Getter private int sceneId;
|
||||
@Getter private int groupId;
|
||||
@Getter private int blockId;
|
||||
@Getter @Setter private List<SpawnDataEntry> spawns;
|
||||
}
|
||||
|
||||
public static class GridBlockId {
|
||||
@Getter private int sceneId;
|
||||
@Getter private int scale;
|
||||
@Getter private int x;
|
||||
@Getter private int z;
|
||||
|
||||
public GridBlockId(int sceneId, int scale, int x, int z) {
|
||||
this.sceneId = sceneId;
|
||||
this.scale = scale;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) {
|
||||
GridBlockId[] results = new GridBlockId[5 * 5 * GameDepot.BLOCK_SIZE.length];
|
||||
int t = 0;
|
||||
for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) {
|
||||
int x = ((int) (pos.getX() / GameDepot.BLOCK_SIZE[scale]));
|
||||
int z = ((int) (pos.getZ() / GameDepot.BLOCK_SIZE[scale]));
|
||||
for (int i = x - 2; i < x + 3; i++) {
|
||||
for (int j = z - 2; j < z + 3; j++) {
|
||||
results[t++] = new GridBlockId(sceneId, scale, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public static int getScale(int gadgetId) {
|
||||
return 0; // you should implement here,this is index of GameDepot.BLOCK_SIZE
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SpawnDataEntryScaledPoint{"
|
||||
+ "sceneId="
|
||||
+ sceneId
|
||||
+ ", scale="
|
||||
+ scale
|
||||
+ ", x="
|
||||
+ x
|
||||
+ ", z="
|
||||
+ z
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
GridBlockId that = (GridBlockId) o;
|
||||
return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(sceneId, scale, x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ public class World implements Iterable<Player> {
|
||||
@Getter private final List<Player> players;
|
||||
@Getter private final Int2ObjectMap<Scene> scenes;
|
||||
|
||||
@Getter private final int levelEntityId;
|
||||
@Getter private int levelEntityId;
|
||||
private int nextEntityId = 0;
|
||||
private int nextPeerId = 0;
|
||||
private int worldLevel;
|
||||
|
||||
private final boolean isMultiplayer;
|
||||
private boolean isMultiplayer;
|
||||
|
||||
private long lastUpdateTime;
|
||||
@Getter private int tickCount = 0;
|
||||
|
||||
Reference in New Issue
Block a user