mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-16 08:56:04 +01:00
Moved some files around
This commit is contained in:
60
src/main/java/emu/grasscutter/game/player/InvokeHandler.java
Normal file
60
src/main/java/emu/grasscutter/game/player/InvokeHandler.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.ForwardTypeOuterClass.ForwardType;
|
||||
|
||||
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_TO_ALL -> entryListForwardAll.add(entry);
|
||||
case FORWARD_TO_ALL_EXCEPT_CUR, FORWARD_TO_ALL_EXIST_EXCEPT_CUR -> entryListForwardAllExceptCur.add(entry);
|
||||
case FORWARD_TO_HOST -> entryListForwardHost.add(entry);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void update(Player player) {
|
||||
if (player.getWorld() == 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
943
src/main/java/emu/grasscutter/game/player/Player.java
Normal file
943
src/main/java/emu/grasscutter/game/player/Player.java
Normal file
@@ -0,0 +1,943 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
import dev.morphia.annotations.*;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.PlayerLevelData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.avatar.AvatarProfileData;
|
||||
import emu.grasscutter.game.avatar.AvatarStorage;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.CoopRequest;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityItem;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.friends.FriendsList;
|
||||
import emu.grasscutter.game.friends.PlayerProfile;
|
||||
import emu.grasscutter.game.gacha.PlayerGachaInfo;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
|
||||
import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType;
|
||||
import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterMpReasonOuterClass.PlayerApplyEnterMpReason;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass;
|
||||
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
|
||||
import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.DateHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity(value = "players", useDiscriminator = false)
|
||||
public class Player {
|
||||
@Id private int id;
|
||||
@Indexed(options = @IndexOptions(unique = true)) private String accountId;
|
||||
|
||||
@Transient private Account account;
|
||||
private String nickname;
|
||||
private String signature;
|
||||
private int headImage;
|
||||
private int nameCardId = 210001;
|
||||
private Position pos;
|
||||
private Position rotation;
|
||||
private PlayerBirthday birthday;
|
||||
|
||||
private Map<Integer, Integer> properties;
|
||||
private Set<Integer> nameCardList;
|
||||
private Set<Integer> flyCloakList;
|
||||
private Set<Integer> costumeList;
|
||||
|
||||
@Transient private long nextGuid = 0;
|
||||
@Transient private int peerId;
|
||||
@Transient private World world;
|
||||
@Transient private Scene scene;
|
||||
@Transient private GameSession session;
|
||||
@Transient private AvatarStorage avatars;
|
||||
@Transient private Inventory inventory;
|
||||
@Transient private FriendsList friendsList;
|
||||
|
||||
private TeamManager teamManager;
|
||||
private PlayerGachaInfo gachaInfo;
|
||||
private PlayerProfile playerProfile;
|
||||
private boolean showAvatar;
|
||||
private ArrayList<AvatarProfileData> shownAvatars;
|
||||
private Set<Integer> rewardedLevels;
|
||||
private ArrayList<Mail> mail;
|
||||
|
||||
private int sceneId;
|
||||
private int regionId;
|
||||
private int mainCharacterId;
|
||||
private boolean godmode;
|
||||
|
||||
private boolean moonCard;
|
||||
private Date moonCardStartTime;
|
||||
private int moonCardDuration;
|
||||
private Set<Date> moonCardGetTimes;
|
||||
|
||||
@Transient private boolean paused;
|
||||
@Transient private int enterSceneToken;
|
||||
@Transient private SceneLoadState sceneState;
|
||||
@Transient private boolean hasSentAvatarDataNotify;
|
||||
@Transient private long nextSendPlayerLocTime = 0;
|
||||
|
||||
@Transient private final Int2ObjectMap<CoopRequest> coopRequests;
|
||||
@Transient private final InvokeHandler<CombatInvokeEntry> combatInvokeHandler;
|
||||
@Transient private final InvokeHandler<AbilityInvokeEntry> abilityInvokeHandler;
|
||||
@Transient private final InvokeHandler<AbilityInvokeEntry> clientAbilityInitFinishHandler;
|
||||
|
||||
@Deprecated
|
||||
@SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
|
||||
public Player() {
|
||||
this.inventory = new Inventory(this);
|
||||
this.avatars = new AvatarStorage(this);
|
||||
this.friendsList = new FriendsList(this);
|
||||
this.pos = new Position();
|
||||
this.rotation = new Position();
|
||||
this.properties = new HashMap<>();
|
||||
for (PlayerProperty prop : PlayerProperty.values()) {
|
||||
if (prop.getId() < 10000) {
|
||||
continue;
|
||||
}
|
||||
this.properties.put(prop.getId(), 0);
|
||||
}
|
||||
|
||||
this.gachaInfo = new PlayerGachaInfo();
|
||||
this.nameCardList = new HashSet<>();
|
||||
this.flyCloakList = new HashSet<>();
|
||||
this.costumeList = new HashSet<>();
|
||||
|
||||
this.mail = new ArrayList<>();
|
||||
|
||||
this.setSceneId(3);
|
||||
this.setRegionId(1);
|
||||
this.sceneState = SceneLoadState.NONE;
|
||||
|
||||
this.coopRequests = new Int2ObjectOpenHashMap<>();
|
||||
this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class);
|
||||
this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class);
|
||||
this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class);
|
||||
|
||||
this.birthday = new PlayerBirthday();
|
||||
this.rewardedLevels = new HashSet<>();
|
||||
this.moonCardGetTimes = new HashSet<>();
|
||||
}
|
||||
|
||||
// On player creation
|
||||
public Player(GameSession session) {
|
||||
this();
|
||||
this.account = session.getAccount();
|
||||
this.accountId = this.getAccount().getId();
|
||||
this.session = session;
|
||||
this.nickname = "Traveler";
|
||||
this.signature = "";
|
||||
this.teamManager = new TeamManager(this);
|
||||
this.birthday = new PlayerBirthday();
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1);
|
||||
this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50);
|
||||
this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000);
|
||||
this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160);
|
||||
this.getFlyCloakList().add(140001);
|
||||
this.getNameCardList().add(210001);
|
||||
this.getPos().set(GameConstants.START_POSITION);
|
||||
this.getRotation().set(0, 307, 0);
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setUid(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getNextGameGuid() {
|
||||
long nextId = ++this.nextGuid;
|
||||
return ((long) this.getUid() << 32) + nextId;
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
this.account = account;
|
||||
this.account.setPlayerId(getUid());
|
||||
}
|
||||
|
||||
public GameSession getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public void setSession(GameSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return this.getSession() != null && this.getSession().isActive();
|
||||
}
|
||||
|
||||
public GameServer getServer() {
|
||||
return this.getSession().getServer();
|
||||
}
|
||||
|
||||
public synchronized World getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
|
||||
public synchronized void setWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public synchronized Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public synchronized void setScene(Scene scene) {
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
public int getGmLevel() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickName) {
|
||||
this.nickname = nickName;
|
||||
this.updateProfile();
|
||||
}
|
||||
|
||||
public int getHeadImage() {
|
||||
return headImage;
|
||||
}
|
||||
|
||||
public void setHeadImage(int picture) {
|
||||
this.headImage = picture;
|
||||
this.updateProfile();
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
this.updateProfile();
|
||||
}
|
||||
|
||||
public Position getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public Position getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL);
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_EXP);
|
||||
}
|
||||
|
||||
public int getWorldLevel() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL);
|
||||
}
|
||||
|
||||
public void setWorldLevel(int level) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_WORLD_LEVEL));
|
||||
}
|
||||
|
||||
public int getPrimogems() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN);
|
||||
}
|
||||
|
||||
public void setPrimogems(int primogem) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HCOIN));
|
||||
}
|
||||
|
||||
public int getMora() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN);
|
||||
}
|
||||
|
||||
public void setMora(int mora) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_SCOIN));
|
||||
}
|
||||
|
||||
private int getExpRequired(int level) {
|
||||
PlayerLevelData levelData = GameData.getPlayerLevelDataMap().get(level);
|
||||
return levelData != null ? levelData.getExp() : 0;
|
||||
}
|
||||
|
||||
private float getExpModifier() {
|
||||
return Grasscutter.getConfig().getGameServerOptions().getGameRates().ADVENTURE_EXP_RATE;
|
||||
}
|
||||
|
||||
// Affected by exp rate
|
||||
public void earnExp(int exp) {
|
||||
addExpDirectly((int) (exp * getExpModifier()));
|
||||
}
|
||||
|
||||
// Directly give player exp
|
||||
public void addExpDirectly(int gain) {
|
||||
boolean hasLeveledUp = false;
|
||||
int level = getLevel();
|
||||
int exp = getExp();
|
||||
int reqExp = getExpRequired(level);
|
||||
|
||||
exp += gain;
|
||||
|
||||
while (exp >= reqExp && reqExp > 0) {
|
||||
exp -= reqExp;
|
||||
level += 1;
|
||||
reqExp = getExpRequired(level);
|
||||
hasLeveledUp = true;
|
||||
}
|
||||
|
||||
if (hasLeveledUp) {
|
||||
// Set level property
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level);
|
||||
// Update social status
|
||||
this.updateProfile();
|
||||
// Update player with packet
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_LEVEL));
|
||||
}
|
||||
|
||||
// Set exp
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp);
|
||||
|
||||
// Update player with packet
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_EXP));
|
||||
}
|
||||
|
||||
private void updateProfile() {
|
||||
getProfile().syncWithCharacter(this);
|
||||
}
|
||||
|
||||
public boolean isFirstLoginEnterScene() {
|
||||
return !this.hasSentAvatarDataNotify;
|
||||
}
|
||||
|
||||
public TeamManager getTeamManager() {
|
||||
return this.teamManager;
|
||||
}
|
||||
|
||||
public PlayerGachaInfo getGachaInfo() {
|
||||
return gachaInfo;
|
||||
}
|
||||
|
||||
public PlayerProfile getProfile() {
|
||||
if (this.playerProfile == null) {
|
||||
this.playerProfile = new PlayerProfile(this);
|
||||
}
|
||||
return playerProfile;
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperty(PlayerProperty prop, int value) {
|
||||
getProperties().put(prop.getId(), value);
|
||||
}
|
||||
|
||||
public int getProperty(PlayerProperty prop) {
|
||||
return getProperties().get(prop.getId());
|
||||
}
|
||||
|
||||
public Set<Integer> getFlyCloakList() {
|
||||
return flyCloakList;
|
||||
}
|
||||
|
||||
public Set<Integer> getCostumeList() {
|
||||
return costumeList;
|
||||
}
|
||||
|
||||
public Set<Integer> getNameCardList() {
|
||||
return this.nameCardList;
|
||||
}
|
||||
|
||||
public MpSettingType getMpSetting() {
|
||||
return MpSettingType.MP_SETTING_ENTER_AFTER_APPLY; // TEMP
|
||||
}
|
||||
|
||||
public synchronized Int2ObjectMap<CoopRequest> getCoopRequests() {
|
||||
return coopRequests;
|
||||
}
|
||||
|
||||
public InvokeHandler<CombatInvokeEntry> getCombatInvokeHandler() {
|
||||
return this.combatInvokeHandler;
|
||||
}
|
||||
|
||||
public InvokeHandler<AbilityInvokeEntry> getAbilityInvokeHandler() {
|
||||
return this.abilityInvokeHandler;
|
||||
}
|
||||
|
||||
public InvokeHandler<AbilityInvokeEntry> getClientAbilityInitFinishHandler() {
|
||||
return clientAbilityInitFinishHandler;
|
||||
}
|
||||
|
||||
public AvatarStorage getAvatars() {
|
||||
return avatars;
|
||||
}
|
||||
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public FriendsList getFriendsList() {
|
||||
return this.friendsList;
|
||||
}
|
||||
|
||||
public int getEnterSceneToken() {
|
||||
return enterSceneToken;
|
||||
}
|
||||
|
||||
public void setEnterSceneToken(int enterSceneToken) {
|
||||
this.enterSceneToken = enterSceneToken;
|
||||
}
|
||||
|
||||
public int getNameCardId() {
|
||||
return nameCardId;
|
||||
}
|
||||
|
||||
public void setNameCardId(int nameCardId) {
|
||||
this.nameCardId = nameCardId;
|
||||
this.updateProfile();
|
||||
}
|
||||
|
||||
public int getMainCharacterId() {
|
||||
return mainCharacterId;
|
||||
}
|
||||
|
||||
public void setMainCharacterId(int mainCharacterId) {
|
||||
this.mainCharacterId = mainCharacterId;
|
||||
}
|
||||
|
||||
public int getPeerId() {
|
||||
return peerId;
|
||||
}
|
||||
|
||||
public void setPeerId(int peerId) {
|
||||
this.peerId = peerId;
|
||||
}
|
||||
|
||||
public int getClientTime() {
|
||||
return session.getClientTime();
|
||||
}
|
||||
|
||||
public long getLastPingTime() {
|
||||
return session.getLastPingTime();
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
public void setPaused(boolean newPauseState) {
|
||||
boolean oldPauseState = this.paused;
|
||||
this.paused = newPauseState;
|
||||
|
||||
if (newPauseState && !oldPauseState) {
|
||||
this.onPause();
|
||||
} else if (oldPauseState && !newPauseState) {
|
||||
this.onUnpause();
|
||||
}
|
||||
}
|
||||
|
||||
public SceneLoadState getSceneLoadState() {
|
||||
return sceneState;
|
||||
}
|
||||
|
||||
public void setSceneLoadState(SceneLoadState sceneState) {
|
||||
this.sceneState = sceneState;
|
||||
}
|
||||
|
||||
public boolean isInMultiplayer() {
|
||||
return this.getWorld() != null && this.getWorld().isMultiplayer();
|
||||
}
|
||||
|
||||
public int getSceneId() {
|
||||
return sceneId;
|
||||
}
|
||||
|
||||
public void setSceneId(int sceneId) {
|
||||
this.sceneId = sceneId;
|
||||
}
|
||||
|
||||
public int getRegionId() {
|
||||
return regionId;
|
||||
}
|
||||
|
||||
public void setRegionId(int regionId) {
|
||||
this.regionId = regionId;
|
||||
}
|
||||
|
||||
public boolean inMoonCard() {
|
||||
return moonCard;
|
||||
}
|
||||
|
||||
public void setMoonCard(boolean moonCard) {
|
||||
this.moonCard = moonCard;
|
||||
}
|
||||
|
||||
public void addMoonCardDays(int days) {
|
||||
this.moonCardDuration += days;
|
||||
}
|
||||
|
||||
public int getMoonCardDuration() {
|
||||
return moonCardDuration;
|
||||
}
|
||||
|
||||
public void setMoonCardDuration(int moonCardDuration) {
|
||||
this.moonCardDuration = moonCardDuration;
|
||||
}
|
||||
|
||||
public Date getMoonCardStartTime() {
|
||||
return moonCardStartTime;
|
||||
}
|
||||
|
||||
public void setMoonCardStartTime(Date moonCardStartTime) {
|
||||
this.moonCardStartTime = moonCardStartTime;
|
||||
}
|
||||
|
||||
public Set<Date> getMoonCardGetTimes() {
|
||||
return moonCardGetTimes;
|
||||
}
|
||||
|
||||
public void setMoonCardGetTimes(Set<Date> moonCardGetTimes) {
|
||||
this.moonCardGetTimes = moonCardGetTimes;
|
||||
}
|
||||
|
||||
public int getMoonCardRemainDays() {
|
||||
Calendar remainCalendar = Calendar.getInstance();
|
||||
remainCalendar.setTime(moonCardStartTime);
|
||||
remainCalendar.add(Calendar.DATE, moonCardDuration);
|
||||
Date theLastDay = remainCalendar.getTime();
|
||||
Date now = DateHelper.onlyYearMonthDay(new Date());
|
||||
return (int) ((theLastDay.getTime() - now.getTime()) / (24 * 60 * 60 * 1000)); // By copilot
|
||||
}
|
||||
|
||||
public void rechargeMoonCard() {
|
||||
LinkedList<GameItem> items = new LinkedList<GameItem>();
|
||||
for (int i = 0; i < 300; i++) {
|
||||
items.add(new GameItem(203));
|
||||
}
|
||||
inventory.addItems(items);
|
||||
if (!moonCard) {
|
||||
moonCard = true;
|
||||
Date now = new Date();
|
||||
moonCardStartTime = DateHelper.onlyYearMonthDay(now);
|
||||
moonCardDuration = 30;
|
||||
} else {
|
||||
moonCardDuration += 30;
|
||||
}
|
||||
if (!moonCardGetTimes.contains(moonCardStartTime)) {
|
||||
moonCardGetTimes.add(moonCardStartTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void getTodayMoonCard() {
|
||||
if (!moonCard) {
|
||||
return;
|
||||
}
|
||||
Date now = DateHelper.onlyYearMonthDay(new Date());
|
||||
if (moonCardGetTimes.contains(now)) {
|
||||
return;
|
||||
}
|
||||
Date stopTime = new Date();
|
||||
Calendar stopCalendar = Calendar.getInstance();
|
||||
stopCalendar.setTime(stopTime);
|
||||
stopCalendar.add(Calendar.DATE, moonCardDuration);
|
||||
stopTime = stopCalendar.getTime();
|
||||
if (now.after(stopTime)) {
|
||||
moonCard = false;
|
||||
return;
|
||||
}
|
||||
moonCardGetTimes.add(now);
|
||||
addMoonCardDays(1);
|
||||
GameItem item = new GameItem(201, 90);
|
||||
getInventory().addItem(item, ActionReason.BlessingRedeemReward);
|
||||
session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays()));
|
||||
}
|
||||
|
||||
public boolean inGodmode() {
|
||||
return godmode;
|
||||
}
|
||||
|
||||
public void setGodmode(boolean godmode) {
|
||||
this.godmode = godmode;
|
||||
}
|
||||
|
||||
public boolean hasSentAvatarDataNotify() {
|
||||
return hasSentAvatarDataNotify;
|
||||
}
|
||||
|
||||
public void setHasSentAvatarDataNotify(boolean hasSentAvatarDataNotify) {
|
||||
this.hasSentAvatarDataNotify = hasSentAvatarDataNotify;
|
||||
}
|
||||
|
||||
public void addAvatar(Avatar avatar) {
|
||||
boolean result = getAvatars().addAvatar(avatar);
|
||||
|
||||
if (result) {
|
||||
// Add starting weapon
|
||||
getAvatars().addStartingWeapon(avatar);
|
||||
|
||||
// Done
|
||||
if (hasSentAvatarDataNotify()) {
|
||||
// Recalc stats
|
||||
avatar.recalcStats();
|
||||
// Packet
|
||||
sendPacket(new PacketAvatarAddNotify(avatar, false));
|
||||
}
|
||||
} else {
|
||||
// Failed adding avatar
|
||||
}
|
||||
}
|
||||
|
||||
public void addFlycloak(int flycloakId) {
|
||||
this.getFlyCloakList().add(flycloakId);
|
||||
this.sendPacket(new PacketAvatarGainFlycloakNotify(flycloakId));
|
||||
}
|
||||
|
||||
public void addCostume(int costumeId) {
|
||||
this.getCostumeList().add(costumeId);
|
||||
this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId));
|
||||
}
|
||||
|
||||
public void addNameCard(int nameCardId) {
|
||||
this.getNameCardList().add(nameCardId);
|
||||
this.sendPacket(new PacketUnlockNameCardNotify(nameCardId));
|
||||
}
|
||||
|
||||
public void setNameCard(int nameCardId) {
|
||||
if (!this.getNameCardList().contains(nameCardId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setNameCardId(nameCardId);
|
||||
|
||||
this.sendPacket(new PacketSetNameCardRsp(nameCardId));
|
||||
}
|
||||
|
||||
public void dropMessage(Object message) {
|
||||
this.sendPacket(new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, getUid(), message.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to another player.
|
||||
*
|
||||
* @param sender The sender of the message.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public void sendMessage(Player sender, Object message) {
|
||||
this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString()));
|
||||
}
|
||||
|
||||
// ---------------------MAIL------------------------
|
||||
|
||||
public List<Mail> getAllMail() { return this.mail; }
|
||||
|
||||
public void sendMail(Mail message) {
|
||||
this.mail.add(message);
|
||||
this.save();
|
||||
Grasscutter.getLogger().info("Mail sent to user [" + this.getUid() + ":" + this.getNickname() + "]!");
|
||||
if(this.isOnline()) {
|
||||
this.sendPacket(new PacketMailChangeNotify(this, message));
|
||||
} // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline
|
||||
}
|
||||
|
||||
public boolean deleteMail(int mailId) {
|
||||
Mail message = getMail(mailId);
|
||||
|
||||
if(message != null) {
|
||||
int index = getMailId(message);
|
||||
message.expireTime = (int) Instant.now().getEpochSecond(); // Just set the mail as expired for now. I don't want to implement a counter specifically for an account...
|
||||
this.replaceMailByIndex(index, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Mail getMail(int index) { return this.mail.get(index); }
|
||||
public int getMailId(Mail message) {
|
||||
return this.mail.indexOf(message);
|
||||
}
|
||||
|
||||
public boolean replaceMailByIndex(int index, Mail message) {
|
||||
if(getMail(index) != null) {
|
||||
this.mail.set(index, message);
|
||||
this.save();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void interactWith(int gadgetEntityId) {
|
||||
GameEntity entity = getScene().getEntityById(gadgetEntityId);
|
||||
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete
|
||||
entity.getScene().removeEntity(entity);
|
||||
|
||||
// Handle
|
||||
if (entity instanceof EntityItem) {
|
||||
// Pick item
|
||||
EntityItem drop = (EntityItem) entity;
|
||||
GameItem item = new GameItem(drop.getItemData(), drop.getCount());
|
||||
// Add to inventory
|
||||
boolean success = getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
if (success) {
|
||||
this.sendPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
|
||||
}
|
||||
|
||||
public void onUnpause() {
|
||||
|
||||
}
|
||||
|
||||
public void sendPacket(BasePacket packet) {
|
||||
if (this.hasSentAvatarDataNotify) {
|
||||
this.getSession().send(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public OnlinePlayerInfo getOnlinePlayerInfo() {
|
||||
OnlinePlayerInfo.Builder onlineInfo = OnlinePlayerInfo.newBuilder()
|
||||
.setUid(this.getUid())
|
||||
.setNickname(this.getNickname())
|
||||
.setPlayerLevel(this.getLevel())
|
||||
.setMpSettingType(this.getMpSetting())
|
||||
.setNameCardId(this.getNameCardId())
|
||||
.setSignature(this.getSignature())
|
||||
.setAvatarId(HeadImage.newBuilder().setAvatarId(this.getHeadImage()).getAvatarId());
|
||||
|
||||
if (this.getWorld() != null) {
|
||||
onlineInfo.setCurPlayerNumInWorld(this.getWorld().getPlayers().indexOf(this) + 1);
|
||||
} else {
|
||||
onlineInfo.setCurPlayerNumInWorld(1);
|
||||
}
|
||||
|
||||
return onlineInfo.build();
|
||||
}
|
||||
|
||||
public PlayerBirthday getBirthday() {
|
||||
return this.birthday;
|
||||
}
|
||||
|
||||
public void setBirthday(int d, int m) {
|
||||
this.birthday = new PlayerBirthday(d, m);
|
||||
this.updateProfile();
|
||||
}
|
||||
|
||||
public boolean hasBirthday() {
|
||||
return this.birthday.getDay() > 0;
|
||||
}
|
||||
|
||||
public Set<Integer> getRewardedLevels() {
|
||||
return rewardedLevels;
|
||||
}
|
||||
|
||||
public void setRewardedLevels(Set<Integer> rewardedLevels) {
|
||||
this.rewardedLevels = rewardedLevels;
|
||||
}
|
||||
|
||||
public SocialDetail.Builder getSocialDetail() {
|
||||
SocialDetail.Builder social = SocialDetail.newBuilder()
|
||||
.setUid(this.getUid())
|
||||
.setAvatarId(HeadImage.newBuilder().setAvatarId(this.getHeadImage()).getAvatarId())
|
||||
.setNickname(this.getNickname())
|
||||
.setSignature(this.getSignature())
|
||||
.setLevel(this.getLevel())
|
||||
.setBirthday(this.getBirthday().getFilledProtoWhenNotEmpty())
|
||||
.setWorldLevel(this.getWorldLevel())
|
||||
.setNameCardId(this.getNameCardId())
|
||||
.setFinishAchievementNum(0);
|
||||
return social;
|
||||
}
|
||||
|
||||
public PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo getWorldPlayerLocationInfo() {
|
||||
return PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo.newBuilder()
|
||||
.setSceneId(this.getSceneId())
|
||||
.setPlayerLoc(this.getPlayerLocationInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public PlayerLocationInfo getPlayerLocationInfo() {
|
||||
return PlayerLocationInfo.newBuilder()
|
||||
.setUid(this.getUid())
|
||||
.setPos(this.getPos().toProto())
|
||||
.setRot(this.getRotation().toProto())
|
||||
.build();
|
||||
}
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Check ping
|
||||
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
|
||||
this.getSession().close();
|
||||
return;
|
||||
}
|
||||
// Check co-op requests
|
||||
Iterator<CoopRequest> it = this.getCoopRequests().values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CoopRequest req = it.next();
|
||||
if (req.isExpired()) {
|
||||
req.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(this, false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.SYSTEM_JUDGE));
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
// Ping
|
||||
if (this.getWorld() != null) {
|
||||
// RTT notify - very important to send this often
|
||||
this.sendPacket(new PacketWorldPlayerRTTNotify(this.getWorld()));
|
||||
|
||||
// Update player locations if in multiplayer every 5 seconds
|
||||
long time = System.currentTimeMillis();
|
||||
if (this.getWorld().isMultiplayer() && this.getScene() != null && time > nextSendPlayerLocTime) {
|
||||
this.sendPacket(new PacketWorldPlayerLocationNotify(this.getWorld()));
|
||||
this.sendPacket(new PacketScenePlayerLocationNotify(this.getScene()));
|
||||
this.resetSendPlayerLocTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resetSendPlayerLocTime() {
|
||||
this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000;
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
private void onLoad() {
|
||||
this.getTeamManager().setPlayer(this);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
DatabaseHelper.savePlayer(this);
|
||||
}
|
||||
|
||||
public void onLogin() {
|
||||
// Make sure these exist
|
||||
if (this.getTeamManager() == null) {
|
||||
this.teamManager = new TeamManager(this);
|
||||
}
|
||||
if (this.getProfile().getUid() == 0) {
|
||||
this.getProfile().syncWithCharacter(this);
|
||||
}
|
||||
|
||||
// Check if player object exists in server
|
||||
// TODO - optimize
|
||||
Player exists = this.getServer().getPlayerByUid(getUid());
|
||||
if (exists != null) {
|
||||
exists.getSession().close();
|
||||
}
|
||||
|
||||
// Load from db
|
||||
this.getAvatars().loadFromDatabase();
|
||||
this.getInventory().loadFromDatabase();
|
||||
this.getAvatars().postLoad();
|
||||
|
||||
this.getFriendsList().loadFromDatabase();
|
||||
|
||||
// Create world
|
||||
World world = new World(this);
|
||||
world.addPlayer(this);
|
||||
|
||||
// Add to gameserver
|
||||
if (getSession().isActive()) {
|
||||
getServer().registerPlayer(this);
|
||||
getProfile().setPlayer(this); // Set online
|
||||
}
|
||||
|
||||
// Multiplayer setting
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber());
|
||||
this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1);
|
||||
|
||||
// Packets
|
||||
session.send(new PacketPlayerDataNotify(this)); // Player data
|
||||
session.send(new PacketStoreWeightLimitNotify());
|
||||
session.send(new PacketPlayerStoreNotify(this));
|
||||
session.send(new PacketAvatarDataNotify(this));
|
||||
|
||||
session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world
|
||||
session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels));
|
||||
session.send(new PacketOpenStateUpdateNotify());
|
||||
|
||||
// First notify packets sent
|
||||
this.setHasSentAvatarDataNotify(true);
|
||||
}
|
||||
|
||||
public void onLogout() {
|
||||
// Leave world
|
||||
if (this.getWorld() != null) {
|
||||
this.getWorld().removePlayer(this);
|
||||
}
|
||||
|
||||
// Status stuff
|
||||
this.getProfile().syncWithCharacter(this);
|
||||
this.getProfile().setPlayer(null); // Set offline
|
||||
|
||||
this.getCoopRequests().clear();
|
||||
|
||||
// Save to db
|
||||
this.save();
|
||||
this.getTeamManager().saveAvatars();
|
||||
this.getFriendsList().save();
|
||||
}
|
||||
|
||||
public enum SceneLoadState {
|
||||
NONE(0), LOADING(1), INIT(2), LOADED(3);
|
||||
|
||||
private final int value;
|
||||
|
||||
private SceneLoadState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/main/java/emu/grasscutter/game/player/TeamInfo.java
Normal file
79
src/main/java/emu/grasscutter/game/player/TeamInfo.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
|
||||
@Entity
|
||||
public class TeamInfo {
|
||||
private String name;
|
||||
private List<Integer> avatars;
|
||||
|
||||
public TeamInfo() {
|
||||
this.name = "";
|
||||
this.avatars = new ArrayList<>(Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam);
|
||||
}
|
||||
|
||||
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 (size() >= Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam || 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, Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
496
src/main/java/emu/grasscutter/game/player/TeamManager.java
Normal file
496
src/main/java/emu/grasscutter/game/player/TeamManager.java
Normal file
@@ -0,0 +1,496 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarDieAnimationEndRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarTeamUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketChangeAvatarRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketChangeTeamNameRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketChooseCurAvatarTeamRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneTeamUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSetUpAvatarTeamRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketWorldPlayerDieNotify;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
@Entity
|
||||
public class TeamManager {
|
||||
@Transient private Player player;
|
||||
|
||||
private Map<Integer, TeamInfo> teams;
|
||||
private int currentTeamIndex;
|
||||
private int currentCharacterIndex;
|
||||
|
||||
@Transient private TeamInfo mpTeam;
|
||||
@Transient private int entityId;
|
||||
@Transient private final List<EntityAvatar> avatars;
|
||||
@Transient private final Set<EntityGadget> gadgets;
|
||||
@Transient private final IntSet teamResonances;
|
||||
@Transient private final IntSet teamResonancesConfig;
|
||||
|
||||
public TeamManager() {
|
||||
this.mpTeam = new TeamInfo();
|
||||
this.avatars = new ArrayList<>();
|
||||
this.gadgets = new HashSet<>();
|
||||
this.teamResonances = new IntOpenHashSet();
|
||||
this.teamResonancesConfig = new IntOpenHashSet();
|
||||
}
|
||||
|
||||
public TeamManager(Player player) {
|
||||
this();
|
||||
this.player = player;
|
||||
|
||||
this.teams = new HashMap<>();
|
||||
this.currentTeamIndex = 1;
|
||||
for (int i = 1; i <= GameConstants.MAX_TEAMS; i++) {
|
||||
this.teams.put(i, new TeamInfo());
|
||||
}
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return player.getWorld();
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Map<Integer, TeamInfo> getTeams() {
|
||||
return this.teams;
|
||||
}
|
||||
|
||||
public TeamInfo getMpTeam() {
|
||||
return mpTeam;
|
||||
}
|
||||
|
||||
public void setMpTeam(TeamInfo mpTeam) {
|
||||
this.mpTeam = mpTeam;
|
||||
}
|
||||
|
||||
public int getCurrentTeamId() {
|
||||
// Starts from 1
|
||||
return currentTeamIndex;
|
||||
}
|
||||
|
||||
private void setCurrentTeamId(int currentTeamIndex) {
|
||||
this.currentTeamIndex = currentTeamIndex;
|
||||
}
|
||||
|
||||
public int getCurrentCharacterIndex() {
|
||||
return currentCharacterIndex;
|
||||
}
|
||||
|
||||
public void setCurrentCharacterIndex(int currentCharacterIndex) {
|
||||
this.currentCharacterIndex = currentCharacterIndex;
|
||||
}
|
||||
|
||||
public long getCurrentCharacterGuid() {
|
||||
return getCurrentAvatarEntity().getAvatar().getGuid();
|
||||
}
|
||||
|
||||
public TeamInfo getCurrentTeamInfo() {
|
||||
if (this.getPlayer().isInMultiplayer()) {
|
||||
return this.getMpTeam();
|
||||
}
|
||||
return this.getTeams().get(this.currentTeamIndex);
|
||||
}
|
||||
|
||||
public TeamInfo getCurrentSinglePlayerTeamInfo() {
|
||||
return this.getTeams().get(this.currentTeamIndex);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public Set<EntityGadget> getGadgets() {
|
||||
return gadgets;
|
||||
}
|
||||
|
||||
public IntSet getTeamResonances() {
|
||||
return teamResonances;
|
||||
}
|
||||
|
||||
public IntSet getTeamResonancesConfig() {
|
||||
return teamResonancesConfig;
|
||||
}
|
||||
|
||||
public List<EntityAvatar> getActiveTeam() {
|
||||
return avatars;
|
||||
}
|
||||
|
||||
public EntityAvatar getCurrentAvatarEntity() {
|
||||
return getActiveTeam().get(currentCharacterIndex);
|
||||
}
|
||||
|
||||
public boolean isSpawned() {
|
||||
return getPlayer().getScene() != null && getPlayer().getScene().getEntities().containsKey(getCurrentAvatarEntity().getId());
|
||||
}
|
||||
|
||||
public int getMaxTeamSize() {
|
||||
if (getPlayer().isInMultiplayer()) {
|
||||
int max = Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeamMultiplayer;
|
||||
if (getPlayer().getWorld().getHost() == this.getPlayer()) {
|
||||
return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount()));
|
||||
}
|
||||
return Math.max(1, (int) Math.floor(max / (double) getWorld().getPlayerCount()));
|
||||
}
|
||||
return Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam;
|
||||
}
|
||||
|
||||
// Methods
|
||||
|
||||
private void updateTeamResonances() {
|
||||
Int2IntOpenHashMap map = new Int2IntOpenHashMap();
|
||||
|
||||
this.getTeamResonances().clear();
|
||||
this.getTeamResonancesConfig().clear();
|
||||
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
AvatarSkillDepotData skillData = entity.getAvatar().getAvatarData().getSkillDepot();
|
||||
if (skillData != null) {
|
||||
map.addTo(skillData.getElementType().getValue(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (Int2IntMap.Entry e : map.int2IntEntrySet()) {
|
||||
if (e.getIntValue() >= 2) {
|
||||
ElementType element = ElementType.getTypeByValue(e.getIntKey());
|
||||
if (element.getTeamResonanceId() != 0) {
|
||||
this.getTeamResonances().add(element.getTeamResonanceId());
|
||||
this.getTeamResonancesConfig().add(element.getConfigHash());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No resonances
|
||||
if (this.getTeamResonances().size() == 0) {
|
||||
this.getTeamResonances().add(ElementType.Default.getTeamResonanceId());
|
||||
this.getTeamResonancesConfig().add(ElementType.Default.getTeamResonanceId());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTeamEntities(BasePacket responsePacket) {
|
||||
// Sanity check - Should never happen
|
||||
if (this.getCurrentTeamInfo().getAvatars().size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If current team has changed
|
||||
EntityAvatar currentEntity = this.getCurrentAvatarEntity();
|
||||
Int2ObjectMap<EntityAvatar> existingAvatars = new Int2ObjectOpenHashMap<>();
|
||||
int prevSelectedAvatarIndex = -1;
|
||||
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
existingAvatars.put(entity.getAvatar().getAvatarId(), entity);
|
||||
}
|
||||
|
||||
// Clear active team entity list
|
||||
this.getActiveTeam().clear();
|
||||
|
||||
// Add back entities into team
|
||||
for (int i = 0; i < this.getCurrentTeamInfo().getAvatars().size(); i++) {
|
||||
int avatarId = this.getCurrentTeamInfo().getAvatars().get(i);
|
||||
EntityAvatar entity = null;
|
||||
|
||||
if (existingAvatars.containsKey(avatarId)) {
|
||||
entity = existingAvatars.get(avatarId);
|
||||
existingAvatars.remove(avatarId);
|
||||
if (entity == currentEntity) {
|
||||
prevSelectedAvatarIndex = i;
|
||||
}
|
||||
} else {
|
||||
entity = new EntityAvatar(getPlayer().getScene(), getPlayer().getAvatars().getAvatarById(avatarId));
|
||||
}
|
||||
|
||||
this.getActiveTeam().add(entity);
|
||||
}
|
||||
|
||||
// Unload removed entities
|
||||
for (EntityAvatar entity : existingAvatars.values()) {
|
||||
getPlayer().getScene().removeEntity(entity);
|
||||
entity.getAvatar().save();
|
||||
}
|
||||
|
||||
// Set new selected character index
|
||||
if (prevSelectedAvatarIndex == -1) {
|
||||
// Previous selected avatar is not in the same spot, we will select the current one in the prev slot
|
||||
prevSelectedAvatarIndex = Math.min(this.currentCharacterIndex, this.getActiveTeam().size() - 1);
|
||||
}
|
||||
this.currentCharacterIndex = prevSelectedAvatarIndex;
|
||||
|
||||
// Update team resonances
|
||||
updateTeamResonances();
|
||||
|
||||
// Packets
|
||||
getPlayer().getWorld().broadcastPacket(new PacketSceneTeamUpdateNotify(getPlayer()));
|
||||
|
||||
// Run callback
|
||||
if (responsePacket != null) {
|
||||
getPlayer().sendPacket(responsePacket);
|
||||
}
|
||||
|
||||
// Check if character changed
|
||||
if (currentEntity != getCurrentAvatarEntity()) {
|
||||
// Remove and Add
|
||||
getPlayer().getScene().replaceEntity(currentEntity, getCurrentAvatarEntity());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setupAvatarTeam(int teamId, List<Long> list) {
|
||||
// Sanity checks
|
||||
if (list.size() == 0 || list.size() > getMaxTeamSize() || getPlayer().isInMultiplayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get team
|
||||
TeamInfo teamInfo = this.getTeams().get(teamId);
|
||||
if (teamInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set team data
|
||||
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(list.get(i));
|
||||
if (avatar == null || newTeam.contains(avatar)) {
|
||||
// Should never happen
|
||||
return;
|
||||
}
|
||||
newTeam.add(avatar);
|
||||
}
|
||||
|
||||
// Clear current team info and add avatars from our new team
|
||||
teamInfo.getAvatars().clear();
|
||||
for (Avatar avatar : newTeam) {
|
||||
teamInfo.addAvatar(avatar);
|
||||
}
|
||||
|
||||
// Update packet
|
||||
getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(getPlayer()));
|
||||
|
||||
// Update entites
|
||||
if (teamId == this.getCurrentTeamId()) {
|
||||
this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, teamInfo));
|
||||
} else {
|
||||
getPlayer().sendPacket(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, teamInfo));
|
||||
}
|
||||
}
|
||||
|
||||
public void setupMpTeam(List<Long> list) {
|
||||
// Sanity checks
|
||||
if (list.size() == 0 || list.size() > getMaxTeamSize() || !getPlayer().isInMultiplayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TeamInfo teamInfo = this.getMpTeam();
|
||||
|
||||
// Set team data
|
||||
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(list.get(i));
|
||||
if (avatar == null || newTeam.contains(avatar)) {
|
||||
// Should never happen
|
||||
return;
|
||||
}
|
||||
newTeam.add(avatar);
|
||||
}
|
||||
|
||||
// Clear current team info and add avatars from our new team
|
||||
teamInfo.getAvatars().clear();
|
||||
for (Avatar avatar : newTeam) {
|
||||
teamInfo.addAvatar(avatar);
|
||||
}
|
||||
|
||||
// Packet
|
||||
this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(getPlayer(), teamInfo));
|
||||
}
|
||||
|
||||
public synchronized void setCurrentTeam(int teamId) {
|
||||
//
|
||||
if (getPlayer().isInMultiplayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get team
|
||||
TeamInfo teamInfo = this.getTeams().get(teamId);
|
||||
if (teamInfo == null || teamInfo.getAvatars().size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set
|
||||
this.setCurrentTeamId(teamId);
|
||||
this.updateTeamEntities(new PacketChooseCurAvatarTeamRsp(teamId));
|
||||
}
|
||||
|
||||
public synchronized void setTeamName(int teamId, String teamName) {
|
||||
// Get team
|
||||
TeamInfo teamInfo = this.getTeams().get(teamId);
|
||||
if (teamInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
teamInfo.setName(teamName);
|
||||
|
||||
// Packet
|
||||
getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName));
|
||||
}
|
||||
|
||||
public synchronized void changeAvatar(long guid) {
|
||||
EntityAvatar oldEntity = this.getCurrentAvatarEntity();
|
||||
|
||||
if (guid == oldEntity.getAvatar().getGuid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityAvatar newEntity = null;
|
||||
int index = -1;
|
||||
for (int i = 0; i < getActiveTeam().size(); i++) {
|
||||
if (guid == getActiveTeam().get(i).getAvatar().getGuid()) {
|
||||
index = i;
|
||||
newEntity = getActiveTeam().get(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0 || newEntity == oldEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set index
|
||||
this.setCurrentCharacterIndex(index);
|
||||
|
||||
// Old entity motion state
|
||||
oldEntity.setMotionState(MotionState.MOTION_STANDBY);
|
||||
|
||||
// Remove and Add
|
||||
getPlayer().getScene().replaceEntity(oldEntity, newEntity);
|
||||
getPlayer().sendPacket(new PacketChangeAvatarRsp(guid));
|
||||
}
|
||||
|
||||
public void onAvatarDie(long dieGuid) {
|
||||
EntityAvatar deadAvatar = this.getCurrentAvatarEntity();
|
||||
|
||||
if (deadAvatar.isAlive() || deadAvatar.getId() != dieGuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replacement avatar
|
||||
EntityAvatar replacement = null;
|
||||
int replaceIndex = -1;
|
||||
|
||||
for (int i = 0; i < this.getActiveTeam().size(); i++) {
|
||||
EntityAvatar entity = this.getActiveTeam().get(i);
|
||||
if (entity.isAlive()) {
|
||||
replaceIndex = i;
|
||||
replacement = entity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replacement == null) {
|
||||
// No more living team members...
|
||||
getPlayer().sendPacket(new PacketWorldPlayerDieNotify(deadAvatar.getKilledType(), deadAvatar.getKilledBy()));
|
||||
} else {
|
||||
// Set index and spawn replacement member
|
||||
this.setCurrentCharacterIndex(replaceIndex);
|
||||
getPlayer().getScene().addEntity(replacement);
|
||||
}
|
||||
|
||||
// Response packet
|
||||
getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0));
|
||||
}
|
||||
|
||||
public boolean reviveAvatar(Avatar avatar) {
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
if (entity.getAvatar() == avatar) {
|
||||
if (entity.isAlive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entity.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_HP,
|
||||
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f
|
||||
);
|
||||
getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
|
||||
getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void respawnTeam() {
|
||||
// Make sure all team members are dead
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
if (entity.isAlive()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Revive all team members
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
entity.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_HP,
|
||||
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .4f
|
||||
);
|
||||
getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
|
||||
getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||
}
|
||||
|
||||
// Teleport player
|
||||
getPlayer().sendPacket(new PacketPlayerEnterSceneNotify(getPlayer(), EnterType.ENTER_SELF, EnterReason.Revival, 3, GameConstants.START_POSITION));
|
||||
|
||||
// Set player position
|
||||
player.setSceneId(3);
|
||||
player.getPos().set(GameConstants.START_POSITION);
|
||||
|
||||
// Packets
|
||||
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
|
||||
}
|
||||
|
||||
public void saveAvatars() {
|
||||
// Save all avatars from active team
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
entity.getAvatar().save();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user