From e1f7da7f9fb50de8e35655c8b0b4fdc919639a88 Mon Sep 17 00:00:00 2001 From: StopWuyu Date: Sun, 19 Oct 2025 12:47:59 +0800 Subject: [PATCH] feat: grid fight in-game panel --- Command/Command/Cmd/CommandUnlockAll.cs | 21 ++ Common/Data/Excel/GridFightAugmentExcel.cs | 23 ++ Common/Data/Excel/GridFightCampExcel.cs | 38 ++++ .../Data/Excel/GridFightDivisionInfoExcel.cs | 20 ++ Common/Data/Excel/GridFightMonsterExcel.cs | 22 ++ Common/Data/Excel/GridFightPortalBuffExcel.cs | 18 ++ .../Data/Excel/GridFightSeasonTalentExcel.cs | 19 ++ Common/Data/Excel/GridFightStageRouteExcel.cs | 30 +++ Common/Data/Excel/GridFightTalentExcel.cs | 19 ++ Common/Data/Excel/RogueBuffGroupExcel.cs | 4 +- Common/Data/GameData.cs | 8 + .../GridFight/GridFightAugmentQualityEnum.cs | 9 + .../Enums/GridFight/GridFightNodeTypeEnum.cs | 11 + .../GridFight/GridFightRolePositionEnum.cs | 9 + Common/Enums/Mission/MissionFinishTypeEnum.cs | 11 + GameServer/Game/Battle/BattleManager.cs | 2 +- .../Component/BaseGridFightComponent.cs | 9 + .../Component/GridFightAvatarComponent.cs | 51 +++++ .../Component/GridFightBasicComponent.cs | 30 +++ .../Component/GridFightLevelComponent.cs | 203 ++++++++++++++++++ .../Game/GridFight/GridFightInstance.cs | 51 +++++ GameServer/Game/GridFight/GridFightManager.cs | 81 ++++--- GameServer/Game/Mission/MissionManager.cs | 2 +- .../HandlerQuickStartCocoonStageCsReq.cs | 4 +- .../HandlerGridFightStartGamePlayCsReq.cs | 18 ++ .../PacketQuickStartCocoonStageScRsp.cs | 2 +- .../GridFight/PacketGridFightGetDataScRsp.cs | 6 +- .../PacketGridFightStartGamePlayScRsp.cs | 21 ++ 28 files changed, 706 insertions(+), 36 deletions(-) create mode 100644 Common/Data/Excel/GridFightAugmentExcel.cs create mode 100644 Common/Data/Excel/GridFightCampExcel.cs create mode 100644 Common/Data/Excel/GridFightDivisionInfoExcel.cs create mode 100644 Common/Data/Excel/GridFightMonsterExcel.cs create mode 100644 Common/Data/Excel/GridFightPortalBuffExcel.cs create mode 100644 Common/Data/Excel/GridFightSeasonTalentExcel.cs create mode 100644 Common/Data/Excel/GridFightStageRouteExcel.cs create mode 100644 Common/Data/Excel/GridFightTalentExcel.cs create mode 100644 Common/Enums/GridFight/GridFightAugmentQualityEnum.cs create mode 100644 Common/Enums/GridFight/GridFightNodeTypeEnum.cs create mode 100644 Common/Enums/GridFight/GridFightRolePositionEnum.cs create mode 100644 GameServer/Game/GridFight/Component/BaseGridFightComponent.cs create mode 100644 GameServer/Game/GridFight/Component/GridFightAvatarComponent.cs create mode 100644 GameServer/Game/GridFight/Component/GridFightBasicComponent.cs create mode 100644 GameServer/Game/GridFight/Component/GridFightLevelComponent.cs create mode 100644 GameServer/Game/GridFight/GridFightInstance.cs create mode 100644 GameServer/Server/Packet/Recv/GridFight/HandlerGridFightStartGamePlayCsReq.cs create mode 100644 GameServer/Server/Packet/Send/GridFight/PacketGridFightStartGamePlayScRsp.cs diff --git a/Command/Command/Cmd/CommandUnlockAll.cs b/Command/Command/Cmd/CommandUnlockAll.cs index cce5f3a1..1c4b02dc 100644 --- a/Command/Command/Cmd/CommandUnlockAll.cs +++ b/Command/Command/Cmd/CommandUnlockAll.cs @@ -45,6 +45,27 @@ public class CommandUnlockAll : ICommand arg.Target!.Stop(); } + [CommandMethod("0 quest")] + public async ValueTask UnlockAllQuests(CommandArg arg) + { + if (arg.Target == null) + { + await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.PlayerNotFound")); + return; + } + + var player = arg.Target!.Player!; + var questManager = player.QuestManager!; + + foreach (var quest in GameData.QuestDataData.Values) + await questManager.FinishQuest(quest.QuestID, false); + + await questManager.SyncQuest(); + + await arg.SendMsg(I18NManager.Translate("Game.Command.UnlockAll.UnlockedAll", + I18NManager.Translate("Word.Quest"))); + } + [CommandMethod("0 tutorial")] public async ValueTask UnlockAllTutorial(CommandArg arg) { diff --git a/Common/Data/Excel/GridFightAugmentExcel.cs b/Common/Data/Excel/GridFightAugmentExcel.cs new file mode 100644 index 00000000..279f95a8 --- /dev/null +++ b/Common/Data/Excel/GridFightAugmentExcel.cs @@ -0,0 +1,23 @@ +using EggLink.DanhengServer.Enums.GridFight; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightAugment.json")] +public class GridFightAugmentExcel : ExcelResource +{ + public uint ID { get; set; } + public uint CategoryID { get; set; } + [JsonConverter(typeof(StringEnumConverter))] public GridFightAugmentQualityEnum Quality { get; set; } + + public override int GetId() + { + return (int)ID; + } + + public override void Loaded() + { + GameData.GridFightAugmentData.TryAdd(ID, this); + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightCampExcel.cs b/Common/Data/Excel/GridFightCampExcel.cs new file mode 100644 index 00000000..921a7a65 --- /dev/null +++ b/Common/Data/Excel/GridFightCampExcel.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; + +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightCamp.json")] +public class GridFightCampExcel : ExcelResource +{ + public uint ID { get; set; } + public uint SeasonID { get; set; } + public uint BossBattleArea { get; set; } + public uint IfRandomEnabled { get; set; } + public uint InitialRandomCode { get; set; } + public List BattleAreaList { get; set; } = []; + public List MonsterList { get; set; } = []; + + [JsonIgnore] public List Monsters { get; set; } = []; + + public override int GetId() + { + return (int)ID; + } + + public override void Loaded() + { + GameData.GridFightCampData.TryAdd(ID, this); + } + + public override void AfterAllDone() + { + foreach (var monsterId in MonsterList) + { + if (GameData.GridFightMonsterData.TryGetValue(monsterId, out var monster)) + { + Monsters.Add(monster); + } + } + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightDivisionInfoExcel.cs b/Common/Data/Excel/GridFightDivisionInfoExcel.cs new file mode 100644 index 00000000..cc790f2a --- /dev/null +++ b/Common/Data/Excel/GridFightDivisionInfoExcel.cs @@ -0,0 +1,20 @@ +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightDivisionInfo.json")] +public class GridFightDivisionInfoExcel : ExcelResource +{ + public uint ID { get; set; } + public uint SeasonID { get; set; } + public uint Progress { get; set; } + public uint DivisionLevel { get; set; } + + public override int GetId() + { + return (int)ID; + } + + public override void Loaded() + { + GameData.GridFightDivisionInfoData.TryAdd(ID, this); + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightMonsterExcel.cs b/Common/Data/Excel/GridFightMonsterExcel.cs new file mode 100644 index 00000000..eb77ab5d --- /dev/null +++ b/Common/Data/Excel/GridFightMonsterExcel.cs @@ -0,0 +1,22 @@ +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightMonster.json")] +public class GridFightMonsterExcel : ExcelResource +{ + public uint MonsterID { get; set; } + public uint Star3EliteGroup3 { get; set; } + public uint MonsterTier { get; set; } + public uint Star1EliteGroup3 { get; set; } + public uint Star4EliteGroup3 { get; set; } + public uint Star2EliteGroup3 { get; set; } + + public override int GetId() + { + return (int)MonsterID; + } + + public override void Loaded() + { + GameData.GridFightMonsterData.TryAdd(MonsterID, this); + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightPortalBuffExcel.cs b/Common/Data/Excel/GridFightPortalBuffExcel.cs new file mode 100644 index 00000000..8e69a4e9 --- /dev/null +++ b/Common/Data/Excel/GridFightPortalBuffExcel.cs @@ -0,0 +1,18 @@ +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightPortalBuff.json")] +public class GridFightPortalBuffExcel : ExcelResource +{ + public uint ID { get; set; } + public bool IfInBook { get; set; } + + public override int GetId() + { + return (int)ID; + } + + public override void Loaded() + { + GameData.GridFightPortalBuffData.TryAdd(ID, this); + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightSeasonTalentExcel.cs b/Common/Data/Excel/GridFightSeasonTalentExcel.cs new file mode 100644 index 00000000..7d8239d5 --- /dev/null +++ b/Common/Data/Excel/GridFightSeasonTalentExcel.cs @@ -0,0 +1,19 @@ +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightSeasonTalent.json")] +public class GridFightSeasonTalentExcel : ExcelResource +{ + public uint ID { get; set; } + public uint Cost { get; set; } + public uint SeasonID { get; set; } + public List PreTalentIDList { get; set; } = []; + + public override int GetId() + { + return (int)ID; + } + public override void Loaded() + { + GameData.GridFightSeasonTalentData.TryAdd(ID, this); + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightStageRouteExcel.cs b/Common/Data/Excel/GridFightStageRouteExcel.cs new file mode 100644 index 00000000..97cc4167 --- /dev/null +++ b/Common/Data/Excel/GridFightStageRouteExcel.cs @@ -0,0 +1,30 @@ +using EggLink.DanhengServer.Enums.GridFight; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightStageRoute.json")] +public class GridFightStageRouteExcel : ExcelResource +{ + public uint SectionID { get; set; } + public uint ChapterID { get; set; } + public uint ID { get; set; } + public uint StageID { get; set; } + public uint NodeTemplateID { get; set; } + public uint BasicGoldRewardNum { get; set; } + + [JsonConverter(typeof(StringEnumConverter))] + public GridFightNodeTypeEnum NodeType { get; set; } + + public override int GetId() + { + return (int)ID; + } + + public override void Loaded() + { + GameData.GridFightStageRouteData.TryAdd(ID, []); + GameData.GridFightStageRouteData[ID][ChapterID << 8 | SectionID] = this; + } +} \ No newline at end of file diff --git a/Common/Data/Excel/GridFightTalentExcel.cs b/Common/Data/Excel/GridFightTalentExcel.cs new file mode 100644 index 00000000..93313986 --- /dev/null +++ b/Common/Data/Excel/GridFightTalentExcel.cs @@ -0,0 +1,19 @@ +namespace EggLink.DanhengServer.Data.Excel; + +[ResourceEntity("GridFightTalent.json")] +public class GridFightTalentExcel : ExcelResource +{ + public uint ID { get; set; } + public uint Cost { get; set; } + public List PreTalentIDList { get; set; } = []; + + public override int GetId() + { + return (int)ID; + } + + public override void Loaded() + { + GameData.GridFightTalentData.TryAdd(ID, this); + } +} \ No newline at end of file diff --git a/Common/Data/Excel/RogueBuffGroupExcel.cs b/Common/Data/Excel/RogueBuffGroupExcel.cs index c544c1ed..2fc7e9f5 100644 --- a/Common/Data/Excel/RogueBuffGroupExcel.cs +++ b/Common/Data/Excel/RogueBuffGroupExcel.cs @@ -7,8 +7,8 @@ namespace EggLink.DanhengServer.Data.Excel; [ResourceEntity("RogueBuffGroup.json")] public class RogueBuffGroupExcel : BaseRogueBuffGroupExcel { - [JsonProperty("IDLBMIHBAPB")] public int GroupID { get; set; } - [JsonProperty("GNGDPDOMDFH")] public List BuffTagList { get; set; } = []; + [JsonProperty("GroupID")] public int GroupID { get; set; } + [JsonProperty("BuffTagList")] public List BuffTagList { get; set; } = []; public override int GetId() { diff --git a/Common/Data/GameData.cs b/Common/Data/GameData.cs index f1310955..0e15795b 100644 --- a/Common/Data/GameData.cs +++ b/Common/Data/GameData.cs @@ -105,9 +105,17 @@ public static class GameData #region GridFight public static Dictionary GridFightRoleBasicInfoData { get; private set; } = []; + public static Dictionary GridFightDivisionInfoData { get; private set; } = []; public static Dictionary GridFightEquipmentData { get; private set; } = []; public static Dictionary GridFightConsumablesData { get; private set; } = []; + public static Dictionary GridFightCampData { get; private set; } = []; + public static Dictionary GridFightMonsterData { get; private set; } = []; + public static Dictionary GridFightAugmentData { get; private set; } = []; + public static Dictionary GridFightPortalBuffData { get; private set; } = []; public static Dictionary GridFightItemsData { get; private set; } = []; + public static Dictionary GridFightTalentData { get; private set; } = []; + public static Dictionary GridFightSeasonTalentData { get; private set; } = []; + public static Dictionary> GridFightStageRouteData { get; private set; } = []; #endregion diff --git a/Common/Enums/GridFight/GridFightAugmentQualityEnum.cs b/Common/Enums/GridFight/GridFightAugmentQualityEnum.cs new file mode 100644 index 00000000..1d734c2e --- /dev/null +++ b/Common/Enums/GridFight/GridFightAugmentQualityEnum.cs @@ -0,0 +1,9 @@ +namespace EggLink.DanhengServer.Enums.GridFight; + +public enum GridFightAugmentQualityEnum +{ + None = 0, + Silver = 1, + Gold = 2, + Prismatic = 3, +} \ No newline at end of file diff --git a/Common/Enums/GridFight/GridFightNodeTypeEnum.cs b/Common/Enums/GridFight/GridFightNodeTypeEnum.cs new file mode 100644 index 00000000..e9d25a2c --- /dev/null +++ b/Common/Enums/GridFight/GridFightNodeTypeEnum.cs @@ -0,0 +1,11 @@ +namespace EggLink.DanhengServer.Enums.GridFight; + +public enum GridFightNodeTypeEnum +{ + GridFightNodeNone = 0, + Monster = 1, + CampMonster = 2, + EliteBranch = 3, + Boss = 4, + Supply = 5 +} \ No newline at end of file diff --git a/Common/Enums/GridFight/GridFightRolePositionEnum.cs b/Common/Enums/GridFight/GridFightRolePositionEnum.cs new file mode 100644 index 00000000..32cba818 --- /dev/null +++ b/Common/Enums/GridFight/GridFightRolePositionEnum.cs @@ -0,0 +1,9 @@ +namespace EggLink.DanhengServer.Enums.GridFight; + +public enum GridFightRolePositionEnum +{ + None = 0, + Foreground = 1, + Background = 2, + Ready = 3 +} \ No newline at end of file diff --git a/Common/Enums/Mission/MissionFinishTypeEnum.cs b/Common/Enums/Mission/MissionFinishTypeEnum.cs index d51e49be..ff40b087 100644 --- a/Common/Enums/Mission/MissionFinishTypeEnum.cs +++ b/Common/Enums/Mission/MissionFinishTypeEnum.cs @@ -778,4 +778,15 @@ public enum MissionFinishTypeEnum GridFightSettleEnemyDifficulty = 370050, GridFightSettlePlayerLevel = 370051, GridFightBattleWinWithEnemyDifficulty = 370052, + GridFightSettleBattleObjCnt = 370053, + GridFightTraitSelectEnhanceGainAll = 370054, + GridFightGainSpecialGoods = 370055, + GridFightGainFrontTraitJoinTraitNumEnterBattle = 370056, + GridFightArcherMakeEquip = 370057, + GridFightTraitBonusThreshold = 370058, + GridFightSettleWinWithRoleId = 370059, + GridFightSettleRoleWithFullEquips = 370060, + GridFightSettleWithNpcCnt = 370061, + GridFightSettleWithEquipCnt = 370062, + GridFightSettleWinWithTraitLayerAndRoleRarityNum = 370063, } \ No newline at end of file diff --git a/GameServer/Game/Battle/BattleManager.cs b/GameServer/Game/Battle/BattleManager.cs index 808983bd..68664123 100644 --- a/GameServer/Game/Battle/BattleManager.cs +++ b/GameServer/Game/Battle/BattleManager.cs @@ -215,7 +215,7 @@ public class BattleManager(PlayerInstance player) : BasePlayerManager(player) GameData.CocoonConfigData.TryGetValue(cocoonId * 100 + worldLevel, out var config); if (config == null) return null; - wave = Math.Min(Math.Max(wave, 1), config.MaxWave); + wave = Math.Max(wave, 1); var cost = config.StaminaCost * wave; if (Player.Data.Stamina < cost) return null; diff --git a/GameServer/Game/GridFight/Component/BaseGridFightComponent.cs b/GameServer/Game/GridFight/Component/BaseGridFightComponent.cs new file mode 100644 index 00000000..0dc4c997 --- /dev/null +++ b/GameServer/Game/GridFight/Component/BaseGridFightComponent.cs @@ -0,0 +1,9 @@ +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component; + +public abstract class BaseGridFightComponent(GridFightInstance inst) +{ + public GridFightInstance Inst { get; } = inst; + public abstract GridFightGameInfo ToProto(); +} \ No newline at end of file diff --git a/GameServer/Game/GridFight/Component/GridFightAvatarComponent.cs b/GameServer/Game/GridFight/Component/GridFightAvatarComponent.cs new file mode 100644 index 00000000..af4c9499 --- /dev/null +++ b/GameServer/Game/GridFight/Component/GridFightAvatarComponent.cs @@ -0,0 +1,51 @@ +using EggLink.DanhengServer.Data; +using EggLink.DanhengServer.Data.Excel; +using EggLink.DanhengServer.Enums.GridFight; +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component; + +public class GridFightAvatarComponent(GridFightInstance inst) : BaseGridFightComponent(inst) +{ + public List Avatars { get; set; } = []; + private uint _curUniqueId; + + public async ValueTask AddAvatar(uint roleId, uint tier = 1) + { + var info = new GridFightAvatarInfo(roleId, ++_curUniqueId, tier); + Avatars.Add(info); + + // TODO sync + await ValueTask.CompletedTask; + } + + public override GridFightGameInfo ToProto() + { + return new GridFightGameInfo + { + GridAvatarGameInfo = new GridFightGameAvatarInfo + { + GridGameAvatarList = { Avatars.Select(x => x.ToProto()) } + } + }; + } +} + +public class GridFightAvatarInfo(uint roleId, uint uniqueId, uint tier = 1) +{ + public GridFightRoleBasicInfoExcel RoleInfo { get; set; } = GameData.GridFightRoleBasicInfoData[roleId]; + public GridFightRolePositionEnum Pos { get; set; } = GridFightRolePositionEnum.Foreground; + public uint Tier { get; set; } = tier; + public uint UniqueId { get; set; } = uniqueId; + + public GridGameAvatarInfo ToProto() + { + return new GridGameAvatarInfo + { + Id = RoleInfo.ID, + Pos = (uint)Pos, + Tier = Tier, + UniqueId = UniqueId + }; + } +} \ No newline at end of file diff --git a/GameServer/Game/GridFight/Component/GridFightBasicComponent.cs b/GameServer/Game/GridFight/Component/GridFightBasicComponent.cs new file mode 100644 index 00000000..bed7e383 --- /dev/null +++ b/GameServer/Game/GridFight/Component/GridFightBasicComponent.cs @@ -0,0 +1,30 @@ +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component; + +public class GridFightBasicComponent(GridFightInstance inst) : BaseGridFightComponent(inst) +{ + public override GridFightGameInfo ToProto() + { + return new GridFightGameInfo + { + GridBasicInfo = new GridFightGameBasicInfo + { + GridFightCurLevel = 1, + GridFightCurLevelExp = 1, + GridFightLevelCost = 1, + GridFightMaxAvatarCount = 2, + GridFightOffFieldMaxCount = 9, + GridFightMaxFieldCount = 13, + GridFightLineupHp = 100, + GridFightCurGold = 200, + GridFightMaxGold = 2000, + OCMGMEHECBB = new OPIBBPCHFII + { + IJDIAOMINLB = new BHJALAPDBLH() + }, + CALCJMHAKPF = new OLEIDBLBILD() + } + }; + } +} \ No newline at end of file diff --git a/GameServer/Game/GridFight/Component/GridFightLevelComponent.cs b/GameServer/Game/GridFight/Component/GridFightLevelComponent.cs new file mode 100644 index 00000000..4f67483f --- /dev/null +++ b/GameServer/Game/GridFight/Component/GridFightLevelComponent.cs @@ -0,0 +1,203 @@ +using EggLink.DanhengServer.Data; +using EggLink.DanhengServer.Data.Excel; +using EggLink.DanhengServer.Enums.GridFight; +using EggLink.DanhengServer.Proto; +using EggLink.DanhengServer.Util; + +namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component; + +public class GridFightLevelComponent : BaseGridFightComponent +{ + private uint _curChapterId = 1; + private uint _curSectionId = 1; + public Dictionary> Sections { get; } = []; + public GridFightGameSectionInfo CurrentSection => Sections[_curChapterId][(int)(_curSectionId - 1)]; + + public GridFightLevelComponent(GridFightInstance inst) : base(inst) + { + // TODO: randomly select a base route id + List chapterIds = [1100]; + List campPool = GameData.GridFightCampData.Values.ToList(); + foreach (var chapterId in Enumerable.Range(1, 3)) + { + var chapters = chapterIds.Count >= chapterId + ? [GameData.GridFightStageRouteData[chapterIds[chapterId - 1]]] + : GameData.GridFightStageRouteData.Values.Where(x => x.Any(j => j.Value.ChapterID == chapterId)) + .ToList(); + if (chapters.Count == 0) + continue; + + var select = chapters.RandomElement(); + + var camp = campPool.RandomElement(); // cannot the same + campPool.Remove(camp); + // create section infos + Sections[(uint)chapterId] = [..select.Values.Select(x => new GridFightGameSectionInfo(x, camp))]; + } + } + + public List GetBossMonsters() + { + // get every chapter last section camp + List bosses = []; + foreach (var chapter in Sections.Values) + { + var lastSection = chapter.Last(); + var bossMonsters = lastSection.MonsterCamp.Monsters.Where(x => x.MonsterTier == 5).ToList(); + if (bossMonsters.Count == 0) + continue; + + var boss = bossMonsters.RandomElement(); + bosses.Add(new GridFightMonsterInfo + { + MonsterId = boss.MonsterID, + Tier = boss.MonsterTier, + MonsterCampId = lastSection.MonsterCamp.ID + }); + } + + return bosses; + } + + public override GridFightGameInfo ToProto() + { + return new GridFightGameInfo + { + GridLevelInfo = new GridFightLevelInfo + { + ChapterId = CurrentSection.ChapterId, + SectionId = CurrentSection.SectionId, + RouteId = CurrentSection.Excel.ID, + GridFightLayerInfo = new GridFightLayerInfo + { + RouteInfo = CurrentSection.ToRouteInfo() + }, + BossInfo = new GridFightBossInfo + { + BossMonsters = { GetBossMonsters() } + }, + GridFightCampList = + { + Sections.Values.SelectMany(x => x).Select(h => h.MonsterCamp.ID).ToHashSet().Select(s => + new GridFightGameCampInfo + { + MonsterCampId = s, + }) + }, + GridChapterInfo = new GridFightChapterInfo + { + SectionInfo = + { + Sections.Values.SelectMany(x => x).Select(s => s.ToProto()) + } + }, + CGAIJCCLKBH = new() + { + DILHFEHBGDN = new ACHJGEEKCAH() + } + } + }; + } +} + +public class GridFightGameSectionInfo +{ + public GridFightStageRouteExcel Excel { get; } + public uint ChapterId { get; } + public uint SectionId { get; } + public GridFightCampExcel MonsterCamp { get; set; } + public List Encounters { get; } = []; + + public GridFightGameSectionInfo(GridFightStageRouteExcel excel, GridFightCampExcel camp) + { + Excel = excel; + ChapterId = excel.ChapterID; + SectionId = excel.SectionID; + + MonsterCamp = camp; + + Encounters.Add(new GridFightGameEncounterInfo(1, 1, this)); + } + + public GridFightRouteInfo ToRouteInfo() + { + return new GridFightRouteInfo + { + FightCampId = MonsterCamp.ID, + EliteBranchId = 0, + RouteEncounterList = { Encounters.Select(x => x.ToProto()) } + }; + } + + public GridFightSectionInfo ToProto() + { + return new GridFightSectionInfo + { + ChapterId = ChapterId, + SectionId = SectionId + }; + } +} + +public class GridFightGameEncounterInfo +{ + public GridFightGameEncounterInfo(uint index, uint difficulty, GridFightGameSectionInfo section) + { + EncounterIndex = index; + EncounterDifficulty = difficulty; + ParentSection = section; + + if (ParentSection.Excel.NodeType != GridFightNodeTypeEnum.Monster) return; + + var monsterPool = ParentSection.MonsterCamp.Monsters.Where(x => x.MonsterTier <= 3).OrderBy(_ => Guid.NewGuid()).ToList(); + + List monsters = []; + + foreach (var _ in Enumerable.Range(0, Random.Shared.Next(1, 5))) + { + monsters.Add(monsterPool.RandomElement()); + } + + MonsterWaves.Add(new GridFightGameMonsterWaveInfo(1, monsters, ParentSection.MonsterCamp.ID)); + } + + public uint EncounterIndex { get; set; } + public uint EncounterDifficulty { get; set; } + public GridFightGameSectionInfo ParentSection { get; } + public List MonsterWaves { get; } = []; + + public GridFightEncounterInfo ToProto() + { + return new GridFightEncounterInfo + { + EncounterIndex = EncounterIndex, + EncounterExtraDifficultyLevel = EncounterDifficulty, + EncounterDropInfo = new GridFightDropInfo(), + MonsterWaveList = { MonsterWaves.Select(x => x.ToProto()) } + }; + } +} + +public class GridFightGameMonsterWaveInfo(uint wave, List monsters, uint campId) +{ + public uint Wave { get; set; } = wave; + public uint CampId { get; set; } = campId; + public List Monsters { get; } = monsters; + + public GridEncounterMonsterWave ToProto() + { + return new GridEncounterMonsterWave + { + EncounterWave = Wave, + FightMonsterList = + { + Monsters.Select(x => new GridFightMonsterInfo + { + MonsterId = x.MonsterID, + MonsterCampId = CampId, + Tier = x.MonsterTier + }) + } + }; + } +} \ No newline at end of file diff --git a/GameServer/Game/GridFight/GridFightInstance.cs b/GameServer/Game/GridFight/GridFightInstance.cs new file mode 100644 index 00000000..3bce147f --- /dev/null +++ b/GameServer/Game/GridFight/GridFightInstance.cs @@ -0,0 +1,51 @@ +using EggLink.DanhengServer.GameServer.Game.GridFight.Component; +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Game.GridFight; + +public class GridFightInstance(uint season, uint divisionId, bool isOverLock, uint uniqueId) +{ + public uint Season { get; } = season; + public uint DivisionId { get; } = divisionId; + public bool IsOverLock { get; } = isOverLock; + public uint UniqueId { get; } = uniqueId; + public List Components { get; } = []; + + public void InitializeComponents() + { + Components.Add(new GridFightBasicComponent(this)); + Components.Add(new GridFightLevelComponent(this)); + Components.Add(new GridFightAvatarComponent(this)); + + _ = GetComponent().AddAvatar(1414, 3); // TODO test + } + + public T GetComponent() where T : BaseGridFightComponent + { + return (T)Components.First(c => c is T); + } + + public GridFightCurrentInfo ToProto() + { + return new GridFightCurrentInfo + { + DivisionId = DivisionId, + Season = Season, + IsOverlock = IsOverLock, + UniqueId = UniqueId, + PendingAction = new GridFightPendingAction(), + GridFightGameData = ToGameDataInfo(), + RogueCurrentGameInfo = { ToGameInfos() } + }; + } + + public List ToGameInfos() + { + return (from c in Components select c.ToProto()).ToList(); + } + + public GridFightGameData ToGameDataInfo() + { + return new GridFightGameData(); + } +} \ No newline at end of file diff --git a/GameServer/Game/GridFight/GridFightManager.cs b/GameServer/Game/GridFight/GridFightManager.cs index e151472b..f14b4bd5 100644 --- a/GameServer/Game/GridFight/GridFightManager.cs +++ b/GameServer/Game/GridFight/GridFightManager.cs @@ -7,6 +7,32 @@ namespace EggLink.DanhengServer.GameServer.Game.GridFight; public class GridFightManager(PlayerInstance player) : BasePlayerManager(player) { + public const uint CurSeasonId = 1; + public uint CurUniqueId { get; set; } + public GridFightInstance? GridFightInstance { get; set; } + + #region Game + + public async ValueTask<(Retcode code, GridFightInstance? inst)> StartGamePlay(uint season, uint divisionId, bool isOverLock) + { + if (season != CurSeasonId) + return (Retcode.RetGridFightConfMiss, null); + + if (GridFightInstance != null) + return (Retcode.RetGridFightAlreadyInGameplay, GridFightInstance); + + GridFightInstance = new GridFightInstance(season, divisionId, isOverLock, ++CurUniqueId); + GridFightInstance.InitializeComponents(); + + await ValueTask.CompletedTask; + return (Retcode.RetSucc, GridFightInstance); + } + + #endregion + + + #region Serialization + public GridFightQueryInfo ToProto() { return new GridFightQueryInfo @@ -16,18 +42,6 @@ public class GridFightManager(PlayerInstance player) : BasePlayerManager(player) }; } - public GridFightCurrentInfo ToCurrentInfo() - { - return new GridFightCurrentInfo - { - GridFightGameData = new GridFightGameData(), - Season = 1, - DivisionId = 1, - UniqueId = 1, - PendingAction = new GridFightPendingAction() - }; - } - public GridFightRewardInfo ToRewardInfo() { var time = RogueManager.GetCurrentRogueTime(); @@ -36,12 +50,13 @@ public class GridFightManager(PlayerInstance player) : BasePlayerManager(player) { GridFightTalentInfo = new GridFightTalentInfo { - JMOJEOALCLO = { 1011 } + DeployIdList = { GameData.GridFightTalentData.Keys } }, - //GridFightWeeklyReward = new GridFightTakeWeeklyRewardInfo - //{ - // EndTime = time.Item2, - //} + GridFightWeeklyReward = new GridFightTakeWeeklyRewardInfo + { + EndTime = time.Item2, + //FeatureBeginTime = time.Item1 + } }; } @@ -51,18 +66,18 @@ public class GridFightManager(PlayerInstance player) : BasePlayerManager(player) { GridFightTalentInfo = new GridFightTalentInfo { - JMOJEOALCLO = { } + DeployIdList = { GameData.GridFightSeasonTalentData.Keys } }, - DivisionId = 10920, + DivisionId = GameData.GridFightDivisionInfoData.Where(x => x.Value.SeasonID == CurSeasonId) + .Select(x => x.Key).Max(), GridFightGameValueInfo = ToFightGameValueInfo(), - Exp = new () + Exp = new GridFightExpInfo { - BNCBPJIBHGI = 1, - GDDHBECJECP = 1 + GridFightLevel = 1, + GridWeeklyExtraExp = 1 }, MGGGAJJBAMN = 1, - ECMBJBBGHGG = 1, - IFEHBIMEMEC = 10 + SubSeasonId = 1 }; } @@ -78,9 +93,21 @@ public class GridFightManager(PlayerInstance player) : BasePlayerManager(player) { GridFightItemList = { GameData.GridFightItemsData.Keys } }, - IADIEGJKNHA = new(), - OCKCODILEOP = new(), - PJBEPNCFGDJ = new() + GridFightCampInfo = new GridFightCampInfo + { + GridFightCampList = { GameData.GridFightCampData.Keys } + }, + GridFightAugmentInfo = new GridFightAugmentInfo + { + GridFightAugmentList = { GameData.GridFightAugmentData.Keys } + }, + GridFightPortalBuffInfo = new GridFightPortalBuffInfo + { + GridFightPortalBuffList = + { GameData.GridFightPortalBuffData.Values.Where(x => x.IfInBook).Select(x => x.ID) } + } }; } + + #endregion } \ No newline at end of file diff --git a/GameServer/Game/Mission/MissionManager.cs b/GameServer/Game/Mission/MissionManager.cs index de57eb02..9df5ac68 100644 --- a/GameServer/Game/Mission/MissionManager.cs +++ b/GameServer/Game/Mission/MissionManager.cs @@ -161,7 +161,7 @@ public class MissionManager(PlayerInstance player) : BasePlayerManager(player) }); if (sendPacket) await Player.SendPacket(new PacketPlayerSyncScNotify(sync)); - Player.SceneInstance!.SyncGroupInfo(); + Player.SceneInstance?.SyncGroupInfo(); if (mission.SubMissionInfo != null) try { diff --git a/GameServer/Server/Packet/Recv/Adventure/HandlerQuickStartCocoonStageCsReq.cs b/GameServer/Server/Packet/Recv/Adventure/HandlerQuickStartCocoonStageCsReq.cs index 41b36a29..7799c0ac 100644 --- a/GameServer/Server/Packet/Recv/Adventure/HandlerQuickStartCocoonStageCsReq.cs +++ b/GameServer/Server/Packet/Recv/Adventure/HandlerQuickStartCocoonStageCsReq.cs @@ -11,12 +11,12 @@ public class HandlerQuickStartCocoonStageCsReq : Handler { var req = QuickStartCocoonStageCsReq.Parser.ParseFrom(data); var battle = - await connection.Player!.BattleManager!.StartCocoonStage((int)req.CocoonId, (int)req.Wave, + await connection.Player!.BattleManager!.StartCocoonStage((int)req.CocoonId, (int)req.CocoonChallengeTimes, (int)req.WorldLevel); connection.Player.SceneInstance?.OnEnterStage(); if (battle != null) - await connection.SendPacket(new PacketQuickStartCocoonStageScRsp(battle, (int)req.CocoonId, (int)req.Wave)); + await connection.SendPacket(new PacketQuickStartCocoonStageScRsp(battle, (int)req.CocoonId, (int)req.CocoonChallengeTimes)); else await connection.SendPacket(new PacketQuickStartCocoonStageScRsp()); } diff --git a/GameServer/Server/Packet/Recv/GridFight/HandlerGridFightStartGamePlayCsReq.cs b/GameServer/Server/Packet/Recv/GridFight/HandlerGridFightStartGamePlayCsReq.cs new file mode 100644 index 00000000..5685855a --- /dev/null +++ b/GameServer/Server/Packet/Recv/GridFight/HandlerGridFightStartGamePlayCsReq.cs @@ -0,0 +1,18 @@ +using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight; +using EggLink.DanhengServer.Kcp; +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight; + +[Opcode(CmdIds.GridFightStartGamePlayCsReq)] +public class HandlerGridFightStartGamePlayCsReq : Handler +{ + public override async Task OnHandle(Connection connection, byte[] header, byte[] data) + { + var req = GridFightStartGamePlayCsReq.Parser.ParseFrom(data); + + var res = await connection.Player!.GridFightManager!.StartGamePlay(req.Season, req.DivisionId, req.IsOverlock); + + await connection.SendPacket(new PacketGridFightStartGamePlayScRsp(res.code, res.inst)); + } +} \ No newline at end of file diff --git a/GameServer/Server/Packet/Send/Adventure/PacketQuickStartCocoonStageScRsp.cs b/GameServer/Server/Packet/Send/Adventure/PacketQuickStartCocoonStageScRsp.cs index efe21241..adf7d185 100644 --- a/GameServer/Server/Packet/Send/Adventure/PacketQuickStartCocoonStageScRsp.cs +++ b/GameServer/Server/Packet/Send/Adventure/PacketQuickStartCocoonStageScRsp.cs @@ -22,7 +22,7 @@ public class PacketQuickStartCocoonStageScRsp : BasePacket var rsp = new QuickStartCocoonStageScRsp { CocoonId = (uint)cocoonId, - Wave = (uint)wave, + CocoonChallengeTimes = (uint)wave, BattleInfo = battle.ToProto() }; diff --git a/GameServer/Server/Packet/Send/GridFight/PacketGridFightGetDataScRsp.cs b/GameServer/Server/Packet/Send/GridFight/PacketGridFightGetDataScRsp.cs index d22a76e7..4a1bcd6f 100644 --- a/GameServer/Server/Packet/Send/GridFight/PacketGridFightGetDataScRsp.cs +++ b/GameServer/Server/Packet/Send/GridFight/PacketGridFightGetDataScRsp.cs @@ -10,10 +10,12 @@ public class PacketGridFightGetDataScRsp : BasePacket { var proto = new GridFightGetDataScRsp { - RogueGetInfo = player.GridFightManager!.ToProto(), - //FightCurrentInfo = player.GridFightManager!.ToCurrentInfo() + RogueGetInfo = player.GridFightManager!.ToProto() }; + if (player.GridFightManager!.GridFightInstance != null) + proto.FightCurrentInfo = player.GridFightManager!.GridFightInstance.ToProto(); + SetData(proto); } } \ No newline at end of file diff --git a/GameServer/Server/Packet/Send/GridFight/PacketGridFightStartGamePlayScRsp.cs b/GameServer/Server/Packet/Send/GridFight/PacketGridFightStartGamePlayScRsp.cs new file mode 100644 index 00000000..28176b14 --- /dev/null +++ b/GameServer/Server/Packet/Send/GridFight/PacketGridFightStartGamePlayScRsp.cs @@ -0,0 +1,21 @@ +using EggLink.DanhengServer.GameServer.Game.GridFight; +using EggLink.DanhengServer.Kcp; +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight; + +public class PacketGridFightStartGamePlayScRsp : BasePacket +{ + public PacketGridFightStartGamePlayScRsp(Retcode ret, GridFightInstance? inst) : base(CmdIds.GridFightStartGamePlayScRsp) + { + var rsp = new GridFightStartGamePlayScRsp + { + Retcode = (uint)ret + }; + + if (inst != null) + rsp.FightCurrentInfo = inst.ToProto(); + + SetData(rsp); + } +} \ No newline at end of file