Player/Bot/PlayerBotController.Roam.cs
using System.Threading;
public partial class PlayerBotController
{
private async Task<bool> Roam( CancellationToken token )
{
if ( FindAndUpdateTarget() != null )
{
// Switch to combat mode
return false;
}
while ( !token.IsCancellationRequested )
{
bool result = await RunParallel(
token,
CheckForTarget,
UpdateRotationToMatchMovement,
token => RunSelector( token,
PickupInventoryItem,
GoSomewhereRandom
)
);
if ( !result )
{
// still return true because we at least did some roaming
return true;
}
}
return false;
}
private async Task<bool> CheckForTarget( CancellationToken token )
{
while ( !token.IsCancellationRequested )
{
_currentTarget = FindAndUpdateTarget();
if ( _currentTarget.IsValid() )
{
return false;
}
await Task.FixedUpdate();
}
return !token.IsCancellationRequested;
}
private async Task<bool> GoSomewhereRandom( CancellationToken token )
{
var randomPoint = Scene.NavMesh.GetRandomPoint();
if ( !randomPoint.HasValue ) return false;
TimeSince timeSinceLastConsumableSearch = 0;
TimeSince timeSinceMoveStart = 0;
const float MoveDuration = 10f;
MeshAgent.MoveTo( randomPoint.Value );
while ( timeSinceMoveStart < MoveDuration && !token.IsCancellationRequested )
{
if ( timeSinceLastConsumableSearch > 0.5f )
{
await TryDivertForConsumable(
token: token
);
timeSinceLastConsumableSearch = 0;
}
MeshAgent.MoveTo( randomPoint.Value );
await Task.FixedUpdate();
}
return !token.IsCancellationRequested;
}
private async Task<bool> PickupInventoryItem( CancellationToken token )
{
var inventoryPickupTarget = FindPickupsInRadius<InventoryPickup>(
2000f,
x => x.Items.Any( item => !Inventory.HasWeapon( item ) )
).FirstOrDefault();
if ( inventoryPickupTarget == null )
return false;
Vector3 inventoryPickupPosition = GetClosestPointOnPickupToNavMesh( inventoryPickupTarget, MeshAgent.Radius );
TimeSince timeSinceLastConsumableSearch = 0;
while ( IsPickupValid( inventoryPickupTarget ) && !token.IsCancellationRequested && inventoryPickupTarget.Items.Any( item => !Inventory.HasWeapon( item ) ) )
{
if ( timeSinceLastConsumableSearch > 0.5f )
{
await TryDivertForConsumable(
token: token,
mainTarget: inventoryPickupTarget.WorldPosition
);
timeSinceLastConsumableSearch = 0;
}
MeshAgent.MoveTo( inventoryPickupPosition );
await Task.FixedUpdate();
}
return !token.IsCancellationRequested;
}
private async Task<bool> UpdateRotationToMatchMovement( CancellationToken token )
{
while ( !token.IsCancellationRequested )
{
var currentAimTarget = MeshAgent.GetLookAhead( 30.0f ).WithZ( Controller.EyePosition.z );
var dir = currentAimTarget - Controller.EyePosition;
if ( dir.LengthSquared > 0.01f * 0.01f )
{
var rotation = Rotation.LookAt( dir );
Controller.EyeAngles = Controller.EyeAngles.LerpTo( rotation, 0.1f );
}
await Task.FixedUpdate();
}
return !token.IsCancellationRequested;
}
}