refactor: challenge

This commit is contained in:
StopWuyu
2025-08-15 20:17:39 +08:00
parent a2948abb72
commit 9b1d029eda
38 changed files with 4243 additions and 561 deletions

View File

@@ -98,4 +98,29 @@ public class CommandUnlockAll : ICommand
await arg.Target!.Player!.SendPacket(new PacketPlayerKickOutScNotify());
arg.Target!.Stop();
}
[CommandMethod("0 challenge")]
public async ValueTask UnlockAllChallenge(CommandArg arg)
{
if (arg.Target == null)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.PlayerNotFound"));
return;
}
var player = arg.Target!.Player!;
List<int> peakList = [2200503, 2200504, 2200505, 2200506];
List<int> allList = [.. peakList];
foreach (var id in allList)
{
// finish mission
await player.QuestManager!.AcceptQuest(id);
await player.QuestManager!.FinishQuest(id);
}
await arg.SendMsg(I18NManager.Translate("Game.Command.UnlockAll.UnlockedAll",
I18NManager.Translate("Word.TypesOfChallenge")));
}
}

View File

@@ -24,6 +24,7 @@
<ItemGroup>
<ProjectReference Include="..\Proto\Proto.csproj" />
<ProjectReference Include="..\ServerSideProto\ServerSideProto.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,18 @@
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("BattleTargetConfig.json")]
public class BattleTargetConfigExcel : ExcelResource
{
public int ID { get; set; }
public int TargetParam { get; set; }
public override int GetId()
{
return ID;
}
public override void Loaded()
{
GameData.BattleTargetConfigData.TryAdd(ID, this);
}
}

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Threading;
namespace EggLink.DanhengServer.Data.Excel;
@@ -31,9 +32,9 @@ public class ChallengeConfigExcel : ExcelResource
public List<int>? NpcMonsterIDList2 { get; set; } = [];
public List<int>? EventIDList2 { get; set; } = [];
[JsonIgnore] public Dictionary<int, ChallengeMonsterInfo> ChallengeMonsters1 { get; set; } = new();
[JsonIgnore] public Dictionary<int, List<ChallengeMonsterInfo>> ChallengeMonsters1 { get; set; } = new();
[JsonIgnore] public Dictionary<int, ChallengeMonsterInfo> ChallengeMonsters2 { get; set; } = new();
[JsonIgnore] public Dictionary<int, List<ChallengeMonsterInfo>> ChallengeMonsters2 { get; set; } = new();
public override int GetId()
{
@@ -53,7 +54,7 @@ public class ChallengeConfigExcel : ExcelResource
public void SetStoryExcel(ChallengeStoryExtraExcel storyExcel)
{
StoryExcel = storyExcel;
ChallengeCountDown = storyExcel.TurnLimit;
ChallengeCountDown = (int)storyExcel.TurnLimit;
}
public void SetBossExcel(ChallengeBossExtraExcel bossExcel)
@@ -68,16 +69,18 @@ public class ChallengeConfigExcel : ExcelResource
{
if (ConfigList1[i] == 0) break;
var Monster = new ChallengeMonsterInfo(ConfigList1[i], NpcMonsterIDList1![i], EventIDList1![i]);
ChallengeMonsters1.Add(Monster.ConfigId, Monster);
var monster = new ChallengeMonsterInfo(ConfigList1[i], NpcMonsterIDList1![i], EventIDList1![i]);
ChallengeMonsters1.TryAdd(MazeGroupID1, []);
ChallengeMonsters1[MazeGroupID1].Add(monster);
}
for (var i = 0; i < ConfigList2?.Count; i++)
{
if (ConfigList2[i] == 0) break;
var Monster = new ChallengeMonsterInfo(ConfigList2[i], NpcMonsterIDList2![i], EventIDList2![i]);
ChallengeMonsters2.Add(Monster.ConfigId, Monster);
var monster = new ChallengeMonsterInfo(ConfigList2[i], NpcMonsterIDList2![i], EventIDList2![i]);
ChallengeMonsters2.TryAdd(MazeGroupID2, []);
ChallengeMonsters2[MazeGroupID2].Add(monster);
}
ConfigList1 = null;
@@ -91,10 +94,10 @@ public class ChallengeConfigExcel : ExcelResource
}
[method: JsonConstructor]
public class ChallengeMonsterInfo(int ConfigId, int NpcMonsterId, int EventId)
public class ChallengeMonsterInfo(int configId, int npcMonsterId, int eventId)
{
public int ConfigId = ConfigId;
public int EventId = EventId;
public int NpcMonsterId = NpcMonsterId;
public int ConfigId = configId;
public int EventId = eventId;
public int NpcMonsterId = npcMonsterId;
}
}

View File

@@ -0,0 +1,30 @@
using EggLink.DanhengServer.Data.Custom;
using Newtonsoft.Json;
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("ChallengePeakBossConfig.json")]
public class ChallengePeakBossConfigExcel : ExcelResource
{
public int ID { get; set; }
public int HardTarget { get; set; }
public int ColorMedalTarget { get; set; }
public List<int> HardEventIDList { get; set; } = [];
public List<int> HardTagList { get; set; } = [];
public List<int> BuffList { get; set; } = [];
public override int GetId()
{
return ID;
}
public override void Loaded()
{
GameData.ChallengePeakBossConfigData.TryAdd(ID, this);
}
public override void AfterAllDone()
{
GameData.ChallengePeakConfigData[ID].BossExcel = this;
}
}

View File

@@ -0,0 +1,38 @@
using EggLink.DanhengServer.Data.Custom;
using Newtonsoft.Json;
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("ChallengePeakConfig.json")]
public class ChallengePeakConfigExcel : ExcelResource
{
public int ID { get; set; }
public int MazeGroupID { get; set; }
public int MapEntranceID { get; set; }
public List<int> TagList { get; set; } = [];
public List<int> HPProgressValueList { get; set; } = [];
public List<int> ProgressValueList { get; set; } = [];
public List<int> ConfigIDList { get; set; } = [];
public List<int> EventIDList { get; set; } = [];
public List<int> NpcMonsterIDList { get; set; } = [];
public List<int> NormalTargetList { get; set; } = [];
[JsonIgnore] public Dictionary<int, List<ChallengeConfigExcel.ChallengeMonsterInfo>> ChallengeMonsters { get; } = [];
[JsonIgnore] public ChallengePeakBossConfigExcel? BossExcel { get; set; }
public override int GetId()
{
return ID;
}
public override void Loaded()
{
GameData.ChallengePeakConfigData.TryAdd(ID, this);
ChallengeMonsters.Add(MazeGroupID, []);
for (var i = 0; i < ConfigIDList.Count; i++)
{
ChallengeMonsters[MazeGroupID].Add(new ChallengeConfigExcel.ChallengeMonsterInfo(ConfigIDList[i], NpcMonsterIDList[i], EventIDList[i]));
}
}
}

View File

@@ -0,0 +1,22 @@
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("ChallengePeakGroupConfig.json")]
public class ChallengePeakGroupConfigExcel : ExcelResource
{
public int ID { get; set; }
public int RewardGroupID { get; set; }
public int MapEntranceID { get; set; }
public int MapEntranceBoss { get; set; }
public int BossLevelID { get; set; }
public List<int> PreLevelIDList { get; set; } = [];
public override int GetId()
{
return ID;
}
public override void Loaded()
{
GameData.ChallengePeakGroupConfigData.TryAdd(ID, this);
}
}

View File

