feat: friend development & battle record

This commit is contained in:
StopWuyu
2025-08-23 14:24:52 +08:00
parent 3339f44b80
commit c8e0d84f6a
20 changed files with 841 additions and 13 deletions

View File

@@ -19,6 +19,7 @@ public class ChallengeConfigExcel : ExcelResource
public int StageNum { get; set; }
public int ChallengeCountDown { get; set; }
public int MazeBuffID { get; set; }
public uint Floor { get; set; }
public List<int>? ChallengeTargetID { get; set; } = [];

View File

@@ -0,0 +1,273 @@
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
using SqlSugar;
namespace EggLink.DanhengServer.Database.Friend;
[SugarTable("friend_record_data")]
public class FriendRecordData : BaseDatabaseDataHelper
{
[SugarColumn(IsJson = true)] public List<FriendDevelopmentInfoPb> DevelopmentInfos { get; set; } = []; // max 20 entries
[SugarColumn(IsJson = true)] public Dictionary<uint, ChallengeGroupStatisticsPb> ChallengeGroupStatistics { get; set; } = []; // cur group statistics
public uint NextRecordId { get; set; }
public void AddAndRemoveOld(FriendDevelopmentInfoPb info)
{
// get same type
var same = DevelopmentInfos.Where(x => x.DevelopmentType == info.DevelopmentType);
// if param equal remove
foreach (var infoPb in same.ToArray())
{
// ReSharper disable once UsageOfDefaultStructEquality
if (infoPb.Params.SequenceEqual(info.Params))
{
// remove
DevelopmentInfos.Remove(infoPb);
}
}
DevelopmentInfos.Add(info);
}
}
public class FriendDevelopmentInfoPb
{
public DevelopmentType DevelopmentType { get; set; }
public long Time { get; set; } = Extensions.GetUnixSec();
public Dictionary<string, uint> Params { get; set; } = [];
public FriendDevelopmentInfo ToProto()
{
var proto = new FriendDevelopmentInfo
{
Time = Time,
DevelopmentType = DevelopmentType
};
switch (DevelopmentType)
{
case DevelopmentType.DevelopmentNone:
case DevelopmentType.DevelopmentActivityStart:
case DevelopmentType.DevelopmentActivityEnd:
case DevelopmentType.DevelopmentRogueMagic:
break;
case DevelopmentType.DevelopmentRogueCosmos:
case DevelopmentType.DevelopmentRogueChessNous:
case DevelopmentType.DevelopmentRogueChess:
proto.RogueDevelopmentInfo = new FriendRogueDevelopmentInfo
{
AreaId = Params.GetValueOrDefault("AreaId", 0u)
};
break;
case DevelopmentType.DevelopmentMemoryChallenge:
case DevelopmentType.DevelopmentStoryChallenge:
case DevelopmentType.DevelopmentBossChallenge:
proto.ChallengeDevelopmentInfo = new FriendChallengeDevelopmentInfo
{
ChallengeId = Params.GetValueOrDefault("ChallengeId", 0u)
};
break;
case DevelopmentType.DevelopmentUnlockAvatar:
proto.AvatarId = Params.GetValueOrDefault("AvatarId", 0u);
break;
case DevelopmentType.DevelopmentUnlockEquipment:
proto.EquipmentTid = Params.GetValueOrDefault("EquipmentTid", 0u);
break;
case DevelopmentType.DevelopmentRogueTourn:
case DevelopmentType.DevelopmentRogueTournWeek:
case DevelopmentType.DevelopmentRogueTournDivision:
proto.RogueTournDevelopmentInfo = new FriendRogueTournDevelopmentInfo
{
AreaId = Params.GetValueOrDefault("AreaId", 0u),
FinishTournDifficulty = Params.GetValueOrDefault("FinishTournDifficulty", 0u)
};
break;
case DevelopmentType.DevelopmentChallengePeak:
proto.ChallengePeakDevelopmentInfo = new FriendChallengePeakDevelopmentInfo
{
PeakLevelId = Params.GetValueOrDefault("PeakLevelId", 0u)
};
break;
}
return proto;
}
}
public class ChallengeGroupStatisticsPb
{
public uint GroupId { get; set; }
public Dictionary<uint, MemoryGroupStatisticsPb>? MemoryGroupStatistics { get; set; }
public Dictionary<uint, StoryGroupStatisticsPb>? StoryGroupStatistics { get; set; }
public Dictionary<uint, BossGroupStatisticsPb>? BossGroupStatistics { get; set; }
public ChallengeGroupStatistics ToProto()
{
var proto = new ChallengeGroupStatistics
{
GroupId = GroupId
};
if (MemoryGroupStatistics != null)
{
foreach (var memoryGroupStatistic in MemoryGroupStatistics.Values)
{
proto.GroupTotalStars += memoryGroupStatistic.Stars;
}
var maxFloor = MemoryGroupStatistics.Values.MaxBy(x => x.Level);
if (maxFloor != null)
{
proto.MemoryGroup = maxFloor.ToProto();
}
}
if (StoryGroupStatistics != null)
{
foreach (var storyGroupStatistic in StoryGroupStatistics.Values)
{
proto.GroupTotalStars += storyGroupStatistic.Stars;
}
var maxFloor = StoryGroupStatistics.Values.MaxBy(x => x.Level);
if (maxFloor != null)
{
proto.StoryGroup = maxFloor.ToProto();
}
}
if (BossGroupStatistics != null)
{
foreach (var bossGroupStatistic in BossGroupStatistics.Values)
{
proto.GroupTotalStars += bossGroupStatistic.Stars;
}
var maxFloor = BossGroupStatistics.Values.MaxBy(x => x.Level);
if (maxFloor != null)
{
proto.BossGroup = maxFloor.ToProto();
}
}
return proto;
}
}
public class MemoryGroupStatisticsPb
{
public uint RecordId { get; set; }
public uint Level { get; set; }
public uint RoundCount { get; set; }
public uint Stars { get; set; }
public List<List<ChallengeAvatarInfoPb>> Lineups { get; set; } = [];
public MemoryGroupStatistics ToProto()
{
return new MemoryGroupStatistics
{
RecordId = RecordId,
SttInfo = new MemoryStatisticsInfo
{
CurLevelStars = Stars,
Level = Level,
RoundCount = RoundCount,
LineupList =
{
Lineups.Select(x => new ChallengeLineupList
{
AvatarList = { x.Select(avatar => avatar.ToProto()) }
})
}
}
};
}
}
public class StoryGroupStatisticsPb
{
public uint RecordId { get; set; }
public uint Level { get; set; }
public uint Score { get; set; }
public uint BuffOne { get; set; }
public uint BuffTwo { get; set; }
public uint Stars { get; set; }
public List<List<ChallengeAvatarInfoPb>> Lineups { get; set; } = [];
public StoryGroupStatistics ToProto()
{
return new StoryGroupStatistics
{
RecordId = RecordId,
SttInfo = new StoryStatisticsInfo
{
CurLevelStars = Stars,
Level = Level,
LineupList =
{
Lineups.Select(x => new ChallengeLineupList
{
AvatarList = { x.Select(avatar => avatar.ToProto()) }
})
},
BuffOne = BuffOne,
BuffTwo = BuffTwo,
ScoreId = Score
}
};
}
}
public class BossGroupStatisticsPb
{
public uint RecordId { get; set; }
public uint Level { get; set; }
public uint Score { get; set; }
public uint BuffOne { get; set; }
public uint BuffTwo { get; set; }
public uint Stars { get; set; }
public List<List<ChallengeAvatarInfoPb>> Lineups { get; set; } = [];
public BossGroupStatistics ToProto()
{
return new BossGroupStatistics
{
RecordId = RecordId,
SttInfo = new BossStatisticsInfo
{
CurLevelStars = Stars,
Level = Level,
LineupList =
{
Lineups.Select(x => new ChallengeLineupList
{
AvatarList = { x.Select(avatar => avatar.ToProto()) }
})
},
BuffOne = BuffOne,
BuffTwo = BuffTwo,
ScoreId = Score
}
};
}
}
public class ChallengeAvatarInfoPb
{
public uint Level { get; set; }
public uint Index { get; set; }
public uint Id { get; set; }
public AvatarType AvatarType { get; set; } = AvatarType.AvatarFormalType;
public ChallengeAvatarInfo ToProto()
{
return new ChallengeAvatarInfo
{
Level = Level,
AvatarType = AvatarType,
Id = Id,
Index = Index
};
}
}

