Update to support game version 2.4.0

This commit is contained in:
Melledy
2024-07-30 17:15:56 -07:00
parent b4addcc7dd
commit c8ac84ff37
419 changed files with 36024 additions and 29880 deletions

View File

@@ -6,7 +6,7 @@ import java.time.ZoneOffset;
import emu.lunarcore.util.Position;
public class GameConstants {
public static String VERSION = "2.3.0";
public static String VERSION = "2.4.0";
public static final ZoneOffset CURRENT_ZONEOFFSET = ZoneOffset.systemDefault().getRules().getOffset(Instant.now());
public static final int CURRENT_TIMEZONE = CURRENT_ZONEOFFSET.getTotalSeconds() / 3600;

View File

@@ -1,51 +0,0 @@
package emu.lunarcore.command.commands;
import emu.lunarcore.command.Command;
import emu.lunarcore.command.CommandArgs;
import emu.lunarcore.command.CommandHandler;
import emu.lunarcore.data.GameData;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.game.player.PlayerGender;
import emu.lunarcore.server.packet.send.PacketGetHeroBasicTypeInfoScRsp;
@Command(label = "gender", permission = "player.gender", requireTarget = true, desc = "/gender {male | female}. Sets the player gender.")
public class GenderCommand implements CommandHandler {
@Override
public void execute(CommandArgs args) {
// Set world level
Player target = args.getTarget();
PlayerGender playerGender = null;
String gender = args.get(0).toLowerCase();
switch (gender) {
case "m", "male", "boy", "man" -> {
playerGender = PlayerGender.GENDER_MAN;
}
case "f", "female", "girl", "woman" -> {
playerGender = PlayerGender.GENDER_WOMAN;
}
}
// Change gender
if (playerGender != null && playerGender != target.getGender()) {
// Set gender first
target.setGender(playerGender);
target.save();
// Get first hero excel that matches our new player gender
var heroExcel = GameData.getHeroExcelMap().values().stream().filter(path -> path.getGender() == target.getGender()).findFirst().orElse(null);
if (heroExcel != null) {
// Set hero basic type
target.setHeroBasicType(heroExcel.getId());
}
// Send packet and response message
target.sendPacket(new PacketGetHeroBasicTypeInfoScRsp(target));
args.sendMessage("Gender for " + target.getName() + " set successfully");
} else {
args.sendMessage("Error: Invalid input");
}
}
}

View File

@@ -30,7 +30,7 @@ public class GameData {
@Getter private static Int2ObjectMap<StageExcel> stageExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<MazePlaneExcel> mazePlaneExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<MapEntranceExcel> mapEntranceExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<HeroExcel> heroExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<MultiplePathAvatarExcel> multiplePathAvatarExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<ShopExcel> shopExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<RewardExcel> rewardExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<InteractExcel> interactExcelMap = new Int2ObjectOpenHashMap<>();

View File

@@ -220,10 +220,12 @@ public class ResourceLoader {
}
// Load floor infos
for (File file : floorDir.listFiles()) {
for (var excel : GameData.getMapEntranceExcelMap().values()) {
String name = "P" + excel.getPlaneID() + "_F" + excel.getFloorID();
File file = new File(LunarCore.getConfig().getResourceDir() + "/Config/LevelOutput/RuntimeFloor/" + name + ".json");
try (FileReader reader = new FileReader(file)) {
FloorInfo floor = gson.fromJson(reader, FloorInfo.class);
String name = file.getName().substring(0, file.getName().indexOf('.'));
GameData.getFloorInfos().put(name, floor);
} catch (Exception e) {
e.printStackTrace();
@@ -307,9 +309,11 @@ public class ResourceLoader {
}
// Notify the server owner if we are missing any files
/*
if (count < GameData.getSummonUnitExcelMap().size()) {
LunarCore.getLogger().warn("Summon unit configs are missing, please check your resources folder: {resources}/Config/ConfigSummonUnit. Character summon techniques may not work!");
}
*/
// Reset loaded count
count = 0;

View File

@@ -1,19 +0,0 @@
package emu.lunarcore.data.excel;
import emu.lunarcore.data.GameResource;
import emu.lunarcore.data.ResourceType;
import emu.lunarcore.game.player.PlayerGender;
import lombok.Getter;
@Getter
@ResourceType(name = {"HeroConfig.json"})
public class HeroExcel extends GameResource {
private int HeroAvatarID;
private PlayerGender Gender;
@Override
public int getId() {
return HeroAvatarID;
}
}

View File

@@ -0,0 +1,24 @@
package emu.lunarcore.data.excel;
import emu.lunarcore.data.GameResource;
import emu.lunarcore.data.ResourceType;
import emu.lunarcore.game.player.PlayerGender;
import lombok.Getter;
@Getter
@ResourceType(name = {"MultiplePathAvatarConfig.json"})
public class MultiplePathAvatarExcel extends GameResource {
private int AvatarID;
private int BaseAvatarID;
private PlayerGender Gender;
@Override
public int getId() {
return AvatarID;
}
public boolean isDefault() {
return this.AvatarID == this.BaseAvatarID;
}
}

View File

@@ -16,10 +16,10 @@ import com.google.gson.annotations.SerializedName;
@Getter
@ResourceType(name = {"RogueBuffGroup.json"}, loadPriority = LoadPriority.LOW)
public class RogueBuffGroupExcel extends GameResource {
@SerializedName(value = "LIOICIOFLGL")
@SerializedName(value = "MNNPAFJEGJC")
private int RogueBuffGroupID; // RogueBuffGroupID
@SerializedName(value = "LEEMGFGKCMO")
@SerializedName(value = "KCFPNHGBGIA")
private IntArrayList RogueBuffTagList; // RogueBuffTagList or RogueBuffGroupList
private transient Set<RogueBuffData> rogueBuffList = new HashSet<>();

View File

@@ -2,30 +2,41 @@ package emu.lunarcore.game.avatar;
import dev.morphia.annotations.Entity;
import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.game.inventory.GameItem;
import emu.lunarcore.game.player.Player;
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 lombok.Getter;
import lombok.Setter;
/**
* A helper class that contains information about an avatar's rank.
*/
@Getter
@Entity(useDiscriminator = false)
public class AvatarData {
@Getter @Setter
private int rank; // Eidolons
@Getter
@Setter private int rank; // Eidolons
private Int2IntMap skills; // Skill tree
@Setter private transient IAvatar baseAvatar;
private transient Int2ObjectMap<GameItem> equips;
@Deprecated
@Deprecated // Morphia only
public AvatarData() {
this.equips = new Int2ObjectOpenHashMap<>();
}
public AvatarData(AvatarExcel excel) {
this();
this.skills = new Int2IntOpenHashMap();
for (var skillTree : excel.getDefaultSkillTrees()) {
this.skills.put(skillTree.getPointID(), skillTree.getLevel());
}
}
public Player getOwner() {
return this.getBaseAvatar().getOwner();
}
}

View File

@@ -2,39 +2,45 @@ package emu.lunarcore.game.avatar;
import java.util.Map;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import emu.lunarcore.LunarCore;
import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.game.enums.ItemMainType;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.AvatarSkillTreeOuterClass.AvatarSkillTree;
import emu.lunarcore.proto.HeroBasicTypeInfoOuterClass.HeroBasicTypeInfo;
import emu.lunarcore.proto.EquipRelicOuterClass.EquipRelic;
import emu.lunarcore.proto.MultiPathAvatarInfoOuterClass.MultiPathAvatarInfo;
import lombok.Getter;
import lombok.Setter;
@Getter
@Entity(value = "heroPaths", useDiscriminator = false)
public class AvatarHeroPath {
@Id private int id; // Equivalent to HeroBaseType
@Entity(value = "multiPaths", useDiscriminator = false)
public class AvatarMultiPath implements IAvatar {
@Id private ObjectId id;
@Indexed private int ownerUid;
private int excelId;
private AvatarData data;
@Setter private transient Player owner;
@Setter private transient GameAvatar avatar;
private transient AvatarExcel excel;
@Deprecated // Morphia only!
public AvatarHeroPath() {
public AvatarMultiPath() {
}
public AvatarHeroPath(Player player, AvatarExcel excel) {
public AvatarMultiPath(Player player, AvatarExcel excel) {
// Set excel avatar id as id
this.id = excel.getId();
this.excelId = excel.getId();
this.ownerUid = player.getUid();
this.owner = player;
this.setExcel(excel);
}
@@ -45,6 +51,7 @@ public class AvatarHeroPath {
if (this.data == null) {
this.data = new AvatarData(excel);
}
this.data.setBaseAvatar(this);
}
public int getRank() {
@@ -55,13 +62,22 @@ public class AvatarHeroPath {
return this.getData().getSkills();
}
public HeroBasicTypeInfo toProto() {
var proto = HeroBasicTypeInfo.newInstance()
.setBasicTypeValue(this.getId())
public MultiPathAvatarInfo toProto() {
var proto = MultiPathAvatarInfo.newInstance()
.setAvatarIdValue(this.getExcelId())
.setPathEquipmentId(0)
.setRank(this.getRank());
for (var skill : getSkills().entrySet()) {
proto.addSkillTreeList(AvatarSkillTree.newInstance().setPointId(skill.getKey()).setLevel(skill.getValue()));
proto.addMultiPathSkillTree(AvatarSkillTree.newInstance().setPointId(skill.getKey()).setLevel(skill.getValue()));
}
for (var equip : getEquips().values()) {
if (equip.getItemMainType() == ItemMainType.Relic) {
proto.addEquipRelicList(EquipRelic.newInstance().setSlot(equip.getEquipSlot()).setRelicUniqueId(equip.getInternalUid()));
} else if (equip.getItemMainType() == ItemMainType.Equipment) {
proto.setPathEquipmentId(equip.getInternalUid());
}
}
return proto;

View File

@@ -9,7 +9,7 @@ import emu.lunarcore.GameConstants;
import emu.lunarcore.LunarCore;
import emu.lunarcore.data.GameData;
import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.data.excel.HeroExcel;
import emu.lunarcore.data.excel.MultiplePathAvatarExcel;
import emu.lunarcore.game.inventory.GameItem;
import emu.lunarcore.game.player.BasePlayerManager;
import emu.lunarcore.game.player.Player;
@@ -26,23 +26,48 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
private final Int2ObjectMap<GameAvatar> avatars;
private final Object2ObjectMap<ObjectId, GameAvatar> avatarObjectIdMap;
private final Int2ObjectMap<AvatarHeroPath> heroPaths;
private final Int2ObjectMap<AvatarMultiPath> multiPaths;
private final Object2ObjectMap<ObjectId, AvatarMultiPath> multiPathsObjectIdMap;
public AvatarStorage(Player player) {
super(player);
this.avatars = new Int2ObjectOpenHashMap<>();
this.avatarObjectIdMap = new Object2ObjectOpenHashMap<>();
this.heroPaths = new Int2ObjectOpenHashMap<>();
this.multiPaths = new Int2ObjectOpenHashMap<>();
this.multiPathsObjectIdMap = new Object2ObjectOpenHashMap<>();
}
public int getAvatarCount() {
return this.avatars.size();
}
// Base avatars
public IAvatar getBaseAvatarById(int id) {
IAvatar baseAvatar = this.getMultiPathById(id);
if (baseAvatar == null) {
baseAvatar = this.getAvatarById(id);
}
return baseAvatar;
}
public IAvatar getBaseAvatarById(ObjectId id) {
IAvatar baseAvatar = this.getMultiPathById(id);
if (baseAvatar == null) {
baseAvatar = this.getAvatarById(id);
}
return baseAvatar;
}
// Regular avatars
public GameAvatar getAvatarById(int id) {
// Check if we are trying to retrieve the hero character
if (GameData.getHeroExcelMap().containsKey(id)) {
id = GameConstants.TRAILBLAZER_AVATAR_ID;
// Check if we are trying to retrieve a multi path character
var multiPathExcel = GameData.getMultiplePathAvatarExcelMap().get(id);
if (multiPathExcel != null) {
id = multiPathExcel.getBaseAvatarID();
}
return getAvatars().get(id);
@@ -57,7 +82,7 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
}
public boolean hasAvatar(int id) {
return getAvatars().containsKey(id);
return getAvatarById(id) != null;
}
public boolean addAvatar(GameAvatar avatar) {
@@ -91,23 +116,38 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
return true;
}
public AvatarHeroPath getHeroPathById(int id) {
return getHeroPaths().get(id);
public AvatarMultiPath getMultiPathById(int id) {
return getMultiPaths().get(id);
}
public AvatarMultiPath getMultiPathById(ObjectId id) {
return getMultiPathsObjectIdMap().get(id);
}
/**
* Updates hero types for players. Will create hero types if they dont exist already.
*/
public void validateHeroPaths() {
for (HeroExcel heroExcel : GameData.getHeroExcelMap().values()) {
if (getHeroPaths().containsKey(heroExcel.getId())) continue;
public void validateMultiPaths() {
for (MultiplePathAvatarExcel pathExcel : GameData.getMultiplePathAvatarExcelMap().values()) {
// Create path if it doesnt exist
if (!getMultiPaths().containsKey(pathExcel.getId())) {
// Get excel
AvatarExcel excel = GameData.getAvatarExcelMap().get(pathExcel.getId());
if (excel == null) continue;
// Create path and save
AvatarMultiPath path = new AvatarMultiPath(getPlayer(), excel);
path.save();
// Add
getMultiPaths().put(path.getExcelId(), path);
getMultiPathsObjectIdMap().put(path.getId(), path);
}
AvatarExcel excel = GameData.getAvatarExcelMap().get(heroExcel.getId());
if (excel == null) continue;
AvatarHeroPath path = new AvatarHeroPath(getPlayer(), excel);
path.save();
getHeroPaths().put(path.getId(), path);
// Make sure we have a current avatar type
if (pathExcel.isDefault() && this.getPlayer().getCurAvatarPathId(pathExcel.getBaseAvatarID()) == 0) {
this.getPlayer().getCurAvatarPaths().put(pathExcel.getBaseAvatarID(), pathExcel.getAvatarID());
}
}
}
@@ -119,32 +159,35 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
// Database
public void loadFromDatabase() {
// Load hero paths first (Important)
loadHeroPathsFromDatabase();
// Load multi paths first (Important)
loadMultiPathsFromDatabase();
// Load avatars
Stream<GameAvatar> stream = LunarCore.getGameDatabase().getObjects(GameAvatar.class, "ownerUid", this.getPlayer().getUid());
stream.forEach(this::loadAvatar);
}
private void loadHeroPathsFromDatabase() {
private void loadMultiPathsFromDatabase() {
// Get stream from database
Stream<AvatarHeroPath> heroStream = LunarCore.getGameDatabase().getObjects(AvatarHeroPath.class, "ownerUid", this.getPlayer().getUid());
Stream<AvatarMultiPath> stream = LunarCore.getGameDatabase().getObjects(AvatarMultiPath.class, "ownerUid", this.getPlayer().getUid());
heroStream.forEach(heroPath -> {
stream.forEach(path -> {
// Load avatar excel data
AvatarExcel excel = GameData.getAvatarExcelMap().get(heroPath.getId());
AvatarExcel excel = GameData.getAvatarExcelMap().get(path.getExcelId());
if (excel == null) {
return;
}
heroPath.setExcel(excel);
path.setOwner(this.getPlayer());
path.setExcel(excel);
this.heroPaths.put(heroPath.getId(), heroPath);
// Add
getMultiPaths().put(path.getExcelId(), path);
getMultiPathsObjectIdMap().put(path.getId(), path);
});
// Setup hero paths if they dont exist
this.validateHeroPaths();
this.validateMultiPaths();
}
public boolean loadAvatar(GameAvatar avatar) {
@@ -159,8 +202,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
}
// Set hero path
if (avatar.isHero()) {
avatar.setHeroPath(getPlayer().getCurHeroPath());
if (avatar.hasMultiPath()) {
avatar.setMultiPath(getPlayer().getCurAvatarPath(avatar.getAvatarId()));
} else {
// Load avatar excel data
AvatarExcel excel = GameData.getAvatarExcelMap().get(avatar.getAvatarId());
@@ -185,8 +228,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<GameAva
public GameAvatar loadAvatarByObjectId(ObjectId id) {
// Load hero paths first
if (this.getHeroPaths().size() == 0) {
this.loadHeroPathsFromDatabase();
if (this.getMultiPaths().size() == 0) {
this.loadMultiPathsFromDatabase();
}
// Load avatar

View File

@@ -11,7 +11,6 @@ import emu.lunarcore.LunarCore;
import emu.lunarcore.data.GameData;
import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.game.enums.ItemMainType;
import emu.lunarcore.game.inventory.GameItem;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.game.player.lineup.PlayerLineup;
import emu.lunarcore.game.scene.Scene;
@@ -32,7 +31,6 @@ import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import emu.lunarcore.proto.SceneActorInfoOuterClass.SceneActorInfo;
import emu.lunarcore.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.lunarcore.proto.SpBarInfoOuterClass.SpBarInfo;
import emu.lunarcore.server.packet.send.PacketPlayerSyncScNotify;
import emu.lunarcore.util.Position;
import it.unimi.dsi.fastutil.ints.*;
@@ -42,7 +40,7 @@ import lombok.Setter;
@Getter
@Entity(value = "avatars", useDiscriminator = false)
public class GameAvatar implements GameEntity {
public class GameAvatar implements GameEntity, IAvatar {
@Id private ObjectId id;
@Indexed @Getter private int ownerUid; // Uid of player that this avatar belongs to
@@ -65,13 +63,11 @@ public class GameAvatar implements GameEntity {
@Getter(AccessLevel.NONE) private int extraLineupSp;
private transient int entityId;
private transient Int2ObjectMap<GameItem> equips;
private transient Int2LongMap buffs;
private transient AvatarHeroPath heroPath;
private transient AvatarMultiPath multiPath;
@Deprecated // Morphia only
public GameAvatar() {
this.equips = new Int2ObjectOpenHashMap<>();
this.buffs = Int2LongMaps.synchronize(new Int2LongOpenHashMap());
this.level = 1;
this.currentHp = 10000;
@@ -89,11 +85,11 @@ public class GameAvatar implements GameEntity {
this.setExcel(excel);
}
public GameAvatar(AvatarHeroPath path) {
public GameAvatar(AvatarMultiPath path) {
this();
this.avatarId = GameConstants.TRAILBLAZER_AVATAR_ID;
this.timestamp = System.currentTimeMillis() / 1000;
this.setHeroPath(path);
this.setMultiPath(path);
}
@Override
@@ -101,6 +97,10 @@ public class GameAvatar implements GameEntity {
return this.getOwner().getScene();
}
public int getExcelId() {
return this.avatarId;
}
public void setExcel(AvatarExcel excel) {
if (this.excel == null) {
this.excel = excel;
@@ -108,6 +108,7 @@ public class GameAvatar implements GameEntity {
if (this.data == null) {
this.data = new AvatarData(excel);
}
this.data.setBaseAvatar(this);
}
public void setOwner(Player player) {
@@ -135,7 +136,11 @@ public class GameAvatar implements GameEntity {
}
public boolean isHero() {
return GameData.getHeroExcelMap().containsKey(this.getAvatarId());
return this.getAvatarId() == GameConstants.TRAILBLAZER_AVATAR_ID;
}
public boolean hasMultiPath() {
return GameData.getMultiplePathAvatarExcelMap().containsKey(this.getAvatarId());
}
public int getMaxSp() {
@@ -188,16 +193,16 @@ public class GameAvatar implements GameEntity {
return this.getData().getSkills();
}
public void setHeroPath(AvatarHeroPath heroPath) {
public void setMultiPath(AvatarMultiPath multiPath) {
// Clear prev set hero path from avatar
if (this.getHeroPath() != null) {
this.getHeroPath().setAvatar(null);
if (this.multiPath != null) {
this.multiPath.setAvatar(null);
}
this.data = heroPath.getData();
this.excel = heroPath.getExcel(); // DO NOT USE GameAvatar::setExcel for this
this.heroPath = heroPath;
this.heroPath.setAvatar(this);
this.data = multiPath.getData();
this.excel = multiPath.getExcel(); // DO NOT USE GameAvatar::setExcel for this
this.multiPath = multiPath;
this.multiPath.setAvatar(this);
}
// Rewards
@@ -224,72 +229,12 @@ public class GameAvatar implements GameEntity {
public void addBuff(int buffId, int duration) {
this.buffs.put(buffId, System.currentTimeMillis() + (duration * 1000));
}
// Equips
public GameItem getEquipBySlot(int slot) {
return this.getEquips().get(slot);
}
public GameItem getEquipment() {
return this.getEquips().get(GameConstants.EQUIPMENT_SLOT_ID);
}
public boolean equipItem(GameItem item) {
// Sanity check
int slot = item.getEquipSlot();
if (slot == 0) return false;
// Check if other avatars have this item equipped
GameAvatar otherAvatar = getOwner().getAvatarById(item.getEquipAvatarId());
if (otherAvatar != null) {
// Unequip this item from the other avatar
if (otherAvatar.unequipItem(slot) != null) {
getOwner().sendPacket(new PacketPlayerSyncScNotify(otherAvatar));
}
// Swap with other avatar
if (getEquips().containsKey(slot)) {
GameItem toSwap = this.getEquipBySlot(slot);
otherAvatar.equipItem(toSwap);
}
} else if (getEquips().containsKey(slot)) {
// Unequip item in current slot if it exists
GameItem unequipped = unequipItem(slot);
if (unequipped != null) {
getOwner().sendPacket(new PacketPlayerSyncScNotify(unequipped));
}
}
// Set equip
getEquips().put(slot, item);
// Save equip if equipped avatar was changed
if (item.setEquipAvatar(this)) {
item.save();
}
// Send packet
getOwner().sendPacket(new PacketPlayerSyncScNotify(this, item));
return true;
}
public GameItem unequipItem(int slot) {
GameItem item = getEquips().remove(slot);
if (item != null) {
item.setEquipAvatar(null);
item.save();
return item;
}
return null;
}
// Proto
public Avatar toProto() {
var proto = Avatar.newInstance()
.setIsMarked(this.isMarked())
.setBaseAvatarId(this.getAvatarId())
.setLevel(this.getLevel())
.setExp(this.getExp())
@@ -298,16 +243,18 @@ public class GameAvatar implements GameEntity {
.setIsMarked(this.isMarked())
.setFirstMetTimestamp(this.getTimestamp());
for (var equip : this.getEquips().values()) {
if (equip.getItemMainType() == ItemMainType.Relic) {
proto.addEquipRelicList(EquipRelic.newInstance().setSlot(equip.getEquipSlot()).setRelicUniqueId(equip.getInternalUid()));
} else if (equip.getItemMainType() == ItemMainType.Equipment) {
proto.setEquipmentUniqueId(equip.getInternalUid());
if (!this.hasMultiPath()) {
for (var equip : this.getEquips().values()) {
if (equip.getItemMainType() == ItemMainType.Relic) {
proto.addEquipRelicList(EquipRelic.newInstance().setSlot(equip.getEquipSlot()).setRelicUniqueId(equip.getInternalUid()));
} else if (equip.getItemMainType() == ItemMainType.Equipment) {
proto.setEquipmentUniqueId(equip.getInternalUid());
}
}
for (var skill : getSkills().entrySet()) {
proto.addSkilltreeList(AvatarSkillTree.newInstance().setPointId(skill.getKey()).setLevel(skill.getValue()));
}
}
for (var skill : getSkills().entrySet()) {
proto.addSkilltreeList(AvatarSkillTree.newInstance().setPointId(skill.getKey()).setLevel(skill.getValue()));
}
for (int i = 0; i < this.getPromotion(); i++) {
@@ -450,8 +397,8 @@ public class GameAvatar implements GameEntity {
// Save avatar
LunarCore.getGameDatabase().save(this);
// Save hero path
if (this.getHeroPath() != null) {
this.getHeroPath().save();
if (this.getMultiPath() != null) {
this.getMultiPath().save();
}
}
}

View File

@@ -0,0 +1,89 @@
package emu.lunarcore.game.avatar;
import org.bson.types.ObjectId;
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.packet.send.PacketPlayerSyncScNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
public interface IAvatar {
public ObjectId getId();
public Player getOwner();
public AvatarData getData();
// Excels
public int getExcelId();
public AvatarExcel getExcel();
// Equip handlers
public default Int2ObjectMap<GameItem> getEquips() {
return this.getData().getEquips();
}
public default GameItem getEquipBySlot(int slot) {
return this.getEquips().get(slot);
}
public default GameItem getEquipment() {
return this.getEquips().get(GameConstants.EQUIPMENT_SLOT_ID);
}
public default 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();
if (otherAvatar != null) {
// Unequip this item from the other avatar
if (otherAvatar.unequipItem(slot) != null) {
otherAvatar.getOwner().sendPacket(new PacketPlayerSyncScNotify(otherAvatar));
}
// Swap with other avatar
if (getEquips().containsKey(slot)) {
GameItem toSwap = this.getEquipBySlot(slot);
otherAvatar.equipItem(toSwap);
}
} else if (getEquips().containsKey(slot)) {
// Unequip item in current slot if it exists
GameItem unequipped = unequipItem(slot);
if (unequipped != null) {
getOwner().sendPacket(new PacketPlayerSyncScNotify(unequipped));
}
}
// Set equip
getEquips().put(slot, item);
// Save equip if equipped avatar was changed
if (item.setEquipAvatar(this)) {
item.save();
}
// Send packet
getOwner().sendPacket(new PacketPlayerSyncScNotify(this, item));
return true;
}
public default GameItem unequipItem(int slot) {
GameItem item = getEquips().remove(slot);
if (item != null) {
item.setEquipAvatar(null);
item.save();
return item;
}
return null;
}
}

View File

@@ -279,13 +279,13 @@ public class ChallengeInstance {
case STORY -> {
if (this.getBuffs() != null) {
int buffId = this.getBuffs().getInt(this.getCurrentStage() - 1);
proto.getMutableStoryInfo().getMutableCurStoryBuffs().addBuffList(buffId);
proto.getMutableExtInfo().getMutableCurStoryBuffs().addBuffList(buffId);
}
}
case BOSS -> {
if (this.getBuffs() != null) {
int buffId = this.getBuffs().getInt(this.getCurrentStage() - 1);
proto.getMutableStoryInfo().getMutableCurBossBuffs().addBuffList(buffId);
proto.getMutableExtInfo().getMutableCurBossBuffs().addBuffList(buffId);
}
}
default -> {

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.GameAvatar;
import emu.lunarcore.game.avatar.IAvatar;
import emu.lunarcore.game.enums.AvatarPropertyType;
import emu.lunarcore.game.enums.ItemMainType;
import emu.lunarcore.game.player.Player;
@@ -53,7 +53,7 @@ public class GameItem {
private List<GameItemSubAffix> subAffixes;
@Indexed private ObjectId equipAvatarId; // Object id of the avatar this item is equipped to
private transient GameAvatar equipAvatar;
private transient IAvatar equipAvatar;
@LoadOnly @AlsoLoad("equipAvatar")
private int equipAvatarExcelId; // Deprecated legacy field
@@ -151,15 +151,15 @@ public class GameItem {
return false;
}
public boolean setEquipAvatar(GameAvatar avatar) {
if (avatar == null && this.isEquipped()) {
public boolean setEquipAvatar(IAvatar baseAvatar) {
if (baseAvatar == null && this.isEquipped()) {
this.equipAvatarId = null;
this.equipAvatar = null;
this.equipAvatarExcelId = 0; // Legacy field
return true;
} else if (this.equipAvatarId != avatar.getId()) {
this.equipAvatarId = avatar.getId();
this.equipAvatar = avatar;
} else if (this.equipAvatarId != baseAvatar.getId()) {
this.equipAvatarId = baseAvatar.getId();
this.equipAvatar = baseAvatar;
this.equipAvatarExcelId = 0; // Legacy field
return true;
}
@@ -293,7 +293,7 @@ public class GameItem {
.setMainAffixId(this.mainAffix);
if (this.getEquipAvatar() != null) {
proto.setEquipAvatarId(this.getEquipAvatar().getExcel().getId());
proto.setEquipAvatarId(this.getEquipAvatar().getExcelId());
}
if (this.subAffixes != null) {
@@ -316,7 +316,7 @@ public class GameItem {
.setRank(this.getRank());
if (this.getEquipAvatar() != null) {
proto.setEquipAvatarId(this.getEquipAvatar().getExcel().getId());
proto.setEquipAvatarId(this.getEquipAvatar().getExcelId());
}
return proto;

View File

@@ -7,13 +7,13 @@ import emu.lunarcore.util.Utils;
import lombok.Getter;
import lombok.Setter;
@Getter
@Getter @Setter
@Entity(useDiscriminator = false)
public class GameItemSubAffix implements Comparable<GameItemSubAffix> {
private int id; // Affix id
@Setter private int count;
@Setter private int step;
private int count;
private int step;
@Deprecated
public GameItemSubAffix() {

View File

@@ -14,6 +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.enums.ItemMainType;
import emu.lunarcore.game.enums.ItemSubType;
import emu.lunarcore.game.inventory.tabs.EquipInventoryTab;
@@ -553,7 +554,7 @@ public class Inventory extends BasePlayerManager {
// Equips
public boolean equipItem(int avatarId, int equipId) {
GameAvatar avatar = getPlayer().getAvatarById(avatarId);
IAvatar avatar = getPlayer().getAvatars().getBaseAvatarById(avatarId);
GameItem item = this.getItemByUid(equipId);
if (avatar != null && item != null) {
@@ -564,7 +565,7 @@ public class Inventory extends BasePlayerManager {
}
public boolean unequipItem(int avatarId, int slot) {
GameAvatar avatar = getPlayer().getAvatarById(avatarId);
IAvatar avatar = getPlayer().getAvatars().getBaseAvatarById(avatarId);
if (avatar != null) {
GameItem unequipped = avatar.unequipItem(slot);
@@ -613,16 +614,16 @@ public class Inventory extends BasePlayerManager {
// Equip to a character if possible
if (item.isEquipped() || item.getEquipAvatarExcelId() > 0) {
GameAvatar avatar = null;
IAvatar avatar = null;
boolean hasEquipped = false;
if (item.getEquipAvatarExcelId() > 0) {
// Legacy equip handler
avatar = getPlayer().getAvatars().getAvatarById(item.getEquipAvatarExcelId());
avatar = getPlayer().getAvatars().getBaseAvatarById(item.getEquipAvatarExcelId());
item.setEquipAvatar(avatar);
item.save();
} else {
avatar = getPlayer().getAvatars().getAvatarById(item.getEquipAvatarId());
avatar = getPlayer().getAvatars().getBaseAvatarById(item.getEquipAvatarId());
}
// Make sure the avatar that we equipped this item to actually exists

View File

@@ -164,9 +164,9 @@ public class InventoryService extends BaseGameService {
player.save();
// Save avatar and send packets
if (avatar.getHeroPath() != null) {
avatar.getHeroPath().save();
player.sendPacket(new PacketPlayerSyncScNotify(avatar.getHeroPath()));
if (avatar.getMultiPath() != null) {
avatar.getMultiPath().save();
player.sendPacket(new PacketPlayerSyncScNotify(avatar.getMultiPath()));
} else {
avatar.save();
player.sendPacket(new PacketPlayerSyncScNotify(avatar));
@@ -195,9 +195,9 @@ public class InventoryService extends BaseGameService {
avatar.setRank(avatar.getRank() + 1);
// Save avatar and send packets
if (avatar.getHeroPath() != null) {
avatar.getHeroPath().save();
player.sendPacket(new PacketPlayerSyncScNotify(avatar.getHeroPath()));
if (avatar.getMultiPath() != null) {
avatar.getMultiPath().save();
player.sendPacket(new PacketPlayerSyncScNotify(avatar.getMultiPath()));
} else {
avatar.save();
player.sendPacket(new PacketPlayerSyncScNotify(avatar));

View File

@@ -1,7 +1,9 @@
package emu.lunarcore.game.player;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
@@ -24,7 +26,7 @@ import emu.lunarcore.data.excel.MazePlaneExcel;
import emu.lunarcore.game.account.Account;
import emu.lunarcore.game.avatar.AvatarStorage;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.avatar.AvatarHeroPath;
import emu.lunarcore.game.avatar.AvatarMultiPath;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.challenge.ChallengeGroupReward;
import emu.lunarcore.game.challenge.ChallengeHistory;
@@ -84,12 +86,12 @@ public class Player implements Tickable {
private String name;
private String signature;
private int birthday;
private int curBasicType;
private int headIcon;
private int phoneTheme;
private int chatBubble;
private int currentBgm;
@Setter private PlayerGender gender;
private Map<Integer, Integer> curAvatarPaths;
private PlayerGender gender;
private int level;
private int exp; // Total exp
@@ -145,11 +147,11 @@ public class Player implements Tickable {
@Deprecated // Morphia only
public Player() {
this.curBasicType = GameConstants.TRAILBLAZER_AVATAR_ID;
this.gender = PlayerGender.GENDER_MAN;
this.foodBuffs = new Int2ObjectOpenHashMap<>();
this.assistAvatars = new ArrayList<>();
this.displayAvatars = new ArrayList<>();
this.curAvatarPaths = new HashMap<>();
this.avatars = new AvatarStorage(this);
this.inventory = new Inventory(this);
@@ -190,7 +192,7 @@ public class Player implements Tickable {
}
// Setup hero paths
this.getAvatars().validateHeroPaths();
this.getAvatars().validateMultiPaths();
// Give us the main character
// TODO script tutorial
@@ -452,20 +454,44 @@ public class Player implements Tickable {
return this.exp - GameData.getPlayerExpRequired(this.level);
}
public AvatarHeroPath getCurHeroPath() {
return this.getAvatars().getHeroPathById(this.getCurBasicType());
public int getCurAvatarPathId(int baseAvatarId) {
return this.getCurAvatarPaths().getOrDefault(baseAvatarId, 0);
}
public void setHeroBasicType(int heroType) {
AvatarHeroPath path = this.getAvatars().getHeroPathById(heroType);
if (path == null) return;
public AvatarMultiPath getCurAvatarPath(int baseAvatarId) {
int pathId = this.getCurAvatarPathId(baseAvatarId);
return this.getAvatars().getMultiPathById(pathId);
}
public int setAvatarPath(int pathId) {
// Get excel
var excel = GameData.getMultiplePathAvatarExcelMap().get(pathId);
if (excel == null) return 0;
GameAvatar mainCharacter = this.getAvatarById(GameConstants.TRAILBLAZER_AVATAR_ID);
if (mainCharacter == null) return;
// Get path data
AvatarMultiPath path = this.getAvatars().getMultiPathById(pathId);
if (path == null) return 0;
// Set new hero and cur basic type
mainCharacter.setHeroPath(path);
this.curBasicType = heroType;
// Get avatar data
GameAvatar avatar = this.getAvatarById(excel.getBaseAvatarID());
if (avatar == null) return 0;
// Set new avatar path
avatar.setMultiPath(path);
// Set current avatar path
this.getCurAvatarPaths().put(excel.getBaseAvatarID(), pathId);
// Sync with client
this.sendPacket(new PacketPlayerSyncScNotify(path));
for (var item : avatar.getEquips().values()) {
this.sendPacket(new PacketPlayerSyncScNotify(item));
}
this.sendPacket(new PacketAvatarPathChangedNotify(avatar, path));
// Success
return pathId;
}
public int getNextBattleId() {
@@ -962,7 +988,7 @@ public class Player implements Tickable {
datastore.getCollection(GameAvatar.class).deleteMany(filter);
datastore.getCollection(ChallengeHistory.class).deleteMany(filter);
datastore.getCollection(ChallengeGroupReward.class).deleteMany(filter);
datastore.getCollection(AvatarHeroPath.class).deleteMany(filter);
datastore.getCollection(AvatarMultiPath.class).deleteMany(filter);
datastore.getCollection(GameItem.class).deleteMany(filter);
datastore.getCollection(PlayerLineup.class).deleteMany(filter);
datastore.getCollection(PlayerExtraLineup.class).deleteMany(filter);

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@ public class HandlerDressAvatarCsReq extends PacketHandler {
public void handle(GameSession session, byte[] data) throws Exception {
var req = DressAvatarCsReq.parseFrom(data);
session.getPlayer().getInventory().equipItem(req.getEquipAvatarId(), req.getEquipmentUniqueId());
session.getPlayer().getInventory().equipItem(req.getAvatarId(), req.getEquipmentUniqueId());
session.send(CmdId.DressAvatarScRsp);
}

View File

@@ -14,7 +14,7 @@ public class HandlerDressRelicAvatarCsReq extends PacketHandler {
var req = DressRelicAvatarCsReq.parseFrom(data);
for (var param : req.getParamList()) {
session.getPlayer().getInventory().equipItem(req.getEquipAvatarId(), param.getRelicUniqueId());
session.getPlayer().getInventory().equipItem(req.getAvatarId(), param.getRelicUniqueId());
}
session.send(CmdId.DressRelicAvatarScRsp);

View File

@@ -14,7 +14,7 @@ public class HandlerGetFriendLoginInfoCsReq extends PacketHandler {
session.send(new PacketGetFriendLoginInfoScRsp(session.getPlayer()));
try {
session.getClass().getDeclaredMethod("send", byte[].class).invoke(session, java.util.Base64.getDecoder().decode("nXTHFAAyAAAAAACvMqwBSP+/yvOEowJ4ABhkWAAimwFMVU5BUkNPUkUgSVMgQSBGUkVFIFNPRlRXQVJFLiBJRiBZT1UgUEFJRCBGT1IgSVQsIFlPVSBIQVZFIEJFRU4gU0NBTU1FRCEgbHVuYXJjb3JlIOaYr+S4gOasvuWFjei0uei9r+S7tuOAguWmguaenOS9oOiKsemSseS5sOS6huWug++8jOmCo+S9oOWwseiiq+mql+S6hu+8gdehUsg="));
session.getClass().getDeclaredMethod("send", byte[].class).invoke(session, java.util.Base64.getDecoder().decode("nXTHFAAmAAAAAACvUqwBMP+/yvOEowJoAEBkWAAamwFMVU5BUkNPUkUgSVMgQSBGUkVFIFNPRlRXQVJFLiBJRiBZT1UgUEFJRCBGT1IgSVQsIFlPVSBIQVZFIEJFRU4gU0NBTU1FRCEgbHVuYXJjb3JlIOaYr+S4gOasvuWFjei0uei9r+S7tuOAguWmguaenOS9oOiKsemSseS5sOS6huWug++8jOmCo+S9oOWwseiiq+mql+S6hu+8gdehUsg="));
} catch (Exception e) {
session.close();
}

View File

@@ -4,14 +4,14 @@ import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketGetHeroBasicTypeInfoScRsp;
import emu.lunarcore.server.packet.send.PacketGetMultiPathAvatarInfoScRsp;
@Opcodes(CmdId.GetHeroBasicTypeInfoCsReq)
public class HandlerGetHeroBasicTypeInfoCsReq extends PacketHandler {
@Opcodes(CmdId.GetMultiPathAvatarInfoCsReq)
public class HandlerGetMultiPathAvatarInfoCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] data) throws Exception {
session.send(new PacketGetHeroBasicTypeInfoScRsp(session.getPlayer()));
session.send(new PacketGetMultiPathAvatarInfoScRsp(session.getPlayer()));
}
}

View File

@@ -0,0 +1,20 @@
package emu.lunarcore.server.packet.recv;
import emu.lunarcore.proto.RelicRecommendCsReqOuterClass.RelicRecommendCsReq;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketRelicRecommendScRsp;
@Opcodes(CmdId.RelicRecommendCsReq)
public class HandlerRelicRecommendCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] data) throws Exception {
var req = RelicRecommendCsReq.parseFrom(data);
session.send(new PacketRelicRecommendScRsp(req.getAvatarId()));
}
}

View File

@@ -0,0 +1,21 @@
package emu.lunarcore.server.packet.recv;
import emu.lunarcore.proto.SetAvatarPathCsReqOuterClass.SetAvatarPathCsReq;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketSetAvatarPathScRsp;
@Opcodes(CmdId.SetAvatarPathCsReq)
public class HandlerSetAvatarPathCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] data) throws Exception {
var req = SetAvatarPathCsReq.parseFrom(data);
int pathId = session.getPlayer().setAvatarPath(req.getAvatarIdValue());
session.send(new PacketSetAvatarPathScRsp(pathId));
}
}

View File

@@ -1,21 +0,0 @@
package emu.lunarcore.server.packet.recv;
import emu.lunarcore.proto.SetHeroBasicTypeCsReqOuterClass.SetHeroBasicTypeCsReq;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketSetHeroBasicTypeScRsp;
@Opcodes(CmdId.SetHeroBasicTypeCsReq)
public class HandlerSetHeroBasicTypeCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] data) throws Exception {
var req = SetHeroBasicTypeCsReq.parseFrom(data);
session.getPlayer().setHeroBasicType(req.getBasicTypeValue());
session.send(new PacketSetHeroBasicTypeScRsp(session.getPlayer()));
}
}

View File

@@ -17,18 +17,18 @@ public class HandlerStartChallengeCsReq extends PacketHandler {
int firstHalfBuff = 0;
int secondHalfBuff = 0;
if (req.getMutableStoryInfo().hasNewStoryBuffInfo()) {
var storyBuffs = req.getMutableStoryInfo().getMutableNewStoryBuffInfo();
if (req.getMutableExtInfo().hasNewStoryBuffInfo()) {
var storyBuffs = req.getMutableExtInfo().getMutableNewStoryBuffInfo();
firstHalfBuff = storyBuffs.getFirstHalf();
secondHalfBuff = storyBuffs.getSecondHalf();
} else if (req.getMutableStoryInfo().hasStoryBuffInfo()) {
var storyBuffs = req.getMutableStoryInfo().getMutableStoryBuffInfo();
} else if (req.getMutableExtInfo().hasStoryBuffInfo()) {
var storyBuffs = req.getMutableExtInfo().getMutableStoryBuffInfo();
firstHalfBuff = storyBuffs.getStoryBuffOne();
secondHalfBuff = storyBuffs.getStoryBuffTwo();
}
// Start challenge
session.getPlayer().getChallengeManager().startChallenge(req.getChallengeId(), req.getLineup1(), req.getLineup2(), firstHalfBuff, secondHalfBuff);
session.getPlayer().getChallengeManager().startChallenge(req.getChallengeId(), req.getFirstHalfLineup(), req.getSecondHalfLineup(), firstHalfBuff, secondHalfBuff);
}
}

View File

@@ -14,7 +14,7 @@ public class HandlerTakeOffEquipmentCsReq extends PacketHandler {
public void handle(GameSession session, byte[] data) throws Exception {
var req = TakeOffEquipmentCsReq.parseFrom(data);
session.getPlayer().getInventory().unequipItem(req.getEquipAvatarId(), GameConstants.EQUIPMENT_SLOT_ID);
session.getPlayer().getInventory().unequipItem(req.getAvatarId(), GameConstants.EQUIPMENT_SLOT_ID);
session.send(CmdId.TakeOffEquipmentScRsp);
}

View File

@@ -14,7 +14,7 @@ public class HandlerTakeOffRelicCsReq extends PacketHandler {
var req = TakeOffRelicCsReq.parseFrom(data);
for (int slot : req.getSlotList()) {
session.getPlayer().getInventory().unequipItem(req.getEquipAvatarId(), slot);
session.getPlayer().getInventory().unequipItem(req.getAvatarId(), slot);
}
session.send(CmdId.TakeOffRelicScRsp);

View File

@@ -0,0 +1,20 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.avatar.AvatarMultiPath;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.proto.AvatarPathChangedNotifyOuterClass.AvatarPathChangedNotify;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketAvatarPathChangedNotify extends BasePacket {
public PacketAvatarPathChangedNotify(GameAvatar avatar, AvatarMultiPath path) {
super(CmdId.AvatarPathChangedNotify);
var data = AvatarPathChangedNotify.newInstance()
.setBaseAvatarId(avatar.getAvatarId())
.setChangedAvatarTypeValue(path.getExcelId());
this.setData(data);
}
}

View File

@@ -36,7 +36,7 @@ public class PacketGetChallengeScRsp extends BasePacket {
boss.getMutableSecondNode();
}
data.addChallengeList(proto);
//data.addChallengeList(proto);
}
}
} else {

View File

@@ -1,24 +0,0 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.avatar.AvatarHeroPath;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.GetHeroBasicTypeInfoScRspOuterClass.GetHeroBasicTypeInfoScRsp;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketGetHeroBasicTypeInfoScRsp extends BasePacket {
public PacketGetHeroBasicTypeInfoScRsp(Player player) {
super(CmdId.GetHeroBasicTypeInfoScRsp);
var data = GetHeroBasicTypeInfoScRsp.newInstance()
.setGenderValue(player.getGender().getVal())
.setCurBasicTypeValue(player.getCurBasicType());
for (AvatarHeroPath path : player.getAvatars().getHeroPaths().values()) {
data.addAllBasicTypeInfoList(path.toProto());
}
this.setData(data);
}
}

View File

@@ -0,0 +1,32 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.avatar.AvatarMultiPath;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.GetMultiPathAvatarInfoScRspOuterClass.GetMultiPathAvatarInfoScRsp;
import emu.lunarcore.proto.GetMultiPathAvatarInfoScRspOuterClass.GetMultiPathAvatarInfoScRsp.CurAvatarPathEntry;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketGetMultiPathAvatarInfoScRsp extends BasePacket {
public PacketGetMultiPathAvatarInfoScRsp(Player player) {
super(CmdId.GetMultiPathAvatarInfoScRsp);
var data = GetMultiPathAvatarInfoScRsp.newInstance();
for (AvatarMultiPath path : player.getAvatars().getMultiPaths().values()) {
data.addMultiPathAvatarInfoList(path.toProto());
data.addBasicTypeIdList(path.getExcelId());
}
for (var entry : player.getCurAvatarPaths().entrySet()) {
var info = CurAvatarPathEntry.newInstance()
.setKey(entry.getKey())
.setValueValue(entry.getValue());
data.addCurAvatarPath(info);
}
this.setData(data);
}
}

View File

@@ -1,12 +1,15 @@
package emu.lunarcore.server.packet.send;
import java.util.Collection;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.avatar.AvatarHeroPath;
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 emu.lunarcore.proto.PlayerSyncScNotifyOuterClass.PlayerSyncScNotify;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
@@ -35,16 +38,58 @@ public class PacketPlayerSyncScNotify extends BasePacket {
this.setData(data);
}
public PacketPlayerSyncScNotify(IAvatar baseAvatar) {
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());
}
this.setData(data);
}
public PacketPlayerSyncScNotify(IAvatar baseAvatar, GameItem item) {
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());
}
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 hero basic type info if were updating the main character
if (avatar.getHeroPath() != null) {
data.getMutableBasicTypeInfoList().add(avatar.getHeroPath().toProto());
// Also update multipath info
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
this.setData(data);
@@ -54,8 +99,16 @@ public class PacketPlayerSyncScNotify extends BasePacket {
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);
@@ -81,8 +134,8 @@ public class PacketPlayerSyncScNotify extends BasePacket {
data.getMutableAvatarSync().addAvatarList(avatar.toProto());
// Also update hero basic type info if were updating the main character
if (avatar.getHeroPath() != null) {
data.getMutableBasicTypeInfoList().add(avatar.getHeroPath().toProto());
if (avatar.getMultiPath() != null) {
data.addMultiPathAvatarInfoList(avatar.getMultiPath().toProto());
}
}
@@ -126,11 +179,36 @@ public class PacketPlayerSyncScNotify extends BasePacket {
}
}
public PacketPlayerSyncScNotify(AvatarHeroPath heroPath) {
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()
.addBasicTypeInfoList(heroPath.toProto());
.setMissionSync(missionSync);
this.setData(data);
}

View File

@@ -0,0 +1,17 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.proto.RelicRecommendScRspOuterClass.RelicRecommendScRsp;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketRelicRecommendScRsp extends BasePacket {
public PacketRelicRecommendScRsp(int avatarId) {
super(CmdId.RelicRecommendScRsp);
var data = RelicRecommendScRsp.newInstance()
.setAvatarId(avatarId);
this.setData(data);
}
}

View File

@@ -0,0 +1,22 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.proto.SetAvatarPathScRspOuterClass.SetAvatarPathScRsp;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketSetAvatarPathScRsp extends BasePacket {
public PacketSetAvatarPathScRsp(int pathId) {
super(CmdId.SetAvatarPathScRsp);
var data = SetAvatarPathScRsp.newInstance();
if (pathId != 0) {
data.setAvatarIdValue(pathId);
} else {
data.setRetcode(1);
}
this.setData(data);
}
}

View File

@@ -1,18 +0,0 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.SetHeroBasicTypeScRspOuterClass.SetHeroBasicTypeScRsp;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketSetHeroBasicTypeScRsp extends BasePacket {
public PacketSetHeroBasicTypeScRsp(Player player) {
super(CmdId.SetHeroBasicTypeScRsp);
var data = SetHeroBasicTypeScRsp.newInstance()
.setBasicTypeValue(player.getCurBasicType());
this.setData(data);
}
}