riversong code showcase
This commit is contained in:
183
Source/Riversong/Game/World/Agents/Intents/AgentIntent.cs
Normal file
183
Source/Riversong/Game/World/Agents/Intents/AgentIntent.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public struct AgentIntent
|
||||
{
|
||||
public static readonly AgentIntent None = new() { Type = AgentIntentType.None };
|
||||
|
||||
public AgentIntentType Type;
|
||||
|
||||
public TileRect Rect;
|
||||
|
||||
public int TargetId;
|
||||
|
||||
public PathTraversalRules PathTraversalRules;
|
||||
|
||||
public ushort PathMaxDistance;
|
||||
|
||||
public byte StopBeforeGoalStepCount;
|
||||
|
||||
public int StorageId;
|
||||
|
||||
public byte ProductHandle;
|
||||
|
||||
public byte ProductAmount;
|
||||
|
||||
public float GenericFloatParam0;
|
||||
|
||||
public static AgentIntent MakeLive()
|
||||
{
|
||||
return new AgentIntent { Type = AgentIntentType.MakeLive };
|
||||
}
|
||||
|
||||
public static AgentIntent WaitSeconds(float time)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.WaitSeconds,
|
||||
GenericFloatParam0 = time
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent WaitForever()
|
||||
{
|
||||
return new AgentIntent { Type = AgentIntentType.WaitForever };
|
||||
}
|
||||
|
||||
public static AgentIntent FindPath(TileRect rect, int targetId = Entity.InvalidId, PathTraversalRules traversalRules = PathTraversalRules.None)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.FindPath,
|
||||
Rect = rect,
|
||||
TargetId = targetId,
|
||||
PathTraversalRules = traversalRules
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent SearchResourceNode(int targetId, PathTraversalRules traversalRules = PathTraversalRules.None, int maxDistance = 0)
|
||||
{
|
||||
var intent = new AgentIntent { Type = AgentIntentType.SearchResourceNode };
|
||||
SetupSearchTargetIntent(ref intent, targetId, traversalRules, maxDistance);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static AgentIntent SearchFertileTile(PathTraversalRules traversalRules = PathTraversalRules.None, int maxDistance = 0)
|
||||
{
|
||||
var intent = new AgentIntent { Type = AgentIntentType.SearchFertileTile };
|
||||
SetupSearchTargetIntent(ref intent, Entity.InvalidId, traversalRules, maxDistance);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static AgentIntent SearchCritter(int targetId, PathTraversalRules traversalRules = PathTraversalRules.None, int maxDistance = 0)
|
||||
{
|
||||
var intent = new AgentIntent { Type = AgentIntentType.SearchCritter };
|
||||
SetupSearchTargetIntent(ref intent, targetId, traversalRules, maxDistance);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static void SetupSearchTargetIntent(ref AgentIntent intent, int targetId, PathTraversalRules traversalRules, int maxDistance)
|
||||
{
|
||||
intent.TargetId = targetId;
|
||||
intent.PathTraversalRules = traversalRules;
|
||||
intent.PathMaxDistance = (ushort)maxDistance;
|
||||
}
|
||||
|
||||
public static AgentIntent FollowPath(int stopBeforeGoalStepCount = 0)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.FollowPath,
|
||||
StopBeforeGoalStepCount = (byte)stopBeforeGoalStepCount
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent MoveToHarvestPosition(float positionOffset)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.MoveToHarvestPosition,
|
||||
GenericFloatParam0 = positionOffset
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent HarvestResource()
|
||||
{
|
||||
return new AgentIntent { Type = AgentIntentType.HarvestResource };
|
||||
}
|
||||
|
||||
public static AgentIntent HarvestFertileTile()
|
||||
{
|
||||
return new AgentIntent { Type = AgentIntentType.HarvestFertileTile };
|
||||
}
|
||||
|
||||
public static AgentIntent SetFertileTileLockState(int lockId)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.SetFertileTileLockState,
|
||||
TargetId = lockId
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent FireProjectile(int targetId)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.FireProjectile,
|
||||
TargetId = targetId
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent Take(int storageId, int productHandle, int productAmount)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.TakeProduct,
|
||||
StorageId = storageId,
|
||||
ProductHandle = (byte)productHandle,
|
||||
ProductAmount = (byte)productAmount
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent Put(int storageId, int productHandle, int productAmount)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.PutProduct,
|
||||
StorageId = storageId,
|
||||
ProductHandle = (byte)productHandle,
|
||||
ProductAmount = (byte)productAmount
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent Wander()
|
||||
{
|
||||
return new AgentIntent { Type = AgentIntentType.Wander };
|
||||
}
|
||||
|
||||
public static AgentIntent LoopWandering()
|
||||
{
|
||||
return new AgentIntent { Type = AgentIntentType.LoopWandering };
|
||||
}
|
||||
|
||||
public static AgentIntent LookAt(int2 tile)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.LookAt,
|
||||
Rect = TileRect.OneTile(tile)
|
||||
};
|
||||
}
|
||||
|
||||
public static AgentIntent PlayAnimation(AgentAnimation animation)
|
||||
{
|
||||
return new AgentIntent
|
||||
{
|
||||
Type = AgentIntentType.PlayAnimation,
|
||||
TargetId = (int)animation
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public enum AgentIntentType : byte
|
||||
{
|
||||
MakeLive,
|
||||
|
||||
WaitSeconds,
|
||||
|
||||
WaitForever,
|
||||
|
||||
FindPath,
|
||||
|
||||
SearchResourceNode,
|
||||
|
||||
SearchFertileTile,
|
||||
|
||||
SearchCritter,
|
||||
|
||||
FollowPath,
|
||||
|
||||
MoveToHarvestPosition,
|
||||
|
||||
HarvestResource,
|
||||
|
||||
HarvestFertileTile,
|
||||
|
||||
SetFertileTileLockState,
|
||||
|
||||
FireProjectile,
|
||||
|
||||
TakeProduct,
|
||||
|
||||
PutProduct,
|
||||
|
||||
Wander,
|
||||
|
||||
LoopWandering,
|
||||
|
||||
LookAt,
|
||||
|
||||
PlayAnimation,
|
||||
|
||||
Count,
|
||||
|
||||
None = byte.MaxValue
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class FireProjectileExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private IEntityCollection _entityCollection;
|
||||
|
||||
private IProjectileManager _projectileManager;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_entityCollection = serviceLocator.GetService<IEntityCollection>();
|
||||
_projectileManager = serviceLocator.GetService<IProjectileManager>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
var critter = _entityCollection.Get<Agent>(intent.TargetId);
|
||||
_projectileManager.FireProjectile(agent, critter);
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class FollowPathIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
private IAgentCommonLogic _agentCommonLogic;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
_agentCommonLogic = serviceLocator.GetService<IAgentCommonLogic>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult OnStartingIntent(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
agent.PathIndex = 0;
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
ref var path = ref agent.GetPathRW();
|
||||
if (path.StepCount <= 1) return IntentExecutionResult.Success;
|
||||
|
||||
var nextTile = path.Steps[agent.PathIndex + 1];
|
||||
var targetPosition = (float3)_tileSpace.TileToWorld(nextTile);
|
||||
var targetReached = _agentCommonLogic.MoveAgent(agent, targetPosition, Time.deltaTime);
|
||||
|
||||
var lastStepReached = targetReached && ++agent.PathIndex >= path.StepCount - 1 - intent.StopBeforeGoalStepCount;
|
||||
return lastStepReached ? IntentExecutionResult.Success : IntentExecutionResult.InProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HarvestFertileTileIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private IEntityCollection _entityCollection;
|
||||
|
||||
private IProductStackFactory _productStackFactory;
|
||||
|
||||
private World _world;
|
||||
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_entityCollection = serviceLocator.GetService<IEntityCollection>();
|
||||
_productStackFactory = serviceLocator.GetService<IProductStackFactory>();
|
||||
_world = serviceLocator.GetService<World>();
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
if (!_entityCollection.TryGet<Building>(agent.HomeId, out var farm)) return IntentExecutionResult.Failure;
|
||||
|
||||
var tile = _tileSpace.WorldToTile(agent.Position);
|
||||
|
||||
ref var fertility = ref _world.Fertility.GetValueRW(tile);
|
||||
fertility.CurrentFertility = 0;
|
||||
|
||||
var product = farm.Definition.FarmProduct;
|
||||
var amount = Random.Range(farm.Definition.MinDroppedAmount, farm.Definition.MaxDroppedAmount + 1);
|
||||
_productStackFactory.CreateOrMerge(tile, product, amount);
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HarvestResourceIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private World _world;
|
||||
|
||||
private ISignalBus _signalBus;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_world = serviceLocator.GetService<World>();
|
||||
_signalBus = serviceLocator.GetService<ISignalBus>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
ref var jobState = ref agent.GetJobStateRW();
|
||||
var resourceNodeId = jobState.Harvester.ResourceNodeId;
|
||||
|
||||
if (!_world.RawResources.Exists(resourceNodeId)) return IntentExecutionResult.Failure;
|
||||
|
||||
_signalBus.Raise(new RawResourceHarvestedSignal(resourceNodeId));
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public interface IIntentLogicExecutor
|
||||
{
|
||||
ref IntentQueue CancelRemainingIntents(Agent agent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public abstract class IntentExecutionLogic
|
||||
{
|
||||
public virtual UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual IntentExecutionResult OnStartingIntent(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
public virtual void OnCanceled(Agent agent, AgentIntent intent)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract IntentExecutionResult Execute(Agent agent, in AgentIntent intent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public enum IntentExecutionResult
|
||||
{
|
||||
InProgress,
|
||||
|
||||
Failure,
|
||||
|
||||
Success
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public enum IntentExecutionState
|
||||
{
|
||||
WaitingIntent,
|
||||
|
||||
ExecutingIntent,
|
||||
|
||||
EmptyQueue
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
156
Source/Riversong/Game/World/Agents/Intents/IntentQueue.cs
Normal file
156
Source/Riversong/Game/World/Agents/Intents/IntentQueue.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public struct IntentQueue
|
||||
{
|
||||
private FixedList512Bytes<AgentIntent> _intentQueue;
|
||||
|
||||
public int Count => _intentQueue.Length;
|
||||
|
||||
public void EnqueueIntent(in AgentIntent intent)
|
||||
{
|
||||
_intentQueue.Add(intent);
|
||||
}
|
||||
|
||||
public bool TryDequeueIntent(out AgentIntent intent)
|
||||
{
|
||||
if (_intentQueue.Length > 0)
|
||||
{
|
||||
intent = _intentQueue[0];
|
||||
_intentQueue.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
intent = AgentIntent.None;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPeekIntent(out AgentIntent intent)
|
||||
{
|
||||
if (_intentQueue.Length > 0)
|
||||
{
|
||||
intent = _intentQueue[0];
|
||||
return true;
|
||||
}
|
||||
intent = AgentIntent.None;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_intentQueue.Clear();
|
||||
}
|
||||
|
||||
public static void Fetch(ref IntentQueue intentQueue,
|
||||
TileRect sourceRect,
|
||||
int sourceId,
|
||||
TileRect destinationRect,
|
||||
int destinationId,
|
||||
int productHandle,
|
||||
int amount,
|
||||
PathTraversalRules traversalRules)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(destinationRect, destinationId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MakeLive());
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.Take(destinationId, productHandle, amount));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(sourceRect, sourceId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.Put(sourceId, productHandle, amount));
|
||||
}
|
||||
|
||||
public static void Deliver(ref IntentQueue intentQueue,
|
||||
TileRect sourceRect,
|
||||
int sourceId,
|
||||
TileRect destinationRect,
|
||||
int destinationId,
|
||||
int productHandle,
|
||||
int amount,
|
||||
PathTraversalRules traversalRules)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(destinationRect, destinationId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MakeLive());
|
||||
intentQueue.EnqueueIntent(AgentIntent.Take(sourceId, productHandle, amount));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.Put(destinationId, productHandle, amount));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(sourceRect, sourceId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
}
|
||||
|
||||
public static void MoveProduct(ref IntentQueue intentQueue,
|
||||
TileRect sourceRect,
|
||||
int sourceId,
|
||||
TileRect fetchRect,
|
||||
int fetchId,
|
||||
TileRect deliverRect,
|
||||
int deliverId,
|
||||
int productHandle,
|
||||
int amount,
|
||||
PathTraversalRules traversalRules)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(fetchRect, fetchId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MakeLive());
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.Take(fetchId, productHandle, amount));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(deliverRect, deliverId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.Put(deliverId, productHandle, amount));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(sourceRect, sourceId, traversalRules));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
}
|
||||
|
||||
public static void Harvest(ref IntentQueue intentQueue, TileRect sourceRect, int sourceId, ResourceNodeDefinition resource, int maxDistance)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.SearchResourceNode(resource.RuntimeId, PathTraversalRules.GenericAgent, maxDistance));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MakeLive());
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath(1));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MoveToHarvestPosition(resource.HarvestPositionOffset));
|
||||
intentQueue.EnqueueIntent(AgentIntent.PlayAnimation(resource.HarvestAnimation));
|
||||
intentQueue.EnqueueIntent(AgentIntent.HarvestResource());
|
||||
intentQueue.EnqueueIntent(AgentIntent.WaitSeconds(1.5f));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(sourceRect, sourceId));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
}
|
||||
|
||||
public static void SeekPrey(ref IntentQueue intentQueue, int critterDefinitionId, int maxDistance)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.SearchCritter(critterDefinitionId, PathTraversalRules.GenericAgent, maxDistance));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MakeLive());
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
}
|
||||
|
||||
public static void FireAtPreyAndReturnHome(ref IntentQueue intentQueue, TileRect homeRect, int homeId, int2 critterTile, int critterId, float projectileTravelTime)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.LookAt(critterTile));
|
||||
intentQueue.EnqueueIntent(AgentIntent.PlayAnimation(AgentAnimation.FireProjectile));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FireProjectile(critterId));
|
||||
intentQueue.EnqueueIntent(AgentIntent.WaitSeconds(projectileTravelTime + 1));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(homeRect, homeId));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
}
|
||||
|
||||
public static void WorkFertileTile(ref IntentQueue intentQueue, TileRect sourceRect, int sourceId, int agentId, int maxDistance)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.SearchFertileTile(PathTraversalRules.GenericAgent | PathTraversalRules.FertileTilesOnly, maxDistance));
|
||||
intentQueue.EnqueueIntent(AgentIntent.SetFertileTileLockState(agentId));
|
||||
intentQueue.EnqueueIntent(AgentIntent.MakeLive());
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.PlayAnimation(AgentAnimation.Farming));
|
||||
intentQueue.EnqueueIntent(AgentIntent.HarvestFertileTile());
|
||||
intentQueue.EnqueueIntent(AgentIntent.WaitSeconds(2.5f));
|
||||
intentQueue.EnqueueIntent(AgentIntent.SetFertileTileLockState(Entity.InvalidId));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FindPath(sourceRect, sourceId));
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
}
|
||||
|
||||
public static void LoopWandering(ref IntentQueue intentQueue, float idleTime)
|
||||
{
|
||||
intentQueue.EnqueueIntent(AgentIntent.WaitSeconds(idleTime));
|
||||
intentQueue.EnqueueIntent(AgentIntent.Wander());
|
||||
intentQueue.EnqueueIntent(AgentIntent.FollowPath());
|
||||
intentQueue.EnqueueIntent(AgentIntent.LoopWandering());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Burst;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[BurstCompile]
|
||||
public class LookAtIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
private float _rotationSpeed;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
_rotationSpeed = serviceLocator.GetService<GameConfig>().Agents.RotationSpeed;
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
var lookAt = math.normalizesafe((float3)_tileSpace.TileToWorld(intent.Rect.Center) - agent.Position);
|
||||
if (math.all(lookAt == 0)) return IntentExecutionResult.Success;
|
||||
|
||||
var step = math.radians(_rotationSpeed) * Time.deltaTime;
|
||||
var heading = agent.Heading;
|
||||
LookAt(ref heading, lookAt, step);
|
||||
agent.Heading = heading;
|
||||
|
||||
return math.dot(heading, lookAt) > 0.995f ? IntentExecutionResult.Success : IntentExecutionResult.InProgress;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void LookAt(ref float3 heading, in float3 lookAt, float maxRadiansDelta)
|
||||
{
|
||||
var currentRotation = quaternion.LookRotationSafe(heading, math.up());
|
||||
var targetRotation = quaternion.LookRotationSafe(lookAt, math.up());
|
||||
|
||||
var dot = math.dot(currentRotation, targetRotation);
|
||||
if (dot < 0)
|
||||
{
|
||||
dot = -dot;
|
||||
targetRotation.value = -targetRotation.value;
|
||||
}
|
||||
dot = math.clamp(dot, -1, 1);
|
||||
|
||||
var angle = math.acos(dot) * 2;
|
||||
if (angle <= maxRadiansDelta)
|
||||
{
|
||||
heading = lookAt;
|
||||
return;
|
||||
}
|
||||
|
||||
currentRotation = math.slerp(currentRotation, targetRotation, maxRadiansDelta / angle);
|
||||
heading = math.mul(currentRotation, math.forward());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class MakeLiveIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
private IAgentVisualizationCollection _visualizationCollection;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
_visualizationCollection = serviceLocator.GetService<IAgentVisualizationCollection>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
switch (agent.LifecycleState)
|
||||
{
|
||||
case AgentLifecycleState.DeSpawning:
|
||||
return IntentExecutionResult.Failure;
|
||||
|
||||
case AgentLifecycleState.Live:
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
if (!_visualizationCollection.TryGetVisualization(agent.Id, out _)) return IntentExecutionResult.InProgress;
|
||||
|
||||
agent.LifecycleState = AgentLifecycleState.Live;
|
||||
|
||||
SetInitialHeading(agent);
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
private void SetInitialHeading(Agent agent)
|
||||
{
|
||||
ref var path = ref agent.GetPathRW();
|
||||
if (path.StepCount <= 1) return;
|
||||
|
||||
var p0 = _tileSpace.TileToWorld(path.Steps[0]);
|
||||
var p1 = _tileSpace.TileToWorld(path.Steps[1]);
|
||||
agent.Heading = math.normalizesafe(p1 - p0, math.forward());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class MoveToHarvestPositionIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private GameConfig _config;
|
||||
|
||||
private World _world;
|
||||
|
||||
private IAgentCommonLogic _agentCommonLogic;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_config = serviceLocator.GetService<GameConfig>();
|
||||
_world = serviceLocator.GetService<World>();
|
||||
_agentCommonLogic = serviceLocator.GetService<IAgentCommonLogic>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult OnStartingIntent(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
ref var path = ref agent.GetPathRW();
|
||||
var tile = path.Steps[^1];
|
||||
|
||||
using var resourceNodesScope = ListPool<(int, bool)>.Get(out var resourceNodeIds);
|
||||
_world.RawResources.GetResourceNodes(TileRect.OneTile(tile), _config.GeneralSettings.BaseElevation, resourceNodeIds);
|
||||
|
||||
if (resourceNodeIds.Count <= 0) return IntentExecutionResult.Failure;
|
||||
|
||||
var (id, _) = resourceNodeIds[0];
|
||||
_world.RawResources.TryGetResourceNode(id, out var resourceNode);
|
||||
|
||||
ref var jobState = ref agent.GetJobStateRW();
|
||||
jobState.Harvester.ResourceNodeId = id;
|
||||
jobState.Harvester.TargetPosition = resourceNode.Position + math.normalizesafe(agent.Position - resourceNode.Position) * intent.GenericFloatParam0;
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
ref var jobState = ref agent.GetJobStateRW();
|
||||
|
||||
var targetReached = _agentCommonLogic.MoveAgent(agent, jobState.Harvester.TargetPosition, Time.deltaTime);
|
||||
if (!targetReached) return IntentExecutionResult.InProgress;
|
||||
|
||||
if (!_world.RawResources.TryGetResourceNode(jobState.Harvester.ResourceNodeId, out var resourceNode)) return IntentExecutionResult.Failure;
|
||||
|
||||
var desiredHeading = math.normalizesafe(resourceNode.Position - agent.Position, agent.Heading);
|
||||
return _agentCommonLogic.UpdateHeading(agent, desiredHeading, Time.deltaTime) ? IntentExecutionResult.Success : IntentExecutionResult.InProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public struct PathQueryFailedSignal
|
||||
{
|
||||
public PathTraversalRules TraversalRules;
|
||||
|
||||
public PathQueryFailedSignal(PathTraversalRules traversalRules)
|
||||
{
|
||||
TraversalRules = traversalRules;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class PathfindingIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private IPathfinder _pathfinder;
|
||||
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
private IFailedPathCache _failedPathCache;
|
||||
|
||||
private ISignalBus _signalBus;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_pathfinder = serviceLocator.GetService<IPathfinder>();
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
_failedPathCache = serviceLocator.GetService<IFailedPathCache>();
|
||||
_signalBus = serviceLocator.GetService<ISignalBus>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult OnStartingIntent(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
ref var path = ref agent.GetPathRW();
|
||||
path.Steps.Clear();
|
||||
|
||||
var searchType = intent.Type switch
|
||||
{
|
||||
AgentIntentType.FindPath => PathSearchType.FindPath,
|
||||
AgentIntentType.SearchResourceNode => PathSearchType.SearchResourceNode,
|
||||
AgentIntentType.SearchFertileTile => PathSearchType.SearchFertileTile,
|
||||
AgentIntentType.SearchCritter => PathSearchType.SearchCritterHerd,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
var query = new PathQuery
|
||||
{
|
||||
SearchType = searchType,
|
||||
SourceTile = _tileSpace.WorldToTile(agent.Position),
|
||||
DestinationRect = intent.Rect,
|
||||
TargetId = intent.TargetId,
|
||||
TraversalRules = intent.PathTraversalRules,
|
||||
MaxDistance = intent.PathMaxDistance
|
||||
};
|
||||
|
||||
agent.PathQueryHandle = _pathfinder.FindPath(path, ref query);
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
switch (_pathfinder.CompletePath(agent.PathQueryHandle))
|
||||
{
|
||||
case PathQueryResult.InProgress:
|
||||
return IntentExecutionResult.InProgress;
|
||||
|
||||
case PathQueryResult.InvalidQuery:
|
||||
return IntentExecutionResult.Failure;
|
||||
|
||||
case PathQueryResult.Failure:
|
||||
if ((intent.PathTraversalRules & PathTraversalRules.UpdateFailedPathCache) != 0) _failedPathCache.FailPath(agent.HomeId, intent.TargetId);
|
||||
_signalBus.Raise(new PathQueryFailedSignal(intent.PathTraversalRules));
|
||||
return IntentExecutionResult.Failure;
|
||||
}
|
||||
|
||||
ref var path = ref agent.GetPathRW();
|
||||
var agentTile = _tileSpace.WorldToTile(agent.Position);
|
||||
if (path.Steps.Length > 0 && math.any(agentTile != path.Steps[0]))
|
||||
{
|
||||
agent.Position = _tileSpace.TileToWorld(path.Steps[0]);
|
||||
agent.Velocity = float3.zero;
|
||||
}
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class PlayAnimationIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private static readonly int ChopTree = Animator.StringToHash("ChopTree");
|
||||
|
||||
private static readonly int Farming = Animator.StringToHash("Farming");
|
||||
|
||||
private static readonly int FireProjectile = Animator.StringToHash("FireProjectile");
|
||||
|
||||
private IAgentVisualizationCollection _agentVisualizationCollection;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_agentVisualizationCollection = serviceLocator.GetService<IAgentVisualizationCollection>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult OnStartingIntent(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
if (!_agentVisualizationCollection.TryGetVisualization(agent.Id, out var visualization)) return IntentExecutionResult.Failure;
|
||||
|
||||
var triggerID = GetAnimatorTriggerID((AgentAnimation)intent.TargetId);
|
||||
visualization.SetAnimatorTrigger(triggerID);
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
if (!_agentVisualizationCollection.TryGetVisualization(agent.Id, out var visualization)) return IntentExecutionResult.Failure;
|
||||
|
||||
return !visualization.WaitAnimationCompleted() ? IntentExecutionResult.InProgress : IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
private int GetAnimatorTriggerID(AgentAnimation animation)
|
||||
{
|
||||
return animation switch
|
||||
{
|
||||
AgentAnimation.ChopTree => ChopTree,
|
||||
AgentAnimation.Farming => Farming,
|
||||
AgentAnimation.FireProjectile => FireProjectile,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class PutProductIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private IProductStorageManager _productStorageManager;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_productStorageManager = serviceLocator.GetService<IProductStorageManager>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override void OnCanceled(Agent agent, AgentIntent intent)
|
||||
{
|
||||
base.OnCanceled(agent, intent);
|
||||
|
||||
if (!_productStorageManager.TryGetProductStorageEntity(intent.StorageId, out var storageEntity)) return;
|
||||
|
||||
ref var storage = ref storageEntity.GetStorageRW();
|
||||
storage.ReleasePutReservation(intent.ProductHandle, intent.ProductAmount);
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
if (!_productStorageManager.TryGetProductStorageEntity(intent.StorageId, out var storageEntity)) return IntentExecutionResult.Failure;
|
||||
|
||||
ref var storage = ref storageEntity.GetStorageRW();
|
||||
if (!storage.FulfillPut(intent.ProductHandle, intent.ProductAmount))
|
||||
{
|
||||
storage.ReleasePutReservation(intent.ProductHandle, intent.ProductAmount);
|
||||
Debug.LogError("Agent could not fulfill putting product");
|
||||
return IntentExecutionResult.Failure;
|
||||
}
|
||||
|
||||
agent.CarriedProductHandle = IProductCatalog.InvalidHandle;
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class SetFertileTileLockStateIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private World _world;
|
||||
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_world = serviceLocator.GetService<World>();
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override void OnCanceled(Agent agent, AgentIntent intent)
|
||||
{
|
||||
if (intent.TargetId != Entity.InvalidId) return;
|
||||
|
||||
Unlock(agent);
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
return intent.TargetId == Entity.InvalidId ? Unlock(agent) : Lock(agent);
|
||||
}
|
||||
|
||||
private IntentExecutionResult Lock(Agent agent)
|
||||
{
|
||||
ref var path = ref agent.GetPathRW();
|
||||
var tile = path.StepCount > 0 ? path.Steps[^1] : _tileSpace.WorldToTile(agent.Position);
|
||||
|
||||
ref var fertility = ref _world.Fertility.GetValueRW(tile);
|
||||
if (fertility.MaxFertility <= 0 || fertility.CurrentFertility < fertility.MaxFertility || fertility.LockId != Entity.InvalidId) return IntentExecutionResult.Failure;
|
||||
|
||||
fertility.LockId = agent.Id;
|
||||
|
||||
ref var farming = ref agent.GetJobStateRW().Farming;
|
||||
farming.LockedTile = tile;
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
private IntentExecutionResult Unlock(Agent agent)
|
||||
{
|
||||
ref var farming = ref agent.GetJobStateRW().Farming;
|
||||
if (farming.LockedTile == null) return IntentExecutionResult.Success;
|
||||
|
||||
var tile = farming.LockedTile.Value;
|
||||
ref var fertility = ref _world.Fertility.GetValueRW(tile);
|
||||
if (fertility.LockId == agent.Id) fertility.LockId = Entity.InvalidId;
|
||||
|
||||
farming.LockedTile = null;
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class TakeProductIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private IProductStorageManager _productStorageManager;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_productStorageManager = serviceLocator.GetService<IProductStorageManager>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override void OnCanceled(Agent agent, AgentIntent intent)
|
||||
{
|
||||
base.OnCanceled(agent, intent);
|
||||
|
||||
if (!_productStorageManager.TryGetProductStorageEntity(intent.StorageId, out var storageEntity)) return;
|
||||
|
||||
ref var storage = ref storageEntity.GetStorageRW();
|
||||
storage.ReleaseTakeReservation(intent.ProductHandle, intent.ProductAmount);
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
if (!_productStorageManager.TryGetProductStorageEntity(intent.StorageId, out var storageEntity)) return IntentExecutionResult.Failure;
|
||||
|
||||
ref var storage = ref storageEntity.GetStorageRW();
|
||||
if (!storage.FulfillTake(intent.ProductHandle, intent.ProductAmount))
|
||||
{
|
||||
Debug.LogError("Agent could not fulfill taking product");
|
||||
return IntentExecutionResult.Failure;
|
||||
}
|
||||
|
||||
agent.CarriedProductHandle = intent.ProductHandle;
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class WaitForeverIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
return IntentExecutionResult.InProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class WaitSecondsIntentExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
return agent.IntentExecutionTime < intent.GenericFloatParam0 ? IntentExecutionResult.InProgress : IntentExecutionResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Pool;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class WanderingExecutionLogic : IntentExecutionLogic
|
||||
{
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
private World _world;
|
||||
|
||||
public override UniTask InitializeAsync(IServiceLocator serviceLocator)
|
||||
{
|
||||
_tileSpace = serviceLocator.GetService<ITileSpace>();
|
||||
_world = serviceLocator.GetService<World>();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override IntentExecutionResult Execute(Agent agent, in AgentIntent intent)
|
||||
{
|
||||
switch (intent.Type)
|
||||
{
|
||||
case AgentIntentType.Wander:
|
||||
return Wander(agent);
|
||||
|
||||
case AgentIntentType.LoopWandering:
|
||||
LoopWandering(agent);
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private IntentExecutionResult Wander(Agent agent)
|
||||
{
|
||||
using var candidatesScope = ListPool<int2>.Get(out var candidates);
|
||||
|
||||
var tile = _tileSpace.WorldToTile(agent.Position);
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var candidate = ((Directions)i).ToVector();
|
||||
if (!_world.BlockMap.IsBlocked(tile + candidate, BlockReason.BlocksAgents)) candidates.Add(candidate);
|
||||
}
|
||||
if (candidates.Count <= 0) return IntentExecutionResult.Failure;
|
||||
|
||||
var direction = candidates[Random.Range(0, candidates.Count)];
|
||||
|
||||
if (agent.Definition.WanderingRadius > 0)
|
||||
{
|
||||
var distance = TileMath.StepCount(agent.WanderingCenter, tile + direction);
|
||||
if (distance > agent.Definition.WanderingRadius) direction = math.sign(agent.WanderingCenter - tile);
|
||||
}
|
||||
|
||||
ref var path = ref agent.GetPathRW();
|
||||
path.Steps.Clear();
|
||||
path.Steps.Add(tile);
|
||||
path.Steps.Add(tile + direction);
|
||||
|
||||
return IntentExecutionResult.Success;
|
||||
}
|
||||
|
||||
private void LoopWandering(Agent agent)
|
||||
{
|
||||
var idleTimeRange = agent.Definition.WanderingIdleTime;
|
||||
var idleTime = Random.Range(idleTimeRange.x, idleTimeRange.y);
|
||||
|
||||
IntentQueue.LoopWandering(ref agent.GetIntentQueueRW(), idleTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user