// UltimateInventorySpawner.cs using System.Collections; using System.Collections.Generic; using Simuspaces.Simulation; public class UltimateInventorySpawner : SimuScriptBase { public InventoryItem itemToSpawn = new InventoryItem(); public SceneObject triggerCube; public int maxTotal = 10; public float itemTimeoutSeconds = 30f; public Vector3 spawnOffset = new Vector3(0f, 1f, 0f); public Vector3 spawnEulerAngles = Vector3.zero; public Vector3 spawnScale = Vector3.one; public bool destroySpawnedWhenScriptStops = true; private readonly List spawned = new List(); public override void Start() { if (triggerCube == null || triggerCube.IsNull) { Log("[UltimateInventorySpawner] Assign triggerCube in the SV Inspector."); return; } MakeInteractable( triggerCube, OnTriggerCubeInteracted, highlight: true, targetUsername: null, includeChildren: true, raycastDistance: 10f, hintText: "Spawn"); } private void OnTriggerCubeInteracted(SVInteractionInfo info) { SpawnOne(); } private void SpawnOne() { if (itemToSpawn == null || itemToSpawn.IsEmpty) { Log("[UltimateInventorySpawner] Pick an inventory item in the SV Inspector."); return; } Transform anchor = triggerCube != null && triggerCube.transform != null ? triggerCube.transform : transform; Vector3 position = anchor.position + anchor.TransformDirection(spawnOffset); SceneObject spawnedObject = SpawnInventoryItem( itemToSpawn, position, spawnEulerAngles, spawnScale); if (spawnedObject == null || string.IsNullOrWhiteSpace(spawnedObject.ObjectId)) { Log("[UltimateInventorySpawner] Spawn failed."); return; } var entry = new SpawnedEntry { Object = spawnedObject }; spawned.Add(entry); if (itemTimeoutSeconds > 0f) entry.Timeout = StartCoroutine(DespawnAfter(entry, itemTimeoutSeconds)); int cap = Mathf.Max(1, maxTotal); while (spawned.Count > cap) DespawnEntry(spawned[0]); } private IEnumerator DespawnAfter(SpawnedEntry entry, float seconds) { yield return new WaitForSeconds(seconds); DespawnEntry(entry); } private void DespawnEntry(SpawnedEntry entry) { if (entry == null) return; if (entry.Timeout != null) StopCoroutine(entry.Timeout); spawned.Remove(entry); if (entry.Object != null && !string.IsNullOrWhiteSpace(entry.Object.ObjectId)) DespawnSpawnedObject(entry.Object); } public override void OnDestroy() { if (!destroySpawnedWhenScriptStops) return; for (int i = spawned.Count - 1; i >= 0; i--) DespawnEntry(spawned[i]); spawned.Clear(); } private class SpawnedEntry { public SceneObject Object; public Coroutine Timeout; } }