TH1/Unity/Assets/Scripts/TH1_Logic/MatchConfig/MatchSettlementInfo.cs
2026-05-09 17:30:37 +08:00

416 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @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;
}
}
}