using Cysharp.Threading.Tasks; using UnityEngine; namespace DanieleMarotta.RiversongCodeShowcase { [Service(typeof(IIntentLogicExecutor))] [GameSystemGroup(typeof(DefaultAgentsSystemGroup))] [UpdateAfter(typeof(AgentManagerSystem))] public class IntentExecutionSystem : GameSystem, IInitializable, IUpdatable, IIntentLogicExecutor { [InjectService] private IEntityCollection _entityCollection; private readonly IntentExecutionLogic[] _executionLogic = new IntentExecutionLogic[(int)AgentIntentType.Count]; public IntentExecutionSystem(IServiceLocator serviceLocator) : base(serviceLocator) { } public async UniTask InitializeAsync() { var pathfindingLogic = new PathfindingIntentExecutionLogic(); var wanderingLogic = new WanderingExecutionLogic(); _executionLogic[(int)AgentIntentType.MakeLive] = new MakeLiveIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.WaitSeconds] = new WaitSecondsIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.WaitForever] = new WaitForeverIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.FindPath] = pathfindingLogic; _executionLogic[(int)AgentIntentType.SearchResourceNode] = pathfindingLogic; _executionLogic[(int)AgentIntentType.SearchFertileTile] = pathfindingLogic; _executionLogic[(int)AgentIntentType.SearchCritter] = pathfindingLogic; _executionLogic[(int)AgentIntentType.FollowPath] = new FollowPathIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.MoveToHarvestPosition] = new MoveToHarvestPositionIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.HarvestResource] = new HarvestResourceIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.HarvestFertileTile] = new HarvestFertileTileIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.SetFertileTileLockState] = new SetFertileTileLockStateIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.FireProjectile] = new FireProjectileExecutionLogic(); _executionLogic[(int)AgentIntentType.TakeProduct] = new TakeProductIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.PutProduct] = new PutProductIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.Wander] = wanderingLogic; _executionLogic[(int)AgentIntentType.LoopWandering] = wanderingLogic; _executionLogic[(int)AgentIntentType.LookAt] = new LookAtIntentExecutionLogic(); _executionLogic[(int)AgentIntentType.PlayAnimation] = new PlayAnimationIntentExecutionLogic(); foreach (var executionLogic in _executionLogic) await executionLogic.InitializeAsync(ServiceLocator); } public void Update() { foreach (Agent agent in _entityCollection.GetInternalEntityList(typeof(Agent))) UpdateAgent(agent); } private void UpdateAgent(Agent agent) { if (agent.LifecycleState == AgentLifecycleState.DeSpawning) { CancelRemainingIntents(agent); return; } ref var intentQueue = ref agent.GetIntentQueueRW(); if (!intentQueue.TryPeekIntent(out var intent)) { agent.IntentExecutionState = IntentExecutionState.EmptyQueue; return; } var executionLogic = _executionLogic[(int)intent.Type]; if (agent.IntentExecutionState == IntentExecutionState.WaitingIntent) { if (executionLogic.OnStartingIntent(agent, intent) == IntentExecutionResult.Failure) { intentQueue.TryDequeueIntent(out _); CancelRemainingIntents(agent); return; } agent.IntentExecutionState = IntentExecutionState.ExecutingIntent; agent.IntentExecutionTime = 0; } var result = executionLogic.Execute(agent, intent); if (result == IntentExecutionResult.InProgress) { agent.IntentExecutionTime += Time.deltaTime; return; } intentQueue.TryDequeueIntent(out _); if (result == IntentExecutionResult.Failure) CancelRemainingIntents(agent); agent.IntentExecutionState = IntentExecutionState.WaitingIntent; } public ref IntentQueue CancelRemainingIntents(Agent agent) { ref var intentQueue = ref agent.GetIntentQueueRW(); while (intentQueue.TryDequeueIntent(out var intent)) _executionLogic[(int)intent.Type].OnCanceled(agent, intent); agent.IntentExecutionState = IntentExecutionState.WaitingIntent; return ref intentQueue; } } }