@@ -4,7 +4,7 @@
public class ChallengeStoryExtraExcel : ExcelResource
{
public int ID { get; set; }
public int TurnLimit { get; set; }
public uint TurnLimit { get; set; }
public int ClearScore { get; set; }
public List<int>? BattleTargetID { get; set; }

View File

@@ -76,6 +76,9 @@ public static class GameData
public static Dictionary<int, ChallengeConfigExcel> ChallengeConfigData { get; private set; } = [];
public static Dictionary<int, ChallengeTargetExcel> ChallengeTargetData { get; private set; } = [];
public static Dictionary<int, ChallengeGroupExcel> ChallengeGroupData { get; private set; } = [];
public static Dictionary<int, ChallengePeakGroupConfigExcel> ChallengePeakGroupConfigData { get; private set; } = [];
public static Dictionary<int, ChallengePeakConfigExcel> ChallengePeakConfigData { get; private set; } = [];
public static Dictionary<int, ChallengePeakBossConfigExcel> ChallengePeakBossConfigData { get; private set; } = [];
public static Dictionary<int, List<ChallengeRewardExcel>> ChallengeRewardData { get; private set; } = [];
#endregion
@@ -91,6 +94,7 @@ public static class GameData
public static Dictionary<int, MonsterConfigExcel> MonsterConfigData { get; private set; } = [];
public static Dictionary<int, MonsterDropExcel> MonsterDropData { get; private set; } = [];
public static Dictionary<int, BattleCollegeConfigExcel> BattleCollegeConfigData { get; private set; } = [];
public static Dictionary<int, BattleTargetConfigExcel> BattleTargetConfigData { get; private set; } = [];
#endregion

View File

@@ -268,6 +268,22 @@ public class FormalAvatarInfo : BaseAvatarInfo
return proto;
}
public ChallengePeakAvatar ToPeakAvatarProto()
{
return new ChallengePeakAvatar
{
AvatarId = (uint)AvatarId,
EquipmentUniqueId = (uint)GetCurPathInfo().EquipId,
RelicList =
{
GetCurPathInfo().Relic.Select(relic => new EquipRelic
{
Type = (uint)relic.Key,
RelicUniqueId = (uint)relic.Value
})
}
};
}
public List<MultiPathAvatarInfo> ToAvatarPathProto()
{
var res = new List<MultiPathAvatarInfo>();

View File

@@ -9,16 +9,25 @@ public class ChallengeData : BaseDatabaseDataHelper
{
[SugarColumn(IsJson = true)] public Dictionary<int, ChallengeHistoryData> History { get; set; } = new();
[SugarColumn(IsJson = true)] public ChallengeInstanceData Instance { get; set; } = new();
[SugarColumn(IsNullable = true)] public string? ChallengeInstance { get; set; }
[SugarColumn(IsNullable = true)] public string? Instance { get; set; } = null; // placeholder
[SugarColumn(IsJson = true)] public Dictionary<int, ChallengeGroupReward> TakenRewards { get; set; } = new();
[SugarColumn(IsJson = true)] public Dictionary<int, ChallengePeakLevelData> PeakLevelDatas { get; set; } = new();
public void delete(int ChallengeId)
public void Delete(int challengeId)
{
History.Remove(ChallengeId);
History.Remove(challengeId);
}
}
public class ChallengePeakLevelData
{
public int LevelId { get; set; }
public uint PeakStar { get; set; }
public List<uint> BaseAvatarList { get; set; } = [];
}
public class ChallengeHistoryData(int uid, int challengeId)
{
public int OwnerId { get; set; } = uid;

View File

@@ -1,5 +1,6 @@
using System.Buffers.Binary;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using Newtonsoft.Json;
namespace EggLink.DanhengServer.Util;
@@ -16,6 +17,36 @@ public static class Extensions
};
}
public static Position ToPosition(this Vector3Pb vector)
{
return new Position
{
X = vector.X,
Y = vector.Y,
Z = vector.Z
};
}
public static Vector ToVector(this Position position)
{
return new Vector
{
X = position.X,
Y = position.Y,
Z = position.Z
};
}
public static Vector3Pb ToVector3Pb(this Position position)
{
return new Vector3Pb
{
X = position.X,
Y = position.Y,
Z = position.Z
};
}
public static T RandomElement<T>(this List<T> values)
{
var index = new Random().Next(values.Count);

View File

@@ -16,6 +16,7 @@ public static class GameConstants
public const int LAST_TRAIN_WORLD_ID = 501;
public const int AMBUSH_BUFF_ID = 1000102;
public const int CHALLENGE_ENTRANCE = 100000103;
public const int CHALLENGE_PEAK_ENTRANCE = 100000352;
public const int CHALLENGE_STORY_ENTRANCE = 102020107;
public const int CHALLENGE_BOSS_ENTRANCE = 1030402;
public const int CURRENT_ROGUE_TOURN_SEASON = 2;

View File

@@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proto", "Proto\Proto.csproj
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DanhengKcpSharp", "DanhengKcpSharp\DanhengKcpSharp.csproj", "{CD7EFAA3-C655-40EE-8F6A-A8E2DA3B0FCB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerSideProto", "ServerSideProto\ServerSideProto.csproj", "{1F94D996-0E35-4A56-9437-00949576D6B8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -61,6 +63,10 @@ Global
{CD7EFAA3-C655-40EE-8F6A-A8E2DA3B0FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD7EFAA3-C655-40EE-8F6A-A8E2DA3B0FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD7EFAA3-C655-40EE-8F6A-A8E2DA3B0FCB}.Release|Any CPU.Build.0 = Release|Any CPU
{1F94D996-0E35-4A56-9437-00949576D6B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F94D996-0E35-4A56-9437-00949576D6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F94D996-0E35-4A56-9437-00949576D6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F94D996-0E35-4A56-9437-00949576D6B8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,10 +1,10 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Config.Scene;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.Scene;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Challenge;
@@ -23,16 +23,23 @@ public class ChallengeEntityLoader(SceneInstance scene, PlayerInstance player) :
LoadGroups.SafeAddRange(Scene.FloorInfo!.Groups.Keys.ToList());
// Setup first stage
var excel = instance.Excel;
Scene.FloorInfo.Groups.TryGetValue(excel.MazeGroupID1, out var groupData);
if (groupData != null) await LoadGroup(groupData);
var stages = instance.GetStageMonsters();
// Set leave entry
Scene.LeaveEntryId =
instance.IsStory() ? GameConstants.CHALLENGE_STORY_ENTRANCE : GameConstants.CHALLENGE_ENTRANCE;
foreach (var stage in stages)
{
Scene.FloorInfo.Groups.TryGetValue(stage.Key, out var groupData);
if (groupData != null) await LoadGroup(groupData);
}
if (instance.IsBoss())
Scene.LeaveEntryId = GameConstants.CHALLENGE_BOSS_ENTRANCE;
Scene.LeaveEntryId = instance.Data.ChallengeTypeCase switch
{
// Set leave entry
ChallengeDataPb.ChallengeTypeOneofCase.Boss => GameConstants.CHALLENGE_BOSS_ENTRANCE,
ChallengeDataPb.ChallengeTypeOneofCase.Memory => GameConstants.CHALLENGE_ENTRANCE,
ChallengeDataPb.ChallengeTypeOneofCase.Peak => GameConstants.CHALLENGE_PEAK_ENTRANCE,
ChallengeDataPb.ChallengeTypeOneofCase.Story => GameConstants.CHALLENGE_STORY_ENTRANCE,
_ => Scene.LeaveEntryId
};
foreach (var group in Scene.FloorInfo.Groups.Values)
{
@@ -40,7 +47,7 @@ public class ChallengeEntityLoader(SceneInstance scene, PlayerInstance player) :
if (group.LoadSide != GroupLoadSideEnum.Server) continue;
// Dont load the groups that have monsters in them
if (group.PropList.Count > 0 && group.MonsterList.Count > 0) await LoadGroup(group);
if (group.PropList.Count > 0 && group.MonsterList.Count == 0) await LoadGroup(group);
}
Scene.IsLoaded = true;
@@ -56,21 +63,19 @@ public class ChallengeEntityLoader(SceneInstance scene, PlayerInstance player) :
var instance = Player.ChallengeManager.ChallengeInstance;
// Get current stage monster infos
Dictionary<int, ChallengeConfigExcel.ChallengeMonsterInfo> challengeMonsters;
if (instance.Excel.MazeGroupID1 == group.Id || instance.Excel.MazeGroupID2 == group.Id)
challengeMonsters = instance.CurrentStage == 1
? instance.Excel.ChallengeMonsters1
: instance.Excel.ChallengeMonsters2;
else
var stages = instance.GetStageMonsters();
if (!stages.TryGetValue(group.Id, out var challengeMonsters))
{
return null;
}
// Get challenge monster info
if (!challengeMonsters.ContainsKey(info.ID)) return null;
var challengeMonsterInfo = challengeMonsters[info.ID];
if (challengeMonsters.All(x => x.ConfigId != info.ID)) return null;
var challengeMonsterInfo = challengeMonsters.First(x => x.ConfigId == info.ID);
// Get excels from game data
if (!GameData.NpcMonsterDataData.ContainsKey(challengeMonsterInfo.NpcMonsterId)) return null;
var npcMonsterExcel = GameData.NpcMonsterDataData[challengeMonsterInfo.NpcMonsterId];
if (!GameData.NpcMonsterDataData.TryGetValue(challengeMonsterInfo.NpcMonsterId, out var npcMonsterExcel)) return null;
// Create monster from group monster info
var entity = new EntityMonster(Scene, info.ToPositionProto(), info.ToRotationProto(), group.Id, info.ID,
@@ -79,6 +84,7 @@ public class ChallengeEntityLoader(SceneInstance scene, PlayerInstance player) :
EventId = challengeMonsterInfo.EventId,
CustomStageId = challengeMonsterInfo.EventId
};
await Scene.AddEntity(entity, sendPacket);
return entity;

View File

@@ -1,452 +0,0 @@
using System.Text.Json.Serialization;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Challenge;
using EggLink.DanhengServer.Enums.Item;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Challenge;
public class ChallengeInstance
{
public ChallengeInstance(PlayerInstance player, ChallengeConfigExcel excel)
{
Player = player;
Excel = excel;
ChallengeId = excel.GetId();
StartPos = new Position();
StartRot = new Position();
CurrentStage = 1;
RoundsLeft = Excel.IsStory() ? 5 : Excel.ChallengeCountDown;
SetStatus(ChallengeStatus.ChallengeDoing);
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge);
}
public ChallengeInstance(PlayerInstance player, ChallengeConfigExcel excel, ChallengeInstanceData data)
{
Player = player;
Excel = excel;
StartPos = data.StartPos;
StartRot = data.StartRot;
ChallengeId = data.ChallengeId;
CurrentStage = data.CurrentStage;
CurrentExtraLineup = data.CurrentExtraLineup;
Status = data.Status;
HasAvatarDied = data.HasAvatarDied;
SavedMp = data.SavedMp;
RoundsLeft = data.RoundsLeft;
Stars = data.Stars;
ScoreStage1 = data.ScoreStage1;
ScoreStage2 = data.ScoreStage2;
StoryBuffs = data.StoryBuffs;
BossBuffs = data.BossBuffs;
}
public Position StartPos { get; set; }
public Position StartRot { get; set; }
public int ChallengeId { get; set; }
public int CurrentStage { get; set; }
public int CurrentExtraLineup { get; set; }
public int Status { get; set; }
public bool HasAvatarDied { get; set; }
public int SavedMp { get; set; }
public int RoundsLeft { get; set; }
public int Stars { get; set; }
public int ScoreStage1 { get; set; }
public int ScoreStage2 { get; set; }
[JsonIgnore] public List<BattleTarget>? BossTarget1 { get; set; }
[JsonIgnore] public List<BattleTarget>? BossTarget2 { get; set; }
[JsonIgnore] private PlayerInstance Player { get; }
[JsonIgnore] public ChallengeConfigExcel Excel { get; set; }
public List<int> StoryBuffs { get; set; } = [];
public List<int> BossBuffs { get; set; } = [];
public SceneInstance GetScene()
{
return Player.SceneInstance!;
}
public int GetChallengeId()
{
return Excel.GetId();
}
public bool IsStory()
{
return Excel.IsStory();
}
public bool IsBoss()
{
return Excel.IsBoss();
}
public void SetStatus(ChallengeStatus status)
{
Status = (int)status;
}
public void SetCurrentExtraLineup(ExtraLineupType type)
{
CurrentExtraLineup = (int)type;
}
public int GetRoundsElapsed()
{
return Excel.ChallengeCountDown - RoundsLeft;
}
public int GetTotalScore()
{
return ScoreStage1 + ScoreStage2;
}
public bool IsWin()
{
return Status == (int)ChallengeStatus.ChallengeFinish;
}
#region Serialization
public CurChallenge ToProto()
{
var proto = new CurChallenge
{
ChallengeId = (uint)Excel.GetId(),
Status = (ChallengeStatus)Status,
ScoreId = (uint)ScoreStage1,
ScoreTwo = (uint)ScoreStage2,
RoundCount = (uint)GetRoundsElapsed(),
ExtraLineupType = (ExtraLineupType)CurrentExtraLineup,
StageInfo = new ChallengeCurBuffInfo()
};
if (Excel.IsBoss())
proto.StageInfo.CurBossBuffs = new ChallengeBossBuffList
{
ChallengeBossConst = 1
};
if (Excel.IsStory()) proto.StageInfo.CurStoryBuffs = new ChallengeStoryBuffList();
if (StoryBuffs.Count >= CurrentStage)
proto.StageInfo.CurStoryBuffs.BuffList.Add(StoryBuffs.Select(x => (uint)x));
if (BossBuffs.Count >= CurrentStage)
proto.StageInfo.CurBossBuffs.BuffList.Add(BossBuffs.Select(x => (uint)x));
return proto;
}
public ChallengeStageInfo ToStageInfo()
{
var proto = new ChallengeStageInfo();
if (Excel.IsBoss())
{
proto.BossInfo = new ChallengeBossInfo
{
FirstNode = new ChallengeBossSingleNodeInfo
{
BuffId = (uint)BossBuffs[0]
},
SecondNode = new ChallengeBossSingleNodeInfo
{
BuffId = (uint)BossBuffs[1]
},
NCBDNPGPEAI = true
};
foreach (var lineupAvatar in Player.LineupManager?.GetExtraLineup(ExtraLineupType.LineupChallenge)
?.BaseAvatars ?? [])
{
var avatar = Player.AvatarManager?.GetFormalAvatar(lineupAvatar.BaseAvatarId);
if (avatar == null) continue;
proto.BossInfo.FirstLineup.Add((uint)avatar.AvatarId);
var equip = Player.InventoryManager?.GetItem(0, avatar.GetCurPathInfo().EquipId,
ItemMainTypeEnum.Equipment);
if (equip != null)
proto.BossInfo.ChallengeAvatarEquipmentMap.Add((uint)avatar.AvatarId,
equip.ToChallengeEquipmentProto());
var relicProto = new ChallengeBossAvatarRelicInfo();
foreach (var relicUniqueId in avatar.GetCurPathInfo().Relic)
{
var relic = Player.InventoryManager?.GetItem(0, relicUniqueId.Value, ItemMainTypeEnum.Relic);
if (relic == null) continue;
relicProto.AvatarRelicSlotMap.Add((uint)relicUniqueId.Key, relic.ToChallengeRelicProto());
}
proto.BossInfo.ChallengeAvatarRelicMap.Add((uint)avatar.AvatarId, relicProto);
}
foreach (var lineupAvatar in Player.LineupManager?.GetExtraLineup(ExtraLineupType.LineupChallenge2)
?.BaseAvatars ?? [])
{
var avatar = Player.AvatarManager?.GetFormalAvatar(lineupAvatar.BaseAvatarId);
if (avatar == null) continue;
proto.BossInfo.SecondLineup.Add((uint)avatar.AvatarId);
var equip = Player.InventoryManager?.GetItem(0, avatar.GetCurPathInfo().EquipId,
ItemMainTypeEnum.Equipment);
if (equip != null)
proto.BossInfo.ChallengeAvatarEquipmentMap.Add((uint)avatar.AvatarId,
equip.ToChallengeEquipmentProto());
var relicProto = new ChallengeBossAvatarRelicInfo();
foreach (var relicUniqueId in avatar.GetCurPathInfo().Relic)
{
var relic = Player.InventoryManager?.GetItem(0, relicUniqueId.Value, ItemMainTypeEnum.Relic);
if (relic == null) continue;
relicProto.AvatarRelicSlotMap.Add((uint)relicUniqueId.Key, relic.ToChallengeRelicProto());
}
proto.BossInfo.ChallengeAvatarRelicMap.Add((uint)avatar.AvatarId, relicProto);
}
}
return proto;
}
#endregion
#region Management
public void OnBattleStart(BattleInstance battle)
{
battle.RoundLimit = RoundsLeft;
battle.Buffs.Add(new MazeBuff(Excel.MazeBuffID, 1, -1));
if (StoryBuffs.Count >= CurrentStage)
{
var buffId = StoryBuffs[CurrentStage - 1];
battle.Buffs.Add(new MazeBuff(buffId, 1, -1));
}
if (Excel.StoryExcel != null)
{
battle.AddBattleTarget(1, 10002, GetTotalScore());
foreach (var id in Excel.StoryExcel.BattleTargetID!) battle.AddBattleTarget(5, id, GetTotalScore());
}
if (Excel.BossExcel != null)
{
battle.AddBattleTarget(1, 90004, 0);
battle.AddBattleTarget(1, 90005, 0);
}
}
public virtual async ValueTask OnBattleEnd(BattleInstance battle, PVEBattleResultCsReq req)
{
if (IsStory())
{
// Calculate score for current stage
var stageScore = (int)req.Stt.ChallengeScore - GetTotalScore();
// Set score
if (CurrentStage == 1)
ScoreStage1 = stageScore;
else
ScoreStage2 = stageScore;
}
if (IsBoss())
{
// Calculate score for current stage
var stageScore = 0;
foreach (var battleTarget in req.Stt.BattleTargetInfo[1].BattleTargetList_)
stageScore += (int)battleTarget.Progress;
// Set score
if (CurrentStage == 1)
ScoreStage1 = stageScore;
else
ScoreStage2 = stageScore;
}
switch (req.EndStatus)
{
case BattleEndStatus.BattleEndWin:
// Check if any avatar in the lineup has died
foreach (var avatar in battle.Lineup.AvatarData!.FormalAvatars)
if (avatar.CurrentHp <= 0)
HasAvatarDied = true;
// Get monster count in stage
long monsters = Player.SceneInstance!.Entities.Values.OfType<EntityMonster>().Count();
if (monsters == 0) await AdvanceStage(req);
// Calculate rounds left
if (!(IsStory() && IsBoss()))
RoundsLeft = (int)Math.Min(Math.Max(RoundsLeft - req.Stt.RoundCnt, 1), RoundsLeft);
// Set saved technique points (This will be restored if the player resets the challenge)
SavedMp = Player.LineupManager!.GetCurLineup()!.Mp;
break;
case BattleEndStatus.BattleEndQuit:
// Reset technique points and move back to start position
var lineup = Player.LineupManager!.GetCurLineup()!;
lineup.Mp = SavedMp;
await Player.MoveTo(StartPos, StartRot);
await Player.SendPacket(new PacketSyncLineupNotify(lineup));
break;
default:
// Determine challenge result
if ((IsStory() || IsBoss()) && req.Stt.EndReason == BattleEndReason.TurnLimit)
{
await AdvanceStage(req);
}
else
{
// Fail challenge
Status = (int)ChallengeStatus.ChallengeFailed;
// Send challenge result data
await Player.SendPacket(new PacketChallengeSettleNotify(this));
}
break;
}
}
private async ValueTask AdvanceStage(PVEBattleResultCsReq req)
{
if (CurrentStage >= Excel.StageNum)
{
// Last stage
Status = (int)ChallengeStatus.ChallengeFinish;
Stars = CalculateStars();
// Save history
Player.ChallengeManager!.AddHistory(ChallengeId, Stars, GetTotalScore());
// Send challenge result data
if (IsBoss())
await Player.SendPacket(new PacketChallengeBossPhaseSettleNotify(this, req.Stt.BattleTargetInfo[1]));
else
await Player.SendPacket(new PacketChallengeSettleNotify(this));
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
}
else
{
if (IsBoss())
{
await Player.SendPacket(new PacketChallengeBossPhaseSettleNotify(this, req.Stt.BattleTargetInfo[1]));
}
else
{
// Increment and reset stage
CurrentStage++;
// Unload scene group for stage 1
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Excel.MazeGroupID1);
// Load scene group for stage 2
await Player.SceneInstance!.EntityLoader!.LoadGroup(Excel.MazeGroupID2);
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup(CurrentExtraLineup + 10);
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)CurrentExtraLineup));
SavedMp = Player.LineupManager.GetCurLineup()!.Mp;
// Move player
if (Excel.MapEntranceID2 != 0 && Excel.MapEntranceID2 != Excel.MapEntranceID)
{
await Player.EnterScene(Excel.MapEntranceID2, 0, true);
StartPos = Player.Data.Pos!;
StartRot = Player.Data.Rot!;
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Excel.MazeGroupID1);
await Player.SceneInstance!.EntityLoader!.LoadGroup(Excel.MazeGroupID2);
}
else
{
await Player.MoveTo(StartPos, StartRot);
}
}
}
}
public async ValueTask NextPhase()
{
// Increment and reset stage
CurrentStage++;
// Load scene group for stage 2
await Player.SceneInstance!.EntityLoader!.LoadGroup(Excel.MazeGroupID2);
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup(CurrentExtraLineup + 10);
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)CurrentExtraLineup));
SavedMp = Player.LineupManager.GetCurLineup()!.Mp;
// Move player
if (Excel.MapEntranceID2 != 0)
{
await Player.EnterScene(Excel.MapEntranceID2, 0, false);
StartPos = Player.Data.Pos!;
StartRot = Player.Data.Rot!;
await Player.SceneInstance!.EntityLoader!.LoadGroup(Excel.MazeGroupID2);
}
else
{
await Player.MoveTo(StartPos, StartRot);
}
}
public void OnUpdate()
{
// End challenge if its done
if (Status != (int)ChallengeStatus.ChallengeDoing) Player.ChallengeManager!.ChallengeInstance = null;
}
public int CalculateStars()
{
var targets = Excel.ChallengeTargetID!;
var stars = 0;
for (var i = 0; i < targets.Count; i++)
{
if (!GameData.ChallengeTargetData.ContainsKey(targets[i])) continue;
var target = GameData.ChallengeTargetData[targets[i]];
switch (target.ChallengeTargetType)
{
case ChallengeTargetExcel.ChallengeType.ROUNDS_LEFT:
if (RoundsLeft >= target.ChallengeTargetParam1) stars += 1 << i;
break;
case ChallengeTargetExcel.ChallengeType.DEAD_AVATAR:
if (!HasAvatarDied) stars += 1 << i;
break;
case ChallengeTargetExcel.ChallengeType.TOTAL_SCORE:
if (GetTotalScore() >= target.ChallengeTargetParam1) stars += 1 << i;
break;
}
}
return Math.Min(stars, 7);
}
#endregion
}