View File

@@ -188,14 +188,14 @@ public class PlayerData : BaseDatabaseDataHelper
var pos = 0;
foreach (var avatar in avatarInfo.AssistAvatars.Select(assist =>
avatarInfo.FormalAvatars.Find(x => x.AvatarId == assist)))
avatarInfo.FormalAvatars.Find(x => x.BaseAvatarId == assist)))
if (avatar != null)
info.AssistAvatarList.Add(avatar.ToDetailProto(pos++,
new PlayerDataCollection(this, inventoryInfo, new LineupInfo())));
pos = 0;
foreach (var avatar in avatarInfo.DisplayAvatars.Select(display =>
avatarInfo.FormalAvatars.Find(x => x.AvatarId == display)))
avatarInfo.FormalAvatars.Find(x => x.BaseAvatarId == display)))
if (avatar != null)
info.DisplayAvatarList.Add(avatar.ToDetailProto(pos++,
new PlayerDataCollection(this, inventoryInfo, new LineupInfo())));

View File

@@ -26,6 +26,8 @@ public static class GameConstants
public const uint CHALLENGE_PEAK_GOLD_FRAME_ID = 226003;
public const uint CHALLENGE_PEAK_ULTRA_FRAME_ID = 226004;
public const uint CHALLENGE_PEAK_CUR_GROUP_ID = 1;
public static readonly List<int> UpgradeWorldLevel = [20, 30, 40, 50, 60, 65];
public static readonly List<int> AllowedChessRogueEntranceId = [8020701, 8020901, 8020401, 8020201];
}

