Run Spotless on src/main

This commit is contained in:
KingRainbow44
2023-03-31 22:30:45 -04:00
parent 99822b0e22
commit fc05602128
1003 changed files with 60650 additions and 58050 deletions

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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));
}
}

View File

@@ -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