View File

@@ -2,9 +2,13 @@
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Challenge;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using Google.Protobuf;
using static EggLink.DanhengServer.GameServer.Plugin.Event.PluginEvent;
namespace EggLink.DanhengServer.GameServer.Game.Challenge;
@@ -13,7 +17,7 @@ public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
{
#region Properties
public ChallengeInstance? ChallengeInstance { get; set; }
public BaseChallengeInstance? ChallengeInstance { get; set; }
public ChallengeData ChallengeData { get; } =
DatabaseHelper.Instance!.GetInstanceOrCreateNew<ChallengeData>(player.Uid);
@@ -82,11 +86,52 @@ public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
}
// Set challenge data for player
ChallengeInstance instance = new(Player, excel);
var data = new ChallengeDataPb();
BaseLegacyChallengeInstance instance;
// Set challenge type
if (excel.IsBoss())
{
data.Boss = new ChallengeBossDataPb
{
ChallengeMazeId = (uint)excel.ID,
CurStatus = 1,
CurrentStage = 1,
CurrentExtraLineup = ChallengeLineupTypePb.Challenge1
};
instance = new ChallengeBossInstance(Player, data);
}
else if (excel.IsStory())
{
data.Story = new ChallengeStoryDataPb
{
ChallengeMazeId = (uint)excel.ID,
CurStatus = 1,
CurrentStage = 1,
CurrentExtraLineup = ChallengeLineupTypePb.Challenge1
};
instance = new ChallengeStoryInstance(Player, data);
}
else
{
data.Memory = new ChallengeMemoryDataPb
{
ChallengeMazeId = (uint)excel.ID,
CurStatus = 1,
CurrentStage = 1,
CurrentExtraLineup = ChallengeLineupTypePb.Challenge1,
RoundsLeft = (uint)excel.ChallengeCountDown
};
instance = new ChallengeMemoryInstance(Player, data);
}
ChallengeInstance = instance;
// Set first lineup before we enter scenes
await Player.LineupManager!.SetCurLineup(instance.CurrentExtraLineup + 10);
await Player.LineupManager!.SetCurLineup(instance.GetCurrentExtraLineupType() + 10);
// Enter scene
try
@@ -104,20 +149,20 @@ public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
}
// Save start positions
instance.StartPos = Player.Data.Pos!;
instance.StartRot = Player.Data.Rot!;
instance.SavedMp = Player.LineupManager.GetCurLineup()!.Mp;
instance.SetStartPos(Player.Data.Pos!);
instance.SetStartRot(Player.Data.Rot!);
instance.SetSavedMp(Player.LineupManager.GetCurLineup()!.Mp);
if (excel.IsStory() && storyBuffs != null)
{
instance.StoryBuffs.Add((int)storyBuffs.BuffOne);
instance.StoryBuffs.Add((int)storyBuffs.BuffTwo);
instance.Data.Story.Buffs.Add(storyBuffs.BuffOne);
instance.Data.Story.Buffs.Add(storyBuffs.BuffTwo);
}
if (bossBuffs != null)
{
instance.BossBuffs.Add((int)bossBuffs.BuffOne);
instance.BossBuffs.Add((int)bossBuffs.BuffTwo);
instance.Data.Boss.Buffs.Add(bossBuffs.BuffOne);
instance.Data.Boss.Buffs.Add(bossBuffs.BuffTwo);
}
InvokeOnPlayerEnterChallenge(Player, instance);
@@ -220,40 +265,37 @@ public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
return rewardInfos;
}
public void SaveInstance(ChallengeInstance instance)
public void SaveInstance(BaseChallengeInstance instance)
{
ChallengeData.Instance.StartPos = instance.StartPos;
ChallengeData.Instance.StartRot = instance.StartRot;
ChallengeData.Instance.ChallengeId = instance.ChallengeId;
ChallengeData.Instance.CurrentStage = instance.CurrentStage;
ChallengeData.Instance.CurrentExtraLineup = instance.CurrentExtraLineup;
ChallengeData.Instance.Status = instance.Status;
ChallengeData.Instance.HasAvatarDied = instance.HasAvatarDied;
ChallengeData.Instance.SavedMp = instance.SavedMp;
ChallengeData.Instance.RoundsLeft = instance.RoundsLeft;
ChallengeData.Instance.Stars = instance.Stars;
ChallengeData.Instance.ScoreStage1 = instance.ScoreStage1;
ChallengeData.Instance.ScoreStage2 = instance.ScoreStage2;
ChallengeData.Instance.StoryBuffs = instance.StoryBuffs;
ChallengeData.Instance.BossBuffs = instance.BossBuffs;
ChallengeData.ChallengeInstance = Convert.ToBase64String(instance.Data.ToByteArray());
}
public void ClearInstance()
{
ChallengeData.Instance.ChallengeId = 0;
ChallengeData.ChallengeInstance = null;
ChallengeInstance = null;
}
public void ResurrectInstance()
{
if (ChallengeData.Instance != null && ChallengeData.Instance.ChallengeId != 0)
if (ChallengeData.ChallengeInstance == null) return;
var protoByte = Convert.FromBase64String(ChallengeData.ChallengeInstance);
var proto = ChallengeDataPb.Parser.ParseFrom(protoByte);
if (proto != null)
{
var ChallengeId = ChallengeData.Instance.ChallengeId;
if (GameData.ChallengeConfigData.TryGetValue(ChallengeId, out var value))
ChallengeInstance = proto.ChallengeTypeCase switch
{
var Excel = value;
var instance = new ChallengeInstance(Player, Excel, ChallengeData.Instance);
ChallengeInstance = instance;
}
ChallengeDataPb.ChallengeTypeOneofCase.Memory => new ChallengeMemoryInstance(Player, proto),
ChallengeDataPb.ChallengeTypeOneofCase.Peak => new ChallengePeakInstance(Player, proto),
ChallengeDataPb.ChallengeTypeOneofCase.Story => new ChallengeStoryInstance(Player, proto),
ChallengeDataPb.ChallengeTypeOneofCase.Boss => new ChallengeBossInstance(Player, proto),
_ => null
};
}
else
{
ChallengeData.ChallengeInstance = null;
}
}

