227 lines
6.6 KiB
C#

/*
* @Author: 白哉
* @Description: AI 逻辑总模块
* @Date: 2025年04月01日 星期二 14:04:01
* @Modify:
*/
using System.Collections.Generic;
using Logic.Action;
using Logic.AI.Director;
using Logic.CrashSight;
using RuntimeData;
using TH1_Core.Managers;
using UnityEngine;
namespace Logic.AI
{
public enum AILogicState
{
Prepare,
Playing,
PrePlay,
Pausing,
Finished,
}
public enum AIActionType
{
Grid,
City,
Unit,
Tech,
Max,
}
public class AILogic
{
public AILogicState AILogicState;
public PlayerData PlayerData => _playerData;
private float _targetTime;
private IAIKernel _kernel;
private AILogicContext _context;
private MapData _mapData;
private PlayerData _playerData;
private int _actionCount;
private int _kernelVersion;
public static uint CurrentAIPlayerId;
public static Dictionary<uint, List<AIRecord>> AIRecordsDict;
public AILogic()
{
AIRecordsDict = new Dictionary<uint, List<AIRecord>>();
AILogicState = AILogicState.Prepare;
RebuildKernel();
}
public void RebuildKernel()
{
_context = new AILogicContext
{
Data = new AICalculatorData(),
Generator = new AIActionGenerator(),
ScoreCalculator = new AIActionScoreCalculator(),
Config = TH1Resource.ResourceLoader.Load<AIConfigAsset>("Export/AIConfig")
};
_kernel = AIKernelRegistry.Create();
_kernel.Initialize(_context);
_kernelVersion = AIKernelRegistry.Version;
}
public void StartAILogic(MapData mapData, PlayerData playerData)
{
if (_kernel == null || _kernel.KernelType != AIKernelRegistry.CurrentKernelType || _kernelVersion != AIKernelRegistry.Version) RebuildKernel();
AILogicState = AILogicState.Playing;
_actionCount = 0;
_mapData = mapData;
_playerData = playerData;
_kernel.StartTurn(_mapData, _playerData);
#if UNITY_EDITOR
CurrentAIPlayerId = _playerData.Id;
if (!AIRecordsDict.ContainsKey(CurrentAIPlayerId)) AIRecordsDict[CurrentAIPlayerId] = new List<AIRecord>();
AIRecordsDict[CurrentAIPlayerId].Clear();
#endif
}
public void FinishAILogic()
{
_kernel?.FinishTurn();
_playerData = null;
_mapData = null;
AILogicState = AILogicState.Prepare;
}
public void Update()
{
if (AILogicState == AILogicState.Finished || AILogicState == AILogicState.Prepare) return;
#if ENABLE_SPEEDUP
if (AILogicState == AILogicState.Pausing)
#else
if (AILogicState == AILogicState.Pausing && (AIDirectorBatchRuntime.SkipPresentationWait || !PresentationManager.Busy))
#endif
{
_targetTime -= Time.deltaTime;
if (_targetTime <= 0) AILogicState = AILogicState.Playing;
}
if (AILogicState != AILogicState.Playing) return;
if (_actionCount > 200)
{
var btNodeId = _kernel?.KernelType == AIKernelType.BehaviourTree ? MainEditor.Instance.BTNodeId : 0;
LogSystem.LogError($"AI 行为次数过多,可能进入死循环,强制结束 AI 逻辑 最终记录点为:{btNodeId}");
AILogicState = AILogicState.Finished;
return;
}
var update = _kernel.Update();
if (update.Result == AIKernelUpdateResult.None) return;
if (update.Result == AIKernelUpdateResult.Finished || update.Action == null)
{
AILogicState = AILogicState.Finished;
return;
}
ExecuteAction(update.Action);
}
private void ExecuteAction(AIActionBase action)
{
action.Param.MapData = _mapData;
action.Param.RefreshParams();
#if TH1_AI_DIRECTOR_DIAGNOSTICS || UNITY_EDITOR
var actionIndex = _actionCount + 1;
var before = AIDirectorDiagnostics.CaptureOutcomeProbe(_mapData, _playerData, action);
var executed = action.ActionLogic.CompleteExecute(action.Param);
var after = AIDirectorDiagnostics.CaptureOutcomeProbe(_mapData, _playerData, action);
if (_kernel?.KernelType == AIKernelType.Director)
{
AIDirectorDiagnostics.RecordExecution(
_mapData,
_playerData,
actionIndex,
action,
executed,
before,
after);
}
#else
action.ActionLogic.CompleteExecute(action.Param);
#endif
action.CheckIsActionDuration();
_targetTime = Mathf.Max(action.Duration, 0f);
#if UNITY_EDITOR
var records = GetCurrentAIRecords();
if (records != null && records.Count != 0)
{
var record = records[^1];
record.Action = action;
}
#endif
_actionCount++;
if (_kernel?.KernelType == AIKernelType.BehaviourTree) MainEditor.Instance.OnActionExcuted();
AILogicState = AILogicState.Pausing;
}
public static void RegisterKernel(AIKernelType kernelType)
{
AIKernelRegistry.Register(kernelType);
}
public static void UseBehaviourTreeKernel()
{
AIKernelRegistry.Register(AIKernelType.BehaviourTree);
}
public static void UseDirectorKernel()
{
AIKernelRegistry.Register(AIKernelType.Director);
}
public static List<AIRecord> GetCurrentAIRecords()
{
return AIRecordsDict.GetValueOrDefault(CurrentAIPlayerId);
}
public static List<AIRecord> GetAIRecords(uint playerId)
{
return AIRecordsDict.GetValueOrDefault(playerId);
}
}
public class AIStateRecord
{
public uint ID;
public string Desc;
public bool Result;
}
public class AIRecord
{
public List<AIStateRecord> StateRecords;
public AIActionBase Action;
public bool IsFoldout;
public AIRecord()
{
IsFoldout = false;
StateRecords = new List<AIStateRecord>();
}
public string GetDesc()
{
if (Action == null) return "暂无动作";
return Action.ActionLogic.GetType().ToString();
}
}
}