Run IntelliJ IDEA code formatter

This commit is contained in:
KingRainbow44
2023-03-31 17:19:26 -04:00
parent 5bf5fb07a2
commit 15e2f3ca34
917 changed files with 30030 additions and 22446 deletions

View File

@@ -4,17 +4,18 @@ import dev.morphia.annotations.*;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.Utils;
import static emu.grasscutter.config.Configuration.*;
import org.bson.Document;
import java.util.*;
import java.util.stream.Stream;
import org.bson.Document;
import static emu.grasscutter.config.Configuration.ACCOUNT;
import static emu.grasscutter.config.Configuration.LANGUAGE;
@Entity(value = "accounts", useDiscriminator = false)
public class Account {
@Id private String id;
@Id
private String id;
@Indexed(options = @IndexOptions(unique = true))
@Collation(locale = "simple", caseLevel = true)
@@ -26,7 +27,7 @@ public class Account {
private String token;
private String sessionKey; // Session token for dispatch server
private List<String> permissions;
private final List<String> permissions;
private Locale locale;
private String banReason;
@@ -40,6 +41,30 @@ public class Account {
this.locale = LANGUAGE;
}
public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) {
String[] wildcardParts = wildcard.split("\\.");
if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission
return false;
}
for (int i = 0; i < wildcardParts.length; i++) {
switch (wildcardParts[i]) {
case "**": // Recursing match
return true;
case "*": // Match only one layer
if (i >= (permissionParts.length - 1)) {
return true;
}
break;
default: // This layer isn't a wildcard, it needs to match exactly
if (!wildcardParts[i].equals(permissionParts[i])) {
return false;
}
}
}
// At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **).
return (wildcardParts.length == permissionParts.length);
}
public String getId() {
return id;
}
@@ -159,31 +184,8 @@ public class Account {
public boolean addPermission(String permission) {
if (this.permissions.contains(permission)) return false;
this.permissions.add(permission); return true;
}
public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) {
String[] wildcardParts = wildcard.split("\\.");
if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission
return false;
}
for (int i=0; i<wildcardParts.length; i++) {
switch (wildcardParts[i]) {
case "**": // Recursing match
return true;
case "*": // Match only one layer
if (i >= (permissionParts.length-1)) {
return true;
}
break;
default: // This layer isn't a wildcard, it needs to match exactly
if (!wildcardParts[i].equals(permissionParts[i])) {
return false;
}
}
}
// At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **).
return (wildcardParts.length == permissionParts.length);
this.permissions.add(permission);
return true;
}
public boolean hasPermission(String permission) {
@@ -192,8 +194,8 @@ public class Account {
// Add default permissions if it doesn't exist
List<String> permissions = Stream.of(this.permissions, Arrays.asList(ACCOUNT.defaultPermissions))
.flatMap(Collection::stream)
.distinct().toList();
.flatMap(Collection::stream)
.distinct().toList();
if (permissions.contains(permission)) return true;

View File

@@ -3,29 +3,29 @@ package emu.grasscutter.game;
import emu.grasscutter.game.player.Player;
public class CoopRequest {
private final Player requester;
private final long requestTime;
private final long expireTime;
public CoopRequest(Player requester) {
this.requester = requester;
this.requestTime = System.currentTimeMillis();
this.expireTime = this.requestTime + 10000;
}
private final Player requester;
private final long requestTime;
private final long expireTime;
public Player getRequester() {
return requester;
}
public CoopRequest(Player requester) {
this.requester = requester;
this.requestTime = System.currentTimeMillis();
this.expireTime = this.requestTime + 10000;
}
public long getRequestTime() {
return requestTime;
}
public Player getRequester() {
return requester;
}
public long getExpireTime() {
return expireTime;
}
public boolean isExpired() {
return System.currentTimeMillis() > getExpireTime();
}
public long getRequestTime() {
return requestTime;
}
public long getExpireTime() {
return expireTime;
}
public boolean isExpired() {
return System.currentTimeMillis() > getExpireTime();
}
}

View File

@@ -1,10 +1,9 @@
package emu.grasscutter.game.ability;
import com.google.protobuf.InvalidProtocolBufferException;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.AbilityModifierEntry;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.data.binout.AbilityModifierEntry;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.entity.gadget.GadgetGatherObject;
@@ -22,7 +21,8 @@ import lombok.Getter;
public final class AbilityManager extends BasePlayerManager {
HealAbilityManager healAbilityManager;
@Getter private boolean abilityInvulnerable = false;
@Getter
private boolean abilityInvulnerable = false;
public AbilityManager(Player player) {
super(player);
@@ -32,21 +32,23 @@ public final class AbilityManager extends BasePlayerManager {
public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception {
this.healAbilityManager.healHandler(invoke);
//Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
//Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
switch (invoke.getArgumentType()) {
case ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM -> this.handleOverrideParam(invoke);
case ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP -> this.handleReinitOverrideMap(invoke);
case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE -> this.handleModifierChange(invoke);
case ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA -> this.handleMixinCostStamina(invoke);
case ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL -> this.handleGenerateElemBall(invoke);
default -> {}
default -> {
}
}
}
/**
* Invoked when a player starts a skill.
* @param player The player who started the skill.
* @param skillId The skill ID.
*
* @param player The player who started the skill.
* @param skillId The skill ID.
* @param casterId The caster ID.
*/
public void onSkillStart(Player player, int skillId, int casterId) {
@@ -76,6 +78,7 @@ public final class AbilityManager extends BasePlayerManager {
/**
* Invoked when a player ends a skill.
*
* @param player The player who started the skill.
*/
public void onSkillEnd(Player player) {
@@ -195,7 +198,8 @@ public final class AbilityManager extends BasePlayerManager {
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
switch (action.type) {
case HealHP -> {}
case HealHP -> {
}
case LoseHP -> {
if (action.amountByTargetCurrentHPRatio == null) {
return;
@@ -211,8 +215,8 @@ public final class AbilityManager extends BasePlayerManager {
target.damage(damageAmount);
}
}
default -> {}
default -> {
}
}
}
}

View File

@@ -1,38 +1,135 @@
package emu.grasscutter.game.ability;
import java.util.*;
import java.util.Optional;
import java.util.Map.Entry;
import com.google.protobuf.InvalidProtocolBufferException;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.AbilityModifierEntry;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.data.excels.AvatarSkillDepotData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntityClientGadget;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ElementType;
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityMetaReInitOverrideMap;
import emu.grasscutter.net.proto.AbilityMixinCostStaminaOuterClass.AbilityMixinCostStamina;
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils;
import emu.grasscutter.game.props.FightProperty;
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"
@@ -41,7 +138,7 @@ public class HealAbilityManager {
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;
@@ -63,7 +160,7 @@ public class HealAbilityManager {
private class HealDataAvatar {
public int avatarId = 0;
public String avatarName = "";
public int fightPropertyType= 0; //0: maxHP, 1: curAttack, 2: curDefense
public int fightPropertyType = 0; //0: maxHP, 1: curAttack, 2: curDefense
public ArrayList<HealData> healDataList;
public HealDataAvatar(int _avatarId, String _avatarName, int _fightPropertyType) {
@@ -85,124 +182,4 @@ public class HealAbilityManager {
return this;
}
}
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;
}
}
}
}

View File

@@ -11,8 +11,8 @@ import lombok.Setter;
public class Achievement {
@Setter
private StatusOuterClass.Status status;
private int id;
private int totalProgress;
private final int id;
private final int totalProgress;
@Setter
private int curProgress;
@Setter

View File

@@ -22,7 +22,10 @@ import lombok.Getter;
import org.bson.types.ObjectId;
import javax.annotation.Nullable;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntSupplier;

View File

@@ -27,18 +27,19 @@ public abstract class ActivityHandler {
Map<WatcherTriggerType, List<ActivityWatcher>> watchersMap = new HashMap<>();
abstract public void onProtoBuild(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo);
abstract public void onInitPlayerActivityData(PlayerActivityData playerActivityData);
public void initWatchers(Map<WatcherTriggerType, ConstructorAccess<?>> activityWatcherTypeMap){
public void initWatchers(Map<WatcherTriggerType, ConstructorAccess<?>> activityWatcherTypeMap) {
activityData = GameData.getActivityDataMap().get(activityConfigItem.getActivityId());
// add watcher to map by id
activityData.getWatcherDataList().forEach(watcherData -> {
var watcherType = activityWatcherTypeMap.get(watcherData.getTriggerConfig().getWatcherTriggerType());
ActivityWatcher watcher;
if(watcherType != null){
if (watcherType != null) {
watcher = (ActivityWatcher) watcherType.newInstance();
}else{
} else {
watcher = new DefaultWatcher();
}
@@ -50,14 +51,14 @@ public abstract class ActivityHandler {
});
}
private Map<Integer, PlayerActivityData.WatcherInfo> initWatchersDataForPlayer(){
private Map<Integer, PlayerActivityData.WatcherInfo> initWatchersDataForPlayer() {
return watchersMap.values().stream()
.flatMap(Collection::stream)
.map(PlayerActivityData.WatcherInfo::init)
.collect(Collectors.toMap(PlayerActivityData.WatcherInfo::getWatcherId, y -> y));
}
public PlayerActivityData initPlayerActivityData(Player player){
public PlayerActivityData initPlayerActivityData(Player player) {
PlayerActivityData playerActivityData = PlayerActivityData.of()
.activityId(activityConfigItem.getActivityId())
.uid(player.getUid())
@@ -68,7 +69,7 @@ public abstract class ActivityHandler {
return playerActivityData;
}
public ActivityInfoOuterClass.ActivityInfo toProto(PlayerActivityData playerActivityData){
public ActivityInfoOuterClass.ActivityInfo toProto(PlayerActivityData playerActivityData) {
var proto = ActivityInfoOuterClass.ActivityInfo.newBuilder();
proto.setActivityId(activityConfigItem.getActivityId())
.setActivityType(activityConfigItem.getActivityType())
@@ -78,7 +79,7 @@ public abstract class ActivityHandler {
.setEndTime(DateHelper.getUnixTime(activityConfigItem.getEndTime()))
.addAllMeetCondList(activityConfigItem.getMeetCondList());
if (playerActivityData != null){
if (playerActivityData != null) {
proto.addAllWatcherInfoList(playerActivityData.getAllWatcherInfoList());
}

View File

@@ -19,8 +19,8 @@ import java.util.concurrent.ConcurrentHashMap;
@Getter
public class ActivityManager extends BasePlayerManager {
private static final Map<Integer, ActivityConfigItem> activityConfigItemMap;
@Getter private static final Map<Integer, ActivityConfigItem> scheduleActivityConfigMap;
private final Map<Integer, PlayerActivityData> playerActivityDataMap;
@Getter
private static final Map<Integer, ActivityConfigItem> scheduleActivityConfigMap;
static {
activityConfigItemMap = new HashMap<>();
@@ -28,6 +28,27 @@ public class ActivityManager extends BasePlayerManager {
loadActivityConfigData();
}
private final Map<Integer, PlayerActivityData> playerActivityDataMap;
public ActivityManager(Player player) {
super(player);
playerActivityDataMap = new ConcurrentHashMap<>();
// load data for player
activityConfigItemMap.values().forEach(item -> {
var data = PlayerActivityData.getByPlayer(player, item.getActivityId());
if (data == null) {
data = item.getActivityHandler().initPlayerActivityData(player);
data.save();
}
data.setPlayer(player);
data.setActivityHandler(item.getActivityHandler());
playerActivityDataMap.put(item.getActivityId(), data);
});
player.sendPacket(new PacketActivityScheduleInfoNotify(activityConfigItemMap.values()));
}
private static void loadActivityConfigData() {
// scan activity type handler & watcher type
var activityHandlerTypeMap = new HashMap<ActivityType, ConstructorAccess<?>>();
@@ -55,7 +76,7 @@ public class ActivityManager extends BasePlayerManager {
if (activityHandlerType != null) {
activityHandler = (ActivityHandler) activityHandlerType.newInstance();
}else {
} else {
activityHandler = new DefaultActivityHandler();
}
activityHandler.setActivityConfigItem(item);
@@ -73,25 +94,6 @@ public class ActivityManager extends BasePlayerManager {
}
public ActivityManager(Player player) {
super(player);
playerActivityDataMap = new ConcurrentHashMap<>();
// load data for player
activityConfigItemMap.values().forEach(item -> {
var data = PlayerActivityData.getByPlayer(player, item.getActivityId());
if (data == null) {
data = item.getActivityHandler().initPlayerActivityData(player);
data.save();
}
data.setPlayer(player);
data.setActivityHandler(item.getActivityHandler());
playerActivityDataMap.put(item.getActivityId(), data);
});
player.sendPacket(new PacketActivityScheduleInfoNotify(activityConfigItemMap.values()));
}
/**
* trigger activity watcher
*/
@@ -124,8 +126,9 @@ public class ActivityManager extends BasePlayerManager {
.findFirst();
}
@SuppressWarnings("unchecked")
public <T extends ActivityHandler> Optional<T> getActivityHandlerAs(ActivityType type, Class<T> clazz) {
return getActivityHandler(type).map(x -> (T)x);
return getActivityHandler(type).map(x -> (T) x);
}
public Optional<Integer> getActivityIdByActivityType(ActivityType type) {
@@ -133,13 +136,15 @@ public class ActivityManager extends BasePlayerManager {
.map(ActivityHandler::getActivityConfigItem)
.map(ActivityConfigItem::getActivityId);
}
public Optional<PlayerActivityData> getPlayerActivityDataByActivityType(ActivityType type) {
return getActivityIdByActivityType(type)
.map(playerActivityDataMap::get);
}
public Optional<ActivityInfoOuterClass.ActivityInfo> getInfoProtoByActivityType(ActivityType type) {
return getActivityIdByActivityType(type)
.map(this::getInfoProtoByActivityId);
return getActivityIdByActivityType(type)
.map(this::getInfoProtoByActivityId);
}
}

View File

@@ -16,8 +16,8 @@ public abstract class ActivityWatcher {
protected abstract boolean isMeet(String... param);
public void trigger(PlayerActivityData playerActivityData, String... param){
if(isMeet(param)){
public void trigger(PlayerActivityData playerActivityData, String... param) {
if (isMeet(param)) {
playerActivityData.addWatcherProgress(watcherId);
playerActivityData.save();
}

View File

@@ -4,7 +4,7 @@ import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.net.proto.ActivityInfoOuterClass;
@GameActivity(ActivityType.NONE)
public class DefaultActivityHandler extends ActivityHandler{
public class DefaultActivityHandler extends ActivityHandler {
@Override
public void onProtoBuild(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo) {

View File

@@ -3,7 +3,7 @@ package emu.grasscutter.game.activity;
import emu.grasscutter.game.props.WatcherTriggerType;
@ActivityWatcherType(WatcherTriggerType.TRIGGER_NONE)
public class DefaultWatcher extends ActivityWatcher{
public class DefaultWatcher extends ActivityWatcher {
@Override
protected boolean isMeet(String... param) {
return false;

View File

@@ -37,16 +37,19 @@ public class PlayerActivityData {
* the detail data of each type of activity (Json format)
*/
String detail;
@Transient Player player;
@Transient ActivityHandler activityHandler;
public void save() {
DatabaseHelper.savePlayerActivityData(this);
}
@Transient
Player player;
@Transient
ActivityHandler activityHandler;
public static PlayerActivityData getByPlayer(Player player, int activityId) {
return DatabaseHelper.getPlayerActivityData(player.getUid(), activityId);
}
public void save() {
DatabaseHelper.savePlayerActivityData(this);
}
public synchronized void addWatcherProgress(int watcherId) {
var watcherInfo = watcherInfoMap.get(watcherId);
if (watcherInfo == null) {
@@ -100,16 +103,12 @@ public class PlayerActivityData {
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Builder(builderMethodName = "of")
public static class WatcherInfo{
public static class WatcherInfo {
int watcherId;
int totalProgress;
int curProgress;
boolean isTakenReward;
public ActivityWatcherData getMetadata() {
return GameData.getActivityWatcherDataMap().get(watcherId);
}
public static WatcherInfo init(ActivityWatcher watcher) {
return WatcherInfo.of()
.watcherId(watcher.getWatcherId())
@@ -118,6 +117,10 @@ public class PlayerActivityData {
.build();
}
public ActivityWatcherData getMetadata() {
return GameData.getActivityWatcherDataMap().get(watcherId);
}
public ActivityWatcherInfoOuterClass.ActivityWatcherInfo toProto() {
return ActivityWatcherInfoOuterClass.ActivityWatcherInfo.newBuilder()
.setWatcherId(watcherId)

View File

@@ -5,7 +5,6 @@ import emu.grasscutter.game.activity.GameActivity;
import emu.grasscutter.game.activity.PlayerActivityData;
import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.net.proto.ActivityInfoOuterClass;
import emu.grasscutter.net.proto.UgcMusicBriefInfoOuterClass;
import emu.grasscutter.net.proto.MusicGameActivityDetailInfoOuterClass;
import emu.grasscutter.utils.JsonUtils;
@@ -62,6 +61,7 @@ public class MusicGameActivityHandler extends ActivityHandler {
return newRecord.getMaxScore() > saveRecord.getMaxScore();
}
public void setMusicGameCustomBeatmapRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.CustomBeatmapRecord newRecord) {
var musicGamePlayerData = getMusicGamePlayerData(playerActivityData);
musicGamePlayerData.getOthersCustomBeatmapRecord().put(newRecord.getMusicShareId(), newRecord);

View File

@@ -3,10 +3,10 @@ package emu.grasscutter.game.activity.musicgame;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.net.proto.UgcMusicRecordOuterClass;
import emu.grasscutter.net.proto.UgcMusicNoteOuterClass;
import emu.grasscutter.net.proto.UgcMusicTrackOuterClass;
import emu.grasscutter.net.proto.UgcMusicBriefInfoOuterClass;
import emu.grasscutter.net.proto.UgcMusicNoteOuterClass;
import emu.grasscutter.net.proto.UgcMusicRecordOuterClass;
import emu.grasscutter.net.proto.UgcMusicTrackOuterClass;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
@@ -32,17 +32,10 @@ public class MusicGameBeatmap {
List<List<BeatmapNote>> beatmap;
public static MusicGameBeatmap getByShareId(long musicShareId){
public static MusicGameBeatmap getByShareId(long musicShareId) {
return DatabaseHelper.getMusicGameBeatmap(musicShareId);
}
public void save(){
if(musicShareId == 0){
musicShareId = new Random().nextLong(100000000000000L,999999999999999L);
}
DatabaseHelper.saveMusicGameBeatmap(this);
}
public static List<List<BeatmapNote>> parse(List<UgcMusicTrackOuterClass.UgcMusicTrack> beatmapItemListList) {
return beatmapItemListList.stream()
.map(item -> item.getMusicNoteListList().stream()
@@ -51,7 +44,14 @@ public class MusicGameBeatmap {
.toList();
}
public UgcMusicRecordOuterClass.UgcMusicRecord toProto(){
public void save() {
if (musicShareId == 0) {
musicShareId = new Random().nextLong(100000000000000L, 999999999999999L);
}
DatabaseHelper.saveMusicGameBeatmap(this);
}
public UgcMusicRecordOuterClass.UgcMusicRecord toProto() {
return UgcMusicRecordOuterClass.UgcMusicRecord.newBuilder()
.setMusicId(musicId)
.addAllMusicTrackList(beatmap.stream()
@@ -60,7 +60,7 @@ public class MusicGameBeatmap {
.build();
}
public UgcMusicBriefInfoOuterClass.UgcMusicBriefInfo.Builder toBriefProto(){
public UgcMusicBriefInfoOuterClass.UgcMusicBriefInfo.Builder toBriefProto() {
var player = DatabaseHelper.getPlayerByUid(authorUid);
return UgcMusicBriefInfoOuterClass.UgcMusicBriefInfo.newBuilder()
@@ -73,7 +73,7 @@ public class MusicGameBeatmap {
.setVersion(1);
}
private UgcMusicTrackOuterClass.UgcMusicTrack musicBeatmapListToProto(List<BeatmapNote> beatmapNoteList){
private UgcMusicTrackOuterClass.UgcMusicTrack musicBeatmapListToProto(List<BeatmapNote> beatmapNoteList) {
return UgcMusicTrackOuterClass.UgcMusicTrack.newBuilder()
.addAllMusicNoteList(beatmapNoteList.stream()
.map(BeatmapNote::toProto)
@@ -85,18 +85,18 @@ public class MusicGameBeatmap {
@FieldDefaults(level = AccessLevel.PRIVATE)
@Builder(builderMethodName = "of")
@Entity
public static class BeatmapNote{
public static class BeatmapNote {
int startTime;
int endTime;
public static BeatmapNote parse(UgcMusicNoteOuterClass.UgcMusicNote note){
public static BeatmapNote parse(UgcMusicNoteOuterClass.UgcMusicNote note) {
return BeatmapNote.of()
.startTime(note.getStartTime())
.endTime(note.getEndTime())
.build();
}
public UgcMusicNoteOuterClass.UgcMusicNote toProto(){
public UgcMusicNoteOuterClass.UgcMusicNote toProto() {
return UgcMusicNoteOuterClass.UgcMusicNote.newBuilder()
.setStartTime(startTime)
.setEndTime(endTime)

View File

@@ -2,8 +2,8 @@ package emu.grasscutter.game.activity.musicgame;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.MusicGameBasicData;
import emu.grasscutter.net.proto.UgcMusicBriefInfoOuterClass;
import emu.grasscutter.net.proto.MusicGameRecordOuterClass;
import emu.grasscutter.net.proto.UgcMusicBriefInfoOuterClass;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
@@ -85,5 +85,3 @@ public class MusicGamePlayerData {
}
}

View File

@@ -8,11 +8,11 @@ import emu.grasscutter.game.props.WatcherTriggerType;
public class MusicGameScoreTrigger extends ActivityWatcher {
@Override
protected boolean isMeet(String... param) {
if(param.length != 2){
if (param.length != 2) {
return false;
}
var paramList = getActivityWatcherData().getTriggerConfig().getParamList();
if(!paramList.get(0).equals(param[0])){
if (!paramList.get(0).equals(param[0])) {
return false;
}

View File

@@ -1,41 +1,12 @@
package emu.grasscutter.game.avatar;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import java.util.Set;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.PostLoad;
import dev.morphia.annotations.PrePersist;
import dev.morphia.annotations.Transient;
import dev.morphia.annotations.*;
import emu.grasscutter.GameConstants;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.OpenConfigEntry;
import emu.grasscutter.data.binout.OpenConfigEntry.SkillPointModifier;
import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.data.excels.AvatarPromoteData;
import emu.grasscutter.data.excels.AvatarSkillData;
import emu.grasscutter.data.excels.AvatarSkillDepotData;
import emu.grasscutter.data.excels.AvatarTalentData;
import emu.grasscutter.data.excels.EquipAffixData;
import emu.grasscutter.data.excels.ProudSkillData;
import emu.grasscutter.data.excels.ReliquaryAffixData;
import emu.grasscutter.data.excels.ReliquaryLevelData;
import emu.grasscutter.data.excels.ReliquaryMainPropData;
import emu.grasscutter.data.excels.ReliquarySetData;
import emu.grasscutter.data.excels.WeaponCurveData;
import emu.grasscutter.data.excels.WeaponPromoteData;
import emu.grasscutter.data.excels.*;
import emu.grasscutter.data.excels.AvatarSkillDepotData.InherentProudSkillOpens;
import emu.grasscutter.data.excels.ItemData.WeaponProperty;
import emu.grasscutter.database.DatabaseHelper;
@@ -44,11 +15,7 @@ import emu.grasscutter.game.inventory.EquipType;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ElementType;
import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.FetterState;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.*;
import emu.grasscutter.net.proto.AvatarFetterInfoOuterClass.AvatarFetterInfo;
import emu.grasscutter.net.proto.AvatarInfoOuterClass.AvatarInfo;
import emu.grasscutter.net.proto.AvatarSkillInfoOuterClass.AvatarSkillInfo;
@@ -58,60 +25,105 @@ import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass.ShowAvatarInfo;
import emu.grasscutter.net.proto.ShowEquipOuterClass.ShowEquip;
import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.*;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
import org.bson.types.ObjectId;
import java.util.*;
import java.util.stream.Stream;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
@Entity(value = "avatars", useDiscriminator = false)
public class Avatar {
@Id private ObjectId id;
@Indexed @Getter private int ownerId; // Id of player that this avatar belongs to
@Transient private Player owner;
@Transient @Getter private AvatarData data;
@Transient @Getter private AvatarSkillDepotData skillDepot;
@Transient @Getter private long guid; // Player unique id
@Getter private int avatarId; // Id of avatar
@Getter @Setter private int level = 1;
@Getter @Setter private int exp;
@Getter @Setter private int promoteLevel;
@Getter @Setter private int satiation; // Fullness
@Getter @Setter private int satiationPenalty; // When eating too much
@Getter @Setter private float currentHp;
@Transient
@Getter
private final Int2ObjectMap<GameItem> equips;
@Transient
@Getter
private final Int2FloatOpenHashMap fightProperties;
@Transient
@Getter
private final Int2FloatOpenHashMap fightPropOverrides;
@Id
private ObjectId id;
@Indexed
@Getter
private int ownerId; // Id of player that this avatar belongs to
@Transient
private Player owner;
@Transient
@Getter
private AvatarData data;
@Transient
@Getter
private AvatarSkillDepotData skillDepot;
@Transient
@Getter
private long guid; // Player unique id
@Getter
private int avatarId; // Id of avatar
@Getter
@Setter
private int level = 1;
@Getter
@Setter
private int exp;
@Getter
@Setter
private int promoteLevel;
@Getter
@Setter
private int satiation; // Fullness
@Getter
@Setter
private int satiationPenalty; // When eating too much
@Getter
@Setter
private float currentHp;
private float currentEnergy;
@Transient @Getter private final Int2ObjectMap<GameItem> equips;
@Transient @Getter private final Int2FloatOpenHashMap fightProperties;
@Transient @Getter private final Int2FloatOpenHashMap fightPropOverrides;
@Transient @Getter private Set<String> extraAbilityEmbryos;
@Transient
@Getter
private Set<String> extraAbilityEmbryos;
private List<Integer> fetters;
private Map<Integer, Integer> skillLevelMap = new Int2IntArrayMap(7); // Talent levels
@Transient @Getter private Map<Integer, Integer> skillExtraChargeMap = new Int2IntArrayMap(2); // Charges
@Transient private Map<Integer, Integer> proudSkillBonusMap = new Int2IntArrayMap(2); // Talent bonus levels (from const)
@Getter private int skillDepotId;
private final Map<Integer, Integer> skillLevelMap = new Int2IntArrayMap(7); // Talent levels
@Transient
@Getter
private final Map<Integer, Integer> skillExtraChargeMap = new Int2IntArrayMap(2); // Charges
@Transient
private final Map<Integer, Integer> proudSkillBonusMap = new Int2IntArrayMap(2); // Talent bonus levels (from const)
@Getter
private int skillDepotId;
private Set<Integer> talentIdList; // Constellation id list
@Getter private Set<Integer> proudSkillList; // Character passives
@Getter
private Set<Integer> proudSkillList; // Character passives
@Getter @Setter private int flyCloak;
@Getter @Setter private int costume;
@Getter private int bornTime;
@Getter
@Setter
private int flyCloak;
@Getter
@Setter
private int costume;
@Getter
private int bornTime;
@Getter @Setter private int fetterLevel = 1;
@Getter @Setter private int fetterExp;
@Getter
@Setter
private int fetterLevel = 1;
@Getter
@Setter
private int fetterExp;
@Getter @Setter private int nameCardRewardId;
@Getter @Setter private int nameCardId;
@Getter
@Setter
private int nameCardRewardId;
@Getter
@Setter
private int nameCardId;
@Deprecated // Do not use. Morhpia only!
public Avatar() {
@@ -149,10 +161,8 @@ public class Avatar {
this.setSkillDepotData(switch (this.avatarId) {
case GameConstants.MAIN_CHARACTER_MALE ->
GameData.getAvatarSkillDepotDataMap().get(504); // Hack to start with anemo skills
case GameConstants.MAIN_CHARACTER_FEMALE ->
GameData.getAvatarSkillDepotDataMap().get(704);
default ->
data.getSkillDepot();
case GameConstants.MAIN_CHARACTER_FEMALE -> GameData.getAvatarSkillDepotDataMap().get(704);
default -> data.getSkillDepot();
});
// Set stats
@@ -164,6 +174,23 @@ public class Avatar {
this.onLoad();
}
static public int getMinPromoteLevel(int level) {
if (level > 80) {
return 6;
} else if (level > 70) {
return 5;
} else if (level > 60) {
return 4;
} else if (level > 50) {
return 3;
} else if (level > 40) {
return 2;
} else if (level > 20) {
return 1;
}
return 0;
}
public Player getPlayer() {
return this.owner;
}
@@ -187,23 +214,6 @@ public class Avatar {
this.guid = player.getNextGameGuid();
}
static public int getMinPromoteLevel(int level) {
if (level > 80) {
return 6;
} else if (level > 70) {
return 5;
} else if (level > 60) {
return 4;
} else if (level > 50) {
return 3;
} else if (level > 40) {
return 2;
} else if (level > 20) {
return 1;
}
return 0;
}
public boolean addSatiation(int value) {
if (this.satiation >= 10000) return false;
this.satiation += value;
@@ -213,7 +223,7 @@ public class Avatar {
public float reduceSatiation(int value) {
if (this.satiation == 0) return 0;
this.satiation -= value;
if(this.satiation < 0) {
if (this.satiation < 0) {
this.satiation = 0;
}
return this.satiation;
@@ -222,7 +232,7 @@ public class Avatar {
public float reduceSatiationPenalty(int value) {
if (this.satiationPenalty == 0) return 0;
this.satiationPenalty -= value;
if(this.satiationPenalty < 0) {
if (this.satiationPenalty < 0) {
this.satiationPenalty = 0;
}
return this.satiationPenalty;
@@ -263,14 +273,14 @@ public class Avatar {
this.recalcStats();
}
public void setFetterList(List<Integer> fetterList) {
this.fetters = fetterList;
}
public List<Integer> getFetterList() {
return fetters;
}
public void setFetterList(List<Integer> fetterList) {
this.fetters = fetterList;
}
public void setCurrentEnergy() {
if (GAME_OPTIONS.energyUsage) {
this.setCurrentEnergy(this.currentEnergy);
@@ -591,7 +601,7 @@ public class Avatar {
.map(AvatarTalentData::getOpenConfig)
.filter(Objects::nonNull)
.forEach(this::addToExtraAbilityEmbryos);
// Add any skill strings from this constellation
// Add any skill strings from this constellation
// Set % stats
FightProperty.forEachCompoundProperty(c -> this.setFightProperty(c.getResult(),
@@ -724,7 +734,7 @@ public class Avatar {
}
private int addProudSkillLevelBonus(int proudSkillGroupId, int bonus) {
return this.proudSkillBonusMap.compute(proudSkillGroupId, (k,v) -> (v==null) ? bonus : v + bonus);
return this.proudSkillBonusMap.compute(proudSkillGroupId, (k, v) -> (v == null) ? bonus : v + bonus);
}
public boolean upgradeSkill(int skillId) {
@@ -771,14 +781,17 @@ public class Avatar {
public boolean unlockConstellation() {
return this.unlockConstellation(false);
}
public boolean unlockConstellation(boolean skipPayment) {
int currentTalentLevel = this.getCoreProudSkillLevel();
int talentId = this.skillDepot.getTalents().get(currentTalentLevel);
return this.unlockConstellation(talentId, skipPayment);
}
public boolean unlockConstellation(int talentId) {
return unlockConstellation(talentId, false);
}
public boolean unlockConstellation(int talentId, boolean skipPayment) {
// Get talent
AvatarTalentData talentData = GameData.getAvatarTalentDataMap().get(talentId);
@@ -852,7 +865,7 @@ public class Avatar {
public AvatarInfo toProto() {
int fetterLevel = this.getFetterLevel();
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
.setExpLevel(fetterLevel);
.setExpLevel(fetterLevel);
if (fetterLevel != 10) {
avatarFetter.setExpNumber(this.getFetterExp());
@@ -873,21 +886,21 @@ public class Avatar {
}
AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder()
.setAvatarId(this.getAvatarId())
.setGuid(this.getGuid())
.setLifeState(1)
.addAllTalentIdList(this.getTalentIdList())
.putAllFightPropMap(this.getFightProperties())
.setSkillDepotId(this.getSkillDepotId())
.setCoreProudSkillLevel(this.getCoreProudSkillLevel())
.putAllSkillLevelMap(this.getSkillLevelMap())
.addAllInherentProudSkillList(this.getProudSkillList())
.putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap())
.setAvatarType(1)
.setBornTime(this.getBornTime())
.setFetterInfo(avatarFetter)
.setWearingFlycloakId(this.getFlyCloak())
.setCostumeId(this.getCostume());
.setAvatarId(this.getAvatarId())
.setGuid(this.getGuid())
.setLifeState(1)
.addAllTalentIdList(this.getTalentIdList())
.putAllFightPropMap(this.getFightProperties())
.setSkillDepotId(this.getSkillDepotId())
.setCoreProudSkillLevel(this.getCoreProudSkillLevel())
.putAllSkillLevelMap(this.getSkillLevelMap())
.addAllInherentProudSkillList(this.getProudSkillList())
.putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap())
.setAvatarType(1)
.setBornTime(this.getBornTime())
.setFetterInfo(avatarFetter)
.setWearingFlycloakId(this.getFlyCloak())
.setCostumeId(this.getCostume());
this.getSkillExtraChargeMap().forEach((skillId, count) ->
avatarInfo.putSkillMap(skillId, AvatarSkillInfo.newBuilder().setMaxChargeCount(count).build()));
@@ -906,19 +919,19 @@ public class Avatar {
// used only in character showcase
public ShowAvatarInfo toShowAvatarInfoProto() {
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
.setExpLevel(this.getFetterLevel());
.setExpLevel(this.getFetterLevel());
ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder()
.setAvatarId(avatarId)
.addAllTalentIdList(this.getTalentIdList())
.putAllFightPropMap(this.getFightProperties())
.setSkillDepotId(this.getSkillDepotId())
.setCoreProudSkillLevel(this.getCoreProudSkillLevel())
.addAllInherentProudSkillList(this.getProudSkillList())
.putAllSkillLevelMap(this.getSkillLevelMap())
.putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap())
.setFetterInfo(avatarFetter)
.setCostumeId(this.getCostume());
.setAvatarId(avatarId)
.addAllTalentIdList(this.getTalentIdList())
.putAllFightPropMap(this.getFightProperties())
.setSkillDepotId(this.getSkillDepotId())
.setCoreProudSkillLevel(this.getCoreProudSkillLevel())
.addAllInherentProudSkillList(this.getProudSkillList())
.putAllSkillLevelMap(this.getSkillLevelMap())
.putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap())
.setFetterInfo(avatarFetter)
.setCostumeId(this.getCostume());
showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel()));
showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp()));
@@ -931,12 +944,12 @@ public class Avatar {
for (GameItem item : this.getEquips().values()) {
if (item.getItemType() == ItemType.ITEM_RELIQUARY) {
showAvatarInfo.addEquipList(ShowEquip.newBuilder()
.setItemId(item.getItemId())
.setReliquary(item.toReliquaryProto()));
.setItemId(item.getItemId())
.setReliquary(item.toReliquaryProto()));
} else if (item.getItemType() == ItemType.ITEM_WEAPON) {
showAvatarInfo.addEquipList(ShowEquip.newBuilder()
.setItemId(item.getItemId())
.setWeapon(item.toWeaponProto()));
.setItemId(item.getItemId())
.setWeapon(item.toWeaponProto()));
}
}

View File

@@ -1,8 +1,5 @@
package emu.grasscutter.game.avatar;
import java.util.Iterator;
import java.util.List;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.data.excels.AvatarSkillDepotData;
@@ -18,6 +15,9 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.Iterator;
import java.util.List;
public class AvatarStorage extends BasePlayerManager implements Iterable<Avatar> {
private final Int2ObjectMap<Avatar> avatars;
private final Long2ObjectMap<Avatar> avatarsGuid;

View File

@@ -1,17 +1,5 @@
package emu.grasscutter.game.battlepass;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
@@ -32,32 +20,50 @@ import emu.grasscutter.game.props.BattlePassMissionStatus;
import emu.grasscutter.game.props.ItemUseOp;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.proto.BattlePassCycleOuterClass.BattlePassCycle;
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption;
import emu.grasscutter.net.proto.BattlePassScheduleOuterClass.BattlePassSchedule;
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
import emu.grasscutter.server.packet.send.PacketBattlePassCurScheduleUpdateNotify;
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp;
import lombok.Getter;
import org.bson.types.ObjectId;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Entity(value = "battlepass", useDiscriminator = false)
public class BattlePassManager extends BasePlayerDataManager {
@Id @Getter private ObjectId id;
@Id
@Getter
private ObjectId id;
@Indexed private int ownerUid;
@Getter private int point;
@Getter private int cyclePoints; // Weekly maximum cap
@Getter private int level;
@Indexed
private int ownerUid;
@Getter
private int point;
@Getter
private int cyclePoints; // Weekly maximum cap
@Getter
private int level;
@Getter private boolean viewed;
@Getter
private boolean viewed;
private boolean paid;
private Map<Integer, BattlePassMission> missions;
private Map<Integer, BattlePassReward> takenRewards;
@Deprecated // Morphia only
public BattlePassManager() {}
public BattlePassManager() {
}
public BattlePassManager(Player player) {
super(player);
@@ -219,8 +225,7 @@ public class BattlePassManager extends BasePlayerDataManager {
GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(r.getItemId()), r.getItemCount());
rewardItems.add(rewardItem);
}
}
else {
} else {
Grasscutter.getLogger().error("Invalid chest type for BP reward.");
}
}
@@ -246,8 +251,7 @@ public class BattlePassManager extends BasePlayerDataManager {
rewardList.add(option);
} else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) {
rewardList.add(option);
}
else {
} else {
Grasscutter.getLogger().info("Not in rewards list: {}", option.getTag().getRewardId());
}
}
@@ -360,20 +364,20 @@ public class BattlePassManager extends BasePlayerDataManager {
var nextSundayTime = LocalDateTime.of(nextSundayDate.getYear(), nextSundayDate.getMonthValue(), nextSundayDate.getDayOfMonth(), 23, 59, 59);
BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder()
.setScheduleId(2700)
.setLevel(this.getLevel())
.setPoint(this.getPoint())
.setScheduleId(2700)
.setLevel(this.getLevel())
.setPoint(this.getPoint())
.setBeginTime(0)
.setEndTime(2059483200)
.setIsViewed(this.isViewed())
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
.setPaidPlatformFlags(2) // Not bought on Playstation.
.setCurCyclePoints(this.getCyclePoints())
.setCurCycle(BattlePassCycle.newBuilder()
.setBeginTime(0)
.setEndTime(2059483200)
.setIsViewed(this.isViewed())
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
.setPaidPlatformFlags(2) // Not bought on Playstation.
.setCurCyclePoints(this.getCyclePoints())
.setCurCycle(BattlePassCycle.newBuilder()
.setBeginTime(0)
.setEndTime((int)nextSundayTime.atZone(ZoneId.systemDefault()).toEpochSecond())
.setCycleIdx(3)
);
.setEndTime((int) nextSundayTime.atZone(ZoneId.systemDefault()).toEpochSecond())
.setCycleIdx(3)
);
for (BattlePassReward reward : getTakenRewards().values()) {
schedule.addRewardTakenList(reward.toProto());

View File

@@ -8,67 +8,68 @@ import emu.grasscutter.game.props.BattlePassMissionStatus;
@Entity
public class BattlePassMission {
private int id;
private int progress;
private BattlePassMissionStatus status;
@Transient
private BattlePassMissionData data;
@Deprecated // Morphia only
public BattlePassMission() {}
public BattlePassMission(int id) {
this.id = id;
}
private int id;
private int progress;
private BattlePassMissionStatus status;
public int getId() {
return id;
}
@Transient
private BattlePassMissionData data;
public BattlePassMissionData getData() {
if (this.data == null) {
this.data = GameData.getBattlePassMissionDataMap().get(getId());
}
return this.data;
}
@Deprecated // Morphia only
public BattlePassMission() {
}
public int getProgress() {
return progress;
}
public BattlePassMission(int id) {
this.id = id;
}
public void setProgress(int value) {
this.progress = value;
}
public int getId() {
return id;
}
public void addProgress(int addProgress, int maxProgress) {
this.progress = Math.min(addProgress + this.progress, maxProgress);
}
public BattlePassMissionData getData() {
if (this.data == null) {
this.data = GameData.getBattlePassMissionDataMap().get(getId());
}
return this.data;
}
public BattlePassMissionStatus getStatus() {
if (status == null) status = BattlePassMissionStatus.MISSION_STATUS_UNFINISHED;
return status;
}
public int getProgress() {
return progress;
}
public void setStatus(BattlePassMissionStatus status) {
this.status = status;
}
public void setProgress(int value) {
this.progress = value;
}
public boolean isFinshed() {
return getStatus().getValue() >= 2;
}
public void addProgress(int addProgress, int maxProgress) {
this.progress = Math.min(addProgress + this.progress, maxProgress);
}
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
protoBuilder
.setMissionId(getId())
.setCurProgress(getProgress())
.setTotalProgress(getData().getProgress())
.setRewardBattlePassPoint(getData().getAddPoint())
.setMissionStatus(getStatus().getMissionStatus())
.setMissionType(getData().getRefreshType() == null ? 0 : getData().getRefreshType().getValue());
return protoBuilder.build();
}
public BattlePassMissionStatus getStatus() {
if (status == null) status = BattlePassMissionStatus.MISSION_STATUS_UNFINISHED;
return status;
}
public void setStatus(BattlePassMissionStatus status) {
this.status = status;
}
public boolean isFinshed() {
return getStatus().getValue() >= 2;
}
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
protoBuilder
.setMissionId(getId())
.setCurProgress(getProgress())
.setTotalProgress(getData().getProgress())
.setRewardBattlePassPoint(getData().getAddPoint())
.setMissionStatus(getStatus().getMissionStatus())
.setMissionType(getData().getRefreshType() == null ? 0 : getData().getRefreshType().getValue());
return protoBuilder.build();
}
}

View File

@@ -2,51 +2,49 @@ package emu.grasscutter.game.battlepass;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.BattlePassMissionData;
import emu.grasscutter.data.excels.BattlePassRewardData;
import emu.grasscutter.game.props.BattlePassMissionStatus;
import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag;
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
@Entity
public class BattlePassReward {
private int level;
private int rewardId;
private boolean paid;
private int level;
private int rewardId;
private boolean paid;
@Transient
private BattlePassMissionData data;
@Deprecated // Morphia only
public BattlePassReward() {}
public BattlePassReward(int level, int rewardId, boolean paid) {
this.level = level;
this.rewardId = rewardId;
this.paid = paid;
}
@Transient
private BattlePassMissionData data;
public int getLevel() {
return level;
}
@Deprecated // Morphia only
public BattlePassReward() {
}
public int getRewardId() {
return rewardId;
}
public BattlePassReward(int level, int rewardId, boolean paid) {
this.level = level;
this.rewardId = rewardId;
this.paid = paid;
}
public boolean isPaid() {
return paid;
}
public int getLevel() {
return level;
}
public BattlePassRewardTag toProto() {
var protoBuilder = BattlePassRewardTag.newBuilder();
protoBuilder
.setLevel(this.getLevel())
.setRewardId(this.getRewardId())
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE);
return protoBuilder.build();
}
public int getRewardId() {
return rewardId;
}
public boolean isPaid() {
return paid;
}
public BattlePassRewardTag toProto() {
var protoBuilder = BattlePassRewardTag.newBuilder();
protoBuilder
.setLevel(this.getLevel())
.setRewardId(this.getRewardId())
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE);
return protoBuilder.build();
}
}

View File

@@ -1,20 +1,19 @@
package emu.grasscutter.game.battlepass;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.BattlePassMissionData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
import emu.grasscutter.game.props.BattlePassMissionStatus;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.server.game.BaseGameSystem;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BattlePassSystem extends BaseGameSystem {
private final Map<WatcherTriggerType, List<BattlePassMissionData>> cachedTriggers;

View File

@@ -11,14 +11,13 @@ import emu.grasscutter.server.packet.send.PacketPullPrivateChatRsp;
import emu.grasscutter.server.packet.send.PacketPullRecentChatRsp;
import emu.grasscutter.utils.Utils;
import java.util.regex.Pattern;
import static emu.grasscutter.config.Configuration.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static emu.grasscutter.config.Configuration.GAME_INFO;
public class ChatSystem implements ChatSystemHandler {
static final String PREFIXES = "[/!]";
@@ -52,8 +51,8 @@ public class ChatSystem implements ChatSystemHandler {
********************/
private void putInHistory(int uid, int partnerId, ChatInfo info) {
this.history.computeIfAbsent(uid, x -> new HashMap<>())
.computeIfAbsent(partnerId, x -> new ArrayList<>())
.add(info);
.computeIfAbsent(partnerId, x -> new ArrayList<>())
.add(info);
}
public void clearHistoryOnLogout(Player player) {
@@ -62,7 +61,7 @@ public class ChatSystem implements ChatSystemHandler {
public void handlePullPrivateChatReq(Player player, int partnerId) {
var chatHistory = this.history.computeIfAbsent(player.getUid(), x -> new HashMap<>())
.computeIfAbsent(partnerId, x -> new ArrayList<>());
.computeIfAbsent(partnerId, x -> new ArrayList<>());
player.sendPacket(new PacketPullPrivateChatRsp(chatHistory));
}
@@ -102,6 +101,7 @@ public class ChatSystem implements ChatSystemHandler {
// Send.
target.sendPacket(packet);
}
public void sendPrivateMessageFromServer(int targetUid, int emote) {
// Get target.
Player target = getServer().getPlayerByUid(targetUid);
@@ -181,6 +181,7 @@ public class ChatSystem implements ChatSystemHandler {
// Create and send chat packet
player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, message));
}
public void sendTeamMessage(Player player, int channel, int icon) {
// Create and send chat packet
player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, icon));

View File

@@ -5,13 +5,22 @@ import emu.grasscutter.server.game.GameServer;
public interface ChatSystemHandler {
GameServer getServer();
void sendPrivateMessage(Player player, int targetUid, String message);
void sendPrivateMessage(Player player, int targetUid, int emote);
void sendTeamMessage(Player player, int channel, String message);
void sendTeamMessage(Player player, int channel, int icon);
void sendPrivateMessageFromServer(int targetUid, String message);
void sendPrivateMessageFromServer(int targetUid, int emote);
void handlePullPrivateChatReq(Player player, int targetUid);
void clearHistoryOnLogout(Player player);
void handlePullRecentChatReq(Player player);
}

View File

@@ -36,8 +36,7 @@ public class CombineManger extends BaseGameSystem {
reliquaryDecomposeData.put(entry.getConfigId(), entry.getItems());
});
Grasscutter.getLogger().debug("Loaded {} reliquary decompose entries.", reliquaryDecomposeData.size());
}
catch (Exception ex) {
} catch (Exception ex) {
Grasscutter.getLogger().error("Unable to load reliquary decompose data.", ex);
}
}
@@ -77,12 +76,12 @@ public class CombineManger extends BaseGameSystem {
// make the result
player.getInventory().addItem(combineData.getResultItemId(),
combineData.getResultItemCount() * count);
combineData.getResultItemCount() * count);
CombineResult result = new CombineResult();
result.setMaterial(List.of());
result.setResult(List.of(new ItemParamData(combineData.getResultItemId(),
combineData.getResultItemCount() * count)));
combineData.getResultItemCount() * count)));
// TODO lucky characters
result.setExtra(List.of());
result.setBack(List.of());

View File

@@ -1,9 +1,8 @@
package emu.grasscutter.game.combine;
import java.util.List;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.excels.CombineData;
import java.util.List;
public class CombineResult {
private List<ItemParamData> material;

View File

@@ -9,6 +9,7 @@ public class ReliquaryDecomposeEntry {
public int getConfigId() {
return configId;
}
public void setConfigId(int configId) {
this.configId = configId;
}
@@ -16,7 +17,8 @@ public class ReliquaryDecomposeEntry {
public List<Integer> getItems() {
return items;
}
public void setItems(List<Integer> items) {
this.items = items;
}
}
}

View File

@@ -3,6 +3,9 @@ package emu.grasscutter.game.drop;
import java.util.List;
public class DropInfo {
private int monsterId;
private List<DropData> dropDataList;
public int getMonsterId() {
return monsterId;
}
@@ -10,7 +13,4 @@ public class DropInfo {
public List<DropData> getDropDataList() {
return dropDataList;
}
private int monsterId;
private List<DropData> dropDataList;
}

View File

@@ -49,6 +49,7 @@ public class DropSystem extends BaseGameSystem {
Grasscutter.getLogger().error("Unable to load drop data.", e);
}
}
private void addDropEntity(DropData dd, Scene dropScene, ItemData itemData, Position pos, int num, Player target) {
if (!dd.isGive() && (itemData.getItemType() != ItemType.ITEM_VIRTUAL || itemData.getGadgetId() != 0)) {
EntityItem entity = new EntityItem(dropScene, target, itemData, pos, num, dd.isShare());

View File

@@ -3,20 +3,22 @@ package emu.grasscutter.game.dungeons;
import java.util.List;
public class DungeonDrop {
private int dungeonId;
private List<DungeonDropEntry> drops;
private int dungeonId;
private List<DungeonDropEntry> drops;
public int getDungeonId() {
return dungeonId;
}
public void setDungeonId(int dungeonId) {
this.dungeonId = dungeonId;
}
public List<DungeonDropEntry> getDrops() {
return drops;
}
public void setDrops(List<DungeonDropEntry> drops) {
this.drops = drops;
}
public int getDungeonId() {
return dungeonId;
}
public void setDungeonId(int dungeonId) {
this.dungeonId = dungeonId;
}
public List<DungeonDropEntry> getDrops() {
return drops;
}
public void setDrops(List<DungeonDropEntry> drops) {
this.drops = drops;
}
}

View File

@@ -3,44 +3,49 @@ package emu.grasscutter.game.dungeons;
import java.util.List;
public class DungeonDropEntry {
private List<Integer> counts;
private List<Integer> items;
private List<Integer> probabilities;
private List<Integer> itemProbabilities;
private boolean mpDouble;
private List<Integer> counts;
private List<Integer> items;
private List<Integer> probabilities;
private List<Integer> itemProbabilities;
private boolean mpDouble;
public List<Integer> getCounts() {
return counts;
}
public void setCounts(List<Integer> counts) {
this.counts = counts;
}
public List<Integer> getItems() {
return items;
}
public void setItems(List<Integer> items) {
this.items = items;
}
public List<Integer> getCounts() {
return counts;
}
public List<Integer> getProbabilities() {
return probabilities;
}
public void setProbabilities(List<Integer> probabilities) {
this.probabilities = probabilities;
}
public void setCounts(List<Integer> counts) {
this.counts = counts;
}
public List<Integer> getItemProbabilities() {
return itemProbabilities;
}
public void setItemProbabilities(List<Integer> itemProbabilities) {
this.itemProbabilities = itemProbabilities;
}
public List<Integer> getItems() {
return items;
}
public boolean isMpDouble() {
return mpDouble;
}
public void setMpDouble(boolean mpDouble) {
this.mpDouble = mpDouble;
}
public void setItems(List<Integer> items) {
this.items = items;
}
public List<Integer> getProbabilities() {
return probabilities;
}
public void setProbabilities(List<Integer> probabilities) {
this.probabilities = probabilities;
}
public List<Integer> getItemProbabilities() {
return itemProbabilities;
}
public void setItemProbabilities(List<Integer> itemProbabilities) {
this.itemProbabilities = itemProbabilities;
}
public boolean isMpDouble() {
return mpDouble;
}
public void setMpDouble(boolean mpDouble) {
this.mpDouble = mpDouble;
}
}

View File

@@ -44,7 +44,7 @@ public class DungeonSystem extends BaseGameSystem {
if (data == null) {
return false;
}
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}", player.getNickname(), player.getUid(), dungeonId);
int sceneId = data.getSceneId();
player.getScene().setPrevScene(sceneId);
@@ -68,7 +68,7 @@ public class DungeonSystem extends BaseGameSystem {
if (data == null) {
return false;
}
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}", player.getNickname(), player.getUid(), dungeonId);
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
@@ -79,7 +79,7 @@ public class DungeonSystem extends BaseGameSystem {
public void exitDungeon(Player player) {
Scene scene = player.getScene();
if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
return;
}

View File

@@ -9,8 +9,8 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
if(scene.getScriptManager().getVariables().containsKey("stage")
&& scene.getScriptManager().getVariables().get("stage") == 1){
if (scene.getScriptManager().getVariables().containsKey("stage")
&& scene.getScriptManager().getVariables().get("stage") == 1) {
return;
}
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
@@ -18,17 +18,17 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
towerManager.notifyCurLevelRecordChangeWhenDone(3);
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(
towerManager.getCurrentFloorId(),
3,
towerManager.canEnterScheduleFloor()
towerManager.getCurrentFloorId(),
3,
towerManager.canEnterScheduleFloor()
));
scene.broadcastPacket(new PacketDungeonSettleNotify(
scene.getChallenge(),
towerManager.hasNextFloor(),
towerManager.hasNextLevel(),
towerManager.hasNextLevel() ? 0 : towerManager.getNextFloorId()
));
scene.getChallenge(),
towerManager.hasNextFloor(),
towerManager.hasNextLevel(),
towerManager.hasNextLevel() ? 0 : towerManager.getNextFloorId()
));
}
}

View File

@@ -31,27 +31,13 @@ import java.util.stream.IntStream;
public class DungeonChallenge extends WorldChallenge {
private final static Int2ObjectMap<List<DungeonDropEntry>> dungeonDropData = new Int2ObjectOpenHashMap<>();
/**
* has more challenge
*/
private boolean stage;
private IntSet rewardedPlayers;
private final static Int2ObjectMap<List<DungeonDropEntry>> dungeonDropData = new Int2ObjectOpenHashMap<>();
public static void initialize() {
// Read the data we need for dungeon rewards drops.
try {
DataLoader.loadList("DungeonDrop.json", DungeonDrop.class).forEach(entry -> {
dungeonDropData.put(entry.getDungeonId(), entry.getDrops());
});
Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size());
}
catch (Exception ex) {
Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex);
}
}
public DungeonChallenge(Scene scene, SceneGroup group,
int challengeId, int challengeIndex,
List<Integer> paramList,
@@ -61,6 +47,18 @@ public class DungeonChallenge extends WorldChallenge {
this.setRewardedPlayers(new IntOpenHashSet());
}
public static void initialize() {
// Read the data we need for dungeon rewards drops.
try {
DataLoader.loadList("DungeonDrop.json", DungeonDrop.class).forEach(entry -> {
dungeonDropData.put(entry.getDungeonId(), entry.getDrops());
});
Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size());
} catch (Exception ex) {
Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex);
}
}
public boolean isStage() {
return stage;
}
@@ -91,7 +89,7 @@ public class DungeonChallenge extends WorldChallenge {
var scene = this.getScene();
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(getScene()));
scene.getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
new ScriptArgs(this.isSuccess() ? 1 : 0));
new ScriptArgs(this.isSuccess() ? 1 : 0));
// Battle pass trigger
scene.getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
}
@@ -129,8 +127,7 @@ public class DungeonChallenge extends WorldChallenge {
// for the currently existing set of dungeons.
if (entry.getItems().size() == 1) {
rewards.add(new GameItem(entry.getItems().get(0), amount));
}
else {
} else {
for (int i = 0; i < amount; i++) {
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
// int itemId = entry.getItems().get(itemIndex);
@@ -180,8 +177,7 @@ public class DungeonChallenge extends WorldChallenge {
// Roll rewards.
rewards.addAll(this.rollRewards(true));
}
else {
} else {
// Spend the resin and only proceed if the transaction succeeds.
if (!player.getResinManager().useResin(resinCost)) return;

View File

@@ -26,17 +26,17 @@ public class WorldChallenge {
private final List<Integer> paramList;
private final int timeLimit;
private final List<ChallengeTrigger> challengeTriggers;
private final int goal;
private final AtomicInteger score;
private boolean progress;
private boolean success;
private long startedAt;
private int finishedTime;
private final int goal;
private final AtomicInteger score;
public WorldChallenge(Scene scene, SceneGroup group,
int challengeId, int challengeIndex, List<Integer> paramList,
int timeLimit, int goal,
List<ChallengeTrigger> challengeTriggers){
List<ChallengeTrigger> challengeTriggers) {
this.scene = scene;
this.group = group;
this.challengeId = challengeId;
@@ -47,20 +47,23 @@ public class WorldChallenge {
this.goal = goal;
this.score = new AtomicInteger(0);
}
public boolean inProgress(){
public boolean inProgress() {
return this.progress;
}
public void onCheckTimeOut(){
if(!inProgress()){
public void onCheckTimeOut() {
if (!inProgress()) {
return;
}
if(timeLimit <= 0){
if (timeLimit <= 0) {
return;
}
challengeTriggers.forEach(t -> t.onCheckTimeout(this));
}
public void start(){
if(inProgress()){
public void start() {
if (inProgress()) {
Grasscutter.getLogger().info("Could not start a in progress challenge.");
return;
}
@@ -70,20 +73,20 @@ public class WorldChallenge {
challengeTriggers.forEach(t -> t.onBegin(this));
}
public void done(){
if(!inProgress()){
public void done() {
if (!inProgress()) {
return;
}
finish(true);
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS,
// TODO record the time in PARAM2 and used in action
new ScriptArgs().setParam2(finishedTime));
// TODO record the time in PARAM2 and used in action
new ScriptArgs().setParam2(finishedTime));
challengeTriggers.forEach(t -> t.onFinish(this));
}
public void fail(){
if(!inProgress()){
public void fail() {
if (!inProgress()) {
return;
}
finish(false);
@@ -91,40 +94,42 @@ public class WorldChallenge {
challengeTriggers.forEach(t -> t.onFinish(this));
}
private void finish(boolean success){
private void finish(boolean success) {
this.progress = false;
this.success = success;
this.finishedTime = (int)((System.currentTimeMillis() - this.startedAt) / 1000L);
this.finishedTime = (int) ((System.currentTimeMillis() - this.startedAt) / 1000L);
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
}
public int increaseScore(){
public int increaseScore() {
return score.incrementAndGet();
}
public void onMonsterDeath(EntityMonster monster){
if(!inProgress()){
public void onMonsterDeath(EntityMonster monster) {
if (!inProgress()) {
return;
}
if(monster.getGroupId() != getGroup().id){
if (monster.getGroupId() != getGroup().id) {
return;
}
this.challengeTriggers.forEach(t -> t.onMonsterDeath(this, monster));
}
public void onGadgetDeath(EntityGadget gadget){
if(!inProgress()){
public void onGadgetDeath(EntityGadget gadget) {
if (!inProgress()) {
return;
}
if(gadget.getGroupId() != getGroup().id){
if (gadget.getGroupId() != getGroup().id) {
return;
}
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
}
public void onGadgetDamage(EntityGadget gadget){
if(!inProgress()){
public void onGadgetDamage(EntityGadget gadget) {
if (!inProgress()) {
return;
}
if(gadget.getGroupId() != getGroup().id){
if (gadget.getGroupId() != getGroup().id) {
return;
}
this.challengeTriggers.forEach(t -> t.onGadgetDamage(this, gadget));

View File

@@ -18,9 +18,9 @@ public class ChallengeFactory {
challengeFactoryHandlers.add(new KillMonsterChallengeFactoryHandler());
}
public static WorldChallenge getChallenge(int param1, int param2, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group){
for(var handler : challengeFactoryHandlers){
if(!handler.isThisType(param1, param2, param3, param4, param5, param6, scene, group)){
public static WorldChallenge getChallenge(int param1, int param2, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
for (var handler : challengeFactoryHandlers) {
if (!handler.isThisType(param1, param2, param3, param4, param5, param6, scene, group)) {
continue;
}
return handler.build(param1, param2, param3, param4, param5, param6, scene, group);

View File

@@ -6,5 +6,6 @@ import emu.grasscutter.scripts.data.SceneGroup;
public interface ChallengeFactoryHandler {
boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group);
WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group);
}

View File

@@ -1,33 +1,33 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class DungeonChallengeFactoryHandler implements ChallengeFactoryHandler{
public class DungeonChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// ActiveChallenge with 1,1000,300,233101003,15,0
return scene.getSceneType() == SceneType.SCENE_DUNGEON
&& param4 == group.id;
&& param4 == group.id;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
var realGroup = scene.getScriptManager().getGroupById(param4);
return new DungeonChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param5, param3),
param3, // Limit
param5, // Goal
List.of(new InTimeTrigger(), new KillMonsterTrigger()));
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param5, param3),
param3, // Limit
param5, // Goal
List.of(new InTimeTrigger(), new KillMonsterTrigger()));
}
}

View File

@@ -3,32 +3,30 @@ package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class DungeonGuardChallengeFactoryHandler implements ChallengeFactoryHandler{
public class DungeonGuardChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// ActiveChallenge with 1,188,234101003,12,3030,0
return scene.getSceneType() == SceneType.SCENE_DUNGEON
&& param3 == group.id;
&& param3 == group.id;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
var realGroup = scene.getScriptManager().getGroupById(param3);
return new DungeonChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param4, 0),
0, // Limit
param4, // Goal
List.of(new GuardTrigger()));
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param4, 0),
0, // Limit
param4, // Goal
List.of(new GuardTrigger()));
}
}

View File

@@ -1,7 +1,6 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactoryHandler;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillGadgetTrigger;
import emu.grasscutter.game.world.Scene;
@@ -22,13 +21,13 @@ public class KillGadgetChallengeFactoryHandler implements ChallengeFactoryHandle
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
return new WorldChallenge(
scene, group,
challengeId, // Id
challengeIndex, // Index
List.of(param3, param6, 0),
param3, // Limit
param6, // Goal
List.of(new InTimeTrigger(), new KillGadgetTrigger())
);
scene, group,
challengeId, // Id
challengeIndex, // Index
List.of(param3, param6, 0),
param3, // Limit
param6, // Goal
List.of(new InTimeTrigger(), new KillGadgetTrigger())
);
}
}

View File

@@ -8,7 +8,7 @@ import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class KillMonsterChallengeFactoryHandler implements ChallengeFactoryHandler{
public class KillMonsterChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// ActiveChallenge with 180,180,45,133108061,1,0
@@ -19,13 +19,13 @@ public class KillMonsterChallengeFactoryHandler implements ChallengeFactoryHandl
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
var realGroup = scene.getScriptManager().getGroupById(param4);
return new WorldChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param5, param3),
param3, // Limit
param5, // Goal
List.of(new KillMonsterTrigger(), new InTimeTrigger())
);
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param5, param3),
param3, // Limit
param5, // Goal
List.of(new KillMonsterTrigger(), new InTimeTrigger())
);
}
}

View File

@@ -5,10 +5,21 @@ import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
public abstract class ChallengeTrigger {
public void onBegin(WorldChallenge challenge){}
public void onFinish(WorldChallenge challenge){}
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster){}
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget){}
public void onCheckTimeout(WorldChallenge challenge){}
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget){}
public void onBegin(WorldChallenge challenge) {
}
public void onFinish(WorldChallenge challenge) {
}
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
}
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) {
}
public void onCheckTimeout(WorldChallenge challenge) {
}
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
}
}

View File

@@ -2,11 +2,10 @@ package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
public class GuardTrigger extends KillMonsterTrigger{
public class GuardTrigger extends KillMonsterTrigger {
@Override
public void onBegin(WorldChallenge challenge) {
super.onBegin(challenge);
@@ -20,7 +19,7 @@ public class GuardTrigger extends KillMonsterTrigger{
int percent = (int) (curHp / maxHp);
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
if(percent <= 0){
if (percent <= 0) {
challenge.fail();
}
}

View File

@@ -2,11 +2,11 @@ package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
public class InTimeTrigger extends ChallengeTrigger{
public class InTimeTrigger extends ChallengeTrigger {
@Override
public void onCheckTimeout(WorldChallenge challenge) {
var current = System.currentTimeMillis();
if(current - challenge.getStartedAt() > challenge.getTimeLimit() * 1000L){
if (current - challenge.getStartedAt() > challenge.getTimeLimit() * 1000L) {
challenge.fail();
}
}

View File

@@ -4,7 +4,7 @@ import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
public class KillGadgetTrigger extends ChallengeTrigger{
public class KillGadgetTrigger extends ChallengeTrigger {
@Override
public void onBegin(WorldChallenge challenge) {
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get()));
@@ -15,7 +15,7 @@ public class KillGadgetTrigger extends ChallengeTrigger{
var newScore = challenge.increaseScore();
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, newScore));
if(newScore >= challenge.getGoal()){
if (newScore >= challenge.getGoal()) {
challenge.done();
}

View File

@@ -4,7 +4,7 @@ import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
public class KillMonsterTrigger extends ChallengeTrigger{
public class KillMonsterTrigger extends ChallengeTrigger {
@Override
public void onBegin(WorldChallenge challenge) {
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
@@ -15,7 +15,7 @@ public class KillMonsterTrigger extends ChallengeTrigger{
var newScore = challenge.increaseScore();
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, newScore));
if(newScore >= challenge.getGoal()){
if (newScore >= challenge.getGoal()) {
challenge.done();
}

View File

@@ -41,10 +41,13 @@ import lombok.Getter;
import lombok.val;
public class EntityAvatar extends GameEntity {
@Getter private final Avatar avatar;
@Getter
private final Avatar avatar;
@Getter private PlayerDieType killedType;
@Getter private int killedBy;
@Getter
private PlayerDieType killedType;
@Getter
private int killedBy;
public EntityAvatar(Avatar avatar) {
this(null, avatar);
@@ -54,8 +57,7 @@ public class EntityAvatar extends GameEntity {
super(scene);
this.avatar = avatar;
this.avatar.setCurrentEnergy();
if (getScene() != null)
{
if (getScene() != null) {
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR);
GameItem weapon = getAvatar().getWeapon();
@@ -65,20 +67,29 @@ public class EntityAvatar extends GameEntity {
}
}
public Player getPlayer() {return this.avatar.getPlayer();}
public Player getPlayer() {
return this.avatar.getPlayer();
}
@Override
public Position getPosition() {return getPlayer().getPosition();}
public Position getPosition() {
return getPlayer().getPosition();
}
@Override
public Position getRotation() {return getPlayer().getRotation();}
public Position getRotation() {
return getPlayer().getRotation();
}
@Override
public boolean isAlive() {
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
}
@Override public Int2FloatMap getFightProperties() {return getAvatar().getFightProperties();}
@Override
public Int2FloatMap getFightProperties() {
return getAvatar().getFightProperties();
}
public int getWeaponEntityId() {
if (getAvatar().getWeapon() != null) {
@@ -141,6 +152,7 @@ public class EntityAvatar extends GameEntity {
public void addEnergy(float amount, PropChangeReason reason) {
this.addEnergy(amount, reason, false);
}
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
// Get current and maximum energy for this avatar.
val elementType = this.getAvatar().getSkillDepot().getElementType();
@@ -171,20 +183,20 @@ public class EntityAvatar extends GameEntity {
val avatar = this.getAvatar();
val player = this.getPlayer();
SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder()
.setUid(player.getUid())
.setAvatarId(avatar.getAvatarId())
.setGuid(avatar.getGuid())
.setPeerId(player.getPeerId())
.addAllTalentIdList(avatar.getTalentIdList())
.setCoreProudSkillLevel(avatar.getCoreProudSkillLevel())
.putAllSkillLevelMap(avatar.getSkillLevelMap())
.setSkillDepotId(avatar.getSkillDepotId())
.addAllInherentProudSkillList(avatar.getProudSkillList())
.putAllProudSkillExtraLevelMap(avatar.getProudSkillBonusMap())
.addAllTeamResonanceList(player.getTeamManager().getTeamResonances())
.setWearingFlycloakId(avatar.getFlyCloak())
.setCostumeId(avatar.getCostume())
.setBornTime(avatar.getBornTime());
.setUid(player.getUid())
.setAvatarId(avatar.getAvatarId())
.setGuid(avatar.getGuid())
.setPeerId(player.getPeerId())
.addAllTalentIdList(avatar.getTalentIdList())
.setCoreProudSkillLevel(avatar.getCoreProudSkillLevel())
.putAllSkillLevelMap(avatar.getSkillLevelMap())
.setSkillDepotId(avatar.getSkillDepotId())
.addAllInherentProudSkillList(avatar.getProudSkillList())
.putAllProudSkillExtraLevelMap(avatar.getProudSkillBonusMap())
.addAllTeamResonanceList(player.getTeamManager().getTeamResonances())
.setWearingFlycloakId(avatar.getFlyCloak())
.setCostumeId(avatar.getCostume())
.setBornTime(avatar.getBornTime());
for (GameItem item : avatar.getEquips().values()) {
if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) {
@@ -201,21 +213,21 @@ public class EntityAvatar extends GameEntity {
@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();
.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_AVATAR)
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority)
.setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs())
.setLastMoveReliableSeq(this.getLastMoveReliableSeq())
.setLifeState(this.getLifeState().getValue());
.setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR)
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority)
.setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs())
.setLastMoveReliableSeq(this.getLastMoveReliableSeq())
.setLifeState(this.getLifeState().getValue());
if (this.getScene() != null) {
entityInfo.setMotionInfo(this.getMotionInfo());
@@ -224,9 +236,9 @@ public class EntityAvatar extends GameEntity {
this.addAllFightPropsToEntityInfo(entityInfo);
PropPair pair = PropPair.newBuilder()
.setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel()))
.build();
.setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel()))
.build();
entityInfo.addPropList(pair);
entityInfo.setAvatar(this.getSceneAvatarInfo());
@@ -243,29 +255,29 @@ public class EntityAvatar extends GameEntity {
if (data.getAbilities() != null) {
for (int id : data.getAbilities()) {
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
abilityControlBlock.addAbilityEmbryoList(emb);
}
}
// Add default abilities
for (int id : GameConstants.DEFAULT_ABILITY_HASHES) {
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
abilityControlBlock.addAbilityEmbryoList(emb);
}
// Add team resonances
for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) {
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
abilityControlBlock.addAbilityEmbryoList(emb);
}
// Add skill depot abilities
@@ -273,10 +285,10 @@ public class EntityAvatar extends GameEntity {
if (skillDepot != null && skillDepot.getAbilities() != null) {
for (int id : skillDepot.getAbilities()) {
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
.setAbilityId(++embryoId)
.setAbilityNameHash(id)
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
abilityControlBlock.addAbilityEmbryoList(emb);
}
}
@@ -284,10 +296,10 @@ public class EntityAvatar extends GameEntity {
if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) {
for (String skill : this.getAvatar().getExtraAbilityEmbryos()) {
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
.setAbilityId(++embryoId)
.setAbilityNameHash(Utils.abilityHash(skill))
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
.setAbilityId(++embryoId)
.setAbilityNameHash(Utils.abilityHash(skill))
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
.build();
abilityControlBlock.addAbilityEmbryoList(emb);
}
}
@@ -299,15 +311,18 @@ public class EntityAvatar extends GameEntity {
/**
* Move this entity to a new position.
* Additionally invoke player move event.
*
* @param newPosition The new position.
* @param rotation The new rotation.
* @param rotation The new rotation.
*/
@Override public void move(Position newPosition, Position rotation) {
@Override
public void move(Position newPosition, Position rotation) {
// Invoke player move event.
PlayerMoveEvent event = new PlayerMoveEvent(
this.getPlayer(), PlayerMoveEvent.MoveType.PLAYER,
this.getPosition(), newPosition
); event.call();
);
event.call();
// Set position and rotation.
super.move(event.getDestination(), rotation);

View File

@@ -23,18 +23,25 @@ import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter;
public class EntityClientGadget extends EntityBaseGadget {
@Getter private final Player owner;
@Getter
private final Player owner;
@Getter(onMethod_ = @Override)
private int gadgetId;
private final int gadgetId;
@Getter private int campId;
@Getter private int campType;
@Getter private int ownerEntityId;
@Getter private int targetEntityId;
@Getter private boolean asyncLoad;
@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 int originalOwnerEntityId;
@Getter
private final int originalOwnerEntityId;
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles()));
@@ -50,8 +57,7 @@ public class EntityClientGadget extends EntityBaseGadget {
GameEntity owner = scene.getEntityById(this.ownerEntityId);
if (owner instanceof EntityClientGadget ownerGadget) {
this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId();
}
else {
} else {
this.originalOwnerEntityId = this.ownerEntityId;
}
}
@@ -61,47 +67,50 @@ public class EntityClientGadget extends EntityBaseGadget {
super.onDeath(killerId); // Invoke super class's onDeath() method.
}
@Override public Int2FloatMap getFightProperties() {return null;}
@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();
.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);
.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();
.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();
.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());
.setGadgetId(this.getGadgetId())
.setOwnerEntityId(this.getOwnerEntityId())
.setIsEnableInteract(true)
.setClientGadget(clientGadget)
.setPropOwnerEntityId(this.getOwnerEntityId())
.setAuthorityPeerId(this.getOwner().getPeerId());
entityInfo.setGadget(gadgetInfo);

View File

@@ -33,24 +33,32 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Optional;
import javax.annotation.Nullable;
import java.util.Optional;
@ToString(callSuper = true)
public class EntityGadget extends EntityBaseGadget {
@Getter private final GadgetData gadgetData;
@Getter(onMethod_ = @Override) @Setter
private int gadgetId;
@Getter @Setter private int state;
@Getter @Setter private int pointType;
@Getter private GadgetContent content;
@Getter
private final GadgetData gadgetData;
@Getter(onMethod_ = @Override, lazy = true)
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
@Getter @Setter private SceneGadget metaGadget;
@Nullable @Getter
private ConfigGadget configGadget;
@Getter(onMethod_ = @Override)
@Setter
private int gadgetId;
@Getter
@Setter
private int state;
@Getter
@Setter
private int pointType;
@Getter
private GadgetContent content;
@Getter
@Setter
private SceneGadget metaGadget;
@Nullable
@Getter
private final ConfigGadget configGadget;
public EntityGadget(Scene scene, int gadgetId, Position pos) {
this(scene, gadgetId, pos, null, null);
@@ -133,25 +141,25 @@ public class EntityGadget extends EntityBaseGadget {
@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();
.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);
.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();
.setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
.build();
entityInfo.addPropList(pair);
// We do not use the getter to null check because the getter will create a fight prop map if it is null
@@ -160,12 +168,12 @@ public class EntityGadget extends EntityBaseGadget {
}
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
.setGadgetId(this.getGadgetId())
.setGroupId(this.getGroupId())
.setConfigId(this.getConfigId())
.setGadgetState(this.getState())
.setIsEnableInteract(true)
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
.setGadgetId(this.getGadgetId())
.setGroupId(this.getGroupId())
.setConfigId(this.getConfigId())
.setGadgetState(this.getState())
.setIsEnableInteract(true)
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
if (this.metaGadget != null) {
gadgetInfo.setDraftId(this.metaGadget.draft_id);

View File

@@ -29,9 +29,12 @@ import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter;
public class EntityItem extends EntityBaseGadget {
@Getter private final GameItem item;
@Getter private final long guid;
@Getter private final boolean share;
@Getter
private final GameItem item;
@Getter
private final long guid;
@Getter
private final boolean share;
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) {
this(scene, player, itemData, pos, count, true);
@@ -61,7 +64,10 @@ public class EntityItem extends EntityBaseGadget {
return this.getItemData().getGadgetId();
}
@Override public Int2FloatMap getFightProperties() {return null;}
@Override
public Int2FloatMap getFightProperties() {
return null;
}
@Override
public void onInteract(Player player, GadgetInteractReq interactReq) {
@@ -90,33 +96,33 @@ public class EntityItem extends EntityBaseGadget {
@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();
.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);
.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();
.setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
.build();
entityInfo.addPropList(pair);
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
.setGadgetId(this.getItemData().getGadgetId())
.setTrifleItem(this.getItem().toProto())
.setBornType(GadgetBornType.GADGET_BORN_TYPE_IN_AIR)
.setAuthorityPeerId(this.getWorld().getHostPeerId())
.setIsEnableInteract(true);
.setGadgetId(this.getItemData().getGadgetId())
.setTrifleItem(this.getItem().toProto())
.setBornType(GadgetBornType.GADGET_BORN_TYPE_IN_AIR)
.setAuthorityPeerId(this.getWorld().getHostPeerId())
.setIsEnableInteract(true);
entityInfo.setGadget(gadgetInfo);

View File

@@ -1,18 +1,12 @@
package emu.grasscutter.game.entity;
import java.util.Optional;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.PropGrowCurve;
import emu.grasscutter.data.excels.EnvAnimalGatherConfigData;
import emu.grasscutter.data.excels.MonsterCurveData;
import emu.grasscutter.data.excels.MonsterData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.game.props.*;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
@@ -35,8 +29,11 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import lombok.Getter;
import lombok.Setter;
import java.util.Optional;
public class EntityMonster extends GameEntity {
@Getter private final MonsterData monsterData;
@Getter
private final MonsterData monsterData;
@Getter(onMethod_ = @Override)
private final Int2FloatOpenHashMap fightProperties;
@@ -44,11 +41,17 @@ public class EntityMonster extends GameEntity {
private final Position position;
@Getter(onMethod_ = @Override)
private final Position rotation;
@Getter private final Position bornPos;
@Getter private final int level;
@Getter
private final Position bornPos;
@Getter
private final int level;
private int weaponEntityId;
@Getter @Setter private int poseId;
@Getter @Setter private int aiId = -1;
@Getter
@Setter
private int poseId;
@Getter
@Setter
private int aiId = -1;
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
super(scene);
@@ -173,20 +176,20 @@ public class EntityMonster extends GameEntity {
@Override
public SceneEntityInfo toProto() {
var authority = EntityAuthorityInfo.newBuilder()
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
.setBornPos(this.getBornPos().toProto())
.build();
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
.setBornPos(this.getBornPos().toProto())
.build();
var entityInfo = SceneEntityInfo.newBuilder()
.setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
.setMotionInfo(this.getMotionInfo())
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority)
.setLifeState(this.getLifeState().getValue());
.setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
.setMotionInfo(this.getMotionInfo())
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority)
.setLifeState(this.getLifeState().getValue());
this.addAllFightPropsToEntityInfo(entityInfo);
@@ -196,15 +199,15 @@ public class EntityMonster extends GameEntity {
.build());
var monsterInfo = SceneMonsterInfo.newBuilder()
.setMonsterId(getMonsterId())
.setGroupId(this.getGroupId())
.setConfigId(this.getConfigId())
.addAllAffixList(getMonsterData().getAffix())
.setAuthorityPeerId(getWorld().getHostPeerId())
.setPoseId(this.getPoseId())
.setBlockId(3001)
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT)
.setSpecialNameId(40);
.setMonsterId(getMonsterId())
.setGroupId(this.getGroupId())
.setConfigId(this.getConfigId())
.addAllAffixList(getMonsterData().getAffix())
.setAuthorityPeerId(getWorld().getHostPeerId())
.setPoseId(this.getPoseId())
.setBlockId(3001)
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT)
.setSpecialNameId(40);
if (getMonsterData().getDescribeData() != null) {
monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleID());
@@ -212,14 +215,14 @@ public class EntityMonster extends GameEntity {
if (this.getMonsterWeaponId() > 0) {
SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder()
.setEntityId(this.weaponEntityId)
.setGadgetId(this.getMonsterWeaponId())
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.build();
.setEntityId(this.weaponEntityId)
.setGadgetId(this.getMonsterWeaponId())
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.build();
monsterInfo.addWeaponList(weaponInfo);
}
if (this.aiId!=-1) {
if (this.aiId != -1) {
monsterInfo.setAiConfigId(aiId);
}

View File

@@ -8,13 +8,14 @@ import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter;
public class EntityNPC extends GameEntity{
public class EntityNPC extends GameEntity {
@Getter(onMethod_ = @Override)
private final Position position;
@Getter(onMethod_ = @Override)
private final Position rotation;
private final SceneNPC metaNpc;
@Getter private final int suiteId;
@Getter
private final int suiteId;
public EntityNPC(Scene scene, SceneNPC metaNPC, int blockId, int suiteId) {
super(scene);
@@ -29,37 +30,40 @@ public class EntityNPC extends GameEntity{
}
@Override public Int2FloatMap getFightProperties() {return null;}
@Override
public Int2FloatMap getFightProperties() {
return null;
}
@Override
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
EntityAuthorityInfoOuterClass.EntityAuthorityInfo authority = EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
.setAbilityInfo(AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
.setIsAiOpen(true)
.setBornPos(getPosition().toProto()))
.setBornPos(getPosition().toProto())
.build();
EntityAuthorityInfoOuterClass.EntityAuthorityInfo authority = EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
.setAbilityInfo(AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
.setIsAiOpen(true)
.setBornPos(getPosition().toProto()))
.setBornPos(getPosition().toProto())
.build();
SceneEntityInfoOuterClass.SceneEntityInfo.Builder entityInfo = SceneEntityInfoOuterClass.SceneEntityInfo.newBuilder()
.setEntityId(getId())
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_NPC)
.setMotionInfo(MotionInfoOuterClass.MotionInfo.newBuilder()
.setPos(getPosition().toProto())
.setRot(getRotation().toProto())
.setSpeed(VectorOuterClass.Vector.newBuilder()))
.addAnimatorParaList(AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientDataOuterClass.EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority)
.setLifeState(1);
.setEntityId(getId())
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_NPC)
.setMotionInfo(MotionInfoOuterClass.MotionInfo.newBuilder()
.setPos(getPosition().toProto())
.setRot(getRotation().toProto())
.setSpeed(VectorOuterClass.Vector.newBuilder()))
.addAnimatorParaList(AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair.newBuilder())
.setEntityClientData(EntityClientDataOuterClass.EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority)
.setLifeState(1);
entityInfo.setNpc(SceneNpcInfoOuterClass.SceneNpcInfo.newBuilder()
.setNpcId(metaNpc.npc_id)
.setBlockId(getBlockId())
.build());
.setNpcId(metaNpc.npc_id)
.setBlockId(getBlockId())
.build());
return entityInfo.build();
}

View File

@@ -12,12 +12,12 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@Getter
public class EntityRegion extends GameEntity{
public class EntityRegion extends GameEntity {
private final Position position;
private boolean hasNewEntities;
private boolean entityLeave;
private final Set<Integer> entities; // Ids of entities inside this region
private final SceneRegion metaRegion;
private boolean hasNewEntities;
private boolean entityLeave;
public EntityRegion(Scene scene, SceneRegion region) {
super(scene);
@@ -55,13 +55,29 @@ public class EntityRegion extends GameEntity{
this.getEntities().remove(entity.getId());
this.entityLeave = true;
}
public boolean entityLeave() {return this.entityLeave;}
public void resetEntityLeave() {this.entityLeave = false;}
@Override public Int2FloatMap getFightProperties() {return null;}
@Override public Position getPosition() {return position;}
public boolean entityLeave() {
return this.entityLeave;
}
@Override public Position getRotation() {return null;}
public void resetEntityLeave() {
this.entityLeave = false;
}
@Override
public Int2FloatMap getFightProperties() {
return null;
}
@Override
public Position getPosition() {
return position;
}
@Override
public Position getRotation() {
return null;
}
@Override
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {

View File

@@ -10,7 +10,8 @@ import lombok.Getter;
public class EntitySolarIsotomaClientGadget extends EntityClientGadget {
public static final int GADGET_ID = 41038001;
public static final int ELEVATOR_GADGET_ID = 41038002;
@Getter private EntityPlatform platformGadget;
@Getter
private EntityPlatform platformGadget;
public EntitySolarIsotomaClientGadget(Scene scene, Player player, EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify notify) {
super(scene, player, notify);

View File

@@ -34,16 +34,24 @@ import java.util.List;
public class EntityVehicle extends EntityBaseGadget {
@Getter private final Player owner;
@Getter
private final Player owner;
@Getter(onMethod_ = @Override)
private final Int2FloatMap fightProperties;
@Getter private final int pointId;
@Getter private final int gadgetId;
@Getter
private final int pointId;
@Getter
private final int gadgetId;
@Getter @Setter private float curStamina;
@Getter private List<VehicleMember> vehicleMembers;
@Nullable @Getter private ConfigGadget configGadget;
@Getter
@Setter
private float curStamina;
@Getter
private final List<VehicleMember> vehicleMembers;
@Nullable
@Getter
private ConfigGadget configGadget;
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
super(scene, pos, rot);
@@ -73,36 +81,36 @@ public class EntityVehicle extends EntityBaseGadget {
public SceneEntityInfo toProto() {
VehicleInfo vehicle = VehicleInfo.newBuilder()
.setOwnerUid(this.owner.getUid())
.setCurStamina(getCurStamina())
.build();
.setOwnerUid(this.owner.getUid())
.setCurStamina(getCurStamina())
.build();
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
.setBornPos(getPosition().toProto())
.build();
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
.setBornPos(getPosition().toProto())
.build();
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
.setGadgetId(this.getGadgetId())
.setAuthorityPeerId(this.getOwner().getPeerId())
.setIsEnableInteract(true)
.setVehicleInfo(vehicle);
.setGadgetId(this.getGadgetId())
.setAuthorityPeerId(this.getOwner().getPeerId())
.setIsEnableInteract(true)
.setVehicleInfo(vehicle);
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())
.setGadget(gadgetInfo)
.setEntityAuthorityInfo(authority)
.setLifeState(1);
.setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
.setGadget(gadgetInfo)
.setEntityAuthorityInfo(authority)
.setLifeState(1);
PropPair pair = PropPair.newBuilder()
.setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
.build();
.setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
.build();
this.addAllFightPropsToEntityInfo(entityInfo);
entityInfo.addPropList(pair);

View File

@@ -25,19 +25,37 @@ import lombok.Getter;
import lombok.Setter;
public abstract class GameEntity {
@Getter protected int id;
@Getter private final Scene scene;
@Getter @Setter private SpawnDataEntry spawnEntry;
@Getter
private final Scene scene;
@Getter
protected int id;
@Getter
@Setter
private SpawnDataEntry spawnEntry;
@Getter @Setter private int blockId;
@Getter @Setter private int configId;
@Getter @Setter private int groupId;
@Getter
@Setter
private int blockId;
@Getter
@Setter
private int configId;
@Getter
@Setter
private int groupId;
@Getter @Setter private MotionState motionState;
@Getter @Setter private int lastMoveSceneTimeMs;
@Getter @Setter private int lastMoveReliableSeq;
@Getter
@Setter
private MotionState motionState;
@Getter
@Setter
private int lastMoveSceneTimeMs;
@Getter
@Setter
private int lastMoveReliableSeq;
@Getter @Setter private boolean lockHP;
@Getter
@Setter
private boolean lockHP;
// Abilities
private Object2FloatMap<String> metaOverrideMap;
@@ -113,11 +131,11 @@ public abstract class GameEntity {
protected MotionInfo getMotionInfo() {
MotionInfo proto = MotionInfo.newBuilder()
.setPos(this.getPosition().toProto())
.setRot(this.getRotation().toProto())
.setSpeed(Vector.newBuilder())
.setState(this.getMotionState())
.build();
.setPos(this.getPosition().toProto())
.setRot(this.getRotation().toProto())
.setSpeed(Vector.newBuilder())
.setState(this.getMotionState())
.build();
return proto;
}
@@ -183,6 +201,7 @@ public abstract class GameEntity {
/**
* Move this entity to a new position.
*
* @param position The new position.
* @param rotation The new rotation.
*/
@@ -194,7 +213,8 @@ public abstract class GameEntity {
/**
* Called when a player interacts with this entity
* @param player Player that is interacting with this entity
*
* @param player Player that is interacting with this entity
* @param interactReq Interact request protobuf data
*/
public void onInteract(Player player, GadgetInteractReq interactReq) {
@@ -214,6 +234,7 @@ public abstract class GameEntity {
/**
* Called when this entity dies
*
* @param killerId Entity id of the entity that killed this entity
*/
public void onDeath(int killerId) {

View File

@@ -4,7 +4,6 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.LifeState;
import emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType;
@@ -14,7 +13,6 @@ import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.scripts.constants.ScriptGadgetState;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
public class GadgetChest extends GadgetContent {
@@ -33,12 +31,12 @@ public class GadgetChest extends GadgetContent {
if (req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()) {
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
return false;
}else {
} else {
boolean success;
if (handler instanceof BossChestInteractHandler bossChestInteractHandler) {
success = bossChestInteractHandler.onInteract(this, player,
req.getResinCostType()== ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE);
}else {
req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE);
} else {
success = handler.onInteract(this, player);
}
if (!success) {
@@ -62,11 +60,11 @@ public class GadgetChest extends GadgetContent {
var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
gadgetInfo.setBossChest(BossChestInfo.newBuilder()
.setMonsterConfigId(bossChest.monster_config_id)
.setResin(bossChest.resin)
.addAllQualifyUidList(players)
.addAllRemainUidList(players)
.build());
.setMonsterConfigId(bossChest.monster_config_id)
.setResin(bossChest.resin)
.addAllQualifyUidList(players)
.addAllRemainUidList(players)
.build());
}
}

View File

@@ -6,17 +6,17 @@ import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
public abstract class GadgetContent {
private final EntityGadget gadget;
private final EntityGadget gadget;
public GadgetContent(EntityGadget gadget) {
this.gadget = gadget;
}
public GadgetContent(EntityGadget gadget) {
this.gadget = gadget;
}
public EntityGadget getGadget() {
return gadget;
}
public abstract boolean onInteract(Player player, GadgetInteractReq req);
public abstract void onBuildProto(SceneGadgetInfo.Builder gadgetInfo);
public EntityGadget getGadget() {
return gadget;
}
public abstract boolean onInteract(Player player, GadgetInteractReq req);
public abstract void onBuildProto(SceneGadgetInfo.Builder gadgetInfo);
}

View File

@@ -8,9 +8,9 @@ import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.utils.Utils;
@@ -52,25 +52,25 @@ public class GadgetGatherObject extends GadgetContent {
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
GatherGadgetInfo gatherGadgetInfo = GatherGadgetInfo.newBuilder()
.setItemId(this.getItemId())
.setIsForbidGuest(this.isForbidGuest())
.build();
.setItemId(this.getItemId())
.setIsForbidGuest(this.isForbidGuest())
.build();
gadgetInfo.setGatherGadget(gatherGadgetInfo);
}
public void dropItems(Player player) {
Scene scene = getGadget().getScene();
int times = Utils.randomRange(1,2);
int times = Utils.randomRange(1, 2);
for (int i = 0 ; i < times ; i++) {
for (int i = 0; i < times; i++) {
EntityItem item = new EntityItem(
scene,
player,
GameData.getItemDataMap().get(itemId),
getGadget().getPosition().nearby2d(1f).addY(2f),
1,
true);
scene,
player,
GameData.getItemDataMap().get(itemId),
getGadget().getPosition().nearby2d(1f).addY(2f),
1,
true);
scene.addEntity(item);
}

View File

@@ -8,13 +8,13 @@ import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.utils.Utils;
public class GadgetGatherPoint extends GadgetContent {
private int itemId;
private final int itemId;
private boolean isForbidGuest;
public GadgetGatherPoint(EntityGadget gadget) {
@@ -47,28 +47,28 @@ public class GadgetGatherPoint extends GadgetContent {
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
GatherGadgetInfo gatherGadgetInfo = GatherGadgetInfo.newBuilder()
.setItemId(this.getItemId())
.setIsForbidGuest(this.isForbidGuest())
.build();
.setItemId(this.getItemId())
.setIsForbidGuest(this.isForbidGuest())
.build();
gadgetInfo.setGatherGadget(gatherGadgetInfo);
}
public void dropItems(Player player) {
Scene scene = getGadget().getScene();
int times = Utils.randomRange(1,2);
int times = Utils.randomRange(1, 2);
for (int i = 0 ; i < times ; i++) {
for (int i = 0; i < times; i++) {
EntityItem item = new EntityItem(
scene,
player,
GameData.getItemDataMap().get(itemId),
getGadget().getPosition().clone()
.addY(2f)
.addX(Utils.randomFloatRange(-1f, 1f))
.addZ(Utils.randomFloatRange(-1f, 1f)),
1,
true);
scene,
player,
GameData.getItemDataMap().get(itemId),
getGadget().getPosition().clone()
.addY(2f)
.addX(Utils.randomFloatRange(-1f, 1f))
.addZ(Utils.randomFloatRange(-1f, 1f)),
1,
true);
scene.addEntity(item);
}

View File

@@ -5,7 +5,7 @@ import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass;
public class GadgetObject extends GadgetContent{
public class GadgetObject extends GadgetContent {
public GadgetObject(EntityGadget gadget) {
super(gadget);
}

View File

@@ -9,22 +9,22 @@ import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
public class GadgetRewardStatue extends GadgetContent {
public GadgetRewardStatue(EntityGadget gadget) {
super(gadget);
}
public boolean onInteract(Player player, GadgetInteractReq req) {
if (player.getScene().getChallenge() != null && player.getScene().getChallenge() instanceof DungeonChallenge dungeonChallenge) {
dungeonChallenge.getStatueDrops(player, req);
}
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_STATUE));
return false;
}
public GadgetRewardStatue(EntityGadget gadget) {
super(gadget);
}
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
}
public boolean onInteract(Player player, GadgetInteractReq req) {
if (player.getScene().getChallenge() != null && player.getScene().getChallenge() instanceof DungeonChallenge dungeonChallenge) {
dungeonChallenge.getStatueDrops(player, req);
}
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_STATUE));
return false;
}
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
}
}

View File

@@ -1,7 +1,5 @@
package emu.grasscutter.game.entity.gadget;
import java.util.Arrays;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.gadget.worktop.WorktopWorktopOptionHandler;
import emu.grasscutter.game.player.Player;
@@ -12,6 +10,8 @@ import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.Arrays;
public class GadgetWorktop extends GadgetContent {
private IntSet worktopOptions;
private WorktopWorktopOptionHandler handler;
@@ -48,8 +48,8 @@ public class GadgetWorktop extends GadgetContent {
}
WorktopInfo worktop = WorktopInfo.newBuilder()
.addAllOptionList(this.getWorktopOptions())
.build();
.addAllOptionList(this.getWorktopOptions())
.build();
gadgetInfo.setWorktop(worktop);
}
@@ -57,6 +57,7 @@ public class GadgetWorktop extends GadgetContent {
public void setOnSelectWorktopOptionEvent(WorktopWorktopOptionHandler handler) {
this.handler = handler;
}
public boolean onSelectWorktopOption(SelectWorktopOptionReq req) {
if (this.handler != null) {
this.handler.onSelectWorktopOption(this, req.getOptionId());

View File

@@ -11,7 +11,7 @@ import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import java.util.ArrayList;
import java.util.List;
public class BossChestInteractHandler implements ChestInteractHandler{
public class BossChestInteractHandler implements ChestInteractHandler {
@Override
public boolean isTwoStep() {
return true;
@@ -19,12 +19,12 @@ public class BossChestInteractHandler implements ChestInteractHandler{
@Override
public boolean onInteract(GadgetChest chest, Player player) {
return this.onInteract(chest,player,false);
return this.onInteract(chest, player, false);
}
public boolean onInteract(GadgetChest chest, Player player,boolean useCondensedResin) {
var blossomRewards = player.getScene().getBlossomManager().onReward(player,chest.getGadget(),useCondensedResin);
if (blossomRewards!=null) {
public boolean onInteract(GadgetChest chest, Player player, boolean useCondensedResin) {
var blossomRewards = player.getScene().getBlossomManager().onReward(player, chest.getGadget(), useCondensedResin);
if (blossomRewards != null) {
player.getInventory().addItems(blossomRewards, ActionReason.OpenWorldBossChest);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(blossomRewards));
return true;

View File

@@ -9,7 +9,7 @@ import java.util.Random;
public class NormalChestInteractHandler implements ChestInteractHandler {
private final ChestReward chestReward;
public NormalChestInteractHandler(ChestReward rewardData){
public NormalChestInteractHandler(ChestReward rewardData) {
this.chestReward = rewardData;
}
@@ -24,14 +24,14 @@ public class NormalChestInteractHandler implements ChestInteractHandler {
player.getInventory().addItem(201, chestReward.getResin());
var mora = chestReward.getMora() * (1 + (player.getWorldLevel() - 1) * 0.5);
player.getInventory().addItem(202, (int)mora);
player.getInventory().addItem(202, (int) mora);
for(int i=0;i<chestReward.getContent().size();i++){
for (int i = 0; i < chestReward.getContent().size(); i++) {
chest.getGadget().getScene().addItemEntity(chestReward.getContent().get(i).getItemId(), chestReward.getContent().get(i).getCount(), chest.getGadget());
}
var random = new Random(System.currentTimeMillis());
for(int i=0;i<chestReward.getRandomCount();i++){
for (int i = 0; i < chestReward.getRandomCount(); i++) {
var index = random.nextInt(chestReward.getRandomContent().size());
var item = chestReward.getRandomContent().get(index);
chest.getGadget().getScene().addItemEntity(item.getItemId(), item.getCount(), chest.getGadget());

View File

@@ -1,6 +1,7 @@
package emu.grasscutter.game.entity.gadget.worktop;
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
public interface WorktopWorktopOptionHandler {
boolean onSelectWorktopOption(GadgetWorktop gadgetWorktop,int option);
boolean onSelectWorktopOption(GadgetWorktop gadgetWorktop, int option);
}

View File

@@ -26,12 +26,12 @@ public class EntityPlatform extends EntityBaseGadget {
private final EntityClientGadget gadget;
@Getter(onMethod_ = @Override)
private final Int2FloatMap fightProperties;
@Getter
private final MovingPlatformTypeOuterClass.MovingPlatformType movingPlatformType;
@Nullable
@Getter
private ConfigGadget configGadget;
@Getter
private final MovingPlatformTypeOuterClass.MovingPlatformType movingPlatformType;
@Getter
@Setter
private boolean isStarted;
@Getter

View File

@@ -2,8 +2,8 @@ package emu.grasscutter.game.entity.platform;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.ConfigGadget;
import emu.grasscutter.game.entity.EntitySolarIsotomaClientGadget;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntitySolarIsotomaClientGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;

View File

@@ -6,7 +6,8 @@ import lombok.Getter;
import lombok.Setter;
@Entity
@Getter @Setter
@Getter
@Setter
public class ExpeditionInfo {
private int state;
private int expId;
@@ -15,10 +16,10 @@ public class ExpeditionInfo {
public AvatarExpeditionInfo toProto() {
return AvatarExpeditionInfo.newBuilder()
.setStateValue(this.getState())
.setExpId(this.getExpId())
.setHourTime(this.getHourTime())
.setStartTime(this.getStartTime())
.build();
.setStateValue(this.getState())
.setExpId(this.getExpId())
.setHourTime(this.getHourTime())
.setStartTime(this.getStartTime())
.build();
}
}

View File

@@ -5,9 +5,12 @@ import emu.grasscutter.utils.Utils;
import lombok.Getter;
public class ExpeditionRewardData {
@Getter private int itemId;
@Getter private int minCount;
@Getter private int maxCount;
@Getter
private int itemId;
@Getter
private int minCount;
@Getter
private int maxCount;
public GameItem getReward() {
return new GameItem(itemId, Utils.randomRange(minCount, maxCount));

View File

@@ -1,14 +1,16 @@
package emu.grasscutter.game.expedition;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.game.inventory.GameItem;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
public class ExpeditionRewardDataList {
@Getter private int hourTime;
@Getter private List<ExpeditionRewardData> expeditionRewardData;
@Getter
private int hourTime;
@Getter
private List<ExpeditionRewardData> expeditionRewardData;
public List<GameItem> getRewards() {
List<GameItem> rewards = new ArrayList<>();

View File

@@ -1,10 +1,12 @@
package emu.grasscutter.game.expedition;
import java.util.List;
import lombok.Getter;
import java.util.List;
public class ExpeditionRewardInfo {
@Getter private int expId;
@Getter private List<ExpeditionRewardDataList> expeditionRewardDataList;
@Getter
private int expId;
@Getter
private List<ExpeditionRewardDataList> expeditionRewardDataList;
}

View File

@@ -1,19 +1,15 @@
package emu.grasscutter.game.friends;
import java.util.List;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.DealAddFriendResultTypeOuterClass.DealAddFriendResultType;
import emu.grasscutter.server.packet.send.PacketAskAddFriendNotify;
import emu.grasscutter.server.packet.send.PacketAskAddFriendRsp;
import emu.grasscutter.server.packet.send.PacketDealAddFriendRsp;
import emu.grasscutter.server.packet.send.PacketDeleteFriendNotify;
import emu.grasscutter.server.packet.send.PacketDeleteFriendRsp;
import emu.grasscutter.server.packet.send.*;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.List;
public class FriendsList extends BasePlayerManager {
private final Int2ObjectMap<Friendship> friends;
private final Int2ObjectMap<Friendship> pendingFriends;
@@ -191,8 +187,9 @@ public class FriendsList extends BasePlayerManager {
this.getPlayer().sendPacket(new PacketAskAddFriendRsp(targetUid));
}
/** Gets total amount of potential friends
* */
/**
* Gets total amount of potential friends
*/
public int getFullFriendCount() {
return this.getPendingFriends().size() + this.getFriends().size();
}

View File

@@ -1,109 +1,116 @@
package emu.grasscutter.game.friends;
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
import org.bson.types.ObjectId;
import dev.morphia.annotations.*;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.Transient;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief;
import emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState;
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
import org.bson.types.ObjectId;
@Entity(value = "friendships", useDiscriminator = false)
public class Friendship {
@Id private ObjectId id;
@Id
private ObjectId id;
@Transient private Player owner;
@Transient
private Player owner;
@Indexed private int ownerId;
@Indexed private int friendId;
private boolean isFriend;
private int askerId;
@Indexed
private int ownerId;
@Indexed
private int friendId;
private boolean isFriend;
private int askerId;
private PlayerProfile profile;
private PlayerProfile profile;
@Deprecated // Morphia use only
public Friendship() { }
@Deprecated // Morphia use only
public Friendship() {
}
public Friendship(Player owner, Player friend, Player asker) {
this.setOwner(owner);
this.ownerId = owner.getUid();
this.friendId = friend.getUid();
this.profile = friend.getProfile();
this.askerId = asker.getUid();
}
public Friendship(Player owner, Player friend, Player asker) {
this.setOwner(owner);
this.ownerId = owner.getUid();
this.friendId = friend.getUid();
this.profile = friend.getProfile();
this.askerId = asker.getUid();
}
public Player getOwner() {
return owner;
}
public Player getOwner() {
return owner;
}
public void setOwner(Player owner) {
this.owner = owner;
}
public void setOwner(Player owner) {
this.owner = owner;
}
public boolean isFriend() {
return isFriend;
}
public boolean isFriend() {
return isFriend;
}
public void setIsFriend(boolean b) {
this.isFriend = b;
}
public void setIsFriend(boolean b) {
this.isFriend = b;
}
public int getOwnerId() {
return ownerId;
}
public int getOwnerId() {
return ownerId;
}
public int getFriendId() {
return friendId;
}
public int getFriendId() {
return friendId;
}
public int getAskerId() {
return askerId;
}
public int getAskerId() {
return askerId;
}
public void setAskerId(int askerId) {
this.askerId = askerId;
}
public void setAskerId(int askerId) {
this.askerId = askerId;
}
public PlayerProfile getFriendProfile() {
return profile;
}
public PlayerProfile getFriendProfile() {
return profile;
}
public void setFriendProfile(Player character) {
if (character == null || this.friendId != character.getUid()) return;
this.profile = character.getProfile();
}
public void setFriendProfile(Player character) {
if (character == null || this.friendId != character.getUid()) return;
this.profile = character.getProfile();
}
public boolean isOnline() {
return getFriendProfile().getPlayer() != null;
}
public boolean isOnline() {
return getFriendProfile().getPlayer() != null;
}
public void save() {
DatabaseHelper.saveFriendship(this);
}
public void save() {
DatabaseHelper.saveFriendship(this);
}
public void delete() {
DatabaseHelper.deleteFriendship(this);
}
public void delete() {
DatabaseHelper.deleteFriendship(this);
}
public FriendBrief toProto() {
FriendBrief proto = FriendBrief.newBuilder()
.setUid(getFriendProfile().getUid())
.setNickname(getFriendProfile().getName())
.setLevel(getFriendProfile().getPlayerLevel())
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
.setWorldLevel(getFriendProfile().getWorldLevel())
.setSignature(getFriendProfile().getSignature())
.setOnlineState(getFriendProfile().isOnline() ? FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE : FriendOnlineState.FRIEND_ONLINE_STATE_DISCONNECT)
.setIsMpModeAvailable(true)
.setLastActiveTime(getFriendProfile().getLastActiveTime())
.setNameCardId(getFriendProfile().getNameCard())
.setParam(getFriendProfile().getDaysSinceLogin())
.setIsGameSource(true)
.setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
.build();
public FriendBrief toProto() {
FriendBrief proto = FriendBrief.newBuilder()
.setUid(getFriendProfile().getUid())
.setNickname(getFriendProfile().getName())
.setLevel(getFriendProfile().getPlayerLevel())
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
.setWorldLevel(getFriendProfile().getWorldLevel())
.setSignature(getFriendProfile().getSignature())
.setOnlineState(getFriendProfile().isOnline() ? FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE : FriendOnlineState.FRIEND_ONLINE_STATE_DISCONNECT)
.setIsMpModeAvailable(true)
.setLastActiveTime(getFriendProfile().getLastActiveTime())
.setNameCardId(getFriendProfile().getNameCard())
.setParam(getFriendProfile().getDaysSinceLogin())
.setIsGameSource(true)
.setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
.build();
return proto;
}
return proto;
}
}

View File

@@ -1,101 +1,106 @@
package emu.grasscutter.game.friends;
import dev.morphia.annotations.*;
import dev.morphia.annotations.AlsoLoad;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Utils;
@Entity
public class PlayerProfile {
@Transient private Player player;
@AlsoLoad("id") private int uid;
private int nameCard;
private int avatarId;
private String name;
private String signature;
private int achievements;
private int playerLevel;
private int worldLevel;
private int lastActiveTime;
@Transient
private Player player;
@Deprecated // Morphia only
public PlayerProfile() { }
public PlayerProfile(Player player) {
this.uid = player.getUid();
this.syncWithCharacter(player);
}
public int getUid() {
return uid;
}
@AlsoLoad("id")
private int uid;
private int nameCard;
private int avatarId;
private String name;
private String signature;
private int achievements;
public Player getPlayer() {
return player;
}
public synchronized void setPlayer(Player player) {
this.player = player;
}
public String getName() {
return name;
}
private int playerLevel;
private int worldLevel;
private int lastActiveTime;
public int getNameCard() {
return nameCard;
}
@Deprecated // Morphia only
public PlayerProfile() {
}
public int getAvatarId() {
return avatarId;
}
public PlayerProfile(Player player) {
this.uid = player.getUid();
this.syncWithCharacter(player);
}
public String getSignature() {
return signature;
}
public int getUid() {
return uid;
}
public int getAchievements() {
return achievements;
}
public Player getPlayer() {
return player;
}
public int getPlayerLevel() {
return playerLevel;
}
public synchronized void setPlayer(Player player) {
this.player = player;
}
public int getWorldLevel() {
return worldLevel;
}
public String getName() {
return name;
}
public int getLastActiveTime() {
return lastActiveTime;
}
public void updateLastActiveTime() {
this.lastActiveTime = Utils.getCurrentSeconds();
}
public int getDaysSinceLogin() {
return (int) Math.floor((Utils.getCurrentSeconds() - getLastActiveTime()) / 86400.0);
}
public int getNameCard() {
return nameCard;
}
public boolean isOnline() {
return this.getPlayer() != null;
}
public int getAvatarId() {
return avatarId;
}
public void syncWithCharacter(Player player) {
if (player == null) {
return;
}
this.uid = player.getUid();
this.name = player.getNickname();
this.avatarId = player.getHeadImage();
this.signature = player.getSignature();
this.nameCard = player.getNameCardId();
this.playerLevel = player.getLevel();
this.worldLevel = player.getWorldLevel();
//this.achievements = 0;
this.updateLastActiveTime();
}
public String getSignature() {
return signature;
}
public int getAchievements() {
return achievements;
}
public int getPlayerLevel() {
return playerLevel;
}
public int getWorldLevel() {
return worldLevel;
}
public int getLastActiveTime() {
return lastActiveTime;
}
public void updateLastActiveTime() {
this.lastActiveTime = Utils.getCurrentSeconds();
}
public int getDaysSinceLogin() {
return (int) Math.floor((Utils.getCurrentSeconds() - getLastActiveTime()) / 86400.0);
}
public boolean isOnline() {
return this.getPlayer() != null;
}
public void syncWithCharacter(Player player) {
if (player == null) {
return;
}
this.uid = player.getUid();
this.name = player.getNickname();
this.avatarId = player.getHeadImage();
this.signature = player.getSignature();
this.nameCard = player.getNameCardId();
this.playerLevel = player.getLevel();
this.worldLevel = player.getWorldLevel();
//this.achievements = 0;
this.updateLastActiveTime();
}
}

View File

@@ -1,7 +1,5 @@
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;
@@ -10,70 +8,103 @@ import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
import emu.grasscutter.utils.Utils;
import lombok.Getter;
import static emu.grasscutter.config.Configuration.*;
public class GachaBanner {
@Getter private int gachaType = -1;
@Getter int scheduleId = -1;
@Getter int sortId = -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;
// Constants used by the BannerType enum
static final int[][] DEFAULT_WEIGHTS_4 = {{1,510}, {8,510}, {10,10000}};
static final int[][] DEFAULT_WEIGHTS_4 = {{1, 510}, {8, 510}, {10, 10000}};
static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}};
static final int[][] DEFAULT_WEIGHTS_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_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 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;
@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;
@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;
@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 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;
@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.");
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)
@@ -160,13 +191,13 @@ public class GachaBanner {
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;
+ 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;
+ 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);
@@ -175,23 +206,23 @@ public class GachaBanner {
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());
.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())

View File

@@ -1,30 +1,35 @@
package emu.grasscutter.game.gacha;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import org.bson.types.ObjectId;
import java.util.Date;
import org.bson.types.ObjectId;
import dev.morphia.annotations.*;
@Entity(value = "gachas", useDiscriminator = false)
public class GachaRecord {
@Id private ObjectId id;
@Indexed private int ownerId;
@Id
private ObjectId id;
private Date transactionDate;
@Indexed
private int ownerId;
private Date transactionDate;
private int itemID;
@Indexed private int gachaType;
@Indexed
private int gachaType;
public GachaRecord() {}
public GachaRecord() {
}
public GachaRecord(int itemId ,int ownerId, int gachaType){
public GachaRecord(int itemId, int ownerId, int gachaType) {
this.transactionDate = new Date();
this.itemID = itemId;
this.ownerId = ownerId;
this.gachaType = gachaType;
}
public int getOwnerId() {
return ownerId;
}
@@ -44,7 +49,7 @@ public class GachaRecord {
public Date getTransactionDate() {
return transactionDate;
}
public void setTransactionDate(Date transactionDate) {
this.transactionDate = transactionDate;
}
@@ -57,7 +62,7 @@ public class GachaRecord {
this.itemID = itemID;
}
public ObjectId getId(){
public ObjectId getId() {
return id;
}
@@ -68,8 +73,9 @@ public class GachaRecord {
public String toString() {
return toJsonString();
}
public String toJsonString() {
return "{\"time\": " + this.transactionDate.getTime() + ",\"item\":" + this.itemID + "}";
}
}

View File

@@ -1,13 +1,5 @@
package emu.grasscutter.game.gacha;
import static emu.grasscutter.config.Configuration.*;
import java.io.File;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import com.sun.nio.file.SensitivityWatchEventModifier;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.DataLoader;
@@ -39,12 +31,18 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import org.greenrobot.eventbus.Subscribe;
public class GachaSystem extends BaseGameSystem {
private final Int2ObjectMap<GachaBanner> gachaBanners;
private WatchService watchService;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
public class GachaSystem extends BaseGameSystem {
private static final int starglitterId = 221;
private static final int stardustId = 222;
private final Int2ObjectMap<GachaBanner> gachaBanners;
private WatchService watchService;
public GachaSystem(GameServer server) {
super(server);
@@ -96,40 +94,6 @@ public class GachaSystem extends BaseGameSystem {
}
}
private class BannerPools {
public int[] rateUpItems4;
public int[] rateUpItems5;
public int[] fallbackItems4Pool1;
public int[] fallbackItems4Pool2;
public int[] fallbackItems5Pool1;
public int[] fallbackItems5Pool2;
public BannerPools(GachaBanner banner) {
rateUpItems4 = banner.getRateUpItems4();
rateUpItems5 = banner.getRateUpItems5();
fallbackItems4Pool1 = banner.getFallbackItems4Pool1();
fallbackItems4Pool2 = banner.getFallbackItems4Pool2();
fallbackItems5Pool1 = banner.getFallbackItems5Pool1();
fallbackItems5Pool2 = banner.getFallbackItems5Pool2();
if (banner.isAutoStripRateUpFromFallback()) {
fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, rateUpItems4);
fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, rateUpItems4);
fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, rateUpItems5);
fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, rateUpItems5);
}
}
public void removeFromAllPools(int[] itemIds) {
rateUpItems4 = Utils.setSubtract(rateUpItems4, itemIds);
rateUpItems5 = Utils.setSubtract(rateUpItems5, itemIds);
fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, itemIds);
fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, itemIds);
fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, itemIds);
fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, itemIds);
}
}
private synchronized int[] removeC6FromPool(int[] itemPool, Player player) {
IntList temp = new IntArrayList();
for (int itemId : itemPool) {
@@ -151,9 +115,9 @@ public class GachaSystem extends BaseGameSystem {
}
total += weight;
}
int roll = ThreadLocalRandom.current().nextInt((total < cutoff)? total : cutoff);
int roll = ThreadLocalRandom.current().nextInt((total < cutoff) ? total : cutoff);
int subTotal = 0;
for (int i=0; i<weights.length; i++) {
for (int i = 0; i < weights.length; i++) {
subTotal += weights[i];
if (roll < subTotal) {
return i;
@@ -166,7 +130,7 @@ public class GachaSystem extends BaseGameSystem {
private synchronized int doFallbackRarePull(int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) {
if (fallback1.length < 1) {
if (fallback2.length < 1) {
return getRandom((rarity==5)? GachaBanner.DEFAULT_FALLBACK_ITEMS_5_POOL_2 : GachaBanner.DEFAULT_FALLBACK_ITEMS_4_POOL_2);
return getRandom((rarity == 5) ? GachaBanner.DEFAULT_FALLBACK_ITEMS_5_POOL_2 : GachaBanner.DEFAULT_FALLBACK_ITEMS_4_POOL_2);
} else {
return getRandom(fallback2);
}
@@ -175,9 +139,9 @@ public class GachaSystem extends BaseGameSystem {
} else { // Both pools are possible, use the pool balancer
int pityPool1 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 1));
int pityPool2 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 2));
int chosenPool = switch ((pityPool1 >= pityPool2)? 1 : 0) { // Larger weight must come first for the hard cutoff to function correctly
case 1 -> 1 + drawRoulette(new int[] {pityPool1, pityPool2}, 10000);
default -> 2 - drawRoulette(new int[] {pityPool2, pityPool1}, 10000);
int chosenPool = switch ((pityPool1 >= pityPool2) ? 1 : 0) { // Larger weight must come first for the hard cutoff to function correctly
case 1 -> 1 + drawRoulette(new int[]{pityPool1, pityPool2}, 10000);
default -> 2 - drawRoulette(new int[]{pityPool2, pityPool1}, 10000);
};
return switch (chosenPool) {
case 1:
@@ -321,12 +285,12 @@ public class GachaSystem extends BaseGameSystem {
break;
default:
if (constellation >= 6) { // C6, give consolation starglitter
addStarglitter = (itemData.getRankLevel()==5)? 25 : 5;
addStarglitter = (itemData.getRankLevel() == 5) ? 25 : 5;
} else { // C0-C5, give constellation item
if (banner.isRemoveC6FromPool() && constellation == 5) { // New C6, remove it from the pools so we don't get C7 in a 10pull
pools.removeFromAllPools(new int[] {itemId});
pools.removeFromAllPools(new int[]{itemId});
}
addStarglitter = (itemData.getRankLevel()==5)? 10 : 2;
addStarglitter = (itemData.getRankLevel() == 5) ? 10 : 2;
int constItemId = itemId + 100; // This may not hold true for future characters. Examples of strictly correct constellation item lookup are elsewhere for now.
boolean haveConstItem = inventory.getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(constItemId) == null;
gachaItem.addTransferItems(GachaTransferItem.newBuilder().setItem(ItemParam.newBuilder().setItemId(constItemId).setCount(1)).setIsTransferItemNew(haveConstItem));
@@ -404,7 +368,6 @@ public class GachaSystem extends BaseGameSystem {
boolean valid = watchKey.reset();
if (!valid) {
Grasscutter.getLogger().error("Unable to reset Gacha Manager Watch Key. Auto-reload of banners.json will no longer work.");
return;
}
} catch (Exception e) {
e.printStackTrace();
@@ -418,8 +381,7 @@ public class GachaSystem extends BaseGameSystem {
long currentTime = System.currentTimeMillis() / 1000L;
for (GachaBanner banner : getGachaBanners().values()) {
if ((banner.getEndTime() >= currentTime && banner.getBeginTime() <= currentTime) || (banner.getBannerType() == BannerType.STANDARD))
{
if ((banner.getEndTime() >= currentTime && banner.getBeginTime() <= currentTime) || (banner.getBannerType() == BannerType.STANDARD)) {
proto.addGachaInfoList(banner.toProto(player));
}
}
@@ -430,4 +392,38 @@ public class GachaSystem extends BaseGameSystem {
public GetGachaInfoRsp toProto(Player player) {
return createProto(player);
}
private class BannerPools {
public int[] rateUpItems4;
public int[] rateUpItems5;
public int[] fallbackItems4Pool1;
public int[] fallbackItems4Pool2;
public int[] fallbackItems5Pool1;
public int[] fallbackItems5Pool2;
public BannerPools(GachaBanner banner) {
rateUpItems4 = banner.getRateUpItems4();
rateUpItems5 = banner.getRateUpItems5();
fallbackItems4Pool1 = banner.getFallbackItems4Pool1();
fallbackItems4Pool2 = banner.getFallbackItems4Pool2();
fallbackItems5Pool1 = banner.getFallbackItems5Pool1();
fallbackItems5Pool2 = banner.getFallbackItems5Pool2();
if (banner.isAutoStripRateUpFromFallback()) {
fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, rateUpItems4);
fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, rateUpItems4);
fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, rateUpItems5);
fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, rateUpItems5);
}
}
public void removeFromAllPools(int[] itemIds) {
rateUpItems4 = Utils.setSubtract(rateUpItems4, itemIds);
rateUpItems5 = Utils.setSubtract(rateUpItems5, itemIds);
fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, itemIds);
fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, itemIds);
fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, itemIds);
fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, itemIds);
}
}
}

View File

@@ -6,111 +6,127 @@ import lombok.Setter;
@Entity
public class PlayerGachaBannerInfo {
@Getter @Setter private int totalPulls = 0;
@Getter @Setter private int pity5 = 0;
@Getter @Setter private int pity4 = 0;
private int failedFeaturedItemPulls = 0;
private int failedFeatured4ItemPulls = 0;
private int pity5Pool1 = 0;
private int pity5Pool2 = 0;
private int pity4Pool1 = 0;
private int pity4Pool2 = 0;
@Getter
@Setter
private int totalPulls = 0;
@Getter
@Setter
private int pity5 = 0;
@Getter
@Setter
private int pity4 = 0;
private int failedFeaturedItemPulls = 0;
private int failedFeatured4ItemPulls = 0;
private int pity5Pool1 = 0;
private int pity5Pool2 = 0;
private int pity4Pool1 = 0;
private int pity4Pool2 = 0;
@Getter @Setter private int failedChosenItemPulls = 0;
@Getter @Setter private int wishItemId = 0;
@Getter
@Setter
private int failedChosenItemPulls = 0;
@Getter
@Setter
private int wishItemId = 0;
public void addTotalPulls(int amount) {
this.totalPulls += amount;
}
public void addTotalPulls(int amount) {
this.totalPulls += amount;
}
public void addPity5(int amount) {
this.pity5 += amount;
}
public void addPity5(int amount) {
this.pity5 += amount;
}
public void addPity4(int amount) {
this.pity4 += amount;
}
public void addPity4(int amount) {
this.pity4 += amount;
}
public void addFailedChosenItemPulls(int amount) {
failedChosenItemPulls += amount;
}
public int getFailedFeaturedItemPulls(int rarity) {
return switch (rarity) {
case 4 -> failedFeatured4ItemPulls;
default -> failedFeaturedItemPulls; // 5
};
}
public void setFailedFeaturedItemPulls(int rarity, int amount) {
switch (rarity) {
case 4 -> failedFeatured4ItemPulls = amount;
default -> failedFeaturedItemPulls = amount; // 5
};
}
public void addFailedFeaturedItemPulls(int rarity, int amount) {
switch (rarity) {
case 4 -> failedFeatured4ItemPulls += amount;
default -> failedFeaturedItemPulls += amount; // 5
};
}
public int getPityPool(int rarity, int pool) {
return switch (rarity) {
case 4 -> switch (pool) {
case 1 -> pity4Pool1;
default -> pity4Pool2;
};
default -> switch (pool) {
case 1 -> pity5Pool1;
default -> pity5Pool2;
};
};
}
public void setPityPool(int rarity, int pool, int amount) {
switch (rarity) {
case 4:
switch (pool) {
case 1 -> pity4Pool1 = amount;
default -> pity4Pool2 = amount;
};
break;
case 5:
default:
switch (pool) {
case 1 -> pity5Pool1 = amount;
default -> pity5Pool2 = amount;
};
break;
};
}
public void addPityPool(int rarity, int pool, int amount) {
switch (rarity) {
case 4:
switch (pool) {
case 1 -> pity4Pool1 += amount;
default -> pity4Pool2 += amount;
};
break;
case 5:
default:
switch (pool) {
case 1 -> pity5Pool1 += amount;
default -> pity5Pool2 += amount;
};
break;
};
}
public void addFailedChosenItemPulls(int amount) {
failedChosenItemPulls += amount;
}
public void incPityAll() {
pity4++;
pity5++;
pity4Pool1++;
pity4Pool2++;
pity5Pool1++;
pity5Pool2++;
}
public int getFailedFeaturedItemPulls(int rarity) {
return switch (rarity) {
case 4 -> failedFeatured4ItemPulls;
default -> failedFeaturedItemPulls; // 5
};
}
public void setFailedFeaturedItemPulls(int rarity, int amount) {
if (rarity == 4) {
failedFeatured4ItemPulls = amount;
} else {
failedFeaturedItemPulls = amount; // 5
}
}
public void addFailedFeaturedItemPulls(int rarity, int amount) {
if (rarity == 4) {
failedFeatured4ItemPulls += amount;
} else {
failedFeaturedItemPulls += amount; // 5
}
}
public int getPityPool(int rarity, int pool) {
return switch (rarity) {
case 4 -> switch (pool) {
case 1 -> pity4Pool1;
default -> pity4Pool2;
};
default -> switch (pool) {
case 1 -> pity5Pool1;
default -> pity5Pool2;
};
};
}
public void setPityPool(int rarity, int pool, int amount) {
switch (rarity) {
case 4:
if (pool == 1) {
pity4Pool1 = amount;
} else {
pity4Pool2 = amount;
}
break;
case 5:
default:
if (pool == 1) {
pity5Pool1 = amount;
} else {
pity5Pool2 = amount;
}
break;
}
}
public void addPityPool(int rarity, int pool, int amount) {
switch (rarity) {
case 4:
if (pool == 1) {
pity4Pool1 += amount;
} else {
pity4Pool2 += amount;
}
break;
case 5:
default:
if (pool == 1) {
pity5Pool1 += amount;
} else {
pity5Pool2 += amount;
}
break;
}
}
public void incPityAll() {
pity4++;
pity5++;
pity4Pool1++;
pity4Pool2++;
pity5Pool1++;
pity5Pool2++;
}
}

View File

@@ -3,7 +3,6 @@ package emu.grasscutter.game.home;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import emu.grasscutter.net.proto.FurnitureMakeDataOuterClass;
import emu.grasscutter.net.proto.FurnitureMakeSlotOuterClass;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
@@ -23,11 +22,11 @@ public class FurnitureMakeSlotItem {
public FurnitureMakeDataOuterClass.FurnitureMakeData toProto() {
return FurnitureMakeDataOuterClass.FurnitureMakeData.newBuilder()
.setIndex(index)
.setAvatarId(avatarId)
.setMakeId(makeId)
.setBeginTime(beginTime)
.setDurTime(durTime)
.build();
.setIndex(index)
.setAvatarId(avatarId)
.setMakeId(makeId)
.setBeginTime(beginTime)
.setDurTime(durTime)
.build();
}
}

View File

@@ -1,10 +1,6 @@
package emu.grasscutter.game.home;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.IndexOptions;
import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.Transient;
import dev.morphia.annotations.*;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.HomeWorldLevelData;
@@ -19,12 +15,7 @@ import lombok.experimental.FieldDefaults;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -38,7 +29,8 @@ public class GameHome {
@Indexed(options = @IndexOptions(unique = true))
long ownerUid;
@Transient Player player;
@Transient
Player player;
int level;
int exp;
@@ -51,10 +43,6 @@ public class GameHome {
Set<Integer> unlockedHomeBgmList;
int enterHomeOption;
public void save() {
DatabaseHelper.saveHome(this);
}
public static GameHome getByUid(Integer uid) {
var home = DatabaseHelper.getHomeByUid(uid);
if (home == null) {
@@ -65,11 +53,15 @@ public class GameHome {
public static GameHome create(Integer uid) {
return GameHome.of()
.ownerUid(uid)
.level(1)
.sceneMap(new ConcurrentHashMap<>())
.unlockedHomeBgmList(new HashSet<>())
.build();
.ownerUid(uid)
.level(1)
.sceneMap(new ConcurrentHashMap<>())
.unlockedHomeBgmList(new HashSet<>())
.build();
}
public void save() {
DatabaseHelper.saveHome(this);
}
public HomeSceneItem getHomeSceneItem(int sceneId) {

View File

@@ -2,7 +2,6 @@ package emu.grasscutter.game.home;
import dev.morphia.annotations.Entity;
import emu.grasscutter.net.proto.HomeAnimalDataOuterClass;
import emu.grasscutter.net.proto.HomeFurnitureDataOuterClass;
import emu.grasscutter.utils.Position;
import lombok.AccessLevel;
import lombok.Builder;
@@ -18,20 +17,20 @@ public class HomeAnimalItem {
Position spawnPos;
Position spawnRot;
public HomeAnimalDataOuterClass.HomeAnimalData toProto(){
return HomeAnimalDataOuterClass.HomeAnimalData.newBuilder()
.setFurnitureId(furnitureId)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.build();
}
public static HomeAnimalItem parseFrom(HomeAnimalDataOuterClass.HomeAnimalData homeAnimalData) {
return HomeAnimalItem.of()
.furnitureId(homeAnimalData.getFurnitureId())
.spawnPos(new Position(homeAnimalData.getSpawnPos()))
.spawnRot(new Position(homeAnimalData.getSpawnRot()))
.build();
.furnitureId(homeAnimalData.getFurnitureId())
.spawnPos(new Position(homeAnimalData.getSpawnPos()))
.spawnRot(new Position(homeAnimalData.getSpawnRot()))
.build();
}
public HomeAnimalDataOuterClass.HomeAnimalData toProto() {
return HomeAnimalDataOuterClass.HomeAnimalData.newBuilder()
.setFurnitureId(furnitureId)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.build();
}
}

View File

@@ -4,7 +4,6 @@ import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo;
import emu.grasscutter.utils.Position;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
@@ -25,37 +24,57 @@ public class HomeBlockItem {
List<HomeAnimalItem> deployAnimalList;
List<HomeNPCItem> deployNPCList;
public static HomeBlockItem parseFrom(HomeworldDefaultSaveData.HomeBlock homeBlock) {
// create from default setting
return HomeBlockItem.of()
.blockId(homeBlock.getBlockId())
.unlocked(homeBlock.getFurnitures() != null)
.deployFurnitureList(
homeBlock.getFurnitures() == null ? List.of() :
homeBlock.getFurnitures().stream()
.map(HomeFurnitureItem::parseFrom)
.toList())
.persistentFurnitureList(
homeBlock.getPersistentFurnitures() == null ? List.of() :
homeBlock.getPersistentFurnitures().stream()
.map(HomeFurnitureItem::parseFrom)
.toList())
.deployAnimalList(List.of())
.deployNPCList(List.of())
.build();
}
public void update(HomeBlockArrangementInfo homeBlockArrangementInfo) {
this.blockId = homeBlockArrangementInfo.getBlockId();
this.deployFurnitureList = homeBlockArrangementInfo.getDeployFurniureListList().stream()
.map(HomeFurnitureItem::parseFrom)
.toList();
.map(HomeFurnitureItem::parseFrom)
.toList();
this.persistentFurnitureList = homeBlockArrangementInfo.getPersistentFurnitureListList().stream()
.map(HomeFurnitureItem::parseFrom)
.toList();
.map(HomeFurnitureItem::parseFrom)
.toList();
this.deployAnimalList = homeBlockArrangementInfo.getDeployAnimalListList().stream()
.map(HomeAnimalItem::parseFrom)
.toList();
.map(HomeAnimalItem::parseFrom)
.toList();
this.deployNPCList = homeBlockArrangementInfo.getDeployNpcListList().stream()
.map(HomeNPCItem::parseFrom)
.toList();
.map(HomeNPCItem::parseFrom)
.toList();
}
public int calComfort() {
return this.deployFurnitureList.stream()
.mapToInt(HomeFurnitureItem::getComfort)
.sum();
.mapToInt(HomeFurnitureItem::getComfort)
.sum();
}
public HomeBlockArrangementInfo toProto() {
var proto = HomeBlockArrangementInfo.newBuilder()
.setBlockId(blockId)
.setIsUnlocked(unlocked)
.setComfortValue(calComfort());
.setBlockId(blockId)
.setIsUnlocked(unlocked)
.setComfortValue(calComfort());
this.deployFurnitureList.forEach(f -> proto.addDeployFurniureList(f.toProto()));
this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto()));
@@ -64,24 +83,4 @@ public class HomeBlockItem {
return proto.build();
}
public static HomeBlockItem parseFrom(HomeworldDefaultSaveData.HomeBlock homeBlock) {
// create from default setting
return HomeBlockItem.of()
.blockId(homeBlock.getBlockId())
.unlocked(homeBlock.getFurnitures() != null)
.deployFurnitureList(
homeBlock.getFurnitures() == null ? List.of() :
homeBlock.getFurnitures().stream()
.map(HomeFurnitureItem::parseFrom)
.toList())
.persistentFurnitureList(
homeBlock.getPersistentFurnitures() == null ? List.of() :
homeBlock.getPersistentFurnitures().stream()
.map(HomeFurnitureItem::parseFrom)
.toList())
.deployAnimalList(List.of())
.deployNPCList(List.of())
.build();
}
}

View File

@@ -6,7 +6,6 @@ import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.net.proto.HomeFurnitureDataOuterClass;
import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
import emu.grasscutter.net.proto.VectorOuterClass;
import emu.grasscutter.utils.Position;
import lombok.AccessLevel;
import lombok.Builder;
@@ -24,45 +23,46 @@ public class HomeFurnitureItem {
Position spawnPos;
Position spawnRot;
int version;
public HomeFurnitureDataOuterClass.HomeFurnitureData toProto(){
return HomeFurnitureDataOuterClass.HomeFurnitureData.newBuilder()
.setFurnitureId(furnitureId)
.setGuid(guid)
.setParentFurnitureIndex(parentFurnitureIndex)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.setVersion(version)
.build();
}
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto(int type){
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
.setFurnitureId(furnitureId)
.setGuid(guid)
.setFurnitureType(type)
.setPos(spawnPos.toProto())
// TODO NPC and farm
.build();
}
public static HomeFurnitureItem parseFrom(HomeFurnitureDataOuterClass.HomeFurnitureData homeFurnitureData) {
return HomeFurnitureItem.of()
.furnitureId(homeFurnitureData.getFurnitureId())
.guid(homeFurnitureData.getGuid())
.parentFurnitureIndex(homeFurnitureData.getParentFurnitureIndex())
.spawnPos(new Position(homeFurnitureData.getSpawnPos()))
.spawnRot(new Position(homeFurnitureData.getSpawnRot()))
.version(homeFurnitureData.getVersion())
.build();
.furnitureId(homeFurnitureData.getFurnitureId())
.guid(homeFurnitureData.getGuid())
.parentFurnitureIndex(homeFurnitureData.getParentFurnitureIndex())
.spawnPos(new Position(homeFurnitureData.getSpawnPos()))
.spawnRot(new Position(homeFurnitureData.getSpawnRot()))
.version(homeFurnitureData.getVersion())
.build();
}
public static HomeFurnitureItem parseFrom(HomeworldDefaultSaveData.HomeFurniture homeFurniture) {
return HomeFurnitureItem.of()
.furnitureId(homeFurniture.getId())
.parentFurnitureIndex(1)
.spawnPos(homeFurniture.getPos() == null ? new Position() : homeFurniture.getPos())
.spawnRot(homeFurniture.getRot() == null ? new Position() : homeFurniture.getRot())
.build();
.furnitureId(homeFurniture.getId())
.parentFurnitureIndex(1)
.spawnPos(homeFurniture.getPos() == null ? new Position() : homeFurniture.getPos())
.spawnRot(homeFurniture.getRot() == null ? new Position() : homeFurniture.getRot())
.build();
}
public HomeFurnitureDataOuterClass.HomeFurnitureData toProto() {
return HomeFurnitureDataOuterClass.HomeFurnitureData.newBuilder()
.setFurnitureId(furnitureId)
.setGuid(guid)
.setParentFurnitureIndex(parentFurnitureIndex)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.setVersion(version)
.build();
}
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto(int type) {
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
.setFurnitureId(furnitureId)
.setGuid(guid)
.setFurnitureType(type)
.setPos(spawnPos.toProto())
// TODO NPC and farm
.build();
}
public ItemData getAsItem() {
@@ -72,7 +72,7 @@ public class HomeFurnitureItem {
public int getComfort() {
var item = getAsItem();
if (item == null){
if (item == null) {
return 0;
}
return item.getComfort();

View File

@@ -1,7 +1,6 @@
package emu.grasscutter.game.home;
import dev.morphia.annotations.Entity;
import emu.grasscutter.net.proto.HomeAnimalDataOuterClass;
import emu.grasscutter.net.proto.HomeNpcDataOuterClass;
import emu.grasscutter.utils.Position;
import lombok.AccessLevel;
@@ -19,21 +18,21 @@ public class HomeNPCItem {
Position spawnRot;
int costumeId;
public HomeNpcDataOuterClass.HomeNpcData toProto(){
return HomeNpcDataOuterClass.HomeNpcData.newBuilder()
.setAvatarId(avatarId)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.setCostumeId(costumeId)
.build();
}
public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData) {
return HomeNPCItem.of()
.avatarId(homeNpcData.getAvatarId())
.spawnPos(new Position(homeNpcData.getSpawnPos()))
.spawnRot(new Position(homeNpcData.getSpawnRot()))
.costumeId(homeNpcData.getCostumeId())
.build();
.avatarId(homeNpcData.getAvatarId())
.spawnPos(new Position(homeNpcData.getSpawnPos()))
.spawnRot(new Position(homeNpcData.getSpawnRot()))
.costumeId(homeNpcData.getCostumeId())
.build();
}
public HomeNpcDataOuterClass.HomeNpcData toProto() {
return HomeNpcDataOuterClass.HomeNpcData.newBuilder()
.setAvatarId(avatarId)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.setCostumeId(costumeId)
.build();
}
}

View File

@@ -28,18 +28,19 @@ public class HomeSceneItem {
int homeBgmId;
HomeFurnitureItem mainHouse;
int tmpVersion;
public static HomeSceneItem parseFrom(HomeworldDefaultSaveData defaultItem, int sceneId) {
return HomeSceneItem.of()
.sceneId(sceneId)
.blockItems(defaultItem.getHomeBlockLists().stream()
.map(HomeBlockItem::parseFrom)
.collect(Collectors.toMap(HomeBlockItem::getBlockId, y -> y)))
.bornPos(defaultItem.getBornPos())
.bornRot(defaultItem.getBornRot() == null ? new Position() : defaultItem.getBornRot())
.djinnPos(defaultItem.getDjinPos() == null ? new Position() : defaultItem.getDjinPos())
.mainHouse(defaultItem.getMainhouse() == null ? null :
HomeFurnitureItem.parseFrom(defaultItem.getMainhouse()))
.build();
.sceneId(sceneId)
.blockItems(defaultItem.getHomeBlockLists().stream()
.map(HomeBlockItem::parseFrom)
.collect(Collectors.toMap(HomeBlockItem::getBlockId, y -> y)))
.bornPos(defaultItem.getBornPos())
.bornRot(defaultItem.getBornRot() == null ? new Position() : defaultItem.getBornRot())
.djinnPos(defaultItem.getDjinPos() == null ? new Position() : defaultItem.getDjinPos())
.mainHouse(defaultItem.getMainhouse() == null ? null :
HomeFurnitureItem.parseFrom(defaultItem.getMainhouse()))
.build();
}
public void update(HomeSceneArrangementInfo arrangementInfo) {
@@ -70,8 +71,8 @@ public class HomeSceneItem {
public int calComfort() {
return this.blockItems.values().stream()
.mapToInt(HomeBlockItem::calComfort)
.sum();
.mapToInt(HomeBlockItem::calComfort)
.sum();
}
public HomeSceneArrangementInfo toProto() {
@@ -79,13 +80,13 @@ public class HomeSceneItem {
blockItems.values().forEach(b -> proto.addBlockArrangementInfoList(b.toProto()));
proto.setComfortValue(calComfort())
.setBornPos(bornPos.toProto())
.setBornRot(bornRot.toProto())
.setDjinnPos(djinnPos.toProto())
.setIsSetBornPos(true)
.setSceneId(sceneId)
.setBgmId(homeBgmId)
.setTmpVersion(tmpVersion);
.setBornPos(bornPos.toProto())
.setBornRot(bornRot.toProto())
.setDjinnPos(djinnPos.toProto())
.setIsSetBornPos(true)
.setSceneId(sceneId)
.setBgmId(homeBgmId)
.setTmpVersion(tmpVersion);
if (mainHouse != null) {
proto.setMainHouse(mainHouse.toProto());

View File

@@ -4,36 +4,36 @@ import java.util.HashSet;
import java.util.Set;
public class EquipInventoryTab implements InventoryTab {
private final Set<GameItem> items;
private final int maxCapacity;
public EquipInventoryTab(int maxCapacity) {
this.items = new HashSet<GameItem>();
this.maxCapacity = maxCapacity;
}
private final Set<GameItem> items;
private final int maxCapacity;
@Override
public GameItem getItemById(int id) {
return null;
}
public EquipInventoryTab(int maxCapacity) {
this.items = new HashSet<GameItem>();
this.maxCapacity = maxCapacity;
}
@Override
public void onAddItem(GameItem item) {
this.items.add(item);
}
@Override
public GameItem getItemById(int id) {
return null;
}
@Override
public void onRemoveItem(GameItem item) {
this.items.remove(item);
}
@Override
public void onAddItem(GameItem item) {
this.items.add(item);
}
@Override
public int getSize() {
return this.items.size();
}
@Override
public void onRemoveItem(GameItem item) {
this.items.remove(item);
}
@Override
public int getMaxCapacity() {
return this.maxCapacity;
}
@Override
public int getSize() {
return this.items.size();
}
@Override
public int getMaxCapacity() {
return this.maxCapacity;
}
}

View File

@@ -1,45 +1,46 @@
package emu.grasscutter.game.inventory;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum EquipType {
EQUIP_NONE (0),
EQUIP_BRACER (1),
EQUIP_NECKLACE (2),
EQUIP_SHOES (3),
EQUIP_RING (4),
EQUIP_DRESS (5),
EQUIP_WEAPON (6);
private final int value;
private static final Int2ObjectMap<EquipType> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, EquipType> stringMap = new HashMap<>();
static {
Stream.of(values()).forEach(e -> {
map.put(e.getValue(), e);
stringMap.put(e.name(), e);
});
}
private EquipType(int value) {
this.value = value;
}
EQUIP_NONE(0),
EQUIP_BRACER(1),
EQUIP_NECKLACE(2),
EQUIP_SHOES(3),
EQUIP_RING(4),
EQUIP_DRESS(5),
EQUIP_WEAPON(6);
public int getValue() {
return value;
}
public static EquipType getTypeByValue(int value) {
return map.getOrDefault(value, EQUIP_NONE);
}
public static EquipType getTypeByName(String name) {
return stringMap.getOrDefault(name, EQUIP_NONE);
}
private static final Int2ObjectMap<EquipType> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, EquipType> stringMap = new HashMap<>();
static {
Stream.of(values()).forEach(e -> {
map.put(e.getValue(), e);
stringMap.put(e.name(), e);
});
}
private final int value;
EquipType(int value) {
this.value = value;
}
public static EquipType getTypeByValue(int value) {
return map.getOrDefault(value, EQUIP_NONE);
}
public static EquipType getTypeByName(String name) {
return stringMap.getOrDefault(name, EQUIP_NONE);
}
public int getValue() {
return value;
}
}

View File

@@ -1,18 +1,6 @@
package emu.grasscutter.game.inventory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.PostLoad;
import dev.morphia.annotations.Transient;
import dev.morphia.annotations.*;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.common.ItemParamData;
@@ -36,34 +24,72 @@ import emu.grasscutter.net.proto.WeaponOuterClass.Weapon;
import emu.grasscutter.utils.WeightedList;
import lombok.Getter;
import lombok.Setter;
import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Entity(value = "items", useDiscriminator = false)
public class GameItem {
@Id private ObjectId id;
@Indexed private int ownerId;
@Getter @Setter private int itemId;
@Getter @Setter private int count;
@Id
private ObjectId id;
@Indexed
private int ownerId;
@Getter
@Setter
private int itemId;
@Getter
@Setter
private int count;
@Transient @Getter private long guid; // Player unique id
@Transient @Getter @Setter private ItemData itemData;
@Transient
@Getter
private long guid; // Player unique id
@Transient
@Getter
@Setter
private ItemData itemData;
// Equips
@Getter @Setter private int level;
@Getter @Setter private int exp;
@Getter @Setter private int totalExp;
@Getter @Setter private int promoteLevel;
@Getter @Setter private boolean locked;
@Getter
@Setter
private int level;
@Getter
@Setter
private int exp;
@Getter
@Setter
private int totalExp;
@Getter
@Setter
private int promoteLevel;
@Getter
@Setter
private boolean locked;
// Weapon
@Getter private List<Integer> affixes;
@Getter @Setter private int refinement = 0;
@Getter
private List<Integer> affixes;
@Getter
@Setter
private int refinement = 0;
// Relic
@Getter @Setter private int mainPropId;
@Getter private List<Integer> appendPropIdList;
@Getter
@Setter
private int mainPropId;
@Getter
private List<Integer> appendPropIdList;
@Getter @Setter private int equipCharacter;
@Transient @Getter @Setter private int weaponEntityId;
@Getter
@Setter
private int equipCharacter;
@Transient
@Getter
@Setter
private int weaponEntityId;
public GameItem() {
// Morphia only
@@ -91,7 +117,7 @@ public class GameItem {
switch (data.getItemType()) {
case ITEM_VIRTUAL:
this.count = count;
this.count = count;
break;
case ITEM_WEAPON:
this.count = 1;
@@ -122,23 +148,6 @@ public class GameItem {
}
}
public int getOwnerId() {
return ownerId;
}
public void setOwner(Player player) {
this.ownerId = player.getUid();
this.guid = player.getNextGameGuid();
}
public ObjectId getObjectId() {
return id;
}
public ItemType getItemType() {
return this.itemData.getItemType();
}
public static int getMinPromoteLevel(int level) {
if (level > 80) {
return 6;
@@ -156,6 +165,23 @@ public class GameItem {
return 0;
}
public int getOwnerId() {
return ownerId;
}
public void setOwner(Player player) {
this.ownerId = player.getUid();
this.guid = player.getNextGameGuid();
}
public ObjectId getObjectId() {
return id;
}
public ItemType getItemType() {
return this.itemData.getItemType();
}
public int getEquipSlot() {
return this.getItemData().getEquipType().getValue();
}
@@ -270,28 +296,28 @@ public class GameItem {
public SceneWeaponInfo createSceneWeaponInfo() {
SceneWeaponInfo.Builder weaponInfo = SceneWeaponInfo.newBuilder()
.setEntityId(this.getWeaponEntityId())
.setItemId(this.getItemId())
.setGuid(this.getGuid())
.setLevel(this.getLevel())
.setGadgetId(this.getItemData().getGadgetId())
.setAbilityInfo(AbilitySyncStateInfo.newBuilder().setIsInited(getAffixes().size() > 0));
.setEntityId(this.getWeaponEntityId())
.setItemId(this.getItemId())
.setGuid(this.getGuid())
.setLevel(this.getLevel())
.setGadgetId(this.getItemData().getGadgetId())
.setAbilityInfo(AbilitySyncStateInfo.newBuilder().setIsInited(getAffixes().size() > 0));
if (this.getAffixes() != null && this.getAffixes().size() > 0) {
for (int affix : this.getAffixes()) {
weaponInfo.putAffixMap(affix, this.getRefinement());
}
}
if (this.getAffixes() != null && this.getAffixes().size() > 0) {
for (int affix : this.getAffixes()) {
weaponInfo.putAffixMap(affix, this.getRefinement());
}
}
return weaponInfo.build();
}
public SceneReliquaryInfo createSceneReliquaryInfo() {
SceneReliquaryInfo relicInfo = SceneReliquaryInfo.newBuilder()
.setItemId(this.getItemId())
.setGuid(this.getGuid())
.setLevel(this.getLevel())
.build();
.setItemId(this.getItemId())
.setGuid(this.getGuid())
.setLevel(this.getLevel())
.build();
return relicInfo;
}
@@ -324,8 +350,8 @@ public class GameItem {
public Item toProto() {
Item.Builder proto = Item.newBuilder()
.setGuid(this.getGuid())
.setItemId(this.getItemId());
.setGuid(this.getGuid())
.setItemId(this.getItemId());
switch (getItemType()) {
case ITEM_WEAPON:

View File

@@ -214,7 +214,7 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
case MATERIAL_FLYCLOAK:
case MATERIAL_COSTUME:
case MATERIAL_NAMECARD:
Grasscutter.getLogger().warn("Attempted to add a "+item.getItemData().getMaterialType().name()+" to inventory, but item definition lacks isUseOnGain. This indicates a Resources error.");
Grasscutter.getLogger().warn("Attempted to add a " + item.getItemData().getMaterialType().name() + " to inventory, but item definition lacks isUseOnGain. This indicates a Resources error.");
return null;
default:
if (tab == null) {
@@ -236,7 +236,7 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
existingItem.save();
return existingItem;
}
}
}
}
}

View File

@@ -1,13 +1,13 @@
package emu.grasscutter.game.inventory;
public interface InventoryTab {
public GameItem getItemById(int id);
public void onAddItem(GameItem item);
public void onRemoveItem(GameItem item);
public int getSize();
public int getMaxCapacity();
GameItem getItemById(int id);
void onAddItem(GameItem item);
void onRemoveItem(GameItem item);
int getSize();
int getMaxCapacity();
}

View File

@@ -1,27 +1,27 @@
package emu.grasscutter.game.inventory;
public class ItemDef {
private int itemId;
private int count;
public ItemDef(int itemId, int count) {
this.itemId = itemId;
this.count = count;
}
public int getItemId() {
return itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
private int itemId;
private int count;
public int getCount() {
return count;
}
public ItemDef(int itemId, int count) {
this.itemId = itemId;
this.count = count;
}
public void setCount(int count) {
this.count = count;
}
public int getItemId() {
return itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}

View File

@@ -1,45 +1,46 @@
package emu.grasscutter.game.inventory;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum ItemQuality {
QUALITY_NONE(0),
QUALITY_WHITE(1),
QUALITY_GREEN(2),
QUALITY_BLUE(3),
QUALITY_PURPLE(4),
QUALITY_ORANGE(5),
QUALITY_ORANGE_SP(105);
private final int value;
private static final Int2ObjectMap<ItemQuality> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, ItemQuality> stringMap = new HashMap<>();
static {
Stream.of(values()).forEach(e -> {
map.put(e.getValue(), e);
stringMap.put(e.name(), e);
});
}
private ItemQuality(int value) {
this.value = value;
}
QUALITY_NONE(0),
QUALITY_WHITE(1),
QUALITY_GREEN(2),
QUALITY_BLUE(3),
QUALITY_PURPLE(4),
QUALITY_ORANGE(5),
QUALITY_ORANGE_SP(105);
public int getValue() {
return value;
}
public static ItemQuality getTypeByValue(int value) {
return map.getOrDefault(value, QUALITY_NONE);
}
public static ItemQuality getTypeByName(String name) {
return stringMap.getOrDefault(name, QUALITY_NONE);
}
private static final Int2ObjectMap<ItemQuality> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, ItemQuality> stringMap = new HashMap<>();
static {
Stream.of(values()).forEach(e -> {
map.put(e.getValue(), e);
stringMap.put(e.name(), e);
});
}
private final int value;
ItemQuality(int value) {
this.value = value;
}
public static ItemQuality getTypeByValue(int value) {
return map.getOrDefault(value, QUALITY_NONE);
}
public static ItemQuality getTypeByName(String name) {
return stringMap.getOrDefault(name, QUALITY_NONE);
}
public int getValue() {
return value;
}
}

View File

@@ -1,45 +1,46 @@
package emu.grasscutter.game.inventory;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum ItemType {
ITEM_NONE (0),
ITEM_VIRTUAL (1),
ITEM_MATERIAL (2),
ITEM_RELIQUARY (3),
ITEM_WEAPON (4),
ITEM_DISPLAY (5),
ITEM_FURNITURE (6);
private final int value;
private static final Int2ObjectMap<ItemType> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, ItemType> stringMap = new HashMap<>();
static {
Stream.of(values()).forEach(e -> {
map.put(e.getValue(), e);
stringMap.put(e.name(), e);
});
}
private ItemType(int value) {
this.value = value;
}
ITEM_NONE(0),
ITEM_VIRTUAL(1),
ITEM_MATERIAL(2),
ITEM_RELIQUARY(3),
ITEM_WEAPON(4),
ITEM_DISPLAY(5),
ITEM_FURNITURE(6);
public int getValue() {
return value;
}
public static ItemType getTypeByValue(int value) {
return map.getOrDefault(value, ITEM_NONE);
}
public static ItemType getTypeByName(String name) {
return stringMap.getOrDefault(name, ITEM_NONE);
}
private static final Int2ObjectMap<ItemType> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, ItemType> stringMap = new HashMap<>();
static {
Stream.of(values()).forEach(e -> {
map.put(e.getValue(), e);
stringMap.put(e.name(), e);
});
}
private final int value;
ItemType(int value) {
this.value = value;
}
public static ItemType getTypeByValue(int value) {
return map.getOrDefault(value, ITEM_NONE);
}
public static ItemType getTypeByName(String name) {
return stringMap.getOrDefault(name, ITEM_NONE);
}
public int getValue() {
return value;
}
}

View File

@@ -4,36 +4,36 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class MaterialInventoryTab implements InventoryTab {
private final Int2ObjectMap<GameItem> items;
private final int maxCapacity;
public MaterialInventoryTab(int maxCapacity) {
this.items = new Int2ObjectOpenHashMap<>();
this.maxCapacity = maxCapacity;
}
@Override
public GameItem getItemById(int id) {
return this.items.get(id);
}
private final Int2ObjectMap<GameItem> items;
private final int maxCapacity;
@Override
public void onAddItem(GameItem item) {
this.items.put(item.getItemId(), item);
}
public MaterialInventoryTab(int maxCapacity) {
this.items = new Int2ObjectOpenHashMap<>();
this.maxCapacity = maxCapacity;
}
@Override
public void onRemoveItem(GameItem item) {
this.items.remove(item.getItemId());
}
@Override
public GameItem getItemById(int id) {
return this.items.get(id);
}
@Override
public int getSize() {
return this.items.size();
}
@Override
public void onAddItem(GameItem item) {
this.items.put(item.getItemId(), item);
}
@Override
public int getMaxCapacity() {
return this.maxCapacity;
}
@Override
public void onRemoveItem(GameItem item) {
this.items.remove(item.getItemId());
}
@Override
public int getSize() {
return this.items.size();
}
@Override
public int getMaxCapacity() {
return this.maxCapacity;
}
}

View File

@@ -1,56 +1,55 @@
package emu.grasscutter.game.inventory;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum MaterialType {
MATERIAL_NONE (0),
MATERIAL_FOOD (1),
MATERIAL_QUEST (2),
MATERIAL_EXCHANGE (4),
MATERIAL_CONSUME (5),
MATERIAL_EXP_FRUIT (6),
MATERIAL_AVATAR (7),
MATERIAL_ADSORBATE (8),
MATERIAL_CRICKET (9),
MATERIAL_ELEM_CRYSTAL (10),
MATERIAL_WEAPON_EXP_STONE (11),
MATERIAL_CHEST (12),
MATERIAL_RELIQUARY_MATERIAL (13),
MATERIAL_AVATAR_MATERIAL (14),
MATERIAL_NOTICE_ADD_HP (15),
MATERIAL_SEA_LAMP (16),
MATERIAL_SELECTABLE_CHEST (17),
MATERIAL_FLYCLOAK (18),
MATERIAL_NAMECARD (19),
MATERIAL_TALENT (20),
MATERIAL_WIDGET (21),
MATERIAL_CHEST_BATCH_USE (22),
MATERIAL_FAKE_ABSORBATE (23),
MATERIAL_CONSUME_BATCH_USE (24),
MATERIAL_WOOD (25),
MATERIAL_FURNITURE_FORMULA (27),
MATERIAL_CHANNELLER_SLAB_BUFF (28),
MATERIAL_FURNITURE_SUITE_FORMULA (29),
MATERIAL_COSTUME (30),
MATERIAL_HOME_SEED (31),
MATERIAL_FISH_BAIT (32),
MATERIAL_FISH_ROD (33),
MATERIAL_SUMO_BUFF (34),
MATERIAL_FIREWORKS (35),
MATERIAL_BGM (36),
MATERIAL_SPICE_FOOD (37),
MATERIAL_ACTIVITY_ROBOT (38),
MATERIAL_ACTIVITY_GEAR (39),
MATERIAL_ACTIVITY_JIGSAW (40),
MATERIAL_ARANARA (41),
MATERIAL_DESHRET_MANUAL (46);
MATERIAL_NONE(0),
MATERIAL_FOOD(1),
MATERIAL_QUEST(2),
MATERIAL_EXCHANGE(4),
MATERIAL_CONSUME(5),
MATERIAL_EXP_FRUIT(6),
MATERIAL_AVATAR(7),
MATERIAL_ADSORBATE(8),
MATERIAL_CRICKET(9),
MATERIAL_ELEM_CRYSTAL(10),
MATERIAL_WEAPON_EXP_STONE(11),
MATERIAL_CHEST(12),
MATERIAL_RELIQUARY_MATERIAL(13),
MATERIAL_AVATAR_MATERIAL(14),
MATERIAL_NOTICE_ADD_HP(15),
MATERIAL_SEA_LAMP(16),
MATERIAL_SELECTABLE_CHEST(17),
MATERIAL_FLYCLOAK(18),
MATERIAL_NAMECARD(19),
MATERIAL_TALENT(20),
MATERIAL_WIDGET(21),
MATERIAL_CHEST_BATCH_USE(22),
MATERIAL_FAKE_ABSORBATE(23),
MATERIAL_CONSUME_BATCH_USE(24),
MATERIAL_WOOD(25),
MATERIAL_FURNITURE_FORMULA(27),
MATERIAL_CHANNELLER_SLAB_BUFF(28),
MATERIAL_FURNITURE_SUITE_FORMULA(29),
MATERIAL_COSTUME(30),
MATERIAL_HOME_SEED(31),
MATERIAL_FISH_BAIT(32),
MATERIAL_FISH_ROD(33),
MATERIAL_SUMO_BUFF(34),
MATERIAL_FIREWORKS(35),
MATERIAL_BGM(36),
MATERIAL_SPICE_FOOD(37),
MATERIAL_ACTIVITY_ROBOT(38),
MATERIAL_ACTIVITY_GEAR(39),
MATERIAL_ACTIVITY_JIGSAW(40),
MATERIAL_ARANARA(41),
MATERIAL_DESHRET_MANUAL(46);
private final int value;
private static final Int2ObjectMap<MaterialType> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, MaterialType> stringMap = new HashMap<>();
@@ -61,12 +60,10 @@ public enum MaterialType {
});
}
private MaterialType(int value) {
this.value = value;
}
private final int value;
public int getValue() {
return value;
MaterialType(int value) {
this.value = value;
}
public static MaterialType getTypeByValue(int value) {
@@ -76,4 +73,8 @@ public enum MaterialType {
public static MaterialType getTypeByName(String name) {
return stringMap.getOrDefault(name, MATERIAL_NONE);
}
public int getValue() {
return value;
}
}

View File

@@ -6,17 +6,14 @@ import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.Transient;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import org.bson.types.ObjectId;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import org.bson.types.ObjectId;
@Entity(value = "mail", useDiscriminator = false)
public class Mail {
@Id private ObjectId id;
@Indexed private int ownerUid;
public MailContent mailContent;
public List<MailItem> itemList;
public long sendTime;
@@ -25,7 +22,12 @@ public class Mail {
public boolean isRead;
public boolean isAttachmentGot;
public int stateValue;
@Transient private boolean shouldDelete;
@Id
private ObjectId id;
@Indexed
private int ownerUid;
@Transient
private boolean shouldDelete;
public Mail() {
this(new MailContent(), new ArrayList<MailItem>(), (int) Instant.now().getEpochSecond() + 604800); // TODO: add expire time to send mail command
@@ -51,18 +53,26 @@ public class Mail {
}
public ObjectId getId() {
return id;
}
return id;
}
public int getOwnerUid() {
return ownerUid;
}
public int getOwnerUid() {
return ownerUid;
}
public void setOwnerUid(int ownerUid) {
this.ownerUid = ownerUid;
}
public void setOwnerUid(int ownerUid) {
this.ownerUid = ownerUid;
}
@Entity
public void save() {
if (this.expireTime * 1000 < System.currentTimeMillis()) {
DatabaseHelper.deleteMail(this);
} else {
DatabaseHelper.saveMail(this);
}
}
@Entity
public static class MailContent {
public String title;
public String content;
@@ -105,7 +115,9 @@ public class Mail {
this(itemId, 1);
}
public MailItem(int itemId, int itemCount) { this(itemId, itemCount, 1); }
public MailItem(int itemId, int itemCount) {
this(itemId, itemCount, 1);
}
public MailItem(int itemId, int itemCount, int itemLevel) {
this.itemId = itemId;
@@ -113,12 +125,4 @@ public class Mail {
this.itemLevel = itemLevel;
}
}
public void save() {
if (this.expireTime * 1000 < System.currentTimeMillis()) {
DatabaseHelper.deleteMail(this);
} else {
DatabaseHelper.saveMail(this);
}
}
}

View File

@@ -1,9 +1,5 @@
package emu.grasscutter.game.mail;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.BasePlayerManager;
@@ -12,6 +8,10 @@ import emu.grasscutter.server.event.player.PlayerReceiveMailEvent;
import emu.grasscutter.server.packet.send.PacketDelMailRsp;
import emu.grasscutter.server.packet.send.PacketMailChangeNotify;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MailHandler extends BasePlayerManager {
private final List<Mail> mail;
@@ -29,15 +29,17 @@ public class MailHandler extends BasePlayerManager {
public void sendMail(Mail message) {
// Call mail receive event.
PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this.getPlayer(), message); event.call();
if (event.isCanceled()) return; message = event.getMessage();
PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this.getPlayer(), message);
event.call();
if (event.isCanceled()) return;
message = event.getMessage();
message.setOwnerUid(this.getPlayer().getUid());
message.save();
this.mail.add(message);
Grasscutter.getLogger().debug("Mail sent to user [" + this.getPlayer().getUid() + ":" + this.getPlayer().getNickname() + "]!");
Grasscutter.getLogger().debug("Mail sent to user [" + this.getPlayer().getUid() + ":" + this.getPlayer().getNickname() + "]!");
if (this.getPlayer().isOnline()) {
this.getPlayer().sendPacket(new PacketMailChangeNotify(this.getPlayer(), message));
@@ -75,7 +77,9 @@ public class MailHandler extends BasePlayerManager {
player.getSession().send(new PacketMailChangeNotify(player, null, deleted));
}
public Mail getMailById(int index) { return this.mail.get(index); }
public Mail getMailById(int index) {
return this.mail.get(index);
}
public int getMailIndex(Mail message) {
return this.mail.indexOf(message);

View File

@@ -68,18 +68,18 @@ public class FurnitureManager extends BasePlayerManager {
}
var furnitureSlot = FurnitureMakeSlotItem.of()
.avatarId(avatarId)
.makeId(makeId)
.beginTime(Utils.getCurrentSeconds())
.durTime(makeData.getMakeTime())
.build();
.avatarId(avatarId)
.makeId(makeId)
.beginTime(Utils.getCurrentSeconds())
.durTime(makeData.getMakeTime())
.build();
// add furniture make task
player.getHome().getFurnitureMakeSlotItemList().add(furnitureSlot);
player.getSession().send(new PacketFurnitureMakeStartRsp(Retcode.RET_SUCC_VALUE,
player.getHome().getFurnitureMakeSlotItemList().stream()
.map(FurnitureMakeSlotItem::toProto)
.toList()
player.getHome().getFurnitureMakeSlotItemList().stream()
.map(FurnitureMakeSlotItem::toProto)
.toList()
));
player.getHome().save();
@@ -102,8 +102,8 @@ public class FurnitureManager extends BasePlayerManager {
}
var slotItem = player.getHome().getFurnitureMakeSlotItemList().stream()
.filter(x -> x.getIndex() == index && x.getMakeId() == makeId)
.findFirst();
.filter(x -> x.getIndex() == index && x.getMakeId() == makeId)
.findFirst();
if (slotItem.isEmpty()) {
player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_FURNITURE_MAKE_NO_MAKE_DATA_VALUE, makeId, null, null));
@@ -111,7 +111,7 @@ public class FurnitureManager extends BasePlayerManager {
}
// pay the speedup item
if (isFastFinish && !player.getInventory().payItem(107013,1)) {
if (isFastFinish && !player.getInventory().payItem(107013, 1)) {
player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_FURNITURE_MAKE_UNFINISH_VALUE, makeId, null, null));
return;
}
@@ -129,14 +129,14 @@ public class FurnitureManager extends BasePlayerManager {
player.getInventory().addItem(121, makeData.getExp(), ActionReason.FurnitureMakeTake);
player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_SUCC_VALUE, makeId,
List.of(ItemParamOuterClass.ItemParam.newBuilder()
.setItemId(makeData.getFurnitureItemID())
.setCount(makeData.getCount())
.build()),
player.getHome().getFurnitureMakeSlotItemList().stream()
.map(FurnitureMakeSlotItem::toProto)
.toList()
));
List.of(ItemParamOuterClass.ItemParam.newBuilder()
.setItemId(makeData.getFurnitureItemID())
.setCount(makeData.getCount())
.build()),
player.getHome().getFurnitureMakeSlotItemList().stream()
.map(FurnitureMakeSlotItem::toProto)
.toList()
));
player.getHome().save();
}
}

View File

@@ -1,15 +1,14 @@
package emu.grasscutter.game.managers;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.server.packet.send.PacketPlayerPropNotify;
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
import emu.grasscutter.utils.Utils;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
public class ResinManager extends BasePlayerManager {
public ResinManager(Player player) {
@@ -104,7 +103,7 @@ public class ResinManager extends BasePlayerManager {
// Calculate how much resin we need to refill and update player.
// Note that this can be more than one in case the player
// logged off with uncapped resin and is now logging in again.
int recharge = 1 + (int)((currentTime - this.player.getNextResinRefresh()) / GAME_OPTIONS.resinOptions.rechargeTime);
int recharge = 1 + ((currentTime - this.player.getNextResinRefresh()) / GAME_OPTIONS.resinOptions.rechargeTime);
int newResin = Math.min(GAME_OPTIONS.resinOptions.cap, currentResin + recharge);
int resinChange = newResin - currentResin;
@@ -114,8 +113,7 @@ public class ResinManager extends BasePlayerManager {
// Set to zero to disable recharge (because on/over cap.)
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
this.player.setNextResinRefresh(0);
}
else {
} else {
int nextRecharge = this.player.getNextResinRefresh() + resinChange * GAME_OPTIONS.resinOptions.rechargeTime;
this.player.setNextResinRefresh(nextRecharge);
}

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