View File

@@ -0,0 +1,27 @@
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
public abstract class BaseChallengeInstance(PlayerInstance player, ChallengeDataPb data)
{
public PlayerInstance Player { get; } = player;
public ChallengeDataPb Data { get; } = data;
public virtual void OnBattleStart(BattleInstance battle)
{
}
public virtual async ValueTask OnBattleEnd(BattleInstance battle, PVEBattleResultCsReq req)
{
await ValueTask.CompletedTask;
}
public abstract Dictionary<int, List<ChallengeConfigExcel.ChallengeMonsterInfo>> GetStageMonsters();
public virtual void OnUpdate() { }
}

View File

@@ -0,0 +1,35 @@
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
public abstract class BaseLegacyChallengeInstance(PlayerInstance player, ChallengeDataPb data) : BaseChallengeInstance(player, data)
{
public abstract CurChallenge ToProto();
public bool IsWin { get; set; }
public abstract ChallengeConfigExcel Config { get; }
public abstract uint GetStars();
public abstract int GetCurrentExtraLineupType();
public abstract void SetStartPos(Position pos);
public abstract void SetStartRot(Position rot);
public abstract void SetSavedMp(int mp);
public virtual uint GetScore1()
{
return 0;
}
public virtual uint GetScore2()
{
return 0;
}
public virtual ChallengeStageInfo ToStageInfo()
{
return new ChallengeStageInfo();
}
}