View File

@@ -2,7 +2,9 @@
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.Enums.Item;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Avatar;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.PlayerSync;
@@ -47,6 +49,16 @@ public class AvatarManager(PlayerInstance player) : BasePlayerManager(player)
AvatarData.FormalAvatars.Add(avatar);
if (avatarExcel.Rarity == RarityEnum.CombatPowerAvatarRarityType5 && avatarExcel.AvatarID <= 3000)
{
// add development
Player.FriendRecordData!.AddAndRemoveOld(new FriendDevelopmentInfoPb
{
DevelopmentType = DevelopmentType.DevelopmentUnlockAvatar,
Params = { { "AvatarId", (uint)avatarExcel.AvatarID } }
});
}
if (sync)
await Player.SendPacket(new PacketPlayerSyncScNotify(avatar));

View File

@@ -1,6 +1,7 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Challenge;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
using EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
@@ -9,6 +10,7 @@ using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using Google.Protobuf;
using System;
using static EggLink.DanhengServer.GameServer.Plugin.Event.PluginEvent;
namespace EggLink.DanhengServer.GameServer.Game.Challenge;
@@ -131,7 +133,7 @@ public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
ChallengeInstance = instance;
// Set first lineup before we enter scenes
await Player.LineupManager!.SetCurLineup(instance.GetCurrentExtraLineupType() + 10);
await Player.LineupManager!.SetExtraLineup((ExtraLineupType)instance.GetCurrentExtraLineupType());
// Enter scene
try
@@ -299,6 +301,201 @@ public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
}
}
public void SaveBattleRecord(BaseLegacyChallengeInstance inst)
{
switch (inst)
{
case ChallengeMemoryInstance memory:
{
Player.FriendRecordData!.ChallengeGroupStatistics.TryAdd((uint)memory.Config.GroupID,
new ChallengeGroupStatisticsPb
{
GroupId = (uint)memory.Config.GroupID
});
var stats = Player.FriendRecordData.ChallengeGroupStatistics[(uint)memory.Config.GroupID];
stats.MemoryGroupStatistics ??= [];
var starCount = 0u;
for (var i = 0; i < 3; i++) starCount += (memory.Data.Memory.Stars & (1 << i)) != 0 ? 1u : 0u;
if (stats.MemoryGroupStatistics.GetValueOrDefault((uint)memory.Config.ID)?.Stars >
starCount) return; // dont save if we have more stars already
var pb = new MemoryGroupStatisticsPb
{
RoundCount = (uint)(memory.Config.ChallengeCountDown - memory.Data.Memory.RoundsLeft),
Stars = starCount,
RecordId = Player.FriendRecordData!.NextRecordId++,
Level = memory.Config.Floor
};
List<ExtraLineupType> lineupTypes =
[
ExtraLineupType.LineupChallenge
];
if (memory.Config.StageNum >= 2)
lineupTypes.Add(ExtraLineupType.LineupChallenge2);
foreach (var type in lineupTypes)
{
var lineup = Player.LineupManager!.GetExtraLineup(type);
if (lineup == null) continue;
var index = 0u;
var lineupPb = new List<ChallengeAvatarInfoPb>();
foreach (var avatar in lineup.BaseAvatars ?? [])
{
var formalAvatar = Player.AvatarManager!.GetFormalAvatar(avatar.BaseAvatarId);
if (formalAvatar == null) continue;
lineupPb.Add(new ChallengeAvatarInfoPb
{
Index = index++,
Id = (uint)formalAvatar.BaseAvatarId,
AvatarType = AvatarType.AvatarFormalType,
Level = (uint)formalAvatar.Level
});
}
pb.Lineups.Add(lineupPb);
}
stats.MemoryGroupStatistics[(uint)memory.Config.ID] = pb;
break;
}
case ChallengeStoryInstance story:
{
Player.FriendRecordData!.ChallengeGroupStatistics.TryAdd((uint)story.Config.GroupID,
new ChallengeGroupStatisticsPb
{
GroupId = (uint)story.Config.GroupID
});
var stats = Player.FriendRecordData.ChallengeGroupStatistics[(uint)story.Config.GroupID];
stats.StoryGroupStatistics ??= [];
var starCount = 0u;
for (var i = 0; i < 3; i++) starCount += (story.Data.Story.Stars & (1 << i)) != 0 ? 1u : 0u;
if (stats.StoryGroupStatistics.GetValueOrDefault((uint)story.Config.ID)?.Stars >
starCount) return; // dont save if we have more stars already
var pb = new StoryGroupStatisticsPb
{
Stars = starCount,
RecordId = Player.FriendRecordData!.NextRecordId++,
Level = story.Config.Floor,
BuffOne = story.Data.Story.Buffs.Count > 0 ? story.Data.Story.Buffs[0] : 0,
BuffTwo = story.Data.Story.Buffs.Count > 1 ? story.Data.Story.Buffs[1] : 0,
Score = (uint)story.GetTotalScore()
};
List<ExtraLineupType> lineupTypes =
[
ExtraLineupType.LineupChallenge
];
if (story.Config.StageNum >= 2)
lineupTypes.Add(ExtraLineupType.LineupChallenge2);
foreach (var type in lineupTypes)
{
var lineup = Player.LineupManager!.GetExtraLineup(type);
if (lineup == null) continue;
var index = 0u;
var lineupPb = new List<ChallengeAvatarInfoPb>();
foreach (var avatar in lineup.BaseAvatars ?? [])
{
var formalAvatar = Player.AvatarManager!.GetFormalAvatar(avatar.BaseAvatarId);
if (formalAvatar == null) continue;
lineupPb.Add(new ChallengeAvatarInfoPb
{
Index = index++,
Id = (uint)formalAvatar.BaseAvatarId,
AvatarType = AvatarType.AvatarFormalType,
Level = (uint)formalAvatar.Level
});
}
pb.Lineups.Add(lineupPb);
}
stats.StoryGroupStatistics[(uint)story.Config.ID] = pb;
break;
}
case ChallengeBossInstance boss:
{
Player.FriendRecordData!.ChallengeGroupStatistics.TryAdd((uint)boss.Config.GroupID,
new ChallengeGroupStatisticsPb
{
GroupId = (uint)boss.Config.GroupID
});
var stats = Player.FriendRecordData.ChallengeGroupStatistics[(uint)boss.Config.GroupID];
stats.BossGroupStatistics ??= [];
var starCount = 0u;
for (var i = 0; i < 3; i++) starCount += (boss.Data.Boss.Stars & (1 << i)) != 0 ? 1u : 0u;
if (stats.BossGroupStatistics.GetValueOrDefault((uint)boss.Config.ID)?.Stars >
starCount) return; // dont save if we have more stars already
var pb = new BossGroupStatisticsPb
{
Stars = starCount,
RecordId = Player.FriendRecordData!.NextRecordId++,
Level = boss.Config.Floor,
BuffOne = boss.Data.Boss.Buffs.Count > 0 ? boss.Data.Boss.Buffs[0] : 0,
BuffTwo = boss.Data.Boss.Buffs.Count > 1 ? boss.Data.Boss.Buffs[1] : 0,
Score = (uint)boss.GetTotalScore()
};
List<ExtraLineupType> lineupTypes =
[
ExtraLineupType.LineupChallenge
];
if (boss.Config.StageNum >= 2)
lineupTypes.Add(ExtraLineupType.LineupChallenge2);
foreach (var type in lineupTypes)
{
var lineup = Player.LineupManager!.GetExtraLineup(type);
if (lineup == null) continue;
var index = 0u;
var lineupPb = new List<ChallengeAvatarInfoPb>();
foreach (var avatar in lineup.BaseAvatars ?? [])
{
var formalAvatar = Player.AvatarManager!.GetFormalAvatar(avatar.BaseAvatarId);
if (formalAvatar == null) continue;
lineupPb.Add(new ChallengeAvatarInfoPb
{
Index = index++,
Id = (uint)formalAvatar.BaseAvatarId,
AvatarType = AvatarType.AvatarFormalType,
Level = (uint)formalAvatar.Level
});
}
pb.Lineups.Add(lineupPb);
}
stats.BossGroupStatistics[(uint)boss.Config.ID] = pb;
break;
}
}
}
#endregion
}

