diff --git a/Command/Command/Cmd/CommandAvatar.cs b/Command/Command/Cmd/CommandAvatar.cs index 9e7af3e3..e5031f31 100644 --- a/Command/Command/Cmd/CommandAvatar.cs +++ b/Command/Command/Cmd/CommandAvatar.cs @@ -42,8 +42,8 @@ public class CommandAvatar : ICommand avatarInfo.PathInfos)) { if (!GameData.AvatarConfigData.TryGetValue(path.Key, out var pathExcel)) continue; - foreach (var talent in pathExcel.SkillTree) - path.Value.SkillTree[talent.PointID] = Math.Min(level, talent.MaxLevel); + foreach (var talent in pathExcel.SkillTree.GetValueOrDefault(path.Value.EnhanceId, [])) + path.Value.GetSkillTree()[talent.PointID] = Math.Min(level, talent.MaxLevel); } await arg.SendMsg(I18NManager.Translate("Game.Command.Avatar.AllAvatarsLevelSet", @@ -79,8 +79,8 @@ public class CommandAvatar : ICommand return; } - foreach (var talent in excel.SkillTree) - avatarPathInfo.Value.SkillTree[talent.PointID] = Math.Min(level, talent.MaxLevel); + foreach (var talent in excel.SkillTree.GetValueOrDefault(avatarPathInfo.Value.EnhanceId, [])) + avatarPathInfo.Value.GetSkillTree()[talent.PointID] = Math.Min(level, talent.MaxLevel); // sync await player.SendPacket(new PacketPlayerSyncScNotify(avatar)); diff --git a/Command/Command/Cmd/CommandScene.cs b/Command/Command/Cmd/CommandScene.cs index e19aa959..a6f4d5d3 100644 --- a/Command/Command/Cmd/CommandScene.cs +++ b/Command/Command/Cmd/CommandScene.cs @@ -176,7 +176,7 @@ public class CommandScene : ICommand var player = arg.Target!.Player!; - var curDistance = 0L; + var curDistance = 1000000L; EntityProp? nearest = null; foreach (var entityProp in player.SceneInstance!.Entities.Values.OfType()) { diff --git a/Common/Data/Excel/AvatarConfigExcel.cs b/Common/Data/Excel/AvatarConfigExcel.cs index 21cec77b..15190a14 100644 --- a/Common/Data/Excel/AvatarConfigExcel.cs +++ b/Common/Data/Excel/AvatarConfigExcel.cs @@ -8,11 +8,9 @@ namespace EggLink.DanhengServer.Data.Excel; [ResourceEntity("AvatarConfig.json,AvatarConfigTrial.json,AvatarConfigLD.json", true)] public class AvatarConfigExcel : ExcelResource { - [JsonIgnore] public List DefaultSkillTree = []; - - [JsonIgnore] public string? Name; - - [JsonIgnore] public List SkillTree = []; + [JsonIgnore] public Dictionary> DefaultSkillTree { get; set; } = []; + [JsonIgnore] public string? Name { get; set; } + [JsonIgnore] public Dictionary> SkillTree { get; set; } = []; public int AvatarID { get; set; } = 0; public int AdventurePlayerID { get; set; } diff --git a/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs b/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs index a44147d8..232c03ce 100644 --- a/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs +++ b/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs @@ -17,11 +17,14 @@ public class AvatarSkillTreeConfigExcel : ExcelResource public override void AfterAllDone() { - if (EnhancedID == 1) return; GameData.AvatarConfigData.TryGetValue(AvatarID, out var excel); - if (excel != null && DefaultUnlock && excel.DefaultSkillTree.All(x => x.PointID != PointID)) - excel.DefaultSkillTree.Add(this); - if (excel != null && excel.SkillTree.All(x => x.PointID != PointID)) excel.SkillTree.Add(this); GameData.AvatarSkillTreeConfigData.TryAdd(GetId(), this); + if (excel == null) return; + + excel.DefaultSkillTree.TryAdd(EnhancedID, []); + excel.SkillTree.TryAdd(EnhancedID, []); + if (DefaultUnlock && excel.DefaultSkillTree[EnhancedID].All(x => x.PointID != PointID)) + excel.DefaultSkillTree[EnhancedID].Add(this); + if (excel.SkillTree[EnhancedID].All(x => x.PointID != PointID)) excel.SkillTree[EnhancedID].Add(this); } } \ No newline at end of file diff --git a/Common/Database/Avatar/AvatarData.cs b/Common/Database/Avatar/AvatarData.cs index faced437..eb1b8be7 100644 --- a/Common/Database/Avatar/AvatarData.cs +++ b/Common/Database/Avatar/AvatarData.cs @@ -124,12 +124,11 @@ public class FormalAvatarInfo : BaseAvatarInfo { if (!GameData.AvatarConfigData.TryGetValue(AvatarId, out var excel)) return; if (PathInfos.ContainsKey(AvatarId)) return; - if (excel.DefaultSkillTree.Count == 0) return; + if (excel.DefaultSkillTree[0].Count == 0) return; // create path info var path = new PathInfo(AvatarId); - foreach (var skill in excel.DefaultSkillTree) - path.SkillTree.Add(skill.PointID, skill.Level); + path.GetSkillTree(); PathInfos.Add(AvatarId, path); } @@ -163,7 +162,7 @@ public class FormalAvatarInfo : BaseAvatarInfo if (GetCurPathInfo().EquipId != 0) proto.EquipmentUniqueId = (uint)GetCurPathInfo().EquipId; - foreach (var skill in GetCurPathInfo().SkillTree) + foreach (var skill in GetCurPathInfo().GetSkillTree()) proto.SkilltreeList.Add(new AvatarSkillTree { PointId = (uint)skill.Key, @@ -215,7 +214,7 @@ public class FormalAvatarInfo : BaseAvatarInfo AvatarEnhanceId = (uint)GetCurPathInfo().EnhanceId }; - foreach (var skill in GetCurPathInfo().SkillTree) + foreach (var skill in GetCurPathInfo().GetSkillTree()) proto.SkilltreeList.Add(new AvatarSkillTree { PointId = (uint)skill.Key, @@ -245,7 +244,7 @@ public class FormalAvatarInfo : BaseAvatarInfo if (GetCurPathInfo().EquipId != 0) { - var item = collection.InventoryData.EquipmentItems?.Find(item => item.UniqueId == GetCurPathInfo().EquipId); + var item = collection.InventoryData.EquipmentItems.Find(item => item.UniqueId == GetCurPathInfo().EquipId); if (item != null) proto.EquipmentList.Add(new BattleEquipment { @@ -284,7 +283,7 @@ public class FormalAvatarInfo : BaseAvatarInfo CurEnhanceId = (uint)GetCurPathInfo().EnhanceId }; - foreach (var skill in pathInfo.SkillTree) + foreach (var skill in pathInfo.GetSkillTree()) proto.MultiPathSkillTree.Add(new AvatarSkillTree { PointId = (uint)skill.Key, @@ -330,7 +329,7 @@ public class FormalAvatarInfo : BaseAvatarInfo proto.Equipment = equip.ToDisplayEquipmentProto(); } - foreach (var skill in GetCurPathInfo().SkillTree) + foreach (var skill in GetCurPathInfo().GetSkillTree()) proto.SkilltreeList.Add(new AvatarSkillTree { PointId = (uint)skill.Key, @@ -384,7 +383,7 @@ public class SpecialAvatarInfo : BaseAvatarInfo if (GetCurPathInfo().EquipId != 0) proto.EquipmentUniqueId = (uint)GetCurPathInfo().EquipId; - foreach (var skill in GetCurPathInfo().SkillTree) + foreach (var skill in GetCurPathInfo().GetSkillTree()) proto.SkilltreeList.Add(new AvatarSkillTree { PointId = (uint)skill.Key, @@ -431,7 +430,7 @@ public class SpecialAvatarInfo : BaseAvatarInfo WorldLevel = (uint)collection.PlayerData.WorldLevel }; - foreach (var skill in GetCurPathInfo().SkillTree) + foreach (var skill in GetCurPathInfo().GetSkillTree()) proto.SkilltreeList.Add(new AvatarSkillTree { PointId = (uint)skill.Key, @@ -461,7 +460,7 @@ public class SpecialAvatarInfo : BaseAvatarInfo if (GetCurPathInfo().EquipId != 0) { - var item = collection.InventoryData.EquipmentItems?.Find(item => item.UniqueId == GetCurPathInfo().EquipId); + var item = collection.InventoryData.EquipmentItems.Find(item => item.UniqueId == GetCurPathInfo().EquipId); if (item != null) proto.EquipmentList.Add(new BattleEquipment { @@ -488,23 +487,6 @@ public class SpecialAvatarInfo : BaseAvatarInfo public class OldAvatarInfo { - public OldAvatarInfo() - { - // only for db - } - - public OldAvatarInfo(AvatarConfigExcel excel) - { - SkillTree = []; - if (AvatarId == 8001) - { - } - else - { - excel.DefaultSkillTree.ForEach(skill => { SkillTree.Add(skill.PointID, skill.Level); }); - } - } - public int AvatarId { get; set; } public int PathId { get; set; } @@ -534,8 +516,38 @@ public class PathInfo(int pathId) public int EquipId { get; set; } = 0; public Dictionary Relic { get; set; } = []; public ItemData? EquipData { get; set; } // for special avatar - public Dictionary SkillTree { get; set; } = []; public int EnhanceId { get; set; } + public Dictionary EnhanceInfos { get; set; } = []; + + public Dictionary GetSkillTree() + { + if (EnhanceInfos.TryGetValue(EnhanceId, out var enhance)) + { + return enhance.SkillTree; + } + + EnhanceInfos[EnhanceId] = new EnhanceInfo(EnhanceId); + + // create default skill tree + var avatarExcel = GameData.AvatarConfigData.GetValueOrDefault(PathId); + if (avatarExcel == null) return []; + + var skills = avatarExcel.DefaultSkillTree.GetValueOrDefault(EnhanceId); + if (skills == null) return []; + + foreach (var skill in skills) + { + EnhanceInfos[EnhanceId].SkillTree.Add(skill.PointID, skill.Level); + } + + return EnhanceInfos[EnhanceId].SkillTree; + } +} + +public class EnhanceInfo(int enhanceId) +{ + public int EnhanceId { get; set; } = enhanceId; + public Dictionary SkillTree { get; set; } = []; } public record PlayerDataCollection(PlayerData PlayerData, InventoryData InventoryData, LineupInfo LineupInfo); \ No newline at end of file diff --git a/Common/Database/Friend/FriendData.cs b/Common/Database/Friend/FriendData.cs index b2b8d7ef..14ca98e8 100644 --- a/Common/Database/Friend/FriendData.cs +++ b/Common/Database/Friend/FriendData.cs @@ -8,9 +8,8 @@ public class FriendData : BaseDatabaseDataHelper [SugarColumn(IsJson = true, ColumnDataType = "TEXT")] public Dictionary FriendDetailList { get; set; } = []; - [SugarColumn(IsJson = true, ColumnDataType = "TEXT")] - public List FriendList { get; set; } = []; // leave for compatibility + public List FriendList { get; set; } = []; // leave for compatibility [SugarColumn(IsJson = true)] public List BlackList { get; set; } = []; diff --git a/GameServer/Game/Avatar/AvatarManager.cs b/GameServer/Game/Avatar/AvatarManager.cs index f85c9629..f7a3a7b2 100644 --- a/GameServer/Game/Avatar/AvatarManager.cs +++ b/GameServer/Game/Avatar/AvatarManager.cs @@ -61,12 +61,19 @@ public class AvatarManager(PlayerInstance player) : BasePlayerManager(player) (multiPathAvatar?.BaseAvatarID ?? avatarId)); } - public SpecialAvatarInfo? GetTrialAvatar(int avatarId) + public SpecialAvatarInfo? GetTrialAvatar(int avatarId, bool refresh = false) { var avatar = AvatarData.TrialAvatars.Find(avatar => avatar.SpecialAvatarId == avatarId); - if (avatar != null) return avatar; + if (avatar != null) + { + if (refresh) + AvatarData.TrialAvatars.Remove(avatar); + else + return avatar; + } if (!GameData.SpecialAvatarData.TryGetValue(avatarId * 10 + 0, out var excel)) return null; + avatar = new SpecialAvatarInfo { SpecialAvatarId = excel.SpecialAvatarID, @@ -88,10 +95,8 @@ public class AvatarManager(PlayerInstance player) : BasePlayerManager(player) } }); - if (!GameData.AvatarConfigData.TryGetValue(avatar.BaseAvatarId, out var avatarExcel)) return avatar; - foreach (var skill in avatarExcel.DefaultSkillTree) - avatar.GetCurPathInfo().SkillTree.Add(skill.PointID, skill.Level); - + if (!GameData.AvatarConfigData.TryGetValue(avatar.BaseAvatarId, out _)) return avatar; + avatar.GetCurPathInfo().GetSkillTree(); AvatarData.TrialAvatars.Add(avatar); return avatar; } diff --git a/GameServer/Game/Player/PlayerInstance.cs b/GameServer/Game/Player/PlayerInstance.cs index 1cf3d4bd..46c2dd4f 100644 --- a/GameServer/Game/Player/PlayerInstance.cs +++ b/GameServer/Game/Player/PlayerInstance.cs @@ -251,11 +251,11 @@ public class PlayerInstance(PlayerData data) foreach (var avatar in AvatarManager?.AvatarData.FormalAvatars ?? []) foreach (var path in avatar.PathInfos.Values) - foreach (var skill in path.SkillTree) + foreach (var skill in path.GetSkillTree()) { GameData.AvatarSkillTreeConfigData.TryGetValue(skill.Key * 100 + 1, out var config); if (config == null) continue; - path.SkillTree[skill.Key] = Math.Min(skill.Value, config.MaxLevel); // limit skill level + path.GetSkillTree()[skill.Key] = Math.Min(skill.Value, config.MaxLevel); // limit skill level } foreach (var info in LineupManager!.GetAllLineup().SelectMany(lineupInfo => lineupInfo.BaseAvatars ?? [])) diff --git a/GameServer/Game/Scene/SceneInstance.cs b/GameServer/Game/Scene/SceneInstance.cs index 50edae2f..d000c021 100644 --- a/GameServer/Game/Scene/SceneInstance.cs +++ b/GameServer/Game/Scene/SceneInstance.cs @@ -84,19 +84,47 @@ public class SceneInstance { if (entity.Value.GroupId == 0) continue; if (groups.FindIndex(x => x.GroupId == entity.Value.GroupId) == -1) + { + var property = FloorInfo?.Groups.GetValueOrDefault(entity.Value.GroupId)?.GroupPropertyMap ?? []; + + Dictionary resProperty = []; + var savedProp = Player.SceneData!.GroupPropertyData.GetValueOrDefault(FloorId, []) + .GetValueOrDefault(entity.Value.GroupId, []); + + foreach (var info in property.Values.Where(x => x.Side != GroupPropertySideEnum.ClientOnly)) + { + resProperty.Add(info.Name, savedProp.GetValueOrDefault(info.Name, info.DefaultValue)); + } + groups.Add(new SceneEntityGroupInfo { - GroupId = (uint)entity.Value.GroupId + GroupId = (uint)entity.Value.GroupId, + GroupPropertyMap = { resProperty } }); + } groups[groups.FindIndex(x => x.GroupId == entity.Value.GroupId)].EntityList.Add(entity.Value.ToProto()); } foreach (var groupId in Groups) // Add for empty group if (groups.FindIndex(x => x.GroupId == groupId) == -1) + { + var property = FloorInfo?.Groups.GetValueOrDefault(groupId)?.GroupPropertyMap ?? []; + + Dictionary resProperty = []; + var savedProp = Player.SceneData!.GroupPropertyData.GetValueOrDefault(FloorId, []) + .GetValueOrDefault(groupId, []); + + foreach (var info in property.Values.Where(x => x.Side != GroupPropertySideEnum.ClientOnly)) + { + resProperty.Add(info.Name, savedProp.GetValueOrDefault(info.Name, info.DefaultValue)); + } + groups.Add(new SceneEntityGroupInfo { - GroupId = (uint)groupId + GroupId = (uint)groupId, + GroupPropertyMap = { resProperty } }); + } foreach (var group in groups) sceneInfo.EntityGroupList.Add(group); @@ -148,26 +176,27 @@ public class SceneInstance #region Data - public PlayerInstance Player; - public MazePlaneExcel Excel; - public FloorInfo? FloorInfo; - public int FloorId; - public int PlaneId; - public int EntryId; + public PlayerInstance Player { get; set; } + public MazePlaneExcel Excel { get; set; } + public FloorInfo? FloorInfo { get; set; } + public int FloorId { get; set; } + public int PlaneId { get; set; } + public int EntryId { get; set; } - public int LeaveEntryId; - public int LastEntityId; - public bool IsLoaded = false; + public int LeaveEntryId { get; set; } + public int LastEntityId { get; set; } + public bool IsLoaded { get; set; } = false; - public Dictionary AvatarInfo = []; - public int LeaderEntityId; - public Dictionary Entities = []; - public List Groups = []; - public List HealingSprings = []; + public Dictionary AvatarInfo { get; set; } = []; + public int LeaderEntityId { get; set; } + public Dictionary Entities { get; set; } = []; + public List Groups { get; set; } = []; + public List HealingSprings { get; set; } = []; - public SceneEntityLoader? EntityLoader; + public SceneEntityLoader? EntityLoader { get; set; } - public GameModeTypeEnum GameModeType; + public GameModeTypeEnum GameModeType { get; set; } + public List Components { get; set; } = []; public Dictionary SummonUnit { get; set; } = []; @@ -180,7 +209,8 @@ public class SceneInstance EntryId = entryId; LeaveEntryId = 0; - GameData.GetFloorInfo(PlaneId, FloorId, out FloorInfo); + GameData.GetFloorInfo(PlaneId, FloorId, out var floor); + FloorInfo = floor; if (FloorInfo == null) return; GameModeType = (GameModeTypeEnum)excel.PlaneType; @@ -215,16 +245,28 @@ public class SceneInstance EntityLoader = new TrialActivityEntityLoader(this, Player); break; default: - if (Player.StoryLineManager?.StoryLineData.CurStoryLineId != 0) - EntityLoader = new StoryLineEntityLoader(this); - else - EntityLoader = new SceneEntityLoader(this); + EntityLoader = Player.StoryLineManager?.StoryLineData.CurStoryLineId != 0 ? new StoryLineEntityLoader(this) : new SceneEntityLoader(this); break; } + foreach (var module in floor.LevelFeatureModules.ToHashSet()) + { + switch (module) + { + case LevelFeatureTypeEnum.EraFlipper: + Components.Add(new EraFlipperSceneComponent(this)); + break; + case LevelFeatureTypeEnum.RotatableRegion: + Components.Add(new RotatableRegionSceneComponent(this)); + break; + } + } + System.Threading.Tasks.Task.Run(async () => { await EntityLoader.LoadEntity(); }).Wait(); Player.TaskManager?.SceneTaskTrigger.TriggerFloor(PlaneId, FloorId); + + _ = InitializeComponents(); } #endregion @@ -344,6 +386,23 @@ public class SceneInstance #endregion + #region Components + + public async ValueTask InitializeComponents() + { + foreach (var component in Components) + { + await component.Initialize(); + } + } + + public T? GetComponent() where T : BaseSceneComponent + { + return Components.FirstOrDefault(x => x is T) as T; + } + + #endregion + #region Entity Management public async ValueTask AddEntity(BaseGameEntity entity) @@ -565,9 +624,9 @@ public class SceneInstance public class AvatarSceneInfo : BaseGameEntity, IGameModifier { - public BaseAvatarInfo AvatarInfo; - public AvatarType AvatarType; - public PlayerInstance Player; + public BaseAvatarInfo AvatarInfo { get; set; } + public AvatarType AvatarType { get; set; } + public PlayerInstance Player { get; set; } public AvatarSceneInfo(BaseAvatarInfo avatarInfo, AvatarType avatarType, PlayerInstance player) { diff --git a/GameServer/Server/Packet/Recv/Avatar/HandlerSetAvatarEnhancedIdCsReq.cs b/GameServer/Server/Packet/Recv/Avatar/HandlerSetAvatarEnhancedIdCsReq.cs index be4f207a..64f2ceca 100644 --- a/GameServer/Server/Packet/Recv/Avatar/HandlerSetAvatarEnhancedIdCsReq.cs +++ b/GameServer/Server/Packet/Recv/Avatar/HandlerSetAvatarEnhancedIdCsReq.cs @@ -1,4 +1,5 @@ using EggLink.DanhengServer.GameServer.Server.Packet.Send.Avatar; +using EggLink.DanhengServer.GameServer.Server.Packet.Send.PlayerSync; using EggLink.DanhengServer.Kcp; using EggLink.DanhengServer.Proto; @@ -22,5 +23,6 @@ public class HandlerSetAvatarEnhancedIdCsReq : Handler path.EnhanceId = (int)req.AvatarEnhanceId; await connection.Player.SendPacket(new PacketSetAvatarEnhancedIdScRsp(req.AvatarId, path.EnhanceId)); + await connection.Player.SendPacket(new PacketPlayerSyncScNotify(avatar)); } } \ No newline at end of file diff --git a/GameServer/Server/Packet/Recv/Avatar/HandlerUnlockSkilltreeCsReq.cs b/GameServer/Server/Packet/Recv/Avatar/HandlerUnlockSkilltreeCsReq.cs index 4e57ae99..8ca011cb 100644 --- a/GameServer/Server/Packet/Recv/Avatar/HandlerUnlockSkilltreeCsReq.cs +++ b/GameServer/Server/Packet/Recv/Avatar/HandlerUnlockSkilltreeCsReq.cs @@ -32,7 +32,7 @@ public class HandlerUnlockSkilltreeCsReq : Handler await connection.Player!.InventoryManager!.RemoveItem((int)cost.PileItem.ItemId, (int)cost.PileItem.ItemNum); - avatar.GetCurPathInfo().SkillTree[(int)req.PointId] = (int)req.Level; + avatar.GetCurPathInfo().GetSkillTree()[(int)req.PointId] = (int)req.Level; await connection.SendPacket(new PacketPlayerSyncScNotify(avatar)); diff --git a/Program/Program/EntryPoint.cs b/Program/Program/EntryPoint.cs index e914bb30..92c80b84 100644 --- a/Program/Program/EntryPoint.cs +++ b/Program/Program/EntryPoint.cs @@ -360,7 +360,15 @@ public class EntryPoint Rank = info.Value.Rank, Relic = info.Value.Relic, Skin = info.Value.Skin, - SkillTree = avatar.SkillTreeExtra.GetValueOrDefault(info.Value.PathId) ?? [] + EnhanceInfos = + { + { + 0, new EnhanceInfo(0) + { + SkillTree = avatar.SkillTreeExtra.GetValueOrDefault(info.Value.PathId) ?? [] + } + } + } }); }