View File

@@ -0,0 +1,326 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.Item;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
public class ChallengeBossInstance(PlayerInstance player, ChallengeDataPb data) : BaseLegacyChallengeInstance(player, data)
{
#region Properties
public override ChallengeConfigExcel Config { get; } = GameData.ChallengeConfigData[(int)data.Boss.ChallengeMazeId];
#endregion
#region Setter & Getter
public override uint GetStars()
{
return Data.Boss.Stars;
}
public override uint GetScore1()
{
return Data.Boss.ScoreStage1;
}
public override uint GetScore2()
{
return Data.Boss.ScoreStage2;
}
public void SetCurrentExtraLineup(ExtraLineupType type)
{
Data.Boss.CurrentExtraLineup = (ChallengeLineupTypePb)type;
}
public int GetTotalScore()
{
return (int)(Data.Boss.ScoreStage1 + Data.Boss.ScoreStage2);
}
public override int GetCurrentExtraLineupType()
{
return (int)Data.Boss.CurrentExtraLineup;
}
public override void SetStartPos(Position pos)
{
Data.Boss.StartPos = pos.ToVector3Pb();
}
public override void SetStartRot(Position rot)
{
Data.Boss.StartRot = rot.ToVector3Pb();
}
public override void SetSavedMp(int mp)
{
Data.Boss.SavedMp = (uint)mp;
}
public override Dictionary<int, List<ChallengeConfigExcel.ChallengeMonsterInfo>> GetStageMonsters()
{
return Data.Boss.CurrentStage == 1
? Config.ChallengeMonsters1
: Config.ChallengeMonsters2;
}
#endregion
#region Serialization
public override CurChallenge ToProto()
{
return new CurChallenge
{
ChallengeId = Data.Boss.ChallengeMazeId,
ExtraLineupType = (ExtraLineupType)Data.Boss.CurrentExtraLineup,
Status = (ChallengeStatus)Data.Boss.CurStatus,
StageInfo = new ChallengeCurBuffInfo
{
CurBossBuffs = new ChallengeBossBuffList
{
BuffList = { Data.Boss.Buffs },
ChallengeBossConst = 1
}
},
RoundCount = (uint)Config.ChallengeCountDown,
ScoreId = Data.Boss.ScoreStage1,
ScoreTwo = Data.Boss.ScoreStage2,
};
}
public override ChallengeStageInfo ToStageInfo()
{
var proto = new ChallengeStageInfo
{
BossInfo = new ChallengeBossInfo
{
FirstNode = new ChallengeBossSingleNodeInfo
{
BuffId = Data.Boss.Buffs[0]
},
SecondNode = new ChallengeBossSingleNodeInfo
{
BuffId = Data.Boss.Buffs[1]
},
NCBDNPGPEAI = true
}
};
foreach (var lineupAvatar in Player.LineupManager?.GetExtraLineup(ExtraLineupType.LineupChallenge)
?.BaseAvatars ?? [])
{
var avatar = Player.AvatarManager?.GetFormalAvatar(lineupAvatar.BaseAvatarId);
if (avatar == null) continue;
proto.BossInfo.FirstLineup.Add((uint)avatar.AvatarId);
var equip = Player.InventoryManager?.GetItem(0, avatar.GetCurPathInfo().EquipId,
ItemMainTypeEnum.Equipment);
if (equip != null)
proto.BossInfo.ChallengeAvatarEquipmentMap.Add((uint)avatar.AvatarId,
equip.ToChallengeEquipmentProto());
var relicProto = new ChallengeBossAvatarRelicInfo();
foreach (var relicUniqueId in avatar.GetCurPathInfo().Relic)
{
var relic = Player.InventoryManager?.GetItem(0, relicUniqueId.Value, ItemMainTypeEnum.Relic);
if (relic == null) continue;
relicProto.AvatarRelicSlotMap.Add((uint)relicUniqueId.Key, relic.ToChallengeRelicProto());
}
proto.BossInfo.ChallengeAvatarRelicMap.Add((uint)avatar.AvatarId, relicProto);
}
foreach (var lineupAvatar in Player.LineupManager?.GetExtraLineup(ExtraLineupType.LineupChallenge2)
?.BaseAvatars ?? [])
{
var avatar = Player.AvatarManager?.GetFormalAvatar(lineupAvatar.BaseAvatarId);
if (avatar == null) continue;
proto.BossInfo.SecondLineup.Add((uint)avatar.AvatarId);
var equip = Player.InventoryManager?.GetItem(0, avatar.GetCurPathInfo().EquipId,
ItemMainTypeEnum.Equipment);
if (equip != null)
proto.BossInfo.ChallengeAvatarEquipmentMap.Add((uint)avatar.AvatarId,
equip.ToChallengeEquipmentProto());
var relicProto = new ChallengeBossAvatarRelicInfo();
foreach (var relicUniqueId in avatar.GetCurPathInfo().Relic)
{
var relic = Player.InventoryManager?.GetItem(0, relicUniqueId.Value, ItemMainTypeEnum.Relic);
if (relic == null) continue;
relicProto.AvatarRelicSlotMap.Add((uint)relicUniqueId.Key, relic.ToChallengeRelicProto());
}
proto.BossInfo.ChallengeAvatarRelicMap.Add((uint)avatar.AvatarId, relicProto);
}
return proto;
}
#endregion
#region Handlers
public override void OnBattleStart(BattleInstance battle)
{
battle.RoundLimit = Config.ChallengeCountDown;
battle.Buffs.Add(new MazeBuff(Config.MazeBuffID, 1, -1)
{
WaveFlag = -1
});
battle.AddBattleTarget(1, 90004, 0);
battle.AddBattleTarget(1, 90005, 0);
if (Data.Boss.Buffs.Count < Data.Boss.CurrentStage) return;
var buffId = Data.Boss.Buffs[(int)(Data.Boss.CurrentStage - 1)];
battle.Buffs.Add(new MazeBuff((int)buffId, 1, -1)
{
WaveFlag = -1
});
}
public override async ValueTask OnBattleEnd(BattleInstance battle, PVEBattleResultCsReq req)
{
// Calculate score for current stage
var stageScore = 0;
foreach (var battleTarget in req.Stt.BattleTargetInfo[1].BattleTargetList_)
stageScore += (int)battleTarget.Progress;
// Set score
if (Data.Boss.CurrentStage == 1)
Data.Boss.ScoreStage1 = (uint)stageScore;
else
Data.Boss.ScoreStage2 = (uint)stageScore;
switch (req.EndStatus)
{
case BattleEndStatus.BattleEndWin:
// Get monster count in stage
long monsters = Player.SceneInstance!.Entities.Values.OfType<EntityMonster>().Count();
if (monsters == 0) await AdvanceStage(req);
// Set saved technique points (This will be restored if the player resets the challenge)
Data.Boss.SavedMp = (uint)Player.LineupManager!.GetCurLineup()!.Mp;
break;
case BattleEndStatus.BattleEndQuit:
// Reset technique points and move back to start position
var lineup = Player.LineupManager!.GetCurLineup()!;
lineup.Mp = (int)Data.Boss.SavedMp;
await Player.MoveTo(Data.Boss.StartPos.ToPosition(), Data.Boss.StartRot.ToPosition());
await Player.SendPacket(new PacketSyncLineupNotify(lineup));
break;
default:
// Determine challenge result
if (req.Stt.EndReason == BattleEndReason.TurnLimit)
{
await AdvanceStage(req);
}
else
{
// Fail challenge
Data.Boss.CurStatus = (int)ChallengeStatus.ChallengeFailed;
// Send challenge result data
await Player.SendPacket(new PacketChallengeBossPhaseSettleNotify(this));
}
break;
}
}
public uint CalculateStars()
{
var targets = Config.ChallengeTargetID!;
var stars = 0u;
for (var i = 0; i < targets.Count; i++)
{
if (!GameData.ChallengeTargetData.ContainsKey(targets[i])) continue;
var target = GameData.ChallengeTargetData[targets[i]];
switch (target.ChallengeTargetType)
{
case ChallengeTargetExcel.ChallengeType.TOTAL_SCORE:
if (GetTotalScore() >= target.ChallengeTargetParam1) stars += 1u << i;
break;
}
}
return Math.Min(stars, 7);
}
private async ValueTask AdvanceStage(PVEBattleResultCsReq req)
{
if (Data.Boss.CurrentStage >= Config.StageNum)
{
// Last stage
Data.Boss.CurStatus = (int)ChallengeStatus.ChallengeFinish;
Data.Boss.Stars = CalculateStars();
// Save history
Player.ChallengeManager!.AddHistory((int)Data.Boss.ChallengeMazeId, (int)GetStars(), GetTotalScore());
// Send challenge result data
await Player.SendPacket(new PacketChallengeBossPhaseSettleNotify(this, req.Stt.BattleTargetInfo[1]));
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
}
else
{
await Player.SendPacket(new PacketChallengeBossPhaseSettleNotify(this, req.Stt.BattleTargetInfo[1]));
}
}
public async ValueTask NextPhase()
{
// Increment and reset stage
Data.Boss.CurrentStage++;
// unload current scene group
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Config.MazeGroupID1);
// Load scene group for stage 2
await Player.SceneInstance!.EntityLoader!.LoadGroup(Config.MazeGroupID2);
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup(GetCurrentExtraLineupType() + 10);
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)GetCurrentExtraLineupType()));
Data.Boss.SavedMp = (uint)Player.LineupManager.GetCurLineup()!.Mp;
// Move player
if (Config.MapEntranceID2 != 0)
{
await Player.EnterScene(Config.MapEntranceID2, 0, false);
Data.Boss.StartPos = Player.Data.Pos!.ToVector3Pb();
Data.Boss.StartRot = Player.Data.Rot!.ToVector3Pb();
await Player.SceneInstance!.EntityLoader!.LoadGroup(Config.MazeGroupID2);
}
else
{
await Player.MoveTo(Data.Boss.StartPos.ToPosition(), Data.Boss.StartRot.ToPosition());
}
Player.ChallengeManager!.SaveInstance(this);
}
#endregion
}

