Tikfinity/Actions/TikfinitySpawnPrefabAction.cs
using System.Threading.Tasks;
using Sandbox;
namespace TikfinitySbox;
/// <summary>
/// No-code route action that spawns a bounded number of prefab instances on the host.
/// </summary>
public sealed class TikfinitySpawnPrefabAction : Component, ITikfinityEvents
{
[Property] public string Route { get; set; } = "gift.spawn";
[Property] public GameObject Prefab { get; set; }
[Property] public GameObject SpawnPoint { get; set; }
[Property] public bool NetworkSpawnedObjects { get; set; } = true;
[Property, Range( 1, 100 )] public int MaxSpawnsPerInteraction { get; set; } = 10;
[Property, Range( 0f, 3600f )] public float LifetimeSeconds { get; set; }
[Property, Range( 0f, 1000f )] public float RandomRadius { get; set; }
void ITikfinityEvents.OnInteraction( TikfinityInteraction interaction )
{
if ( !Networking.IsHost || interaction is null ) return;
if ( !string.Equals( Route?.Trim(), interaction.Route, System.StringComparison.OrdinalIgnoreCase ) ) return;
if ( !Prefab.IsValid() )
{
Log.Warning( $"TikFinity spawn action '{Route}' has no valid prefab." );
return;
}
var count = interaction.Amount < 1 ? 1 : interaction.Amount;
var maximum = MaxSpawnsPerInteraction < 1 ? 1 : MaxSpawnsPerInteraction;
if ( count > maximum ) count = maximum;
var origin = SpawnPoint.IsValid() ? SpawnPoint.WorldPosition : WorldPosition;
var rotation = SpawnPoint.IsValid() ? SpawnPoint.WorldRotation : WorldRotation;
for ( var i = 0; i < count; i++ )
{
var position = origin + RandomOffset();
var instance = Prefab.Clone( position, rotation );
if ( NetworkSpawnedObjects && Networking.IsActive )
{
if ( !instance.NetworkSpawn( Connection.Host ) )
{
instance.Destroy();
continue;
}
}
if ( LifetimeSeconds > 0f ) _ = DestroyLater( instance );
}
}
Vector3 RandomOffset()
{
if ( RandomRadius <= 0f ) return Vector3.Zero;
var angle = Game.Random.NextSingle() * 360f;
var distance = Game.Random.NextSingle() * RandomRadius;
return Rotation.FromYaw( angle ).Forward * distance;
}
async Task DestroyLater( GameObject instance )
{
await Task.DelaySeconds( LifetimeSeconds );
if ( Networking.IsHost && instance.IsValid() ) instance.Destroy();
}
}