mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-15 08:25:21 +01:00
@@ -1,5 +1,6 @@
|
||||
package emu.grasscutter.game;
|
||||
|
||||
import dev.morphia.annotations.AlsoLoad;
|
||||
import dev.morphia.annotations.Collation;
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
@@ -24,7 +25,7 @@ public class Account {
|
||||
private String username;
|
||||
private String password; // Unused for now
|
||||
|
||||
private int playerId;
|
||||
@AlsoLoad("playerUid") private int playerId;
|
||||
private String email;
|
||||
|
||||
private String token;
|
||||
@@ -68,7 +69,7 @@ public class Account {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public int getPlayerId() {
|
||||
public int getPlayerUid() {
|
||||
return this.playerId;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterMpReasonOuterClass.PlayerApplyEnterMpReason;
|
||||
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketAbilityInvocationsNotify;
|
||||
@@ -49,9 +50,11 @@ import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerPropNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerStoreNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketPrivateChatNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSetNameCardRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketStoreWeightLimitNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
@@ -101,6 +104,7 @@ public class GenshinPlayer {
|
||||
@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;
|
||||
@@ -121,6 +125,12 @@ public class GenshinPlayer {
|
||||
}
|
||||
this.properties.put(prop.getId(), 0);
|
||||
}
|
||||
|
||||
this.gachaInfo = new PlayerGachaInfo();
|
||||
this.nameCardList = new HashSet<>();
|
||||
this.flyCloakList = new HashSet<>();
|
||||
this.costumeList = new HashSet<>();
|
||||
|
||||
this.setSceneId(3);
|
||||
this.setRegionId(1);
|
||||
this.sceneState = SceneLoadState.NONE;
|
||||
@@ -140,11 +150,6 @@ public class GenshinPlayer {
|
||||
this.nickname = "Traveler";
|
||||
this.signature = "";
|
||||
this.teamManager = new TeamManager(this);
|
||||
this.gachaInfo = new PlayerGachaInfo();
|
||||
this.playerProfile = new PlayerProfile(this);
|
||||
this.nameCardList = new HashSet<>();
|
||||
this.flyCloakList = new HashSet<>();
|
||||
this.costumeList = new HashSet<>();
|
||||
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);
|
||||
@@ -165,6 +170,7 @@ public class GenshinPlayer {
|
||||
|
||||
public void setUid(int id) {
|
||||
this.id = id;
|
||||
this.getProfile().syncWithCharacter(this);
|
||||
}
|
||||
|
||||
public long getNextGenshinGuid() {
|
||||
@@ -654,6 +660,13 @@ public class GenshinPlayer {
|
||||
return social;
|
||||
}
|
||||
|
||||
public WorldPlayerLocationInfo getWorldPlayerLocationInfo() {
|
||||
return WorldPlayerLocationInfo.newBuilder()
|
||||
.setSceneId(this.getSceneId())
|
||||
.setPlayerLoc(this.getPlayerLocationInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public PlayerLocationInfo getPlayerLocationInfo() {
|
||||
return PlayerLocationInfo.newBuilder()
|
||||
.setUid(this.getUid())
|
||||
@@ -679,9 +692,22 @@ public class GenshinPlayer {
|
||||
}
|
||||
// Ping
|
||||
if (this.getWorld() != null) {
|
||||
this.sendPacket(new PacketWorldPlayerRTTNotify(this.getWorld())); // Player ping
|
||||
// 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() {
|
||||
@@ -696,12 +722,8 @@ public class GenshinPlayer {
|
||||
// Make sure these exist
|
||||
if (this.getTeamManager() == null) {
|
||||
this.teamManager = new TeamManager(this);
|
||||
} if (this.getGachaInfo() == null) {
|
||||
this.gachaInfo = new PlayerGachaInfo();
|
||||
} if (this.nameCardList == null) {
|
||||
this.nameCardList = new HashSet<>();
|
||||
} if (this.costumeList == null) {
|
||||
this.costumeList = new HashSet<>();
|
||||
} if (this.getProfile().getUid() == 0) {
|
||||
this.getProfile().syncWithCharacter(this);
|
||||
}
|
||||
|
||||
// Check if player object exists in server
|
||||
|
||||
@@ -206,28 +206,9 @@ public class World implements Iterable<GenshinPlayer> {
|
||||
public void deregisterScene(GenshinScene scene) {
|
||||
this.getScenes().remove(scene.getId());
|
||||
}
|
||||
|
||||
public boolean forceTransferPlayerToScene(GenshinPlayer player, int sceneId, Position pos) {
|
||||
// Forces the client to reload the scene map to prevent the player from falling off the map.
|
||||
if (GenshinData.getSceneDataMap().get(sceneId) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.getScene() != null) {
|
||||
player.getScene().removePlayer(player);
|
||||
}
|
||||
|
||||
GenshinScene scene = this.getSceneById(sceneId);
|
||||
scene.addPlayer(player);
|
||||
player.getPos().set(pos);
|
||||
|
||||
// Teleport packet
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.EnterSelf, EnterReason.TransPoint, sceneId, pos));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(GenshinPlayer player, int sceneId, Position pos) {
|
||||
if (player.getScene().getId() == sceneId || GenshinData.getSceneDataMap().get(sceneId) == null) {
|
||||
if (GenshinData.getSceneDataMap().get(sceneId) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import dev.morphia.annotations.Indexed;
|
||||
import dev.morphia.annotations.PostLoad;
|
||||
import dev.morphia.annotations.PrePersist;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GenshinData;
|
||||
import emu.grasscutter.data.common.FightPropData;
|
||||
import emu.grasscutter.data.custom.OpenConfigEntry;
|
||||
@@ -42,6 +43,7 @@ import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.net.proto.AvatarFetterInfoOuterClass.AvatarFetterInfo;
|
||||
import emu.grasscutter.net.proto.AvatarInfoOuterClass.AvatarInfo;
|
||||
import emu.grasscutter.server.packet.send.PacketAbilityChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropNotify;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
@@ -69,7 +71,7 @@ public class GenshinAvatar {
|
||||
|
||||
@Transient private final Int2ObjectMap<GenshinItem> equips;
|
||||
@Transient private final Int2FloatOpenHashMap fightProp;
|
||||
@Transient private final Set<String> bonusAbilityList;
|
||||
@Transient private Set<String> extraAbilityEmbryos;
|
||||
|
||||
private Map<Integer, Integer> skillLevelMap; // Talent levels
|
||||
private Map<Integer, Integer> proudSkillBonusMap; // Talent bonus levels (from const)
|
||||
@@ -86,7 +88,7 @@ public class GenshinAvatar {
|
||||
// Morhpia only!
|
||||
this.equips = new Int2ObjectOpenHashMap<>();
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.bonusAbilityList = new HashSet<>();
|
||||
this.extraAbilityEmbryos = new HashSet<>();
|
||||
this.proudSkillBonusMap = new HashMap<>(); // TODO Move to genshin avatar
|
||||
}
|
||||
|
||||
@@ -260,8 +262,8 @@ public class GenshinAvatar {
|
||||
return proudSkillBonusMap;
|
||||
}
|
||||
|
||||
public Set<String> getBonusAbilityList() {
|
||||
return bonusAbilityList;
|
||||
public Set<String> getExtraAbilityEmbryos() {
|
||||
return extraAbilityEmbryos;
|
||||
}
|
||||
|
||||
public float getCurrentHp() {
|
||||
@@ -347,14 +349,14 @@ public class GenshinAvatar {
|
||||
item.setEquipCharacter(this.getAvatarId());
|
||||
item.save();
|
||||
|
||||
if (this.getPlayer().hasSentAvatarDataNotify()) {
|
||||
this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item));
|
||||
}
|
||||
|
||||
if (shouldRecalc) {
|
||||
this.recalcStats();
|
||||
}
|
||||
|
||||
if (this.getPlayer().hasSentAvatarDataNotify()) {
|
||||
this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -371,11 +373,18 @@ public class GenshinAvatar {
|
||||
}
|
||||
|
||||
public void recalcStats() {
|
||||
recalcStats(false);
|
||||
}
|
||||
|
||||
public void recalcStats(boolean forceSendAbilityChange) {
|
||||
// Setup
|
||||
AvatarData data = this.getAvatarData();
|
||||
AvatarPromoteData promoteData = GenshinData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel());
|
||||
Int2IntOpenHashMap setMap = new Int2IntOpenHashMap();
|
||||
this.getBonusAbilityList().clear();
|
||||
|
||||
// Extra ability embryos
|
||||
Set<String> prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos();
|
||||
this.extraAbilityEmbryos = new HashSet<>();
|
||||
|
||||
// Get hp percent, set to 100% if none
|
||||
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
@@ -458,7 +467,7 @@ public class GenshinAvatar {
|
||||
}
|
||||
|
||||
// Add any skill strings from this affix
|
||||
this.addToAbilityList(affix.getOpenConfig(), true);
|
||||
this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -505,7 +514,7 @@ public class GenshinAvatar {
|
||||
}
|
||||
|
||||
// Add any skill strings from this affix
|
||||
this.addToAbilityList(affix.getOpenConfig(), true);
|
||||
this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +547,7 @@ public class GenshinAvatar {
|
||||
}
|
||||
|
||||
// Add any skill strings from this proud skill
|
||||
this.addToAbilityList(proudSkillData.getOpenConfig(), true);
|
||||
this.addToExtraAbilityEmbryos(proudSkillData.getOpenConfig(), true);
|
||||
}
|
||||
|
||||
// Constellations
|
||||
@@ -550,7 +559,7 @@ public class GenshinAvatar {
|
||||
}
|
||||
|
||||
// Add any skill strings from this constellation
|
||||
this.addToAbilityList(avatarTalentData.getOpenConfig(), false);
|
||||
this.addToExtraAbilityEmbryos(avatarTalentData.getOpenConfig(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,11 +582,17 @@ public class GenshinAvatar {
|
||||
|
||||
// Packet
|
||||
if (getPlayer() != null && getPlayer().hasSentAvatarDataNotify()) {
|
||||
// Update stats for client
|
||||
getPlayer().sendPacket(new PacketAvatarFightPropNotify(this));
|
||||
// Update client abilities
|
||||
EntityAvatar entity = this.getAsEntity();
|
||||
if (entity != null && (!this.getExtraAbilityEmbryos().equals(prevExtraAbilityEmbryos) || forceSendAbilityChange)) {
|
||||
getPlayer().sendPacket(new PacketAbilityChangeNotify(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addToAbilityList(String openConfig, boolean forceAdd) {
|
||||
public void addToExtraAbilityEmbryos(String openConfig, boolean forceAdd) {
|
||||
if (openConfig == null || openConfig.length() == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -586,14 +601,14 @@ public class GenshinAvatar {
|
||||
if (entry == null) {
|
||||
if (forceAdd) {
|
||||
// Add config string to ability skill list anyways
|
||||
this.getBonusAbilityList().add(openConfig);
|
||||
this.getExtraAbilityEmbryos().add(openConfig);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.getAddAbilities() != null) {
|
||||
for (String ability : entry.getAddAbilities()) {
|
||||
this.getBonusAbilityList().add(ability);
|
||||
this.getExtraAbilityEmbryos().add(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,8 +223,8 @@ public class EntityAvatar extends GenshinEntity {
|
||||
}
|
||||
}
|
||||
// Add equip abilities
|
||||
if (this.getAvatar().getBonusAbilityList().size() > 0) {
|
||||
for (String skill : this.getAvatar().getBonusAbilityList()) {
|
||||
if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) {
|
||||
for (String skill : this.getAvatar().getExtraAbilityEmbryos()) {
|
||||
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(Utils.abilityHash(skill))
|
||||
|
||||
@@ -220,7 +220,7 @@ public class FriendsList {
|
||||
friendship.setOwner(getPlayer());
|
||||
|
||||
// Check if friend is online
|
||||
GenshinPlayer friend = getPlayer().getSession().getServer().getPlayerByUid(friendship.getFriendProfile().getId());
|
||||
GenshinPlayer friend = getPlayer().getSession().getServer().getPlayerByUid(friendship.getFriendProfile().getUid());
|
||||
if (friend != null) {
|
||||
// Set friend to online mode
|
||||
friendship.setFriendProfile(friend);
|
||||
|
||||
@@ -88,7 +88,7 @@ public class Friendship {
|
||||
|
||||
public FriendBrief toProto() {
|
||||
FriendBrief proto = FriendBrief.newBuilder()
|
||||
.setUid(getFriendProfile().getId())
|
||||
.setUid(getFriendProfile().getUid())
|
||||
.setNickname(getFriendProfile().getName())
|
||||
.setLevel(getFriendProfile().getPlayerLevel())
|
||||
.setAvatar(HeadImage.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
|
||||
|
||||
@@ -7,7 +7,7 @@ import emu.grasscutter.utils.Utils;
|
||||
public class PlayerProfile {
|
||||
@Transient private GenshinPlayer player;
|
||||
|
||||
private int id;
|
||||
@AlsoLoad("id") private int uid;
|
||||
private int nameCard;
|
||||
private int avatarId;
|
||||
private String name;
|
||||
@@ -22,12 +22,12 @@ public class PlayerProfile {
|
||||
public PlayerProfile() { }
|
||||
|
||||
public PlayerProfile(GenshinPlayer player) {
|
||||
this.id = player.getUid();
|
||||
this.uid = player.getUid();
|
||||
this.syncWithCharacter(player);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
public int getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public GenshinPlayer getPlayer() {
|
||||
@@ -87,6 +87,7 @@ public class PlayerProfile {
|
||||
return;
|
||||
}
|
||||
|
||||
this.uid = player.getUid();
|
||||
this.name = player.getNickname();
|
||||
this.avatarId = player.getHeadImage();
|
||||
this.signature = player.getSignature();
|
||||
|
||||
@@ -589,7 +589,6 @@ public class InventoryManager {
|
||||
|
||||
// Update proud skills
|
||||
AvatarSkillDepotData skillDepot = GenshinData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId());
|
||||
boolean hasAddedProudSkill = false;
|
||||
|
||||
if (skillDepot != null && skillDepot.getInherentProudSkillOpens() != null) {
|
||||
for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) {
|
||||
@@ -599,7 +598,6 @@ public class InventoryManager {
|
||||
if (openData.getNeedAvatarPromoteLevel() == avatar.getPromoteLevel()) {
|
||||
int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1;
|
||||
if (GenshinData.getProudSkillDataMap().containsKey(proudSkillId)) {
|
||||
hasAddedProudSkill = true;
|
||||
avatar.getProudSkillList().add(proudSkillId);
|
||||
player.sendPacket(new PacketProudSkillChangeNotify(avatar));
|
||||
}
|
||||
@@ -607,20 +605,13 @@ public class InventoryManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Racalc stats and save avatar
|
||||
avatar.recalcStats();
|
||||
avatar.save();
|
||||
|
||||
// Resend ability embryos if proud skill has been added
|
||||
if (hasAddedProudSkill && avatar.getAsEntity() != null) {
|
||||
player.sendPacket(new PacketAbilityChangeNotify(avatar.getAsEntity()));
|
||||
}
|
||||
|
||||
// TODO Send entity prop update packet to world
|
||||
|
||||
// Packets
|
||||
player.sendPacket(new PacketAvatarPropNotify(avatar));
|
||||
player.sendPacket(new PacketAvatarPromoteRsp(avatar));
|
||||
|
||||
// TODO Send entity prop update packet to world
|
||||
avatar.recalcStats(true);
|
||||
avatar.save();
|
||||
}
|
||||
|
||||
public void upgradeAvatar(GenshinPlayer player, long guid, int itemId, int count) {
|
||||
@@ -827,25 +818,20 @@ public class InventoryManager {
|
||||
// Apply + recalc
|
||||
avatar.getTalentIdList().add(talentData.getId());
|
||||
avatar.setCoreProudSkillLevel(currentTalentLevel + 1);
|
||||
avatar.recalcStats();
|
||||
|
||||
// Packet
|
||||
player.sendPacket(new PacketAvatarUnlockTalentNotify(avatar, nextTalentId));
|
||||
player.sendPacket(new PacketUnlockAvatarTalentRsp(avatar, nextTalentId));
|
||||
|
||||
// Proud skill bonus map
|
||||
// Proud skill bonus map (Extra skills)
|
||||
OpenConfigEntry entry = GenshinData.getOpenConfigEntries().get(talentData.getOpenConfig());
|
||||
if (entry != null && entry.getExtraTalentIndex() > 0) {
|
||||
avatar.recalcProudSkillBonusMap();
|
||||
player.sendPacket(new PacketProudSkillExtraLevelNotify(avatar, entry.getExtraTalentIndex()));
|
||||
}
|
||||
|
||||
// Resend ability embryos
|
||||
if (avatar.getAsEntity() != null) {
|
||||
player.sendPacket(new PacketAbilityChangeNotify(avatar.getAsEntity()));
|
||||
}
|
||||
|
||||
// Save avatar
|
||||
// Recalc + save avatar
|
||||
avatar.recalcStats(true);
|
||||
avatar.save();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user