View File

@@ -0,0 +1,210 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
public class ChallengeMemoryInstance(PlayerInstance player, ChallengeDataPb data) : BaseLegacyChallengeInstance(player, data)
{
#region Properties
public override ChallengeConfigExcel Config { get; } = GameData.ChallengeConfigData[(int)data.Memory.ChallengeMazeId];
#endregion
#region Getter & Setter
public void SetCurrentExtraLineup(ExtraLineupType type)
{
Data.Memory.CurrentExtraLineup = (ChallengeLineupTypePb)type;
}
public override Dictionary<int, List<ChallengeConfigExcel.ChallengeMonsterInfo>> GetStageMonsters()
{
return Data.Memory.CurrentStage == 1 ? Config.ChallengeMonsters1 : Config.ChallengeMonsters2;
}
public override uint GetStars()
{
return Data.Memory.Stars;
}
public override int GetCurrentExtraLineupType()
{
return (int)Data.Memory.CurrentExtraLineup;
}
public override void SetStartPos(Position pos)
{
Data.Memory.StartPos = pos.ToVector3Pb();
}
public override void SetStartRot(Position rot)
{
Data.Memory.StartRot = rot.ToVector3Pb();
}
public override void SetSavedMp(int mp)
{
Data.Memory.SavedMp = (uint)mp;
}
#endregion
#region Serialization
public override CurChallenge ToProto()
{
return new CurChallenge
{
ChallengeId = Data.Memory.ChallengeMazeId,
DeadAvatarNum = Data.Memory.DeadAvatarNum,
ExtraLineupType = (ExtraLineupType)Data.Memory.CurrentExtraLineup,
Status = (ChallengeStatus)Data.Memory.CurStatus,
StageInfo = new ChallengeCurBuffInfo(),
RoundCount = (uint)(Config.ChallengeCountDown - Data.Memory.RoundsLeft)
};
}
#endregion
#region Handlers
public override void OnBattleStart(BattleInstance battle)
{
battle.RoundLimit = (int)Data.Memory.RoundsLeft;
battle.Buffs.Add(new MazeBuff(Config.MazeBuffID, 1, -1)
{
WaveFlag = -1
});
}
public override async ValueTask OnBattleEnd(BattleInstance battle, PVEBattleResultCsReq req)
{
switch (req.EndStatus)
{
case BattleEndStatus.BattleEndWin:
// Check if any avatar in the lineup has died
foreach (var avatar in battle.Lineup.AvatarData!.FormalAvatars)
if (avatar.CurrentHp <= 0)
Data.Memory.DeadAvatarNum++;
// Get monster count in stage
long monsters = Player.SceneInstance!.Entities.Values.OfType<EntityMonster>().Count();
if (monsters == 0) await AdvanceStage();
// Calculate rounds left
Data.Memory.RoundsLeft = Math.Min(Math.Max(Data.Memory.RoundsLeft - req.Stt.RoundCnt, 1),
Data.Memory.RoundsLeft);
// Set saved technique points (This will be restored if the player resets the challenge)
Data.Memory.SavedMp = (uint)Player.LineupManager!.GetCurLineup()!.Mp;
break;
case BattleEndStatus.BattleEndQuit:
// Reset technique points and move back to start position
var lineup = Player.LineupManager!.GetCurLineup()!;
lineup.Mp = (int)Data.Memory.SavedMp;
await Player.MoveTo(Data.Memory.StartPos.ToPosition(), Data.Memory.StartRot.ToPosition());
await Player.SendPacket(new PacketSyncLineupNotify(lineup));
break;
default:
// Determine challenge result
// Fail challenge
Data.Memory.CurStatus = (int)ChallengeStatus.ChallengeFailed;
// Send challenge result data
await Player.SendPacket(new PacketChallengeSettleNotify(this));
break;
}
}
public uint CalculateStars()
{
var targets = Config.ChallengeTargetID!;
var stars = 0u;
for (var i = 0; i < targets.Count; i++)
{
if (!GameData.ChallengeTargetData.ContainsKey(targets[i])) continue;
var target = GameData.ChallengeTargetData[targets[i]];
switch (target.ChallengeTargetType)
{
case ChallengeTargetExcel.ChallengeType.ROUNDS_LEFT:
if (Data.Memory.RoundsLeft >= target.ChallengeTargetParam1) stars += 1u << i;
break;
case ChallengeTargetExcel.ChallengeType.DEAD_AVATAR:
if (Data.Memory.DeadAvatarNum == 0) stars += 1u << i;
break;
}
}
return Math.Min(stars, 7);
}
private async ValueTask AdvanceStage()
{
if (Data.Memory.CurrentStage >= Config.StageNum)
{
// Last stage
Data.Memory.CurStatus = (int)ChallengeStatus.ChallengeFinish;
Data.Memory.Stars = CalculateStars();
// Save history
Player.ChallengeManager!.AddHistory((int)Data.Memory.ChallengeMazeId, (int)Data.Memory.Stars, 0);
// Send challenge result data
await Player.SendPacket(new PacketChallengeSettleNotify(this));
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
}
else
{
// Increment and reset stage
Data.Memory.CurrentStage++;
// Unload scene group for stage 1
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Config.MazeGroupID1);
// Load scene group for stage 2
await Player.SceneInstance!.EntityLoader!.LoadGroup(Config.MazeGroupID2);
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup((int)(Data.Memory.CurrentExtraLineup + 10));
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)Data.Memory.CurrentExtraLineup));
Data.Memory.SavedMp = (uint)Player.LineupManager.GetCurLineup()!.Mp;
// Move player
if (Config.MapEntranceID2 != 0 && Config.MapEntranceID2 != Config.MapEntranceID)
{
await Player.EnterScene(Config.MapEntranceID2, 0, true);
Data.Memory.StartPos = Player.Data.Pos!.ToVector3Pb();
Data.Memory.StartRot = Player.Data.Rot!.ToVector3Pb();
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Config.MazeGroupID1);
await Player.SceneInstance!.EntityLoader!.LoadGroup(Config.MazeGroupID2);
}
else
{
await Player.MoveTo(Data.Memory.StartPos.ToPosition(), Data.Memory.StartRot.ToPosition());
}
Player.ChallengeManager!.SaveInstance(this);
}
}
#endregion
}

View File

