mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-03 04:36:03 +08:00
502 lines
18 KiB
C#
502 lines
18 KiB
C#
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;
|
|
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 System;
|
|
using static EggLink.DanhengServer.GameServer.Plugin.Event.PluginEvent;
|
|
|
|
namespace EggLink.DanhengServer.GameServer.Game.Challenge;
|
|
|
|
public class ChallengeManager(PlayerInstance player) : BasePlayerManager(player)
|
|
{
|
|
#region Properties
|
|
|
|
public BaseChallengeInstance? ChallengeInstance { get; set; }
|
|
|
|
public ChallengeData ChallengeData { get; } =
|
|
DatabaseHelper.Instance!.GetInstanceOrCreateNew<ChallengeData>(player.Uid);
|
|
|
|
#endregion
|
|
|
|
#region Management
|
|
|
|
public async ValueTask StartChallenge(int challengeId, ChallengeStoryBuffInfo? storyBuffs,
|
|
ChallengeBossBuffInfo? bossBuffs)
|
|
{
|
|
// Get challenge excel
|
|
if (!GameData.ChallengeConfigData.TryGetValue(challengeId, out var value))
|
|
{
|
|
await Player.SendPacket(new PacketStartChallengeScRsp((uint)Retcode.RetChallengeNotExist));
|
|
return;
|
|
}
|
|
|
|
var excel = value;
|
|
|
|
// Sanity check lineups
|
|
if (excel.StageNum > 0)
|
|
{
|
|
// Get lineup
|
|
var lineup = Player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge)!;
|
|
|
|
// Make sure this lineup has avatars set
|
|
if (lineup.AvatarData!.FormalAvatars.Count == 0)
|
|
{
|
|
await Player.SendPacket(new PacketStartChallengeScRsp((uint)Retcode.RetChallengeLineupEmpty));
|
|
return;
|
|
}
|
|
|
|
// Reset hp/sp
|
|
foreach (var avatar in lineup.AvatarData!.FormalAvatars)
|
|
{
|
|
avatar.SetCurHp(10000, true);
|
|
avatar.SetCurSp(5000, true);
|
|
}
|
|
|
|
// Set technique points to full
|
|
lineup.Mp = 5; // Max Mp
|
|
}
|
|
|
|
if (excel.StageNum >= 2)
|
|
{
|
|
// Get lineup
|
|
var lineup = Player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge2)!;
|
|
|
|
// Make sure this lineup has avatars set
|
|
if (lineup.AvatarData!.FormalAvatars.Count == 0)
|
|
{
|
|
await Player.SendPacket(new PacketStartChallengeScRsp((uint)Retcode.RetChallengeLineupEmpty));
|
|
return;
|
|
}
|
|
|
|
// Reset hp/sp
|
|
foreach (var avatar in lineup.AvatarData!.FormalAvatars)
|
|
{
|
|
avatar.SetCurHp(10000, true);
|
|
avatar.SetCurSp(5000, true);
|
|
}
|
|
|
|
// Set technique points to full
|
|
lineup.Mp = 5; // Max Mp
|
|
}
|
|
|
|
// Set challenge data for player
|
|
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!.SetExtraLineup((ExtraLineupType)instance.GetCurrentExtraLineupType());
|
|
|
|
// Enter scene
|
|
try
|
|
{
|
|
await Player.EnterScene(excel.MapEntranceID, 0, false);
|
|
}
|
|
catch
|
|
{
|
|
// Reset lineup/instance if entering scene failed
|
|
ChallengeInstance = null;
|
|
|
|
// Send error packet
|
|
await Player.SendPacket(new PacketStartChallengeScRsp((uint)Retcode.RetChallengeNotExist));
|
|
return;
|
|
}
|
|
|
|
// Save start positions
|
|
instance.SetStartPos(Player.Data.Pos!);
|
|
instance.SetStartRot(Player.Data.Rot!);
|
|
instance.SetSavedMp(Player.LineupManager.GetCurLineup()!.Mp);
|
|
|
|
if (excel.IsStory() && storyBuffs != null)
|
|
{
|
|
instance.Data.Story.Buffs.Add(storyBuffs.BuffOne);
|
|
instance.Data.Story.Buffs.Add(storyBuffs.BuffTwo);
|
|
}
|
|
|
|
if (bossBuffs != null)
|
|
{
|
|
instance.Data.Boss.Buffs.Add(bossBuffs.BuffOne);
|
|
instance.Data.Boss.Buffs.Add(bossBuffs.BuffTwo);
|
|
}
|
|
|
|
InvokeOnPlayerEnterChallenge(Player, instance);
|
|
|
|
// Send packet
|
|
await Player.SendPacket(new PacketStartChallengeScRsp(Player));
|
|
|
|
// Save instance
|
|
SaveInstance(instance);
|
|
}
|
|
|
|
public void AddHistory(int challengeId, int stars, int score)
|
|
{
|
|
if (stars <= 0) return;
|
|
|
|
if (!ChallengeData.History.ContainsKey(challengeId))
|
|
ChallengeData.History[challengeId] = new ChallengeHistoryData(Player.Uid, challengeId);
|
|
var info = ChallengeData.History[challengeId];
|
|
|
|
// Set
|
|
info.SetStars(stars);
|
|
info.Score = score;
|
|
}
|
|
|
|
public async ValueTask<List<TakenChallengeRewardInfo>?> TakeRewards(int groupId)
|
|
{
|
|
// Get excels
|
|
if (!GameData.ChallengeGroupData.ContainsKey(groupId)) return null;
|
|
var challengeGroup = GameData.ChallengeGroupData[groupId];
|
|
|
|
if (!GameData.ChallengeRewardData.ContainsKey(challengeGroup.RewardLineGroupID)) return null;
|
|
var challengeRewardLine = GameData.ChallengeRewardData[challengeGroup.RewardLineGroupID];
|
|
|
|
// Get total stars
|
|
var totalStars = 0;
|
|
foreach (var ch in ChallengeData.History.Values)
|
|
{
|
|
// Legacy compatibility
|
|
if (ch.GroupId == 0)
|
|
{
|
|
if (!GameData.ChallengeConfigData.ContainsKey(ch.ChallengeId)) continue;
|
|
var challengeExcel = GameData.ChallengeConfigData[ch.ChallengeId];
|
|
|
|
ch.GroupId = challengeExcel.GroupID;
|
|
}
|
|
|
|
// Add total stars
|
|
if (ch.GroupId == groupId) totalStars += ch.GetTotalStars();
|
|
}
|
|
|
|
// Rewards
|
|
var rewardInfos = new List<TakenChallengeRewardInfo>();
|
|
var data = new List<ItemData>();
|
|
|
|
// Get challenge rewards
|
|
foreach (var challengeReward in challengeRewardLine)
|
|
{
|
|
// Check if we have enough stars to take this reward
|
|
if (totalStars < challengeReward.StarCount) continue;
|
|
|
|
// Get reward info
|
|
if (!ChallengeData.TakenRewards.ContainsKey(groupId))
|
|
ChallengeData.TakenRewards[groupId] = new ChallengeGroupReward(Player.Uid, groupId);
|
|
var reward = ChallengeData.TakenRewards[groupId];
|
|
|
|
// Check if reward has been taken
|
|
if (reward.HasTakenReward(challengeReward.StarCount)) continue;
|
|
|
|
// Set reward as taken
|
|
reward.SetTakenReward(challengeReward.StarCount);
|
|
|
|
// Get reward excel
|
|
if (!GameData.RewardDataData.ContainsKey(challengeReward.RewardID)) continue;
|
|
var rewardExcel = GameData.RewardDataData[challengeReward.RewardID];
|
|
|
|
// Add rewards
|
|
var proto = new TakenChallengeRewardInfo
|
|
{
|
|
StarCount = (uint)challengeReward.StarCount,
|
|
Reward = new ItemList()
|
|
};
|
|
|
|
foreach (var item in rewardExcel.GetItems())
|
|
{
|
|
var itemData = new ItemData
|
|
{
|
|
ItemId = item.Item1,
|
|
Count = item.Item2
|
|
};
|
|
|
|
proto.Reward.ItemList_.Add(itemData.ToProto());
|
|
data.Add(itemData);
|
|
}
|
|
|
|
rewardInfos.Add(proto);
|
|
}
|
|
|
|
// Add items to inventory
|
|
await Player.InventoryManager!.AddItems(data);
|
|
return rewardInfos;
|
|
}
|
|
|
|
public void SaveInstance(BaseChallengeInstance instance)
|
|
{
|
|
ChallengeData.ChallengeInstance = Convert.ToBase64String(instance.Data.ToByteArray());
|
|
}
|
|
|
|
public void ClearInstance()
|
|
{
|
|
ChallengeData.ChallengeInstance = null;
|
|
ChallengeInstance = null;
|
|
}
|
|
|
|
public void ResurrectInstance()
|
|
{
|
|
if (ChallengeData.ChallengeInstance == null) return;
|
|
var protoByte = Convert.FromBase64String(ChallengeData.ChallengeInstance);
|
|
var proto = ChallengeDataPb.Parser.ParseFrom(protoByte);
|
|
|
|
if (proto != null)
|
|
{
|
|
ChallengeInstance = proto.ChallengeTypeCase switch
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// WatchAndyTW was here |