Game/ControlSystem/ControlContext.cs
/// <summary>
/// Answers "which player caused this?" while entity code is running.
///
/// When a signal input fires or a seat pushes key states, the system notes who did it here.
/// If your code needs to blame someone — kill credit, undo, prop protection — just read
/// <see cref="Player"/>. It's null when nobody is responsible (e.g. map logic).
/// </summary>
public static class ControlContext
{
internal readonly record struct State( Player Player, Connection Connection );
[ThreadStatic]
private static State _current;
/// <summary>
/// The player who caused whatever is currently running, or null.
/// </summary>
public static Player Player => _current.Player;
internal static Connection Connection => _current.Connection;
/// <summary>
/// Restores whoever was responsible before when disposed, so nested pushes unwind cleanly.
/// </summary>
internal readonly struct Scope : IDisposable
{
private readonly State _previous;
internal Scope( State state )
{
_previous = _current;
_current = state;
}
public void Dispose()
{
_current = _previous;
}
}
/// <summary>
/// Mark a player as responsible for the code that runs until the scope is disposed:
/// <code>using var scope = ControlContext.Push( player );</code>
/// </summary>
internal static Scope Push( Player player, Connection connection = null ) => new( new State( player, connection ) );
}