@@ -0,0 +1,250 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
public class ChallengeStoryInstance(PlayerInstance player, ChallengeDataPb data) : BaseLegacyChallengeInstance(player, data)
{
#region Properties
public override ChallengeConfigExcel Config { get; } = GameData.ChallengeConfigData[(int)data.Story.ChallengeMazeId];
#endregion
#region Setter & Getter
public override uint GetStars()
{
return Data.Story.Stars;
}
public override uint GetScore1()
{
return Data.Story.ScoreStage1;
}
public override uint GetScore2()
{
return Data.Story.ScoreStage2;
}
public void SetCurrentExtraLineup(ExtraLineupType type)
{
Data.Story.CurrentExtraLineup = (ChallengeLineupTypePb)type;
}
public int GetTotalScore()
{
return (int)(Data.Story.ScoreStage1 + Data.Story.ScoreStage2);
}
public override int GetCurrentExtraLineupType()
{
return (int)Data.Story.CurrentExtraLineup;
}
public override void SetStartPos(Position pos)
{
Data.Story.StartPos = pos.ToVector3Pb();
}
public override void SetStartRot(Position rot)
{
Data.Story.StartRot = rot.ToVector3Pb();
}
public override void SetSavedMp(int mp)
{
Data.Story.SavedMp = (uint)mp;
}
public override Dictionary<int, List<ChallengeConfigExcel.ChallengeMonsterInfo>> GetStageMonsters()
{
return Data.Story.CurrentStage == 1
? Config.ChallengeMonsters1
: Config.ChallengeMonsters2;
}
#endregion
#region Serialization
public override CurChallenge ToProto()
{
return new CurChallenge
{
ChallengeId = Data.Story.ChallengeMazeId,
ExtraLineupType = (ExtraLineupType)Data.Story.CurrentExtraLineup,
Status = (ChallengeStatus)Data.Story.CurStatus,
StageInfo = new ChallengeCurBuffInfo
{
CurStoryBuffs = new ChallengeStoryBuffList
{
BuffList = { Data.Story.Buffs }
}
},
RoundCount = (uint)Config.ChallengeCountDown,
ScoreId = Data.Story.ScoreStage1,
ScoreTwo = Data.Story.ScoreStage2
};
}
#endregion
#region Handlers
public override void OnBattleStart(BattleInstance battle)
{
battle.RoundLimit = Config.ChallengeCountDown;
battle.Buffs.Add(new MazeBuff(Config.MazeBuffID, 1, -1)
{
WaveFlag = -1
});
if (Config.StoryExcel == null) return;
battle.AddBattleTarget(1, 10002, GetTotalScore());
foreach (var id in Config.StoryExcel.BattleTargetID!) battle.AddBattleTarget(5, id, GetTotalScore());
if (Data.Story.Buffs.Count < Data.Story.CurrentStage) return;
var buffId = Data.Story.Buffs[(int)(Data.Story.CurrentStage - 1)];
battle.Buffs.Add(new MazeBuff((int)buffId, 1, -1)
{
WaveFlag = -1
});
}
public override async ValueTask OnBattleEnd(BattleInstance battle, PVEBattleResultCsReq req)
{
// Calculate score for current stage
var stageScore = (int)req.Stt.ChallengeScore - GetTotalScore();
// Set score
if (Data.Story.CurrentStage == 1)
Data.Story.ScoreStage1 = (uint)stageScore;
else
Data.Story.ScoreStage2 = (uint)stageScore;
switch (req.EndStatus)
{
case BattleEndStatus.BattleEndWin:
// Get monster count in stage
long monsters = Player.SceneInstance!.Entities.Values.OfType<EntityMonster>().Count();
if (monsters == 0) await AdvanceStage();
// Set saved technique points (This will be restored if the player resets the challenge)
Data.Story.SavedMp = (uint)Player.LineupManager!.GetCurLineup()!.Mp;
break;
case BattleEndStatus.BattleEndQuit:
// Reset technique points and move back to start position
var lineup = Player.LineupManager!.GetCurLineup()!;
lineup.Mp = (int)Data.Story.SavedMp;
await Player.MoveTo(Data.Story.StartPos.ToPosition(), Data.Story.StartRot.ToPosition());
await Player.SendPacket(new PacketSyncLineupNotify(lineup));
break;
default:
// Determine challenge result
if (req.Stt.EndReason == BattleEndReason.TurnLimit)
{
await AdvanceStage();
}
else
{
// Fail challenge
Data.Story.CurStatus = (int)ChallengeStatus.ChallengeFailed;
// Send challenge result data
await Player.SendPacket(new PacketChallengeSettleNotify(this));
}
break;
}
}
public uint CalculateStars()
{
var targets = Config.ChallengeTargetID!;
var stars = 0u;
for (var i = 0; i < targets.Count; i++)
{
if (!GameData.ChallengeTargetData.ContainsKey(targets[i])) continue;
var target = GameData.ChallengeTargetData[targets[i]];
switch (target.ChallengeTargetType)
{
case ChallengeTargetExcel.ChallengeType.TOTAL_SCORE:
if (GetTotalScore() >= target.ChallengeTargetParam1) stars += 1u << i;
break;
}
}
return Math.Min(stars, 7);
}
private async ValueTask AdvanceStage()
{
if (Data.Story.CurrentStage >= Config.StageNum)
{
// Last stage
Data.Story.CurStatus = (int)ChallengeStatus.ChallengeFinish;
Data.Story.Stars = CalculateStars();
// Save history
Player.ChallengeManager!.AddHistory((int)Data.Story.ChallengeMazeId, (int)GetStars(), GetTotalScore());
// Send challenge result data
await Player.SendPacket(new PacketChallengeSettleNotify(this));
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
}
else
{
// Increment and reset stage
Data.Story.CurrentStage++;
// Unload scene group for stage 1
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Config.MazeGroupID1);
// Load scene group for stage 2
await Player.SceneInstance!.EntityLoader!.LoadGroup(Config.MazeGroupID2);
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup((int)(Data.Story.CurrentExtraLineup + 10));
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)Data.Story.CurrentExtraLineup));
Data.Story.SavedMp = (uint)Player.LineupManager.GetCurLineup()!.Mp;
// Move player
if (Config.MapEntranceID2 != 0 && Config.MapEntranceID2 != Config.MapEntranceID)
{
await Player.EnterScene(Config.MapEntranceID2, 0, true);
Data.Story.StartPos = Player.Data.Pos!.ToVector3Pb();
Data.Story.StartRot = Player.Data.Rot!.ToVector3Pb();
await Player.SceneInstance!.EntityLoader!.UnloadGroup(Config.MazeGroupID1);
await Player.SceneInstance!.EntityLoader!.LoadGroup(Config.MazeGroupID2);
}
else
{
await Player.MoveTo(Data.Story.StartPos.ToPosition(), Data.Story.StartRot.ToPosition());
}
Player.ChallengeManager!.SaveInstance(this);
}
}
#endregion
}

View File

@@ -2,6 +2,7 @@
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Challenge;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
namespace EggLink.DanhengServer.GameServer.Game.Mission.FinishType.Handler;
@@ -11,16 +12,16 @@ public class MissionHandlerChallengeFinish : MissionFinishTypeHandler
{
public override async ValueTask HandleMissionFinishType(PlayerInstance player, SubMissionInfo info, object? arg)
{
if (arg is ChallengeInstance challenge)
if (challenge.Excel.ID == info.ParamInt1 && challenge.IsWin())
if (arg is BaseLegacyChallengeInstance challenge)
if (challenge.Config.ID == info.ParamInt1 && challenge.IsWin)
await player.MissionManager!.FinishSubMission(info.ID);
}
public override async ValueTask HandleQuestFinishType(PlayerInstance player, QuestDataExcel quest,
FinishWayExcel excel, object? arg)
{
if (arg is ChallengeInstance challenge)
if (challenge.Excel.ID == excel.ParamInt1 && challenge.IsWin())
if (arg is BaseLegacyChallengeInstance challenge)
if (challenge.Config.ID == excel.ParamInt1 && challenge.IsWin)
await player.QuestManager!.AddQuestProgress(quest.QuestID, 1);
}
}

View File

@@ -9,6 +9,7 @@ using EggLink.DanhengServer.GameServer.Game.Activity;
using EggLink.DanhengServer.GameServer.Game.Avatar;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge;
using EggLink.DanhengServer.GameServer.Game.ChallengePeak;
using EggLink.DanhengServer.GameServer.Game.ChessRogue;
using EggLink.DanhengServer.GameServer.Game.Friend;
using EggLink.DanhengServer.GameServer.Game.Gacha;
@@ -93,6 +94,7 @@ public partial class PlayerInstance(PlayerData data)
public MailManager? MailManager { get; private set; }
public FriendManager? FriendManager { get; private set; }
public ChallengeManager? ChallengeManager { get; private set; }
public ChallengePeakManager? ChallengePeakManager { get; private set; }
#endregion
@@ -180,6 +182,7 @@ public partial class PlayerInstance(PlayerData data)
RogueTournManager = new RogueTournManager(this);
RogueMagicManager = new RogueMagicManager(this);
ChallengeManager = new ChallengeManager(this);
ChallengePeakManager = new ChallengePeakManager(this);
TaskManager = new TaskManager(this);
RaidManager = new RaidManager(this);
StoryLineManager = new StoryLineManager(this);
@@ -274,9 +277,6 @@ public partial class PlayerInstance(PlayerData data)
AvatarManager!.GetTrialAvatar(e.SpecialAvatarID)?.CheckLevel(Data.WorldLevel);
}
await LoadScene(Data.PlaneId, Data.FloorId, Data.EntryId, Data.Pos!, Data.Rot!, false);
if (SceneInstance == null) await EnterScene(2000101, 0, false);
if (ConfigManager.Config.ServerOption.EnableMission) await MissionManager!.AcceptMainMissionByCondition();
await QuestManager!.AcceptQuestByCondition();
@@ -308,6 +308,9 @@ public partial class PlayerInstance(PlayerData data)
if (RaidManager != null)
await RaidManager.OnLogin();
await LoadScene(Data.PlaneId, Data.FloorId, Data.EntryId, Data.Pos!, Data.Rot!, false);
if (SceneInstance == null) await EnterScene(2000101, 0, false);
InvokeOnPlayerLogin(this);
}

View File

@@ -20,6 +20,7 @@
<ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\DanhengKcpSharp\DanhengKcpSharp.csproj" />
<ProjectReference Include="..\Proto\Proto.csproj" />
<ProjectReference Include="..\ServerSideProto\ServerSideProto.csproj" />
<PackageReference Include="Google.Protobuf" Version="3.29.1" />
<PackageReference Include="Google.Protobuf.Tools" Version="3.29.1" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />

View File

@@ -1,6 +1,7 @@
using EggLink.DanhengServer.Command;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
@@ -56,12 +57,12 @@ public static class PluginEvent
OnPlayerQuitBattle?.Invoke(player, result);
}
public static void InvokeOnPlayerEnterChallenge(PlayerInstance player, ChallengeInstance challenge)
public static void InvokeOnPlayerEnterChallenge(PlayerInstance player, BaseChallengeInstance challenge)
{
OnPlayerEnterChallenge?.Invoke(player, challenge);
}
public static void InvokeOnPlayerQuitChallenge(PlayerInstance player, ChallengeInstance? challenge)
public static void InvokeOnPlayerQuitChallenge(PlayerInstance player, BaseChallengeInstance? challenge)
{
OnPlayerQuitChallenge?.Invoke(player, challenge);
}
@@ -96,9 +97,9 @@ public static class PluginEvent
public delegate void OnPlayerQuitBattleHandler(PlayerInstance player, PVEBattleResultCsReq result);
public delegate void OnPlayerEnterChallengeHandler(PlayerInstance player, ChallengeInstance challenge);
public delegate void OnPlayerEnterChallengeHandler(PlayerInstance player, BaseChallengeInstance challenge);
public delegate void OnPlayerQuitChallengeHandler(PlayerInstance player, ChallengeInstance? challenge);
public delegate void OnPlayerQuitChallengeHandler(PlayerInstance player, BaseChallengeInstance? challenge);
public delegate void OnPlayerSyncLineupHandler(PlayerInstance player, LineupInfo? lineup);

