using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Sandbox;
///
/// Allows creation of a system that always exists in every scene, is hooked into the scene's lifecycle,
/// and is disposed when the scene is disposed.
///
[Expose]
public abstract partial class GameObjectSystem : IDisposable
{
public Scene Scene { get; private set; }
List disposables = new List();
public GameObjectSystem( Scene scene )
{
Scene = scene;
Id = Guid.NewGuid();
}
public virtual void Dispose()
{
foreach ( var d in disposables )
{
d.Dispose();
}
Scene = null;
}
///
/// Listen to a frame stage. Order is used to determine the order in which listeners are called, the default action always happens at 0, so if you
/// want it to happen before you should go to -1, if you want it to happen after go to 1 etc.
///
protected void Listen( Stage stage, int order, Action function, string debugName )
{
var d = Scene.AddHook( stage, order, function, GetType().Name, debugName );
disposables.Add( d );
}
///
/// A list of stages in the scene tick in which we can hook
///
public enum Stage
{
///
/// At the very start of the scene update
///
StartUpdate,
///
/// Bones are worked out
///
UpdateBones,
///
/// Physics step, called in fixed update
///
PhysicsStep,
///
/// When transforms are interpolated
///
Interpolation,
///
/// At the very end of the scene update
///
FinishUpdate,
///
/// Called at the start of fixed update
///
StartFixedUpdate,
///
/// Called at the end of fixed update
///
FinishFixedUpdate,
///
/// Called after a scene has been loaded
///
SceneLoaded,
}
///
/// When implementing an ITraceProvider, the most important thing to keep in mind
/// is that the call to DoTrace should be thread safe. This might be called from
/// multiple threads at once, so you better watch out.
///
public interface ITraceProvider
{
public void DoTrace( in SceneTrace trace, List results );
public SceneTraceResult? DoTrace( in SceneTrace trace );
}
}
///
/// A syntax sugar wrapper around GameObjectSystem, which allows you to access your system using
/// SystemName.Current instead of Scene.GetSystem.
///
public abstract class GameObjectSystem : GameObjectSystem where T : GameObjectSystem
{
protected GameObjectSystem( Scene scene ) : base( scene )
{
}
public static T Current => Get( Game.ActiveScene );
public static T Get( Scene scene ) => scene?.GetSystem() ?? default;
}