View File

@@ -1,5 +1,6 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Enums.Item;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
@@ -11,6 +12,7 @@ using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
using SqlSugar;
namespace EggLink.DanhengServer.GameServer.Game.Challenge.Instances;
@@ -282,6 +284,16 @@ public class ChallengeBossInstance(PlayerInstance player, ChallengeDataPb data)
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
// save
Player.ChallengeManager.SaveBattleRecord(this);
// add development
Player.FriendRecordData!.AddAndRemoveOld(new FriendDevelopmentInfoPb
{
DevelopmentType = DevelopmentType.DevelopmentBossChallenge,
Params = {{ "ChallengeId", (uint)Config.ID } }
});
}
else
{
@@ -301,7 +313,7 @@ public class ChallengeBossInstance(PlayerInstance player, ChallengeDataPb data)
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup(GetCurrentExtraLineupType() + 10);
await Player.LineupManager!.SetExtraLineup((ExtraLineupType)GetCurrentExtraLineupType());
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)GetCurrentExtraLineupType()));
Data.Boss.SavedMp = (uint)Player.LineupManager.GetCurLineup()!.Mp;

View File

@@ -1,5 +1,6 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
@@ -171,6 +172,16 @@ public class ChallengeMemoryInstance(PlayerInstance player, ChallengeDataPb data
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
// save
Player.ChallengeManager.SaveBattleRecord(this);
// add development
Player.FriendRecordData!.AddAndRemoveOld(new FriendDevelopmentInfoPb
{
DevelopmentType = DevelopmentType.DevelopmentMemoryChallenge,
Params = { { "ChallengeId", (uint)Config.ID } }
});
}
else
{
@@ -184,7 +195,7 @@ public class ChallengeMemoryInstance(PlayerInstance player, ChallengeDataPb data
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup((int)(Data.Memory.CurrentExtraLineup + 10));
await Player.LineupManager!.SetExtraLineup((ExtraLineupType)GetCurrentExtraLineupType());
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)Data.Memory.CurrentExtraLineup));
Data.Memory.SavedMp = (uint)Player.LineupManager.GetCurLineup()!.Mp;