View File

@@ -146,6 +146,7 @@ public class Connection(KcpConversation conversation, IPEndPoint remote) : Danhe
catch (Exception e)
{
Logger.Error("An error occured ", e);
// get the packet rsp and set retCode to Retcode.RetFail
var curPacket = LogMap.GetValueOrDefault(opcode);
if (curPacket == null) return;

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
@@ -9,13 +10,13 @@ public class HandlerEnterChallengeNextPhaseCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
if (connection.Player!.ChallengeManager?.ChallengeInstance == null)
if (connection.Player!.ChallengeManager?.ChallengeInstance is not ChallengeBossInstance boss)
{
await connection.SendPacket(new PacketEnterChallengeNextPhaseScRsp(Retcode.RetChallengeNotDoing));
return;
}
await connection.Player.ChallengeManager.ChallengeInstance.NextPhase();
await boss.NextPhase();
await connection.SendPacket(new PacketEnterChallengeNextPhaseScRsp(connection.Player));
}
}

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Game.Challenge;
using EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
@@ -6,20 +7,20 @@ namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
public class PacketChallengeBossPhaseSettleNotify : BasePacket
{
public PacketChallengeBossPhaseSettleNotify(ChallengeInstance challenge, BattleTargetList? targetLists = null) :
public PacketChallengeBossPhaseSettleNotify(ChallengeBossInstance challenge, BattleTargetList? targetLists = null) :
base(CmdIds
.ChallengeBossPhaseSettleNotify)
{
var proto = new ChallengeBossPhaseSettleNotify
{
ChallengeId = (uint)challenge.Excel.ID,
IsWin = challenge.IsWin(),
ChallengeScore = (uint)challenge.ScoreStage1,
ScoreTwo = (uint)challenge.ScoreStage2,
Star = (uint)challenge.Stars,
Phase = (uint)challenge.CurrentStage,
ChallengeId = (uint)challenge.Config.ID,
IsWin = challenge.IsWin,
ChallengeScore = challenge.Data.Boss.ScoreStage1,
ScoreTwo = challenge.Data.Boss.ScoreStage2,
Star = challenge.Data.Boss.Stars,
Phase = challenge.Data.Boss.CurrentStage,
IsReward = true,
IsSecondHalf = challenge.CurrentStage == challenge.Excel.StageNum,
IsSecondHalf = challenge.Data.Boss.CurrentStage == challenge.Config.StageNum,
PageType = 1
};

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Game.Challenge;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
@@ -6,15 +7,15 @@ namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
public class PacketChallengeSettleNotify : BasePacket
{
public PacketChallengeSettleNotify(ChallengeInstance challenge) : base(CmdIds.ChallengeSettleNotify)
public PacketChallengeSettleNotify(BaseLegacyChallengeInstance challenge) : base(CmdIds.ChallengeSettleNotify)
{
var proto = new ChallengeSettleNotify
{
ChallengeId = (uint)challenge.Excel.ID,
IsWin = challenge.IsWin(),
ChallengeScore = (uint)challenge.ScoreStage1,
ScoreTwo = (uint)challenge.ScoreStage2,
Star = (uint)challenge.Stars,
ChallengeId = (uint)challenge.Config.ID,
IsWin = challenge.IsWin,
ChallengeScore = challenge.GetScore1(),
ScoreTwo = challenge.GetScore2(),
Star = challenge.GetStars(),
Reward = new ItemList()
};

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
@@ -10,13 +11,12 @@ public class PacketGetCurChallengeScRsp : BasePacket
{
var proto = new GetCurChallengeScRsp();
if (player.ChallengeManager!.ChallengeInstance != null)
if (player.ChallengeManager!.ChallengeInstance is BaseLegacyChallengeInstance inst)
{
proto.CurChallenge = player.ChallengeManager.ChallengeInstance.ToProto();
proto.CurChallenge = inst.ToProto();
Task.Run(async () =>
{
await player.LineupManager!.SetCurLineup(player.ChallengeManager.ChallengeInstance
.CurrentExtraLineup + 10);
await player.LineupManager!.SetCurLineup(inst.GetCurrentExtraLineupType() + 10);
}).Wait();
var proto1 = player.LineupManager?.GetExtraLineup(ExtraLineupType.LineupChallenge)?.ToProto();
if (proto1 != null)

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
@@ -22,8 +23,12 @@ public class PacketStartChallengeScRsp : BasePacket
if (player.ChallengeManager!.ChallengeInstance != null)
{
proto.CurChallenge = player.ChallengeManager.ChallengeInstance.ToProto();
proto.StageInfo = player.ChallengeManager.ChallengeInstance.ToStageInfo();
if (player.ChallengeManager.ChallengeInstance is BaseLegacyChallengeInstance inst)
{
proto.CurChallenge = inst.ToProto();
proto.StageInfo = inst.ToStageInfo();
}
proto.LineupList.Add(player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge)!.ToProto());
proto.LineupList.Add(player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge2)!.ToProto());
if (sendScene) proto.Scene = player.SceneInstance!.ToProto();

View File

@@ -23,7 +23,7 @@ public class PacketGetMissionDataScRsp : BasePacket
Status = MissionStatus.MissionDoing
});
foreach (var mission in GameData.SubMissionInfoData.Keys)
foreach (var mission in GameData.SubMissionInfoData.Keys.Concat(GameData.SubMissionData.Keys))
if (player.MissionManager!.GetSubMissionStatus(mission) == MissionPhaseEnum.Accept)
proto.MissionList.Add(new Proto.Mission
{

View File

@@ -8,6 +8,7 @@ using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Enums;
using EggLink.DanhengServer.Enums.Rogue;
using EggLink.DanhengServer.GameServer.Command;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Plugin;
using EggLink.DanhengServer.GameServer.Server;
using EggLink.DanhengServer.GameServer.Server.Packet;
@@ -280,13 +281,14 @@ public class EntryPoint
_ => PlayerStatusEnum.Rogue
};
}
else if ((con as Connection)!.Player!.ChallengeManager?.ChallengeInstance != null)
else if ((con as Connection)!.Player!.ChallengeManager?.ChallengeInstance is
BaseLegacyChallengeInstance inst)
{
status = PlayerStatusEnum.Challenge;
if ((con as Connection)!.Player?.ChallengeManager?.ChallengeInstance?.Excel.StoryExcel != null)
if (inst.Config.StoryExcel != null)
status = PlayerStatusEnum.ChallengeStory;
else if ((con as Connection)!.Player?.ChallengeManager?.ChallengeInstance?.Excel.BossExcel !=
null)
else if (inst.Config.BossExcel != null)
status = PlayerStatusEnum.ChallengeBoss;
}
else if ((con as Connection)!.Player!.RaidManager?.RaidData.CurRaidId != 0)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
syntax = "proto3";
option csharp_namespace = "EggLink.DanhengServer.Proto.ServerSide";
enum ChallengeLineupTypePb {
None = 0;
Challenge1 = 1;
Challenge2 = 3;
Challenge3 = 4;
}
message Vector3Pb {
int32 x = 1;
int32 y = 2;
int32 z = 3;
}
message ChallengeMemoryDataPb {
uint32 ChallengeMazeId = 1;
Vector3Pb StartPos = 2;
Vector3Pb StartRot = 3;
uint32 CurrentStage = 4;
uint32 CurStatus = 5;
uint32 DeadAvatarNum = 6;
uint32 SavedMp = 7;
ChallengeLineupTypePb CurrentExtraLineup = 8;
uint32 RoundsLeft = 9;
uint32 Stars = 10;
}
message ChallengeStoryDataPb {
uint32 ChallengeMazeId = 1;
Vector3Pb StartPos = 2;
Vector3Pb StartRot = 3;
uint32 CurrentStage = 4;
uint32 CurStatus = 5;
uint32 SavedMp = 6;
ChallengeLineupTypePb CurrentExtraLineup = 7;
uint32 Stars = 8;
uint32 ScoreStage1 = 9;
uint32 ScoreStage2 = 10;
repeated uint32 Buffs = 11;
}
message ChallengeBossDataPb {
uint32 ChallengeMazeId = 1;
Vector3Pb StartPos = 2;
Vector3Pb StartRot = 3;
uint32 CurrentStage = 4;
uint32 CurStatus = 5;
uint32 SavedMp = 6;
ChallengeLineupTypePb CurrentExtraLineup = 7;
uint32 Stars = 8;
uint32 ScoreStage1 = 9;
uint32 ScoreStage2 = 10;
repeated uint32 Buffs = 11;
}
message ChallengePeakDataPb {
uint32 CurrentPeakLevelId = 2;
repeated uint32 Buffs = 3;
uint32 CurStatus = 4;
Vector3Pb StartPos = 5;
Vector3Pb StartRot = 6;
uint32 SavedMp = 7;
uint32 Stars = 8;
ChallengeLineupTypePb CurrentExtraLineup = 9;
bool IsHard = 10;
}
message ChallengeDataPb {
oneof challenge_type {
ChallengeMemoryDataPb memory = 1;
ChallengeStoryDataPb story = 2;
ChallengeBossDataPb boss = 3;
ChallengePeakDataPb peak = 4;
}
}

View File

@@ -0,0 +1,4 @@
@echo off
del /s /f .\*.cs
cd ProtoFile
protoc ".\*" --csharp_out=..\

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>EggLink.DanhengServer.Proto.ServerSide</RootNamespace>
<AssemblyName>DanhengSProto</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.29.1" />
</ItemGroup>
</Project>