416 lines
15 KiB
C#
416 lines
15 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description:
|
||
* @Date: 2025年09月05日 星期五 15:09:09
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System.Collections.Generic;
|
||
using Logic.CrashSight;
|
||
using MemoryPack;
|
||
using RuntimeData;
|
||
using TH1_Logic.Collect;
|
||
|
||
|
||
namespace TH1_Logic.MatchConfig
|
||
{
|
||
public enum MatchSettlementType
|
||
{
|
||
None = 0,
|
||
Domination = 1,
|
||
Perfect = 2,
|
||
Tutor = 3,
|
||
Story = 4,
|
||
Creative = 5,
|
||
}
|
||
|
||
|
||
[MemoryPackable]
|
||
public partial class MatchSettlementInfo
|
||
{
|
||
public MatchSettlementType SettlementType;
|
||
public bool IsFinished;
|
||
public Dictionary<uint, PlayerSettlementGroup> PlayerSettlements;
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
public MatchSettlementInfo()
|
||
{
|
||
IsFinished = false;
|
||
PlayerSettlements = new Dictionary<uint, PlayerSettlementGroup>();
|
||
}
|
||
|
||
public void Init(MapData map, MapConfig config)
|
||
{
|
||
SettlementType = config?.MatchSettlement ?? MatchSettlementType.None;
|
||
IsFinished = false;
|
||
PlayerSettlements ??= new Dictionary<uint, PlayerSettlementGroup>();
|
||
PlayerSettlements.Clear();
|
||
var protectedSettlements = BuildProtectedSettlements(config);
|
||
foreach (var player in map.PlayerMap.PlayerDataList)
|
||
{
|
||
PlayerSettlements[player.Id] = new PlayerSettlementGroup();
|
||
PlayerSettlements[player.Id].Init(protectedSettlements);
|
||
}
|
||
}
|
||
|
||
public bool IsWin(uint id)
|
||
{
|
||
if (!IsFinished) return false;
|
||
var settlementGroup = PlayerSettlements.GetValueOrDefault(id);
|
||
if (settlementGroup == null) return false;
|
||
return settlementGroup.IsWin;
|
||
}
|
||
|
||
public MatchSettlementInfo(MatchSettlementInfo copyData)
|
||
{
|
||
SettlementType = copyData.SettlementType;
|
||
IsFinished = copyData.IsFinished;
|
||
PlayerSettlements = new Dictionary<uint, PlayerSettlementGroup>();
|
||
foreach (var kv in copyData.PlayerSettlements)
|
||
{
|
||
PlayerSettlements[kv.Key] = new PlayerSettlementGroup(kv.Value);
|
||
}
|
||
}
|
||
|
||
public void DeepCopy(MatchSettlementInfo copyData)
|
||
{
|
||
SettlementType = copyData.SettlementType;
|
||
IsFinished = copyData.IsFinished;
|
||
PlayerSettlements ??= new Dictionary<uint, PlayerSettlementGroup>();
|
||
PlayerSettlements.Clear();
|
||
foreach (var kv in copyData.PlayerSettlements)
|
||
{
|
||
PlayerSettlements[kv.Key] = new PlayerSettlementGroup(kv.Value);
|
||
}
|
||
}
|
||
|
||
private static List<PlayerSettlementInfo> BuildProtectedSettlements(MapConfig config)
|
||
{
|
||
var protectedSettlements = new List<PlayerSettlementInfo>();
|
||
var sourceSettlements = config?.PlayerSettlements;
|
||
if (sourceSettlements != null)
|
||
{
|
||
foreach (var sourceSettlement in sourceSettlements)
|
||
{
|
||
if (sourceSettlement == null)
|
||
{
|
||
LogSystem.LogWarning("MatchSettlement.Init: 检测到空的 PlayerSettlementInfo,已跳过。");
|
||
continue;
|
||
}
|
||
|
||
protectedSettlements.Add(BuildProtectedSettlement(
|
||
sourceSettlement,
|
||
config?.MatchSettlement ?? MatchSettlementType.None));
|
||
}
|
||
}
|
||
|
||
if (protectedSettlements.Count > 0) return protectedSettlements;
|
||
|
||
LogSystem.LogWarning(
|
||
$"MatchSettlement.Init: 结算配置为空或无效,已注入默认结算任务。MatchType={config?.MatchSettlement}");
|
||
protectedSettlements.Add(CreateFallbackSettlement(config?.MatchSettlement ?? MatchSettlementType.None));
|
||
return protectedSettlements;
|
||
}
|
||
|
||
private static PlayerSettlementInfo BuildProtectedSettlement(
|
||
PlayerSettlementInfo sourceSettlement,
|
||
MatchSettlementType matchType)
|
||
{
|
||
var settlementType = sourceSettlement.SettlementType;
|
||
if (settlementType == PlayerSettlementType.None)
|
||
{
|
||
LogSystem.LogWarning("MatchSettlement.Init: SettlementType=None,已自动修正为 AllSuccessOrFailure。");
|
||
settlementType = PlayerSettlementType.AllSuccessOrFailure;
|
||
}
|
||
|
||
var settlement = new PlayerSettlementInfo
|
||
{
|
||
SettlementType = settlementType,
|
||
IsSettlement = false,
|
||
IsWin = false,
|
||
Tasks = new List<PlayerTaskInfo>()
|
||
};
|
||
|
||
if (sourceSettlement.Tasks != null)
|
||
{
|
||
foreach (var sourceTask in sourceSettlement.Tasks)
|
||
{
|
||
if (sourceTask == null)
|
||
{
|
||
LogSystem.LogWarning("MatchSettlement.Init: 检测到空的 PlayerTaskInfo,已跳过。");
|
||
continue;
|
||
}
|
||
|
||
if (sourceTask.TaskType == PlayerTaskType.None)
|
||
{
|
||
LogSystem.LogWarning("MatchSettlement.Init: TaskType=None,已跳过该任务。");
|
||
continue;
|
||
}
|
||
|
||
settlement.Tasks.Add(new PlayerTaskInfo
|
||
{
|
||
TaskType = sourceTask.TaskType,
|
||
IsSettlement = false,
|
||
IsSuccess = false,
|
||
Param1 = sourceTask.Param1,
|
||
Param2 = sourceTask.Param2,
|
||
Param3 = sourceTask.Param3,
|
||
Param4 = sourceTask.Param4,
|
||
Param1Cur = 0,
|
||
Param2Cur = 0,
|
||
Param3Cur = 0
|
||
});
|
||
}
|
||
}
|
||
|
||
if (settlement.Tasks.Count > 0) return settlement;
|
||
|
||
LogSystem.LogWarning("MatchSettlement.Init: 结算器任务为空或无效,已注入默认任务。");
|
||
settlement.Tasks.Add(CreateFallbackTask(matchType));
|
||
return settlement;
|
||
}
|
||
|
||
private static PlayerSettlementInfo CreateFallbackSettlement(MatchSettlementType matchType)
|
||
{
|
||
return new PlayerSettlementInfo
|
||
{
|
||
SettlementType = PlayerSettlementType.AllSuccessOrFailure,
|
||
IsSettlement = false,
|
||
IsWin = false,
|
||
Tasks = new List<PlayerTaskInfo> { CreateFallbackTask(matchType) }
|
||
};
|
||
}
|
||
|
||
private static PlayerTaskInfo CreateFallbackTask(MatchSettlementType matchType)
|
||
{
|
||
// 教程/剧情默认给可收敛的生存任务;其他模式默认给“其他玩家死亡”任务(N-1)
|
||
if (matchType == MatchSettlementType.Tutor || matchType == MatchSettlementType.Story)
|
||
{
|
||
return new PlayerTaskInfo
|
||
{
|
||
TaskType = PlayerTaskType.SurviveOrLoseMatch,
|
||
IsSettlement = false,
|
||
IsSuccess = false,
|
||
Param1 = 1,
|
||
Param2 = 0,
|
||
Param3 = 0,
|
||
Param4 = UnitType.None,
|
||
Param1Cur = 0,
|
||
Param2Cur = 0,
|
||
Param3Cur = 0
|
||
};
|
||
}
|
||
|
||
return new PlayerTaskInfo
|
||
{
|
||
TaskType = PlayerTaskType.OtherDie,
|
||
IsSettlement = false,
|
||
IsSuccess = false,
|
||
Param1 = -1,
|
||
Param2 = 0,
|
||
Param3 = 0,
|
||
Param4 = UnitType.None,
|
||
Param1Cur = 0,
|
||
Param2Cur = 0,
|
||
Param3Cur = 0
|
||
};
|
||
}
|
||
}
|
||
|
||
|
||
public class MatchSettlementLogicFactory
|
||
{
|
||
private static Dictionary<MatchSettlementType, IMatchSettlement> _logicDict = new Dictionary<MatchSettlementType, IMatchSettlement>()
|
||
{
|
||
{ MatchSettlementType.Domination, new DominationMatchSettlement() },
|
||
{ MatchSettlementType.Perfect, new PerfectMatchSettlement() },
|
||
{ MatchSettlementType.Tutor, new TutorMatchSettlement() },
|
||
{ MatchSettlementType.Story, new StoryMatchSettlement() },
|
||
{ MatchSettlementType.Creative, new StoryMatchSettlement() },
|
||
};
|
||
|
||
public static void RefreshMatchSettlementInfo(MapData map)
|
||
{
|
||
if (!_logicDict.TryGetValue(map.MatchSettlement.SettlementType, out var logic))
|
||
{
|
||
LogSystem.LogError($"RefreshPlayerSettlementInfo Error TaskType:{map.MatchSettlement.SettlementType} No Logic");
|
||
return;
|
||
}
|
||
|
||
foreach (var kv in map.MatchSettlement.PlayerSettlements)
|
||
{
|
||
var player = map.PlayerMap.GetPlayerData(kv.Key);
|
||
if (player == null)
|
||
{
|
||
LogSystem.LogError($"RefreshMatchSettlementInfo Error Player is null");
|
||
continue;
|
||
}
|
||
PlayerSettlementGroup.RefreshPlayerSettlementGroup(map, player, kv.Value);
|
||
}
|
||
logic.Refresh(map, map.MatchSettlement);
|
||
|
||
// DEBUG: 输出结算状态
|
||
/*if (!map.MatchSettlement.IsFinished)
|
||
{
|
||
var debugStr = $"[Settlement] Type={map.MatchSettlement.SettlementType} IsFinished={map.MatchSettlement.IsFinished} PlayerCount={map.MatchSettlement.PlayerSettlements.Count}";
|
||
foreach (var kv in map.MatchSettlement.PlayerSettlements)
|
||
{
|
||
var p = map.PlayerMap.GetPlayerData(kv.Key);
|
||
var isAI = map.CheckIsAI(kv.Key);
|
||
var taskCount = 0;
|
||
foreach (var s in kv.Value.Settlements) taskCount += s.Tasks?.Count ?? 0;
|
||
debugStr += $"\n Player{kv.Key}(AI={isAI},Alive={p?.IsSurvival}): Group.IsSettlement={kv.Value.IsSettlement} IsWin={kv.Value.IsWin} Settlements={kv.Value.Settlements.Count} Tasks={taskCount}";
|
||
foreach (var s in kv.Value.Settlements)
|
||
{
|
||
debugStr += $"\n Settlement(Type={s.SettlementType}): IsSettled={s.IsSettlement} IsWin={s.IsWin}";
|
||
if (s.Tasks != null)
|
||
foreach (var t in s.Tasks)
|
||
debugStr += $"\n Task(Type={t.TaskType} P1={t.Param1}): IsSettled={t.IsSettlement} IsSuccess={t.IsSuccess} Cur={t.Param1Cur}";
|
||
}
|
||
}
|
||
UnityEngine.Debug.Log(debugStr);
|
||
}*/
|
||
}
|
||
}
|
||
|
||
|
||
public abstract class IMatchSettlement
|
||
{
|
||
public abstract MatchSettlementType GetSettlementType();
|
||
public abstract void Refresh(MapData map, MatchSettlementInfo info);
|
||
}
|
||
|
||
|
||
// DOMINATION 任意玩家结算且为胜,游戏结束 所有非AI玩家结算且均为败,游戏结束
|
||
public class DominationMatchSettlement : IMatchSettlement
|
||
{
|
||
public override MatchSettlementType GetSettlementType()
|
||
{
|
||
return MatchSettlementType.Domination;
|
||
}
|
||
|
||
public override void Refresh(MapData map, MatchSettlementInfo info)
|
||
{
|
||
if (info.IsFinished) return;
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (kv.Value.IsSettlement && kv.Value.IsWin)
|
||
{
|
||
info.IsFinished = true;
|
||
return;
|
||
}
|
||
}
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (map.CheckIsAI(kv.Key)) continue;
|
||
if (kv.Value.IsSettlement && !kv.Value.IsWin) continue;
|
||
return;
|
||
}
|
||
info.IsFinished = true;
|
||
}
|
||
}
|
||
|
||
// PERFECT 所有非AI玩家均结算后,游戏结束
|
||
public class PerfectMatchSettlement : IMatchSettlement
|
||
{
|
||
public override MatchSettlementType GetSettlementType()
|
||
{
|
||
return MatchSettlementType.Perfect;
|
||
}
|
||
|
||
public override void Refresh(MapData map, MatchSettlementInfo info)
|
||
{
|
||
if (info.IsFinished) return;
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (kv.Value.IsSettlement && kv.Value.IsWin)
|
||
{
|
||
info.IsFinished = true;
|
||
return;
|
||
}
|
||
}
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (map.CheckIsAI(kv.Key)) continue;
|
||
if (kv.Value.IsSettlement && !kv.Value.IsWin) continue;
|
||
return;
|
||
}
|
||
info.IsFinished = true;
|
||
}
|
||
}
|
||
|
||
// SideTaskConfig 不影响 不参与
|
||
public class TutorMatchSettlement : IMatchSettlement
|
||
{
|
||
public override MatchSettlementType GetSettlementType()
|
||
{
|
||
return MatchSettlementType.Tutor;
|
||
}
|
||
|
||
public override void Refresh(MapData map, MatchSettlementInfo info)
|
||
{
|
||
if (info.IsFinished) return;
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (map.CheckIsAI(kv.Key)) continue;
|
||
if (kv.Value.IsSettlement) continue;
|
||
return;
|
||
}
|
||
info.IsFinished = true;
|
||
}
|
||
}
|
||
|
||
// TutorTaskConfig 若所有List<Task>完成,当前玩家结算 不参与
|
||
public class StoryMatchSettlement : IMatchSettlement
|
||
{
|
||
public override MatchSettlementType GetSettlementType()
|
||
{
|
||
return MatchSettlementType.Story;
|
||
}
|
||
|
||
public override void Refresh(MapData map, MatchSettlementInfo info)
|
||
{
|
||
if (info.IsFinished) return;
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (map.CheckIsAI(kv.Key)) continue;
|
||
if (kv.Value.IsSettlement) continue;
|
||
return;
|
||
}
|
||
info.IsFinished = true;
|
||
}
|
||
}
|
||
|
||
|
||
// CREATIVE 所有非AI玩家均结算后,游戏结束
|
||
public class CreativeMatchSettlement : IMatchSettlement
|
||
{
|
||
public override MatchSettlementType GetSettlementType()
|
||
{
|
||
return MatchSettlementType.Creative;
|
||
}
|
||
|
||
public override void Refresh(MapData map, MatchSettlementInfo info)
|
||
{
|
||
if (info.IsFinished) return;
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (kv.Value.IsSettlement && kv.Value.IsWin)
|
||
{
|
||
info.IsFinished = true;
|
||
return;
|
||
}
|
||
}
|
||
foreach (var kv in info.PlayerSettlements)
|
||
{
|
||
if (map.CheckIsAI(kv.Key)) continue;
|
||
if (kv.Value.IsSettlement && !kv.Value.IsWin) continue;
|
||
return;
|
||
}
|
||
info.IsFinished = true;
|
||
}
|
||
}
|
||
}
|