mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-22 20:04:56 +01:00
Run Spotless on src/main
This commit is contained in:
@@ -1,24 +1,23 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
public abstract class BasePlayerDataManager {
|
||||
protected transient Player player;
|
||||
|
||||
public BasePlayerDataManager() {
|
||||
}
|
||||
|
||||
public BasePlayerDataManager(@NonNull Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
if (this.player == null) {
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
public abstract class BasePlayerDataManager {
|
||||
protected transient Player player;
|
||||
|
||||
public BasePlayerDataManager() {}
|
||||
|
||||
public BasePlayerDataManager(@NonNull Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
if (this.player == null) {
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
public abstract class BasePlayerManager {
|
||||
protected transient final Player player;
|
||||
|
||||
public BasePlayerManager(@NonNull Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the player to the database
|
||||
*/
|
||||
public void save() {
|
||||
getPlayer().save();
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
public abstract class BasePlayerManager {
|
||||
protected final transient Player player;
|
||||
|
||||
public BasePlayerManager(@NonNull Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
/** Saves the player to the database */
|
||||
public void save() {
|
||||
getPlayer().save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +1,64 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.ForwardTypeOuterClass.ForwardType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class InvokeHandler<T> {
|
||||
private final List<T> entryListForwardAll;
|
||||
private final List<T> entryListForwardAllExceptCur;
|
||||
private final List<T> entryListForwardHost;
|
||||
private final Class<? extends BasePacket> packetClass;
|
||||
|
||||
public InvokeHandler(Class<? extends BasePacket> packetClass) {
|
||||
this.entryListForwardAll = new ArrayList<>();
|
||||
this.entryListForwardAllExceptCur = new ArrayList<>();
|
||||
this.entryListForwardHost = new ArrayList<>();
|
||||
this.packetClass = packetClass;
|
||||
}
|
||||
|
||||
public synchronized void addEntry(ForwardType forward, T entry) {
|
||||
switch (forward) {
|
||||
case FORWARD_TYPE_TO_ALL -> entryListForwardAll.add(entry);
|
||||
case FORWARD_TYPE_TO_ALL_EXCEPT_CUR, FORWARD_TYPE_TO_ALL_EXIST_EXCEPT_CUR ->
|
||||
entryListForwardAllExceptCur.add(entry);
|
||||
case FORWARD_TYPE_TO_HOST -> entryListForwardHost.add(entry);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void update(Player player) {
|
||||
if (player.getWorld() == null || player.getScene() == null) {
|
||||
this.entryListForwardAll.clear();
|
||||
this.entryListForwardAllExceptCur.clear();
|
||||
this.entryListForwardHost.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (entryListForwardAll.size() > 0) {
|
||||
BasePacket packet = packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardAll);
|
||||
player.getScene().broadcastPacket(packet);
|
||||
this.entryListForwardAll.clear();
|
||||
}
|
||||
if (entryListForwardAllExceptCur.size() > 0) {
|
||||
BasePacket packet = packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardAllExceptCur);
|
||||
player.getScene().broadcastPacketToOthers(player, packet);
|
||||
this.entryListForwardAllExceptCur.clear();
|
||||
}
|
||||
if (entryListForwardHost.size() > 0) {
|
||||
BasePacket packet = packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardHost);
|
||||
player.getWorld().getHost().sendPacket(packet);
|
||||
this.entryListForwardHost.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.ForwardTypeOuterClass.ForwardType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class InvokeHandler<T> {
|
||||
private final List<T> entryListForwardAll;
|
||||
private final List<T> entryListForwardAllExceptCur;
|
||||
private final List<T> entryListForwardHost;
|
||||
private final Class<? extends BasePacket> packetClass;
|
||||
|
||||
public InvokeHandler(Class<? extends BasePacket> packetClass) {
|
||||
this.entryListForwardAll = new ArrayList<>();
|
||||
this.entryListForwardAllExceptCur = new ArrayList<>();
|
||||
this.entryListForwardHost = new ArrayList<>();
|
||||
this.packetClass = packetClass;
|
||||
}
|
||||
|
||||
public synchronized void addEntry(ForwardType forward, T entry) {
|
||||
switch (forward) {
|
||||
case FORWARD_TYPE_TO_ALL -> entryListForwardAll.add(entry);
|
||||
case FORWARD_TYPE_TO_ALL_EXCEPT_CUR,
|
||||
FORWARD_TYPE_TO_ALL_EXIST_EXCEPT_CUR -> entryListForwardAllExceptCur.add(entry);
|
||||
case FORWARD_TYPE_TO_HOST -> entryListForwardHost.add(entry);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void update(Player player) {
|
||||
if (player.getWorld() == null || player.getScene() == null) {
|
||||
this.entryListForwardAll.clear();
|
||||
this.entryListForwardAllExceptCur.clear();
|
||||
this.entryListForwardHost.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (entryListForwardAll.size() > 0) {
|
||||
BasePacket packet =
|
||||
packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardAll);
|
||||
player.getScene().broadcastPacket(packet);
|
||||
this.entryListForwardAll.clear();
|
||||
}
|
||||
if (entryListForwardAllExceptCur.size() > 0) {
|
||||
BasePacket packet =
|
||||
packetClass
|
||||
.getDeclaredConstructor(List.class)
|
||||
.newInstance(this.entryListForwardAllExceptCur);
|
||||
player.getScene().broadcastPacketToOthers(player, packet);
|
||||
this.entryListForwardAllExceptCur.clear();
|
||||
}
|
||||
if (entryListForwardHost.size() > 0) {
|
||||
BasePacket packet =
|
||||
packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardHost);
|
||||
player.getWorld().getHost().sendPacket(packet);
|
||||
this.entryListForwardHost.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +1,64 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.net.proto.BirthdayOuterClass.Birthday;
|
||||
|
||||
@Entity
|
||||
public class PlayerBirthday {
|
||||
private int day;
|
||||
private int month;
|
||||
|
||||
public PlayerBirthday() {
|
||||
this.day = 0;
|
||||
this.month = 0;
|
||||
}
|
||||
|
||||
public PlayerBirthday(int day, int month) {
|
||||
this.day = day;
|
||||
this.month = month;
|
||||
}
|
||||
|
||||
public PlayerBirthday set(PlayerBirthday birth) {
|
||||
this.day = birth.day;
|
||||
this.month = birth.month;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlayerBirthday set(int d, int m) {
|
||||
this.day = d;
|
||||
this.month = m;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDay() {
|
||||
return this.day;
|
||||
}
|
||||
|
||||
public PlayerBirthday setDay(int value) {
|
||||
this.day = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMonth() {
|
||||
return this.month;
|
||||
}
|
||||
|
||||
public PlayerBirthday setMonth(int value) {
|
||||
this.month = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Birthday toProto() {
|
||||
return Birthday.newBuilder()
|
||||
.setDay(this.getDay())
|
||||
.setMonth(this.getMonth())
|
||||
.build();
|
||||
}
|
||||
|
||||
public Birthday.Builder getFilledProtoWhenNotEmpty() {
|
||||
if (this.getDay() > 0) {
|
||||
return Birthday.newBuilder()
|
||||
.setDay(this.getDay())
|
||||
.setMonth(this.getMonth());
|
||||
}
|
||||
|
||||
return Birthday.newBuilder();
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.net.proto.BirthdayOuterClass.Birthday;
|
||||
|
||||
@Entity
|
||||
public class PlayerBirthday {
|
||||
private int day;
|
||||
private int month;
|
||||
|
||||
public PlayerBirthday() {
|
||||
this.day = 0;
|
||||
this.month = 0;
|
||||
}
|
||||
|
||||
public PlayerBirthday(int day, int month) {
|
||||
this.day = day;
|
||||
this.month = month;
|
||||
}
|
||||
|
||||
public PlayerBirthday set(PlayerBirthday birth) {
|
||||
this.day = birth.day;
|
||||
this.month = birth.month;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlayerBirthday set(int d, int m) {
|
||||
this.day = d;
|
||||
this.month = m;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDay() {
|
||||
return this.day;
|
||||
}
|
||||
|
||||
public PlayerBirthday setDay(int value) {
|
||||
this.day = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMonth() {
|
||||
return this.month;
|
||||
}
|
||||
|
||||
public PlayerBirthday setMonth(int value) {
|
||||
this.month = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Birthday toProto() {
|
||||
return Birthday.newBuilder().setDay(this.getDay()).setMonth(this.getMonth()).build();
|
||||
}
|
||||
|
||||
public Birthday.Builder getFilledProtoWhenNotEmpty() {
|
||||
if (this.getDay() > 0) {
|
||||
return Birthday.newBuilder().setDay(this.getDay()).setMonth(this.getMonth());
|
||||
}
|
||||
|
||||
return Birthday.newBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,214 +1,224 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
||||
import emu.grasscutter.data.excels.BuffData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.net.proto.ServerBuffChangeNotifyOuterClass.ServerBuffChangeNotify.ServerBuffChangeType;
|
||||
import emu.grasscutter.net.proto.ServerBuffOuterClass.ServerBuff;
|
||||
import emu.grasscutter.server.packet.send.PacketServerBuffChangeNotify;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class PlayerBuffManager extends BasePlayerManager {
|
||||
private final List<PlayerBuff> pendingBuffs;
|
||||
private final Int2ObjectMap<PlayerBuff> buffs; // Server buffs
|
||||
private int nextBuffUid;
|
||||
|
||||
public PlayerBuffManager(Player player) {
|
||||
super(player);
|
||||
this.buffs = new Int2ObjectOpenHashMap<>();
|
||||
this.pendingBuffs = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new uid for a server buff
|
||||
*
|
||||
* @return New integer buff uid
|
||||
*/
|
||||
private int getNextBuffUid() {
|
||||
return ++nextBuffUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the player has a buff with this group id
|
||||
*
|
||||
* @param groupId Buff group id
|
||||
* @return True if a buff with this group id exists
|
||||
*/
|
||||
public synchronized boolean hasBuff(int groupId) {
|
||||
return this.buffs.containsKey(groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all player buffs
|
||||
*/
|
||||
public synchronized void clearBuffs() {
|
||||
// Remove from player
|
||||
getPlayer().sendPacket(
|
||||
new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, this.buffs.values())
|
||||
);
|
||||
|
||||
// Clear
|
||||
this.buffs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a server buff to the player.
|
||||
*
|
||||
* @param buffId Server buff id
|
||||
* @return True if a buff was added
|
||||
*/
|
||||
public boolean addBuff(int buffId) {
|
||||
return addBuff(buffId, -1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a server buff to the player.
|
||||
*
|
||||
* @param buffId Server buff id
|
||||
* @param duration Duration of the buff in seconds. Set to 0 for an infinite buff.
|
||||
* @return True if a buff was added
|
||||
*/
|
||||
public synchronized boolean addBuff(int buffId, float duration) {
|
||||
return addBuff(buffId, duration, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a server buff to the player.
|
||||
*
|
||||
* @param buffId Server buff id
|
||||
* @param duration Duration of the buff in seconds. Set to 0 for an infinite buff.
|
||||
* @param target Target avatar
|
||||
* @return True if a buff was added
|
||||
*/
|
||||
public synchronized boolean addBuff(int buffId, float duration, Avatar target) {
|
||||
// Get buff excel data
|
||||
BuffData buffData = GameData.getBuffDataMap().get(buffId);
|
||||
if (buffData == null) return false;
|
||||
|
||||
boolean success = false;
|
||||
|
||||
// Perform onAdded actions
|
||||
success |= Optional.ofNullable(GameData.getAbilityData(buffData.getAbilityName()))
|
||||
.map(data -> data.modifiers.get(buffData.getModifierName()))
|
||||
.map(modifier -> modifier.onAdded)
|
||||
.map(onAdded -> {
|
||||
|
||||
var s = false;
|
||||
for (var a : onAdded) {
|
||||
Grasscutter.getLogger().debug("onAdded exists");
|
||||
if (Objects.requireNonNull(a.type) == AbilityModifierAction.Type.HealHP) {
|
||||
Grasscutter.getLogger().debug("Attempting heal");
|
||||
if (target == null) continue;
|
||||
var maxHp = target.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
var amount = a.amount.get() + a.amountByTargetMaxHPRatio.get() * maxHp;
|
||||
target.getAsEntity().heal(amount);
|
||||
s = true;
|
||||
Grasscutter.getLogger().debug("Healed {}", amount);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
})
|
||||
.orElse(false);
|
||||
Grasscutter.getLogger().debug("Oh no");
|
||||
|
||||
// Set duration
|
||||
if (duration < 0f) {
|
||||
duration = buffData.getTime();
|
||||
}
|
||||
|
||||
// Dont add buff if duration is equal or less than 0
|
||||
if (duration <= 0) {
|
||||
return success;
|
||||
}
|
||||
|
||||
// Clear previous buff if it exists
|
||||
this.removeBuff(buffData.getGroupId());
|
||||
|
||||
// Create and store buff
|
||||
PlayerBuff buff = new PlayerBuff(getNextBuffUid(), buffData, duration);
|
||||
this.buffs.put(buff.getGroupId(), buff);
|
||||
|
||||
// Packet
|
||||
getPlayer().sendPacket(new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_ADD_SERVER_BUFF, buff));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a buff by its group id
|
||||
*
|
||||
* @param buffGroupId Server buff group id
|
||||
* @return True if a buff was remove
|
||||
*/
|
||||
public synchronized boolean removeBuff(int buffGroupId) {
|
||||
PlayerBuff buff = this.buffs.remove(buffGroupId);
|
||||
|
||||
if (buff != null) {
|
||||
getPlayer().sendPacket(
|
||||
new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, buff)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Skip if no buffs
|
||||
if (this.buffs.isEmpty()) return;
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
// Add to pending buffs to remove if buff has expired
|
||||
this.buffs.values().removeIf(buff -> {
|
||||
if (currentTime <= buff.getEndTime())
|
||||
return false;
|
||||
this.pendingBuffs.add(buff);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (this.pendingBuffs.size() > 0) {
|
||||
// Send packet
|
||||
getPlayer().sendPacket(
|
||||
new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, this.pendingBuffs)
|
||||
);
|
||||
this.pendingBuffs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class PlayerBuff {
|
||||
private final int uid;
|
||||
private final BuffData buffData;
|
||||
private final long endTime;
|
||||
|
||||
public PlayerBuff(int uid, BuffData buffData, float duration) {
|
||||
this.uid = uid;
|
||||
this.buffData = buffData;
|
||||
this.endTime = System.currentTimeMillis() + ((long) duration * 1000);
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return getBuffData().getGroupId();
|
||||
}
|
||||
|
||||
public ServerBuff toProto() {
|
||||
return ServerBuff.newBuilder()
|
||||
.setServerBuffUid(this.getUid())
|
||||
.setServerBuffId(this.getBuffData().getId())
|
||||
.setServerBuffType(this.getBuffData().getServerBuffType().getValue())
|
||||
.setInstancedModifierId(1)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
||||
import emu.grasscutter.data.excels.BuffData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.net.proto.ServerBuffChangeNotifyOuterClass.ServerBuffChangeNotify.ServerBuffChangeType;
|
||||
import emu.grasscutter.net.proto.ServerBuffOuterClass.ServerBuff;
|
||||
import emu.grasscutter.server.packet.send.PacketServerBuffChangeNotify;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import lombok.Getter;
|
||||
|
||||
public class PlayerBuffManager extends BasePlayerManager {
|
||||
private final List<PlayerBuff> pendingBuffs;
|
||||
private final Int2ObjectMap<PlayerBuff> buffs; // Server buffs
|
||||
private int nextBuffUid;
|
||||
|
||||
public PlayerBuffManager(Player player) {
|
||||
super(player);
|
||||
this.buffs = new Int2ObjectOpenHashMap<>();
|
||||
this.pendingBuffs = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new uid for a server buff
|
||||
*
|
||||
* @return New integer buff uid
|
||||
*/
|
||||
private int getNextBuffUid() {
|
||||
return ++nextBuffUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the player has a buff with this group id
|
||||
*
|
||||
* @param groupId Buff group id
|
||||
* @return True if a buff with this group id exists
|
||||
*/
|
||||
public synchronized boolean hasBuff(int groupId) {
|
||||
return this.buffs.containsKey(groupId);
|
||||
}
|
||||
|
||||
/** Clears all player buffs */
|
||||
public synchronized void clearBuffs() {
|
||||
// Remove from player
|
||||
getPlayer()
|
||||
.sendPacket(
|
||||
new PacketServerBuffChangeNotify(
|
||||
getPlayer(),
|
||||
ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF,
|
||||
this.buffs.values()));
|
||||
|
||||
// Clear
|
||||
this.buffs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a server buff to the player.
|
||||
*
|
||||
* @param buffId Server buff id
|
||||
* @return True if a buff was added
|
||||
*/
|
||||
public boolean addBuff(int buffId) {
|
||||
return addBuff(buffId, -1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a server buff to the player.
|
||||
*
|
||||
* @param buffId Server buff id
|
||||
* @param duration Duration of the buff in seconds. Set to 0 for an infinite buff.
|
||||
* @return True if a buff was added
|
||||
*/
|
||||
public synchronized boolean addBuff(int buffId, float duration) {
|
||||
return addBuff(buffId, duration, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a server buff to the player.
|
||||
*
|
||||
* @param buffId Server buff id
|
||||
* @param duration Duration of the buff in seconds. Set to 0 for an infinite buff.
|
||||
* @param target Target avatar
|
||||
* @return True if a buff was added
|
||||
*/
|
||||
public synchronized boolean addBuff(int buffId, float duration, Avatar target) {
|
||||
// Get buff excel data
|
||||
BuffData buffData = GameData.getBuffDataMap().get(buffId);
|
||||
if (buffData == null) return false;
|
||||
|
||||
boolean success = false;
|
||||
|
||||
// Perform onAdded actions
|
||||
success |=
|
||||
Optional.ofNullable(GameData.getAbilityData(buffData.getAbilityName()))
|
||||
.map(data -> data.modifiers.get(buffData.getModifierName()))
|
||||
.map(modifier -> modifier.onAdded)
|
||||
.map(
|
||||
onAdded -> {
|
||||
var s = false;
|
||||
for (var a : onAdded) {
|
||||
Grasscutter.getLogger().debug("onAdded exists");
|
||||
if (Objects.requireNonNull(a.type) == AbilityModifierAction.Type.HealHP) {
|
||||
Grasscutter.getLogger().debug("Attempting heal");
|
||||
if (target == null) continue;
|
||||
var maxHp = target.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
var amount = a.amount.get() + a.amountByTargetMaxHPRatio.get() * maxHp;
|
||||
target.getAsEntity().heal(amount);
|
||||
s = true;
|
||||
Grasscutter.getLogger().debug("Healed {}", amount);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
})
|
||||
.orElse(false);
|
||||
Grasscutter.getLogger().debug("Oh no");
|
||||
|
||||
// Set duration
|
||||
if (duration < 0f) {
|
||||
duration = buffData.getTime();
|
||||
}
|
||||
|
||||
// Dont add buff if duration is equal or less than 0
|
||||
if (duration <= 0) {
|
||||
return success;
|
||||
}
|
||||
|
||||
// Clear previous buff if it exists
|
||||
this.removeBuff(buffData.getGroupId());
|
||||
|
||||
// Create and store buff
|
||||
PlayerBuff buff = new PlayerBuff(getNextBuffUid(), buffData, duration);
|
||||
this.buffs.put(buff.getGroupId(), buff);
|
||||
|
||||
// Packet
|
||||
getPlayer()
|
||||
.sendPacket(
|
||||
new PacketServerBuffChangeNotify(
|
||||
getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_ADD_SERVER_BUFF, buff));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a buff by its group id
|
||||
*
|
||||
* @param buffGroupId Server buff group id
|
||||
* @return True if a buff was remove
|
||||
*/
|
||||
public synchronized boolean removeBuff(int buffGroupId) {
|
||||
PlayerBuff buff = this.buffs.remove(buffGroupId);
|
||||
|
||||
if (buff != null) {
|
||||
getPlayer()
|
||||
.sendPacket(
|
||||
new PacketServerBuffChangeNotify(
|
||||
getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, buff));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Skip if no buffs
|
||||
if (this.buffs.isEmpty()) return;
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
// Add to pending buffs to remove if buff has expired
|
||||
this.buffs
|
||||
.values()
|
||||
.removeIf(
|
||||
buff -> {
|
||||
if (currentTime <= buff.getEndTime()) return false;
|
||||
this.pendingBuffs.add(buff);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (this.pendingBuffs.size() > 0) {
|
||||
// Send packet
|
||||
getPlayer()
|
||||
.sendPacket(
|
||||
new PacketServerBuffChangeNotify(
|
||||
getPlayer(),
|
||||
ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF,
|
||||
this.pendingBuffs));
|
||||
this.pendingBuffs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class PlayerBuff {
|
||||
private final int uid;
|
||||
private final BuffData buffData;
|
||||
private final long endTime;
|
||||
|
||||
public PlayerBuff(int uid, BuffData buffData, float duration) {
|
||||
this.uid = uid;
|
||||
this.buffData = buffData;
|
||||
this.endTime = System.currentTimeMillis() + ((long) duration * 1000);
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return getBuffData().getGroupId();
|
||||
}
|
||||
|
||||
public ServerBuff toProto() {
|
||||
return ServerBuff.newBuilder()
|
||||
.setServerBuffUid(this.getUid())
|
||||
.setServerBuffId(this.getBuffData().getId())
|
||||
.setServerBuffType(this.getBuffData().getServerBuffType().getValue())
|
||||
.setInstancedModifierId(1)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,141 +1,136 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.CodexAnimalData;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
public class PlayerCodex {
|
||||
@Transient
|
||||
private Player player;
|
||||
|
||||
//itemId is not codexId!
|
||||
@Getter
|
||||
private final Set<Integer> unlockedWeapon;
|
||||
@Getter
|
||||
private final Map<Integer, Integer> unlockedAnimal;
|
||||
@Getter
|
||||
private final Set<Integer> unlockedMaterial;
|
||||
@Getter
|
||||
private final Set<Integer> unlockedBook;
|
||||
@Getter
|
||||
private final Set<Integer> unlockedTip;
|
||||
@Getter
|
||||
private final Set<Integer> unlockedView;
|
||||
@Getter
|
||||
private Set<Integer> unlockedReliquary;
|
||||
@Getter
|
||||
private final Set<Integer> unlockedReliquarySuitCodex;
|
||||
|
||||
public PlayerCodex() {
|
||||
this.unlockedWeapon = new HashSet<>();
|
||||
this.unlockedAnimal = new HashMap<>();
|
||||
this.unlockedMaterial = new HashSet<>();
|
||||
this.unlockedBook = new HashSet<>();
|
||||
this.unlockedTip = new HashSet<>();
|
||||
this.unlockedView = new HashSet<>();
|
||||
this.unlockedReliquary = new HashSet<>();
|
||||
this.unlockedReliquarySuitCodex = new HashSet<>();
|
||||
}
|
||||
|
||||
public PlayerCodex(Player player) {
|
||||
this();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
this.fixReliquaries();
|
||||
}
|
||||
|
||||
public void checkAddedItem(GameItem item) {
|
||||
val itemData = item.getItemData();
|
||||
val itemId = item.getItemId();
|
||||
switch (itemData.getItemType()) {
|
||||
case ITEM_WEAPON -> {
|
||||
Optional.ofNullable(GameData.getCodexWeaponDataIdMap().get(itemId))
|
||||
.ifPresent(codexData -> {
|
||||
if (this.getUnlockedWeapon().add(itemId)) {
|
||||
this.player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(2, codexData.getId()));
|
||||
}
|
||||
});
|
||||
}
|
||||
case ITEM_MATERIAL -> {
|
||||
switch (itemData.getMaterialType()) {
|
||||
// Is this check even needed?
|
||||
case MATERIAL_FOOD, MATERIAL_WIDGET, MATERIAL_EXCHANGE, MATERIAL_AVATAR_MATERIAL, MATERIAL_NOTICE_ADD_HP -> {
|
||||
Optional.ofNullable(GameData.getCodexMaterialDataIdMap().get(itemId))
|
||||
.ifPresent(codexData -> {
|
||||
if (this.getUnlockedMaterial().add(itemId)) {
|
||||
this.player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(4, codexData.getId()));
|
||||
}
|
||||
});
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
case ITEM_RELIQUARY -> {
|
||||
val reliquaryId = (itemId / 10) * 10; // Normalize to 0-substat form
|
||||
if (this.getUnlockedReliquary().add(reliquaryId))
|
||||
checkUnlockedSuits(reliquaryId);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkAnimal(GameEntity target, CodexAnimalData.CountType countType) {
|
||||
if (target instanceof EntityMonster) {
|
||||
val monsterId = ((EntityMonster) target).getMonsterData().getId();
|
||||
val codexAnimal = GameData.getCodexAnimalDataMap().get(monsterId);
|
||||
if (codexAnimal == null) return;
|
||||
|
||||
val animalCountType = codexAnimal.getCountType();
|
||||
if (animalCountType != countType && animalCountType != null) return;
|
||||
|
||||
this.getUnlockedAnimal().merge(monsterId, 1, (i, j) -> i + 1);
|
||||
|
||||
player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(3, monsterId));
|
||||
}
|
||||
}
|
||||
|
||||
public void checkUnlockedSuits(int reliquaryId) {
|
||||
GameData.getCodexReliquaryArrayList().stream()
|
||||
.filter(x -> !this.getUnlockedReliquarySuitCodex().contains(x.getId()))
|
||||
.filter(x -> x.containsId(reliquaryId))
|
||||
.filter(x -> this.getUnlockedReliquary().containsAll(x.getIds()))
|
||||
.forEach(x -> {
|
||||
int id = x.getId();
|
||||
this.getUnlockedReliquarySuitCodex().add(id);
|
||||
this.player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(8, id));
|
||||
});
|
||||
}
|
||||
|
||||
@Deprecated // Maybe remove this if we ever stop caring about older dbs
|
||||
private void fixReliquaries() {
|
||||
// Migrate older database entries which were using non-canonical forms of itemIds
|
||||
val newReliquaries = new HashSet<Integer>();
|
||||
this.unlockedReliquary.forEach(i -> newReliquaries.add((i / 10) * 10));
|
||||
this.unlockedReliquary = newReliquaries;
|
||||
|
||||
GameData.getCodexReliquaryArrayList().stream()
|
||||
.filter(x -> !this.getUnlockedReliquarySuitCodex().contains(x.getId()))
|
||||
.filter(x -> this.getUnlockedReliquary().containsAll(x.getIds()))
|
||||
.forEach(x -> this.getUnlockedReliquarySuitCodex().add(x.getId()));
|
||||
this.player.save();
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.CodexAnimalData;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify;
|
||||
import java.util.*;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
@Entity
|
||||
public class PlayerCodex {
|
||||
@Transient private Player player;
|
||||
|
||||
// itemId is not codexId!
|
||||
@Getter private final Set<Integer> unlockedWeapon;
|
||||
@Getter private final Map<Integer, Integer> unlockedAnimal;
|
||||
@Getter private final Set<Integer> unlockedMaterial;
|
||||
@Getter private final Set<Integer> unlockedBook;
|
||||
@Getter private final Set<Integer> unlockedTip;
|
||||
@Getter private final Set<Integer> unlockedView;
|
||||
@Getter private Set<Integer> unlockedReliquary;
|
||||
@Getter private final Set<Integer> unlockedReliquarySuitCodex;
|
||||
|
||||
public PlayerCodex() {
|
||||
this.unlockedWeapon = new HashSet<>();
|
||||
this.unlockedAnimal = new HashMap<>();
|
||||
this.unlockedMaterial = new HashSet<>();
|
||||
this.unlockedBook = new HashSet<>();
|
||||
this.unlockedTip = new HashSet<>();
|
||||
this.unlockedView = new HashSet<>();
|
||||
this.unlockedReliquary = new HashSet<>();
|
||||
this.unlockedReliquarySuitCodex = new HashSet<>();
|
||||
}
|
||||
|
||||
public PlayerCodex(Player player) {
|
||||
this();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
this.fixReliquaries();
|
||||
}
|
||||
|
||||
public void checkAddedItem(GameItem item) {
|
||||
val itemData = item.getItemData();
|
||||
val itemId = item.getItemId();
|
||||
switch (itemData.getItemType()) {
|
||||
case ITEM_WEAPON -> {
|
||||
Optional.ofNullable(GameData.getCodexWeaponDataIdMap().get(itemId))
|
||||
.ifPresent(
|
||||
codexData -> {
|
||||
if (this.getUnlockedWeapon().add(itemId)) {
|
||||
this.player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(2, codexData.getId()));
|
||||
}
|
||||
});
|
||||
}
|
||||
case ITEM_MATERIAL -> {
|
||||
switch (itemData.getMaterialType()) {
|
||||
// Is this check even needed?
|
||||
case MATERIAL_FOOD,
|
||||
MATERIAL_WIDGET,
|
||||
MATERIAL_EXCHANGE,
|
||||
MATERIAL_AVATAR_MATERIAL,
|
||||
MATERIAL_NOTICE_ADD_HP -> {
|
||||
Optional.ofNullable(GameData.getCodexMaterialDataIdMap().get(itemId))
|
||||
.ifPresent(
|
||||
codexData -> {
|
||||
if (this.getUnlockedMaterial().add(itemId)) {
|
||||
this.player.save();
|
||||
this.player.sendPacket(
|
||||
new PacketCodexDataUpdateNotify(4, codexData.getId()));
|
||||
}
|
||||
});
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
case ITEM_RELIQUARY -> {
|
||||
val reliquaryId = (itemId / 10) * 10; // Normalize to 0-substat form
|
||||
if (this.getUnlockedReliquary().add(reliquaryId)) checkUnlockedSuits(reliquaryId);
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkAnimal(GameEntity target, CodexAnimalData.CountType countType) {
|
||||
if (target instanceof EntityMonster) {
|
||||
val monsterId = ((EntityMonster) target).getMonsterData().getId();
|
||||
val codexAnimal = GameData.getCodexAnimalDataMap().get(monsterId);
|
||||
if (codexAnimal == null) return;
|
||||
|
||||
val animalCountType = codexAnimal.getCountType();
|
||||
if (animalCountType != countType && animalCountType != null) return;
|
||||
|
||||
this.getUnlockedAnimal().merge(monsterId, 1, (i, j) -> i + 1);
|
||||
|
||||
player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(3, monsterId));
|
||||
}
|
||||
}
|
||||
|
||||
public void checkUnlockedSuits(int reliquaryId) {
|
||||
GameData.getCodexReliquaryArrayList().stream()
|
||||
.filter(x -> !this.getUnlockedReliquarySuitCodex().contains(x.getId()))
|
||||
.filter(x -> x.containsId(reliquaryId))
|
||||
.filter(x -> this.getUnlockedReliquary().containsAll(x.getIds()))
|
||||
.forEach(
|
||||
x -> {
|
||||
int id = x.getId();
|
||||
this.getUnlockedReliquarySuitCodex().add(id);
|
||||
this.player.save();
|
||||
this.player.sendPacket(new PacketCodexDataUpdateNotify(8, id));
|
||||
});
|
||||
}
|
||||
|
||||
@Deprecated // Maybe remove this if we ever stop caring about older dbs
|
||||
private void fixReliquaries() {
|
||||
// Migrate older database entries which were using non-canonical forms of itemIds
|
||||
val newReliquaries = new HashSet<Integer>();
|
||||
this.unlockedReliquary.forEach(i -> newReliquaries.add((i / 10) * 10));
|
||||
this.unlockedReliquary = newReliquaries;
|
||||
|
||||
GameData.getCodexReliquaryArrayList().stream()
|
||||
.filter(x -> !this.getUnlockedReliquarySuitCodex().contains(x.getId()))
|
||||
.filter(x -> this.getUnlockedReliquary().containsAll(x.getIds()))
|
||||
.forEach(x -> this.getUnlockedReliquarySuitCodex().add(x.getId()));
|
||||
this.player.save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,68 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity(useDiscriminator = false)
|
||||
public class PlayerCollectionRecords {
|
||||
private Map<Integer, CollectionRecord> records;
|
||||
|
||||
private Map<Integer, CollectionRecord> getRecords() {
|
||||
if (records == null) {
|
||||
records = new HashMap<>();
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
||||
public void addRecord(int configId, long expiredMillisecond) {
|
||||
Map<Integer, CollectionRecord> records;
|
||||
synchronized (records = getRecords()) {
|
||||
records.put(configId, new CollectionRecord(configId, expiredMillisecond + System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean findRecord(int configId) {
|
||||
Map<Integer, CollectionRecord> records;
|
||||
synchronized (records = getRecords()) {
|
||||
CollectionRecord record = records.get(configId);
|
||||
|
||||
if (record == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean expired = record.getExpiredTime() < System.currentTimeMillis();
|
||||
|
||||
if (expired) {
|
||||
records.remove(configId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class CollectionRecord {
|
||||
private int configId;
|
||||
private long expiredTime;
|
||||
|
||||
@Deprecated // Morphia
|
||||
public CollectionRecord() {
|
||||
}
|
||||
|
||||
public CollectionRecord(int configId, long expiredTime) {
|
||||
this.configId = configId;
|
||||
this.expiredTime = expiredTime;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public long getExpiredTime() {
|
||||
return expiredTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity(useDiscriminator = false)
|
||||
public class PlayerCollectionRecords {
|
||||
private Map<Integer, CollectionRecord> records;
|
||||
|
||||
private Map<Integer, CollectionRecord> getRecords() {
|
||||
if (records == null) {
|
||||
records = new HashMap<>();
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
||||
public void addRecord(int configId, long expiredMillisecond) {
|
||||
Map<Integer, CollectionRecord> records;
|
||||
synchronized (records = getRecords()) {
|
||||
records.put(
|
||||
configId,
|
||||
new CollectionRecord(configId, expiredMillisecond + System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean findRecord(int configId) {
|
||||
Map<Integer, CollectionRecord> records;
|
||||
synchronized (records = getRecords()) {
|
||||
CollectionRecord record = records.get(configId);
|
||||
|
||||
if (record == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean expired = record.getExpiredTime() < System.currentTimeMillis();
|
||||
|
||||
if (expired) {
|
||||
records.remove(configId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class CollectionRecord {
|
||||
private int configId;
|
||||
private long expiredTime;
|
||||
|
||||
@Deprecated // Morphia
|
||||
public CollectionRecord() {}
|
||||
|
||||
public CollectionRecord(int configId, long expiredTime) {
|
||||
this.configId = configId;
|
||||
this.expiredTime = expiredTime;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public long getExpiredTime() {
|
||||
return expiredTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,219 +1,239 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||
import emu.grasscutter.data.excels.OpenStateData;
|
||||
import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.quest.enums.QuestState;
|
||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// @Entity
|
||||
public class PlayerProgressManager extends BasePlayerDataManager {
|
||||
/******************************************************************************************************************
|
||||
******************************************************************************************************************
|
||||
* OPEN STATES
|
||||
******************************************************************************************************************
|
||||
*****************************************************************************************************************/
|
||||
|
||||
// Set of open states that are never unlocked, whether they fulfill the conditions or not.
|
||||
public static final Set<Integer> BLACKLIST_OPEN_STATES = Set.of(
|
||||
48 // blacklist OPEN_STATE_LIMIT_REGION_GLOBAL to make Meledy happy. =D Remove this as soon as quest unlocks are fully implemented.
|
||||
);
|
||||
// Set of open states that are set per default for all accounts. Can be overwritten by an entry in `map`.
|
||||
public static final Set<Integer> DEFAULT_OPEN_STATES = GameData.getOpenStateList().stream()
|
||||
.filter(s ->
|
||||
s.isDefaultState() // Actual default-opened states.
|
||||
// All states whose unlock we don't handle correctly yet.
|
||||
|| (s.getCond().stream().filter(c -> c.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL).count() == 0)
|
||||
// Always unlock OPEN_STATE_PAIMON, otherwise the player will not have a working chat.
|
||||
|| s.getId() == 1
|
||||
)
|
||||
.filter(s -> !BLACKLIST_OPEN_STATES.contains(s.getId())) // Filter out states in the blacklist.
|
||||
.map(s -> s.getId())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
public PlayerProgressManager(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
/**********
|
||||
Handler for player login.
|
||||
**********/
|
||||
public void onPlayerLogin() {
|
||||
// Try unlocking open states on player login. This handles accounts where unlock conditions were
|
||||
// already met before certain open state unlocks were implemented.
|
||||
this.tryUnlockOpenStates(false);
|
||||
|
||||
// Send notify to the client.
|
||||
player.getSession().send(new PacketOpenStateUpdateNotify(this.player));
|
||||
|
||||
// Add statue quests if necessary.
|
||||
this.addStatueQuestsOnLogin();
|
||||
|
||||
// Auto-unlock the first statue and map area, until we figure out how to make
|
||||
// that particular statue interactable.
|
||||
this.player.getUnlockedScenePoints(3).add(7);
|
||||
this.player.getUnlockedSceneAreas(3).add(1);
|
||||
|
||||
}
|
||||
|
||||
/**********
|
||||
Direct getters and setters for open states.
|
||||
**********/
|
||||
public int getOpenState(int openState) {
|
||||
return this.player.getOpenStates().getOrDefault(openState, 0);
|
||||
}
|
||||
|
||||
private void setOpenState(int openState, int value, boolean sendNotify) {
|
||||
int previousValue = this.player.getOpenStates().getOrDefault(openState, 0);
|
||||
|
||||
if (value != previousValue) {
|
||||
this.player.getOpenStates().put(openState, value);
|
||||
|
||||
if (sendNotify) {
|
||||
player.getSession().send(new PacketOpenStateChangeNotify(openState, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setOpenState(int openState, int value) {
|
||||
this.setOpenState(openState, value, true);
|
||||
}
|
||||
|
||||
/**********
|
||||
Condition checking for setting open states.
|
||||
**********/
|
||||
private boolean areConditionsMet(OpenStateData openState) {
|
||||
// Check all conditions and test if at least one of them is violated.
|
||||
for (var condition : openState.getCond()) {
|
||||
// For level conditions, check if the player has reached the necessary level.
|
||||
if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL) {
|
||||
if (this.player.getLevel() < condition.getParam()) {
|
||||
return false;
|
||||
}
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_QUEST) {
|
||||
// ToDo: Implement.
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PARENT_QUEST) {
|
||||
// ToDo: Implement.
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_OFFERING_LEVEL) {
|
||||
// ToDo: Implement.
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_CITY_REPUTATION_LEVEL) {
|
||||
// ToDo: Implement.
|
||||
}
|
||||
}
|
||||
|
||||
// Done. If we didn't find any violations, all conditions are met.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********
|
||||
Setting open states from the client (via `SetOpenStateReq`).
|
||||
**********/
|
||||
public void setOpenStateFromClient(int openState, int value) {
|
||||
// Get the data for this open state.
|
||||
OpenStateData data = GameData.getOpenStateDataMap().get(openState);
|
||||
if (data == null) {
|
||||
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that this is an open state that the client is allowed to set,
|
||||
// and that it doesn't have any further conditions attached.
|
||||
if (!data.isAllowClientOpen() || !this.areConditionsMet(data)) {
|
||||
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set.
|
||||
this.setOpenState(openState, value);
|
||||
this.player.sendPacket(new PacketSetOpenStateRsp(openState, value));
|
||||
}
|
||||
|
||||
/**********
|
||||
Triggered unlocking of open states (unlock states whose conditions have been met.)
|
||||
**********/
|
||||
public void tryUnlockOpenStates(boolean sendNotify) {
|
||||
// Get list of open states that are not yet unlocked.
|
||||
var lockedStates = GameData.getOpenStateList().stream().filter(s -> this.player.getOpenStates().getOrDefault(s, 0) == 0).toList();
|
||||
|
||||
// Try unlocking all of them.
|
||||
for (var state : lockedStates) {
|
||||
// To auto-unlock a state, it has to meet three conditions:
|
||||
// * it can not be a state that is unlocked by the client,
|
||||
// * it has to meet all its unlock conditions, and
|
||||
// * it can not be in the blacklist.
|
||||
if (!state.isAllowClientOpen() && this.areConditionsMet(state) && !BLACKLIST_OPEN_STATES.contains(state.getId())) {
|
||||
this.setOpenState(state.getId(), 1, sendNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void tryUnlockOpenStates() {
|
||||
this.tryUnlockOpenStates(true);
|
||||
}
|
||||
|
||||
/******************************************************************************************************************
|
||||
******************************************************************************************************************
|
||||
* MAP AREAS AND POINTS
|
||||
******************************************************************************************************************
|
||||
*****************************************************************************************************************/
|
||||
private void addStatueQuestsOnLogin() {
|
||||
// Get all currently existing subquests for the "unlock all statues" main quest.
|
||||
var statueMainQuest = GameData.getMainQuestDataMap().get(303);
|
||||
var statueSubQuests = statueMainQuest.getSubQuests();
|
||||
|
||||
// Add the main statue quest if it isn't active yet.
|
||||
var statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
||||
if (statueGameMainQuest == null) {
|
||||
this.player.getQuestManager().addQuest(30302);
|
||||
statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
||||
}
|
||||
|
||||
// Set all subquests to active if they aren't already finished.
|
||||
for (var subData : statueSubQuests) {
|
||||
var subGameQuest = statueGameMainQuest.getChildQuestById(subData.getSubId());
|
||||
if (subGameQuest != null && subGameQuest.getState() == QuestState.QUEST_STATE_UNSTARTED) {
|
||||
this.player.getQuestManager().addQuest(subData.getSubId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean unlockTransPoint(int sceneId, int pointId, boolean isStatue) {
|
||||
// Check whether the unlocked point exists and whether it is still locked.
|
||||
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(sceneId, pointId);
|
||||
|
||||
if (scenePointEntry == null || this.player.getUnlockedScenePoints(sceneId).contains(pointId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the point to the list of unlocked points for its scene.
|
||||
this.player.getUnlockedScenePoints(sceneId).add(pointId);
|
||||
|
||||
// Give primogems and Adventure EXP for unlocking.
|
||||
this.player.getInventory().addItem(201, 5, ActionReason.UnlockPointReward);
|
||||
this.player.getInventory().addItem(102, isStatue ? 50 : 10, ActionReason.UnlockPointReward);
|
||||
|
||||
// this.player.sendPacket(new PacketPlayerPropChangeReasonNotify(this.player.getProperty(PlayerProperty.PROP_PLAYER_EXP), PlayerProperty.PROP_PLAYER_EXP, PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP));
|
||||
|
||||
// Fire quest trigger for trans point unlock.
|
||||
this.player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId);
|
||||
|
||||
// Send packet.
|
||||
this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void unlockSceneArea(int sceneId, int areaId) {
|
||||
// Add the area to the list of unlocked areas in its scene.
|
||||
this.player.getUnlockedSceneAreas(sceneId).add(areaId);
|
||||
|
||||
// Send packet.
|
||||
this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId));
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||
import emu.grasscutter.data.excels.OpenStateData;
|
||||
import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.quest.enums.QuestState;
|
||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// @Entity
|
||||
public class PlayerProgressManager extends BasePlayerDataManager {
|
||||
/******************************************************************************************************************
|
||||
******************************************************************************************************************
|
||||
* OPEN STATES
|
||||
******************************************************************************************************************
|
||||
*****************************************************************************************************************/
|
||||
|
||||
// Set of open states that are never unlocked, whether they fulfill the conditions or not.
|
||||
public static final Set<Integer> BLACKLIST_OPEN_STATES =
|
||||
Set.of(
|
||||
48 // blacklist OPEN_STATE_LIMIT_REGION_GLOBAL to make Meledy happy. =D Remove this as
|
||||
// soon as quest unlocks are fully implemented.
|
||||
);
|
||||
// Set of open states that are set per default for all accounts. Can be overwritten by an entry in
|
||||
// `map`.
|
||||
public static final Set<Integer> DEFAULT_OPEN_STATES =
|
||||
GameData.getOpenStateList().stream()
|
||||
.filter(
|
||||
s ->
|
||||
s.isDefaultState() // Actual default-opened states.
|
||||
// All states whose unlock we don't handle correctly yet.
|
||||
|| (s.getCond().stream()
|
||||
.filter(
|
||||
c ->
|
||||
c.getCondType()
|
||||
== OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL)
|
||||
.count()
|
||||
== 0)
|
||||
// Always unlock OPEN_STATE_PAIMON, otherwise the player will not have a
|
||||
// working chat.
|
||||
|| s.getId() == 1)
|
||||
.filter(
|
||||
s ->
|
||||
!BLACKLIST_OPEN_STATES.contains(s.getId())) // Filter out states in the blacklist.
|
||||
.map(s -> s.getId())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
public PlayerProgressManager(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
/**********
|
||||
* Handler for player login.
|
||||
**********/
|
||||
public void onPlayerLogin() {
|
||||
// Try unlocking open states on player login. This handles accounts where unlock conditions were
|
||||
// already met before certain open state unlocks were implemented.
|
||||
this.tryUnlockOpenStates(false);
|
||||
|
||||
// Send notify to the client.
|
||||
player.getSession().send(new PacketOpenStateUpdateNotify(this.player));
|
||||
|
||||
// Add statue quests if necessary.
|
||||
this.addStatueQuestsOnLogin();
|
||||
|
||||
// Auto-unlock the first statue and map area, until we figure out how to make
|
||||
// that particular statue interactable.
|
||||
this.player.getUnlockedScenePoints(3).add(7);
|
||||
this.player.getUnlockedSceneAreas(3).add(1);
|
||||
}
|
||||
|
||||
/**********
|
||||
* Direct getters and setters for open states.
|
||||
**********/
|
||||
public int getOpenState(int openState) {
|
||||
return this.player.getOpenStates().getOrDefault(openState, 0);
|
||||
}
|
||||
|
||||
private void setOpenState(int openState, int value, boolean sendNotify) {
|
||||
int previousValue = this.player.getOpenStates().getOrDefault(openState, 0);
|
||||
|
||||
if (value != previousValue) {
|
||||
this.player.getOpenStates().put(openState, value);
|
||||
|
||||
if (sendNotify) {
|
||||
player.getSession().send(new PacketOpenStateChangeNotify(openState, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setOpenState(int openState, int value) {
|
||||
this.setOpenState(openState, value, true);
|
||||
}
|
||||
|
||||
/**********
|
||||
* Condition checking for setting open states.
|
||||
**********/
|
||||
private boolean areConditionsMet(OpenStateData openState) {
|
||||
// Check all conditions and test if at least one of them is violated.
|
||||
for (var condition : openState.getCond()) {
|
||||
// For level conditions, check if the player has reached the necessary level.
|
||||
if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL) {
|
||||
if (this.player.getLevel() < condition.getParam()) {
|
||||
return false;
|
||||
}
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_QUEST) {
|
||||
// ToDo: Implement.
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PARENT_QUEST) {
|
||||
// ToDo: Implement.
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_OFFERING_LEVEL) {
|
||||
// ToDo: Implement.
|
||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_CITY_REPUTATION_LEVEL) {
|
||||
// ToDo: Implement.
|
||||
}
|
||||
}
|
||||
|
||||
// Done. If we didn't find any violations, all conditions are met.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********
|
||||
* Setting open states from the client (via `SetOpenStateReq`).
|
||||
**********/
|
||||
public void setOpenStateFromClient(int openState, int value) {
|
||||
// Get the data for this open state.
|
||||
OpenStateData data = GameData.getOpenStateDataMap().get(openState);
|
||||
if (data == null) {
|
||||
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that this is an open state that the client is allowed to set,
|
||||
// and that it doesn't have any further conditions attached.
|
||||
if (!data.isAllowClientOpen() || !this.areConditionsMet(data)) {
|
||||
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set.
|
||||
this.setOpenState(openState, value);
|
||||
this.player.sendPacket(new PacketSetOpenStateRsp(openState, value));
|
||||
}
|
||||
|
||||
/**********
|
||||
* Triggered unlocking of open states (unlock states whose conditions have been met.)
|
||||
**********/
|
||||
public void tryUnlockOpenStates(boolean sendNotify) {
|
||||
// Get list of open states that are not yet unlocked.
|
||||
var lockedStates =
|
||||
GameData.getOpenStateList().stream()
|
||||
.filter(s -> this.player.getOpenStates().getOrDefault(s, 0) == 0)
|
||||
.toList();
|
||||
|
||||
// Try unlocking all of them.
|
||||
for (var state : lockedStates) {
|
||||
// To auto-unlock a state, it has to meet three conditions:
|
||||
// * it can not be a state that is unlocked by the client,
|
||||
// * it has to meet all its unlock conditions, and
|
||||
// * it can not be in the blacklist.
|
||||
if (!state.isAllowClientOpen()
|
||||
&& this.areConditionsMet(state)
|
||||
&& !BLACKLIST_OPEN_STATES.contains(state.getId())) {
|
||||
this.setOpenState(state.getId(), 1, sendNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void tryUnlockOpenStates() {
|
||||
this.tryUnlockOpenStates(true);
|
||||
}
|
||||
|
||||
/******************************************************************************************************************
|
||||
******************************************************************************************************************
|
||||
* MAP AREAS AND POINTS
|
||||
******************************************************************************************************************
|
||||
*****************************************************************************************************************/
|
||||
private void addStatueQuestsOnLogin() {
|
||||
// Get all currently existing subquests for the "unlock all statues" main quest.
|
||||
var statueMainQuest = GameData.getMainQuestDataMap().get(303);
|
||||
var statueSubQuests = statueMainQuest.getSubQuests();
|
||||
|
||||
// Add the main statue quest if it isn't active yet.
|
||||
var statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
||||
if (statueGameMainQuest == null) {
|
||||
this.player.getQuestManager().addQuest(30302);
|
||||
statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
||||
}
|
||||
|
||||
// Set all subquests to active if they aren't already finished.
|
||||
for (var subData : statueSubQuests) {
|
||||
var subGameQuest = statueGameMainQuest.getChildQuestById(subData.getSubId());
|
||||
if (subGameQuest != null && subGameQuest.getState() == QuestState.QUEST_STATE_UNSTARTED) {
|
||||
this.player.getQuestManager().addQuest(subData.getSubId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean unlockTransPoint(int sceneId, int pointId, boolean isStatue) {
|
||||
// Check whether the unlocked point exists and whether it is still locked.
|
||||
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(sceneId, pointId);
|
||||
|
||||
if (scenePointEntry == null || this.player.getUnlockedScenePoints(sceneId).contains(pointId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the point to the list of unlocked points for its scene.
|
||||
this.player.getUnlockedScenePoints(sceneId).add(pointId);
|
||||
|
||||
// Give primogems and Adventure EXP for unlocking.
|
||||
this.player.getInventory().addItem(201, 5, ActionReason.UnlockPointReward);
|
||||
this.player.getInventory().addItem(102, isStatue ? 50 : 10, ActionReason.UnlockPointReward);
|
||||
|
||||
// this.player.sendPacket(new
|
||||
// PacketPlayerPropChangeReasonNotify(this.player.getProperty(PlayerProperty.PROP_PLAYER_EXP),
|
||||
// PlayerProperty.PROP_PLAYER_EXP, PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP));
|
||||
|
||||
// Fire quest trigger for trans point unlock.
|
||||
this.player
|
||||
.getQuestManager()
|
||||
.triggerEvent(QuestTrigger.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId);
|
||||
|
||||
// Send packet.
|
||||
this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void unlockSceneArea(int sceneId, int areaId) {
|
||||
// Add the area to the list of unlocked areas in its scene.
|
||||
this.player.getUnlockedSceneAreas(sceneId).add(areaId);
|
||||
|
||||
// Send packet.
|
||||
this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,97 +1,95 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
@Entity
|
||||
public class TeamInfo {
|
||||
private String name;
|
||||
private final List<Integer> avatars;
|
||||
|
||||
public TeamInfo() {
|
||||
this.name = "";
|
||||
this.avatars = new ArrayList<>(GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||
}
|
||||
|
||||
public TeamInfo(List<Integer> avatars) {
|
||||
this.name = "";
|
||||
this.avatars = avatars;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Integer> getAvatars() {
|
||||
return avatars;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return avatars.size();
|
||||
}
|
||||
|
||||
public boolean contains(Avatar avatar) {
|
||||
return getAvatars().contains(avatar.getAvatarId());
|
||||
}
|
||||
|
||||
public boolean addAvatar(Avatar avatar) {
|
||||
if (contains(avatar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
getAvatars().add(avatar.getAvatarId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeAvatar(int slot) {
|
||||
if (size() <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
getAvatars().remove(slot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void copyFrom(TeamInfo team) {
|
||||
copyFrom(team, GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||
}
|
||||
|
||||
public void copyFrom(TeamInfo team, int maxTeamSize) {
|
||||
// Clone avatar ids from team to copy from
|
||||
List<Integer> avatarIds = new ArrayList<>(team.getAvatars());
|
||||
|
||||
// Clear current avatar list first
|
||||
this.getAvatars().clear();
|
||||
|
||||
// Copy from team
|
||||
int len = Math.min(avatarIds.size(), maxTeamSize);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int id = avatarIds.get(i);
|
||||
this.getAvatars().add(id);
|
||||
}
|
||||
}
|
||||
|
||||
public AvatarTeam toProto(Player player) {
|
||||
AvatarTeam.Builder avatarTeam = AvatarTeam.newBuilder()
|
||||
.setTeamName(this.getName());
|
||||
|
||||
for (int i = 0; i < this.getAvatars().size(); i++) {
|
||||
Avatar avatar = player.getAvatars().getAvatarById(this.getAvatars().get(i));
|
||||
avatarTeam.addAvatarGuidList(avatar.getGuid());
|
||||
}
|
||||
|
||||
return avatarTeam.build();
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class TeamInfo {
|
||||
private String name;
|
||||
private final List<Integer> avatars;
|
||||
|
||||
public TeamInfo() {
|
||||
this.name = "";
|
||||
this.avatars = new ArrayList<>(GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||
}
|
||||
|
||||
public TeamInfo(List<Integer> avatars) {
|
||||
this.name = "";
|
||||
this.avatars = avatars;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Integer> getAvatars() {
|
||||
return avatars;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return avatars.size();
|
||||
}
|
||||
|
||||
public boolean contains(Avatar avatar) {
|
||||
return getAvatars().contains(avatar.getAvatarId());
|
||||
}
|
||||
|
||||
public boolean addAvatar(Avatar avatar) {
|
||||
if (contains(avatar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
getAvatars().add(avatar.getAvatarId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeAvatar(int slot) {
|
||||
if (size() <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
getAvatars().remove(slot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void copyFrom(TeamInfo team) {
|
||||
copyFrom(team, GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||
}
|
||||
|
||||
public void copyFrom(TeamInfo team, int maxTeamSize) {
|
||||
// Clone avatar ids from team to copy from
|
||||
List<Integer> avatarIds = new ArrayList<>(team.getAvatars());
|
||||
|
||||
// Clear current avatar list first
|
||||
this.getAvatars().clear();
|
||||
|
||||
// Copy from team
|
||||
int len = Math.min(avatarIds.size(), maxTeamSize);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int id = avatarIds.get(i);
|
||||
this.getAvatars().add(id);
|
||||
}
|
||||
}
|
||||
|
||||
public AvatarTeam toProto(Player player) {
|
||||
AvatarTeam.Builder avatarTeam = AvatarTeam.newBuilder().setTeamName(this.getName());
|
||||
|
||||
for (int i = 0; i < this.getAvatars().size(); i++) {
|
||||
Avatar avatar = player.getAvatars().getAvatarById(this.getAvatars().get(i));
|
||||
avatarTeam.addAvatarGuidList(avatar.getGuid());
|
||||
}
|
||||
|
||||
return avatarTeam.build();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user