215 lines
6.3 KiB
C#

/*
* @Author: 白哉
* @Description: AI 逻辑总模块
* @Date: 2025年04月01日 星期二 14:04:01
* @Modify:
*/
using System.Collections.Generic;
using Logic.CrashSight;
using NodeCanvas.BehaviourTrees;
using NodeCanvas.Framework;
using UnityEngine;
using RuntimeData;
using TH1_Core.Managers;
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 bool _isWaitFrame;
private AIActionScoreCalculator _scoreCalculator;
private AIActionGenerator _generator;
private List<AIActionBase> RecordActions;
private AIActionBase MaxScoreAction;
private MapData _mapData;
private PlayerData _playerData;
private AIConfigAsset _cfg;
private GameObject _logicObject;
private BehaviourTreeOwner _btOwner;
private AICalculatorData _data;
public static uint CurrentAIPlayerId;
public static Dictionary<uint, List<AIRecord>> AIRecordsDict;
public AILogic()
{
AIRecordsDict = new Dictionary<uint, List<AIRecord>>();
AILogicState = AILogicState.Prepare;
RecordActions = new List<AIActionBase>();
_scoreCalculator = new AIActionScoreCalculator();
_cfg = Resources.Load<AIConfigAsset>("Export/AIConfig");
_generator = new AIActionGenerator();
_logicObject = GameObject.Find("AIBT");
_btOwner = _logicObject.GetComponent<BehaviourTreeOwner>();
var data = _btOwner.blackboard.GetVariable<AICalculatorData>("Data");
if (data.value == null)
{
_data = new AICalculatorData();
data.value = _data;
}
else _data = data.value;
}
// 开始 AI 逻辑
public void StartAILogic(MapData mapData, PlayerData playerData)
{
AILogicState = AILogicState.Playing;
_mapData = mapData;
_playerData = playerData;
var aiDiff = _cfg.GetAIDiffInfo(_mapData.MapConfig.AIDiff);
_data.AiDiffInfo = aiDiff;
_generator.Init(_mapData, _playerData);
_data.Refresh(mapData, playerData);
_btOwner.StopBehaviour();
_btOwner.StartBehaviour();
MainEditor.Instance.Data = _data;
#if UNITY_EDITOR
CurrentAIPlayerId = _playerData.Id;
if (!AIRecordsDict.ContainsKey(CurrentAIPlayerId)) AIRecordsDict[CurrentAIPlayerId] = new List<AIRecord>();
AIRecordsDict[CurrentAIPlayerId].Clear();
#endif
}
// 结束 AI 逻辑
public void FinishAILogic()
{
_playerData = null;
AILogicState = AILogicState.Prepare;
}
// 更新 AI 逻辑
public void Update()
{
if (AILogicState == AILogicState.Finished || AILogicState == AILogicState.Prepare) return;
//if (AILogicState == AILogicState.Pausing && !PresentationManager.Busy)
if (AILogicState == AILogicState.Pausing)
{
_targetTime -= Time.deltaTime;
if (_targetTime <= 0) AILogicState = AILogicState.Playing;
// if (!_isWaitFrame) _isWaitFrame = true;
// else
// {
// _targetTime -= Time.deltaTime;
// if (_targetTime <= 0) AILogicState = AILogicState.Playing;
// }
}
if (AILogicState == AILogicState.Playing)
{
var index = 0;
while (true)
{
if (MainEditor.Instance.IsEditor && !MainEditor.Instance.IsGo) return;
index++;
_data.ClearCache();
_btOwner.UpdateBehaviour();
MainEditor.Instance.IsGo = false;
if (_data.MaxAiAction != null || _data.IsFinish) break;
if (index > 100)
{
LogSystem.LogError($"死循环了,最终记录点为:{MainEditor.Instance.BTNodeId}");
break;
}
}
if (_data.MaxAiAction == null || index > 100) AILogicState = AILogicState.Finished;
else
{
_data.MaxAiAction.ActionLogic.CompleteExecute(_data.MaxAiAction.Param);
_data.MaxAiAction.CheckIsActionDuration();
_targetTime = Mathf.Max(_data.MaxAiAction.Duration, 1f);
#if UNITY_EDITOR
var records = GetCurrentAIRecords();
if (records != null && records.Count != 0)
{
var record = records[^1];
record.Action = _data.MaxAiAction;
}
#endif
_isWaitFrame = false;
MainEditor.Instance.OnActionExcuted();
_data.MaxAiAction = null;
AILogicState = AILogicState.Pausing;
}
}
}
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();
}
}
}