View File

@@ -1,5 +1,6 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
@@ -102,9 +103,16 @@ public class ChallengePeakInstance(PlayerInstance player, ChallengeDataPb data)
await Player.SendPacket(new PacketChallengePeakSettleScNotify(this, res.Item2));
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengePeakBattleFinish, this);
await Player.ChallengePeakManager!.SaveHistory(this, res.Item2);
// add development
Player.FriendRecordData!.AddAndRemoveOld(new FriendDevelopmentInfoPb
{
DevelopmentType = DevelopmentType.DevelopmentChallengePeak,
Params = { { "PeakLevelId", (uint)Config.ID } }
});
}
// Set saved technique points (This will be restored if the player resets the challenge)

View File

@@ -1,5 +1,6 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.Challenge.Definitions;
@@ -211,6 +212,16 @@ public class ChallengeStoryInstance(PlayerInstance player, ChallengeDataPb data)
// Call MissionManager
await Player.MissionManager!.HandleFinishType(MissionFinishTypeEnum.ChallengeFinish, this);
// save
Player.ChallengeManager.SaveBattleRecord(this);
// add development
Player.FriendRecordData!.AddAndRemoveOld(new FriendDevelopmentInfoPb
{
DevelopmentType = DevelopmentType.DevelopmentStoryChallenge,
Params = { { "ChallengeId", (uint)Config.ID } }
});
}
else
{
@@ -224,7 +235,7 @@ public class ChallengeStoryInstance(PlayerInstance player, ChallengeDataPb data)
// Change player line up
SetCurrentExtraLineup(ExtraLineupType.LineupChallenge2);
await Player.LineupManager!.SetCurLineup((int)(Data.Story.CurrentExtraLineup + 10));
await Player.LineupManager!.SetExtraLineup((ExtraLineupType)GetCurrentExtraLineupType());
await Player.SendPacket(new PacketChallengeLineupNotify((ExtraLineupType)Data.Story.CurrentExtraLineup));
Data.Story.SavedMp = (uint)Player.LineupManager.GetCurLineup()!.Mp;

View File

@@ -1,10 +1,8 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Database.Challenge;
using EggLink.DanhengServer.Database.Lineup;
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.GameServer.Server.Packet.Send.ChallengePeak;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
@@ -85,7 +83,7 @@ public class ChallengePeakManager(PlayerInstance player) : BasePlayerManager(pla
HashSet<uint> targetIds = [];
HashSet<uint> avatarIds = [];
if (Player.ChallengeManager!.ChallengeData.PeakBossLevelDatas.TryGetValue(bossLevelId << 2 & 0, out var bossPbData)) // easy (is hard = 0)
if (Player.ChallengeManager!.ChallengeData.PeakBossLevelDatas.TryGetValue(bossLevelId << 2 | 0, out var bossPbData)) // easy (is hard = 0)
{
bossProto.PeakEasyBoss.PeakLevelAvatarIdList.AddRange(bossPbData.BaseAvatarList);
bossProto.PeakEasyBoss.BossDisplayAvatarIdList.AddRange(bossPbData.BaseAvatarList);
@@ -316,7 +314,7 @@ public class ChallengePeakManager(PlayerInstance player) : BasePlayerManager(pla
Player.ChallengeManager!.ChallengeInstance = instance;
// Set first lineup before we enter scenes
await Player.LineupManager!.SetCurLineup((int)instance.Data.Peak.CurrentExtraLineup + 10);
await Player.LineupManager!.SetExtraLineup((ExtraLineupType)instance.Data.Peak.CurrentExtraLineup);
// Enter scene
try

View File

@@ -1,6 +1,6 @@
using System.Collections.Frozen;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.Enums.Item;
using EggLink.DanhengServer.Enums.Mission;
@@ -14,6 +14,7 @@ using EggLink.DanhengServer.GameServer.Server.Packet.Send.Scene;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
using Google.Protobuf.Collections;
using System.Collections.Frozen;
namespace EggLink.DanhengServer.GameServer.Game.Inventory;
@@ -64,6 +65,16 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
}
itemData = await PutItem(itemId, 1, rank, level: level, uniqueId: ++Data.NextUniqueId);
if (itemConfig.Rarity == ItemRarityEnum.SuperRare)
{
// add development
Player.FriendRecordData!.AddAndRemoveOld(new FriendDevelopmentInfoPb
{
DevelopmentType = DevelopmentType.DevelopmentUnlockEquipment,
Params = { { "EquipmentTid", (uint)itemConfig.ID } }
});
}
break;
case ItemMainTypeEnum.Usable:
switch (itemConfig.ItemSubType)

View File

@@ -189,6 +189,28 @@ public class LineupManager : BasePlayerManager
LineupData.CurExtraLineup = index;
}
public async ValueTask SetExtraLineup(ExtraLineupType type, bool notify = true)
{
if (type == ExtraLineupType.LineupNone)
{
// reset lineup
LineupData.CurExtraLineup = -1;
if (notify) await Player.SendPacket(new PacketSyncLineupNotify(GetCurLineup()!));
return;
}
var index = (int)type + 10;
// get cur extra lineup
var lineup = GetExtraLineup(type);
if (lineup == null || lineup.BaseAvatars?.Count == 0) return;
LineupData.CurExtraLineup = index;
// sync
if (notify) await Player.SendPacket(new PacketSyncLineupNotify(GetCurLineup()!));
}
public async ValueTask AddAvatar(int lineupIndex, int avatarId, bool sendPacket = true)
{
if (lineupIndex < 0) return;

View File

@@ -1,6 +1,7 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Database.Player;
using EggLink.DanhengServer.Database.Scene;
using EggLink.DanhengServer.Database.Tutorial;
@@ -105,6 +106,7 @@ public partial class PlayerInstance(PlayerData data)
public PlayerData Data { get; set; } = data;
public PlayerUnlockData? PlayerUnlockData { get; private set; }
public FriendRecordData? FriendRecordData { get; private set; }
public SceneData? SceneData { get; private set; }
public HeartDialData? HeartDialData { get; private set; }
public TutorialData? TutorialData { get; private set; }
@@ -198,6 +200,7 @@ public partial class PlayerInstance(PlayerData data)
TutorialGuideData = InitializeDatabase<TutorialGuideData>();
ServerPrefsData = InitializeDatabase<ServerPrefsData>();
BattleCollegeData = InitializeDatabase<BattleCollegeData>();
FriendRecordData = InitializeDatabase<FriendRecordData>();
Components.Add(new SwitchHandComponent(this));
@@ -234,6 +237,15 @@ public partial class PlayerInstance(PlayerData data)
if (ConfigManager.Config.ServerOption.EnableMission) await MissionManager!.AcceptMainMissionByCondition();
foreach (var friendDevelopmentInfoPb in FriendRecordData.DevelopmentInfos.ToArray())
{
if (Extensions.GetUnixSec() - friendDevelopmentInfoPb.Time >=
TimeSpan.TicksPerDay * 7 / TimeSpan.TicksPerSecond)
{
FriendRecordData.DevelopmentInfos.Remove(friendDevelopmentInfoPb);
}
}
await QuestManager!.AcceptQuestByCondition();
}

View File

@@ -0,0 +1,18 @@
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Challenge;
[Opcode(CmdIds.GetChallengeGroupStatisticsCsReq)]
public class HandlerGetChallengeGroupStatisticsCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GetChallengeGroupStatisticsCsReq.Parser.ParseFrom(data);
await connection.SendPacket(new PacketGetChallengeGroupStatisticsScRsp(req.GroupId,
connection.Player!.FriendRecordData!.ChallengeGroupStatistics.Values.FirstOrDefault(x =>
x.GroupId == req.GroupId)));
}
}

