Refactor player sync packet

This commit is contained in:
Melledy
2024-08-04 01:32:30 -07:00
parent 4cd7a512ae
commit 9ce053c1b3
12 changed files with 135 additions and 215 deletions

View File

@@ -64,7 +64,7 @@ public class AvatarCommand implements CommandHandler {
if (changeList.size() > 0) {
// Send packet
args.getTarget().sendPacket(new PacketPlayerSyncScNotify(changeList.toArray(GameAvatar[]::new)));
args.getTarget().sendPacket(new PacketPlayerSyncScNotify(changeList));
// Send message
args.sendMessage("Set avatar(s) properties successfully");
} else {

View File

@@ -20,7 +20,7 @@ public class AvatarData {
@Setter private int rank; // Eidolons
private Int2IntMap skills; // Skill tree
@Setter private transient IAvatar baseAvatar;
@Setter private transient BaseAvatar baseAvatar;
private transient Int2ObjectMap<GameItem> equips;
@Deprecated // Morphia only

View File

@@ -15,12 +15,13 @@ import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.AvatarSkillTreeOuterClass.AvatarSkillTree;
import emu.lunarcore.proto.EquipRelicOuterClass.EquipRelic;
import emu.lunarcore.proto.MultiPathAvatarInfoOuterClass.MultiPathAvatarInfo;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import lombok.Getter;
import lombok.Setter;
@Getter
@Entity(value = "multiPaths", useDiscriminator = false)
public class AvatarMultiPath implements IAvatar {
public class AvatarMultiPath extends BaseAvatar {
@Id private ObjectId id;
@Indexed private int ownerUid;
@@ -62,6 +63,16 @@ public class AvatarMultiPath implements IAvatar {
return this.getData().getSkills();
}
// Player sync
// Player sync
public void onSync(PlayerSyncScNotify proto) {
proto.addMultiPathAvatarInfoList(this.toProto());
}
// Proto
public MultiPathAvatarInfo toProto() {
var proto = MultiPathAvatarInfo.newInstance()
.setAvatarIdValue(this.getExcelId())
@@ -83,6 +94,8 @@ public class AvatarMultiPath implements IAvatar {
return proto;
}
// Database
public void save() {
LunarCore.getGameDatabase().save(this);
}

View File

@@ -42,8 +42,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
// Base avatars
public IAvatar getBaseAvatarById(int id) {
IAvatar baseAvatar = this.getMultiPathById(id);
public BaseAvatar getBaseAvatarById(int id) {
BaseAvatar baseAvatar = this.getMultiPathById(id);
if (baseAvatar == null) {
baseAvatar = this.getAvatarById(id);
}
@@ -51,8 +51,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
return baseAvatar;
}
public IAvatar getBaseAvatarById(ObjectId id) {
IAvatar baseAvatar = this.getMultiPathById(id);
public BaseAvatar getBaseAvatarById(ObjectId id) {
BaseAvatar baseAvatar = this.getMultiPathById(id);
if (baseAvatar == null) {
baseAvatar = this.getAvatarById(id);
}

View File

@@ -6,43 +6,46 @@ import emu.lunarcore.GameConstants;
import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.game.inventory.GameItem;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.server.game.Syncable;
import emu.lunarcore.server.packet.send.PacketPlayerSyncScNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
public interface IAvatar {
public ObjectId getId();
public abstract class BaseAvatar implements Syncable {
// Properties
public Player getOwner();
public abstract ObjectId getId();
public AvatarData getData();
public abstract Player getOwner();
public abstract AvatarData getData();
// Excels
public int getExcelId();
public abstract int getExcelId();
public AvatarExcel getExcel();
public abstract AvatarExcel getExcel();
// Equip handlers
public default Int2ObjectMap<GameItem> getEquips() {
public Int2ObjectMap<GameItem> getEquips() {
return this.getData().getEquips();
}
public default GameItem getEquipBySlot(int slot) {
public GameItem getEquipBySlot(int slot) {
return this.getEquips().get(slot);
}
public default GameItem getEquipment() {
public GameItem getEquipment() {
return this.getEquips().get(GameConstants.EQUIPMENT_SLOT_ID);
}
public default boolean equipItem(GameItem item) {
public boolean equipItem(GameItem item) {
// Sanity check
int slot = item.getEquipSlot();
if (slot == 0) return false;
// Check if other avatars have this item equipped
IAvatar otherAvatar = item.getEquipAvatar();
BaseAvatar otherAvatar = item.getEquipAvatar();
if (otherAvatar != null) {
// Unequip this item from the other avatar
if (otherAvatar.unequipItem(slot) != null) {
@@ -75,7 +78,7 @@ public interface IAvatar {
return true;
}
public default GameItem unequipItem(int slot) {
public GameItem unequipItem(int slot) {
GameItem item = getEquips().remove(slot);
if (item != null) {

View File

@@ -28,6 +28,7 @@ import emu.lunarcore.proto.DisplayRelicInfoOuterClass.DisplayRelicInfo;
import emu.lunarcore.proto.EquipRelicOuterClass.EquipRelic;
import emu.lunarcore.proto.LineupAvatarOuterClass.LineupAvatar;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import emu.lunarcore.proto.SceneActorInfoOuterClass.SceneActorInfo;
import emu.lunarcore.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.lunarcore.proto.SpBarInfoOuterClass.SpBarInfo;
@@ -40,7 +41,7 @@ import lombok.Setter;
@Getter
@Entity(value = "avatars", useDiscriminator = false)
public class GameAvatar implements GameEntity, IAvatar {
public class GameAvatar extends BaseAvatar implements GameEntity {
@Id private ObjectId id;
@Indexed @Getter private int ownerUid; // Uid of player that this avatar belongs to
@@ -223,6 +224,18 @@ public class GameAvatar implements GameEntity, IAvatar {
this.buffs.put(buffId, System.currentTimeMillis() + (duration * 1000));
}
// Player sync
public void onSync(PlayerSyncScNotify proto) {
// Add to avatar sync
proto.getMutableAvatarSync().addAvatarList(this.toProto());
// Also update multipath info
if (this.getMultiPath() != null) {
proto.addMultiPathAvatarInfoList(this.getMultiPath().toProto());
}
}
// Proto
public Avatar toProto() {

View File

@@ -13,7 +13,7 @@ import emu.lunarcore.data.GameDepot;
import emu.lunarcore.data.excel.ItemExcel;
import emu.lunarcore.data.excel.RelicMainAffixExcel;
import emu.lunarcore.data.excel.RelicSubAffixExcel;
import emu.lunarcore.game.avatar.IAvatar;
import emu.lunarcore.game.avatar.BaseAvatar;
import emu.lunarcore.game.enums.AvatarPropertyType;
import emu.lunarcore.game.enums.ItemMainType;
import emu.lunarcore.game.player.Player;
@@ -21,7 +21,9 @@ import emu.lunarcore.proto.EquipmentOuterClass.Equipment;
import emu.lunarcore.proto.ItemOuterClass.Item;
import emu.lunarcore.proto.MaterialOuterClass.Material;
import emu.lunarcore.proto.PileItemOuterClass.PileItem;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import emu.lunarcore.proto.RelicOuterClass.Relic;
import emu.lunarcore.server.game.Syncable;
import emu.lunarcore.util.Utils;
import emu.lunarcore.util.WeightedList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
@@ -31,7 +33,7 @@ import lombok.Setter;
@Getter
@Entity(value = "items", useDiscriminator = false)
public class GameItem {
public class GameItem implements Syncable {
@Id private ObjectId id;
@Indexed private int ownerUid; // Uid of player that this avatar belongs to
@@ -53,7 +55,7 @@ public class GameItem {
private List<GameItemSubAffix> subAffixes;
@Indexed private ObjectId equipAvatarId; // Object id of the avatar this item is equipped to
private transient IAvatar equipAvatar;
private transient BaseAvatar equipAvatar;
@LoadOnly @AlsoLoad("equipAvatar")
private int equipAvatarExcelId; // Deprecated legacy field
@@ -151,7 +153,7 @@ public class GameItem {
return false;
}
public boolean setEquipAvatar(IAvatar baseAvatar) {
public boolean setEquipAvatar(BaseAvatar baseAvatar) {
if (baseAvatar == null && this.isEquipped()) {
this.equipAvatarId = null;
this.equipAvatar = null;
@@ -271,6 +273,33 @@ public class GameItem {
LunarCore.getGameDatabase().delete(this);
}
}
// Player sync
public void onSync(PlayerSyncScNotify proto) {
switch (this.getExcel().getItemMainType().getTabType()) {
case MATERIAL -> {
proto.addMaterialList(this.toMaterialProto());
}
case RELIC -> {
if (this.getCount() > 0) {
proto.addRelicList(this.toRelicProto());
} else {
proto.addDelRelicList(this.getInternalUid());
}
}
case EQUIPMENT -> {
if (this.getCount() > 0) {
proto.addEquipmentList(this.toEquipmentProto());
} else {
proto.addDelEquipmentList(this.getInternalUid());
}
}
default -> {
// Skip
}
}
}
// Proto

View File

@@ -14,7 +14,7 @@ import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.data.excel.ItemExcel;
import emu.lunarcore.game.avatar.AvatarStorage;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.avatar.IAvatar;
import emu.lunarcore.game.avatar.BaseAvatar;
import emu.lunarcore.game.enums.ItemMainType;
import emu.lunarcore.game.enums.ItemSubType;
import emu.lunarcore.game.inventory.tabs.EquipInventoryTab;
@@ -554,7 +554,7 @@ public class Inventory extends BasePlayerManager {
// Equips
public boolean equipItem(int avatarId, int equipId) {
IAvatar avatar = getPlayer().getAvatars().getBaseAvatarById(avatarId);
BaseAvatar avatar = getPlayer().getAvatars().getBaseAvatarById(avatarId);
GameItem item = this.getItemByUid(equipId);
if (avatar != null && item != null) {
@@ -565,7 +565,7 @@ public class Inventory extends BasePlayerManager {
}
public boolean unequipItem(int avatarId, int slot) {
IAvatar avatar = getPlayer().getAvatars().getBaseAvatarById(avatarId);
BaseAvatar avatar = getPlayer().getAvatars().getBaseAvatarById(avatarId);
if (avatar != null) {
GameItem unequipped = avatar.unequipItem(slot);
@@ -614,7 +614,7 @@ public class Inventory extends BasePlayerManager {
// Equip to a character if possible
if (item.isEquipped() || item.getEquipAvatarExcelId() > 0) {
IAvatar avatar = null;
BaseAvatar avatar = null;
boolean hasEquipped = false;
if (item.getEquipAvatarExcelId() > 0) {

View File

@@ -61,10 +61,12 @@ import emu.lunarcore.proto.HeadIconOuterClass.HeadIcon;
import emu.lunarcore.proto.PlatformTypeOuterClass.PlatformType;
import emu.lunarcore.proto.PlayerBasicInfoOuterClass.PlayerBasicInfo;
import emu.lunarcore.proto.PlayerDetailInfoOuterClass.PlayerDetailInfo;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import emu.lunarcore.proto.RogueCurVirtualItemInfoOuterClass.RogueCurVirtualItemInfo;
import emu.lunarcore.proto.SimpleInfoOuterClass.SimpleInfo;
import emu.lunarcore.server.game.GameServer;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.game.Syncable;
import emu.lunarcore.server.game.Tickable;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
@@ -80,7 +82,7 @@ import us.hebi.quickbuf.RepeatedMessage;
@Entity(value = "players", useDiscriminator = false)
@Getter
public class Player implements Tickable {
public class Player implements Tickable, Syncable {
@Id private int uid;
@Indexed private String accountUid;
private String name;
@@ -1026,6 +1028,12 @@ public class Player implements Tickable {
}
}
// Player sync
public void onSync(PlayerSyncScNotify proto) {
proto.setBasicInfo(this.toProto());
}
// Protobuf serialization
public PlayerBasicInfo toProto() {

View File

@@ -7,6 +7,8 @@ import emu.lunarcore.LunarCore;
import emu.lunarcore.data.GameData;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.enums.PersonalizeShowType;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import emu.lunarcore.server.game.Syncable;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.send.PacketPlayerSyncScNotify;
import emu.lunarcore.server.packet.send.PacketUnlockChatBubbleScNotify;
@@ -17,7 +19,7 @@ import lombok.Getter;
@Getter
@Entity(value = "unlocks", useDiscriminator = false)
public class PlayerUnlockData {
public class PlayerUnlockData implements Syncable {
private transient Player owner;
@Id private int ownerUid;
@@ -89,7 +91,7 @@ public class PlayerUnlockData {
boolean success = this.getHeadIcons().add(headIconId);
if (success && this.getOwner().isLoggedIn()) {
this.sendPacket(new PacketPlayerSyncScNotify(getOwner().toBoardData()));
this.sendPacket(new PacketPlayerSyncScNotify(this));
this.save();
}
}
@@ -115,6 +117,14 @@ public class PlayerUnlockData {
private void sendPacket(BasePacket packet) {
this.getOwner().sendPacket(packet);
}
// Player sync
public void onSync(PlayerSyncScNotify proto) {
proto.setBoardDataSync(this.getOwner().toBoardData());
}
// Database
public void save() {
LunarCore.getGameDatabase().save(this);

View File

@@ -0,0 +1,9 @@
package emu.lunarcore.server.game;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
public interface Syncable {
public void onSync(PlayerSyncScNotify proto);
}

View File

@@ -1,16 +1,9 @@
package emu.lunarcore.server.packet.send;
import java.util.Collection;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.avatar.IAvatar;
import emu.lunarcore.game.avatar.AvatarMultiPath;
import emu.lunarcore.game.inventory.GameItem;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.BoardDataSyncOuterClass.BoardDataSync;
import emu.lunarcore.proto.MissionSyncOuterClass.MissionSync;
import emu.lunarcore.proto.MissionOuterClass.Mission;
import emu.lunarcore.proto.MissionStatusOuterClass.MissionStatus;
import java.util.List;
import emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import emu.lunarcore.server.game.Syncable;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
@@ -20,196 +13,38 @@ public class PacketPlayerSyncScNotify extends BasePacket {
private PacketPlayerSyncScNotify() {
super(CmdId.PlayerSyncScNotify);
}
public PacketPlayerSyncScNotify(Player player) {
this();
var data = PlayerSyncScNotify.newInstance()
.setBasicInfo(player.toProto());
this.setData(data);
}
public PacketPlayerSyncScNotify(BoardDataSync boardData) {
this();
var data = PlayerSyncScNotify.newInstance()
.setBoardDataSync(boardData);
this.setData(data);
}
public PacketPlayerSyncScNotify(IAvatar baseAvatar) {
public PacketPlayerSyncScNotify(Syncable object) {
this();
var data = PlayerSyncScNotify.newInstance();
if (baseAvatar instanceof GameAvatar avatar) {
data.getMutableAvatarSync().addAvatarList(avatar.toProto());
// Also update multipath info
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
} else if (baseAvatar instanceof AvatarMultiPath multiPath) {
data.addMultiPathAvatarInfoList(multiPath.toProto());
object.onSync(data);
this.setData(data);
}
public PacketPlayerSyncScNotify(Syncable... objects) {
this();
var data = PlayerSyncScNotify.newInstance();
for (var object : objects) {
object.onSync(data);
}
this.setData(data);
}
public PacketPlayerSyncScNotify(IAvatar baseAvatar, GameItem item) {
public PacketPlayerSyncScNotify(List<? extends Syncable> objects) {
this();
var data = PlayerSyncScNotify.newInstance();
if (baseAvatar instanceof GameAvatar avatar) {
data.getMutableAvatarSync().addAvatarList(avatar.toProto());
// Also update multipath info
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
} else if (baseAvatar instanceof AvatarMultiPath multiPath) {
data.addMultiPathAvatarInfoList(multiPath.toProto());
for (var object : objects) {
object.onSync(data);
}
this.addItemToProto(data, item);
this.setData(data);
}
public PacketPlayerSyncScNotify(GameAvatar avatar) {
this();
var data = PlayerSyncScNotify.newInstance();
// Update avatar
data.getMutableAvatarSync().addAvatarList(avatar.toProto());
// Also update multipath info
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
this.setData(data);
}
public PacketPlayerSyncScNotify(GameAvatar avatar, GameItem item) {
this();
var data = PlayerSyncScNotify.newInstance();
// Update avatar
data.getMutableAvatarSync().addAvatarList(avatar.toProto());
// Also update multipath info
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
// Update item
this.addItemToProto(data, item);
this.setData(data);
}
public PacketPlayerSyncScNotify(GameItem item) {
this();
var data = PlayerSyncScNotify.newInstance();
this.addItemToProto(data, item);
this.setData(data);
}
public PacketPlayerSyncScNotify(GameAvatar... avatars) { // Ugly workaround
this();
var data = PlayerSyncScNotify.newInstance();
for (var avatar : avatars) {
// Sync avatar
data.getMutableAvatarSync().addAvatarList(avatar.toProto());
// Also update hero basic type info if were updating the main character
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
}
this.setData(data);
}
public PacketPlayerSyncScNotify(Collection<GameItem> items) {
this();
var data = PlayerSyncScNotify.newInstance();
for (GameItem item : items) {
this.addItemToProto(data, item);
}
this.setData(data);
}
private void addItemToProto(PlayerSyncScNotify data, GameItem item) {
switch (item.getExcel().getItemMainType().getTabType()) {
case MATERIAL -> {
data.addMaterialList(item.toMaterialProto());
}
case RELIC -> {
if (item.getCount() > 0) {
data.addRelicList(item.toRelicProto());
} else {
data.addDelRelicList(item.getInternalUid());
}
}
case EQUIPMENT -> {
if (item.getCount() > 0) {
data.addEquipmentList(item.toEquipmentProto());
} else {
data.addDelEquipmentList(item.getInternalUid());
}
}
default -> {
// Skip
}
}
}
public PacketPlayerSyncScNotify(AvatarMultiPath... multiPaths) {
this();
var data = PlayerSyncScNotify.newInstance();
for (var path : multiPaths) {
if (path != null) {
data.addMultiPathAvatarInfoList(path.toProto());
}
}
this.setData(data);
}
public PacketPlayerSyncScNotify(int mainMissionId, int[] subMissionIds, MissionStatus missionStatus) {
this();
var missionSync = MissionSync.newInstance();
for (int subMissionId : subMissionIds) {
missionSync.addMissionList(
Mission.newInstance()
.setId(subMissionId)
.setStatus(missionStatus)
);
}
var data = PlayerSyncScNotify.newInstance()
.setMissionSync(missionSync);
this.setData(data);
}
}