View File

@@ -0,0 +1,32 @@
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Challenge;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Friend;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Friend;
[Opcode(CmdIds.GetFriendBattleRecordDetailCsReq)]
public class HandlerGetFriendBattleRecordDetailCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GetFriendBattleRecordDetailCsReq.Parser.ParseFrom(data);
var uid = req.Uid;
// get data from db
var recordData = DatabaseHelper.Instance!.GetInstance<FriendRecordData>((int)uid);
var challengeData = DatabaseHelper.Instance!.GetInstance<ChallengeData>((int)uid);
var avatarData = DatabaseHelper.Instance!.GetInstance<AvatarData>((int)uid);
if (recordData == null || challengeData == null || avatarData == null)
{
await connection.SendPacket(new PacketGetFriendBattleRecordDetailScRsp(Retcode.RetFriendPlayerNotFound));
return;
}
await connection.SendPacket(new PacketGetFriendBattleRecordDetailScRsp(recordData, challengeData, avatarData));
}
}

View File

@@ -0,0 +1,27 @@
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Friend;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Friend;
[Opcode(CmdIds.GetFriendDevelopmentInfoCsReq)]
public class HandlerGetFriendDevelopmentInfoCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GetFriendDevelopmentInfoCsReq.Parser.ParseFrom(data);
var uid = req.Uid;
// get data
var recordData = DatabaseHelper.Instance!.GetInstance<FriendRecordData>((int)uid);
if (recordData == null)
{
await connection.SendPacket(new PacketGetFriendDevelopmentInfoScRsp(Retcode.RetFriendPlayerNotFound));
return;
}
await connection.SendPacket(new PacketGetFriendDevelopmentInfoScRsp(recordData));
}
}

View File

@@ -0,0 +1,37 @@
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
using System.Linq;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Challenge;
public class PacketGetChallengeGroupStatisticsScRsp : BasePacket
{
public PacketGetChallengeGroupStatisticsScRsp(uint groupId, ChallengeGroupStatisticsPb? data) : base(CmdIds.GetChallengeGroupStatisticsScRsp)
{
var proto = new GetChallengeGroupStatisticsScRsp
{
GroupId = groupId
};
var maxMemory = data?.MemoryGroupStatistics?.Values.MaxBy(x => x.Level);
if (maxMemory != null)
{
proto.MemoryGroup = maxMemory.ToProto();
}
var maxStory = data?.StoryGroupStatistics?.Values.MaxBy(x => x.Level);
if (maxStory != null)
{
proto.StoryGroup = maxStory.ToProto();
}
var maxBoss = data?.BossGroupStatistics?.Values.MaxBy(x => x.Level);
if (maxBoss != null)
{
proto.BossGroup = maxBoss.ToProto();
}
SetData(proto);
}
}

View File

@@ -0,0 +1,105 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Challenge;
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Friend;
public class PacketGetFriendBattleRecordDetailScRsp : BasePacket
{
public PacketGetFriendBattleRecordDetailScRsp(FriendRecordData recordData, ChallengeData challengeData, AvatarData avatarData) : base(
CmdIds.GetFriendBattleRecordDetailScRsp)
{
var proto = new GetFriendBattleRecordDetailScRsp
{
Uid = (uint)recordData.Uid,
ChallengeRecord = { recordData.ChallengeGroupStatistics.Values.Select(x => x.ToProto()) },
RogueRecord = new RogueStatistics()
};
var data = GameData.ChallengePeakGroupConfigData.GetValueOrDefault((int)GameConstants
.CHALLENGE_PEAK_CUR_GROUP_ID);
if (data != null)
{
var peakRec = new ChallengePeakGroupStatistics
{
GroupId = GameConstants.CHALLENGE_PEAK_CUR_GROUP_ID,
BossLevelStt = new BossLevelStatistics()
};
foreach (var preId in data.PreLevelIDList)
{
var stt = new PreLevelStatistics
{
PeakLevelId = (uint)preId,
};
var rec = challengeData.PeakLevelDatas.GetValueOrDefault(preId);
if (rec != null)
{
var index = 0u;
stt.Lineup = new ChallengeLineupList
{
AvatarList =
{
rec.BaseAvatarList.Select(x => new ChallengeAvatarInfo
{
Index = index++,
Id = x,
AvatarType = AvatarType.AvatarFormalType,
Level = (uint)(avatarData.FormalAvatars.Find(avatar => avatar.BaseAvatarId == x)?.Level ?? 1)
})
}
};
stt.PeakRoundsCount = rec.RoundCnt;
}
peakRec.PreLevelSttList.Add(stt);
}
var bossRec = challengeData.PeakBossLevelDatas.GetValueOrDefault(data.BossLevelID << 2 | 1);
bossRec ??= challengeData.PeakBossLevelDatas.GetValueOrDefault(data.BossLevelID << 2 | 0);
if (bossRec != null)
{
peakRec.BossLevelStt = new BossLevelStatistics
{
PeakLevelId = (uint)bossRec.LevelId,
BuffId = bossRec.BuffId,
Lineup = new ChallengeLineupList
{
AvatarList =
{
bossRec.BaseAvatarList.Select((x, index) => new ChallengeAvatarInfo
{
Index = (uint)index,
Id = x,
AvatarType = AvatarType.AvatarFormalType,
Level = (uint)(avatarData.FormalAvatars.Find(avatar => avatar.BaseAvatarId == x)?.Level ?? 1)
})
}
},
LeastRoundsCount = bossRec.RoundCnt
};
}
proto.PeakRecord.Add(peakRec);
}
SetData(proto);
}
public PacketGetFriendBattleRecordDetailScRsp(Retcode code) : base(CmdIds.GetFriendBattleRecordDetailScRsp)
{
var proto = new GetFriendBattleRecordDetailScRsp
{
Retcode = (uint)code
};
SetData(proto);
}
}

View File

@@ -0,0 +1,39 @@
using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Friend;
public class PacketGetFriendDevelopmentInfoScRsp : BasePacket
{
public PacketGetFriendDevelopmentInfoScRsp(Retcode code) : base(CmdIds.GetFriendDevelopmentInfoScRsp)
{
var proto = new GetFriendDevelopmentInfoScRsp
{
Retcode = (uint)code
};
SetData(proto);
}
public PacketGetFriendDevelopmentInfoScRsp(FriendRecordData data) : base(CmdIds.GetFriendDevelopmentInfoScRsp)
{
foreach (var friendDevelopmentInfoPb in data.DevelopmentInfos.ToArray())
{
if (Extensions.GetUnixSec() - friendDevelopmentInfoPb.Time >=
TimeSpan.TicksPerDay * 7 / TimeSpan.TicksPerSecond)
{
data.DevelopmentInfos.Remove(friendDevelopmentInfoPb);
}
}
var proto = new GetFriendDevelopmentInfoScRsp
{
DevelopmentList = { data.DevelopmentInfos.Select(x => x.ToProto()) },
Uid = (uint)data.Uid
};
SetData(proto);
}
}