mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-02 11:28:19 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
285 lines
8.1 KiB
C#
285 lines
8.1 KiB
C#
using Sandbox.Utility;
|
|
|
|
namespace Sandbox;
|
|
|
|
/// <summary>
|
|
/// Marks a method as being an RPC that when invoked will be called for all connected clients including the host.
|
|
/// The state of the object the RPC is called on will be up-to-date including its <see cref="GameTransform"/> and any
|
|
/// properties with the <see cref="SyncAttribute"/> or <see cref="HostSyncAttribute"/> attributes by the time the method
|
|
/// is called on remote clients. The only except is any synchronized properties marked with <see cref="SyncAttribute.Query"/> which
|
|
/// will generally only be received every network tick.
|
|
/// </summary>
|
|
[CodeGenerator( CodeGeneratorFlags.Instance | CodeGeneratorFlags.WrapMethod, "__rpc_Wrapper" )]
|
|
[CodeGenerator( CodeGeneratorFlags.Static | CodeGeneratorFlags.WrapMethod, "Sandbox.Rpc.OnCallRpc" )]
|
|
[Obsolete( "Please use Rpc.Broadcast" )]
|
|
public sealed class BroadcastAttribute : RpcAttribute
|
|
{
|
|
public BroadcastAttribute() : base( RpcMode.Broadcast ) { }
|
|
|
|
NetPermission _permission;
|
|
|
|
public NetPermission Permission
|
|
{
|
|
get => _permission;
|
|
set
|
|
{
|
|
_permission = value;
|
|
|
|
if ( _permission == NetPermission.HostOnly ) Flags |= NetFlags.HostOnly;
|
|
if ( _permission == NetPermission.OwnerOnly ) Flags |= NetFlags.OwnerOnly;
|
|
}
|
|
}
|
|
|
|
public BroadcastAttribute( NetPermission permission ) : base( RpcMode.Broadcast )
|
|
{
|
|
Permission = permission;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marks a method as being an RPC specifically targeted to the owner of the <see cref="GameObject"/>, or the host
|
|
/// if the <see cref="GameObject"/> doesn't have an owner.
|
|
/// <br/><br/>
|
|
/// The state of the object the RPC is called on will be up-to-date including its <see cref="GameTransform"/> and any
|
|
/// properties with the <see cref="SyncAttribute"/> or <see cref="HostSyncAttribute"/> attributes by the time the method
|
|
/// is called on remote clients. The only except is any synchronized properties marked with <see cref="SyncAttribute.Query"/> which
|
|
/// will generally only be received every network tick.
|
|
/// </summary>
|
|
[CodeGenerator( CodeGeneratorFlags.Instance | CodeGeneratorFlags.WrapMethod, "__rpc_Wrapper" )]
|
|
[CodeGenerator( CodeGeneratorFlags.Static | CodeGeneratorFlags.WrapMethod, "Sandbox.Rpc.OnCallRpc" )]
|
|
[Obsolete( "Please use Rpc.Owner" )]
|
|
public sealed class AuthorityAttribute : RpcAttribute
|
|
{
|
|
public AuthorityAttribute() : base( RpcMode.Owner ) { }
|
|
|
|
NetPermission _permission;
|
|
|
|
public NetPermission Permission
|
|
{
|
|
get => _permission;
|
|
set
|
|
{
|
|
_permission = value;
|
|
|
|
if ( _permission == NetPermission.HostOnly ) Flags |= NetFlags.HostOnly;
|
|
if ( _permission == NetPermission.OwnerOnly ) Flags |= NetFlags.OwnerOnly;
|
|
}
|
|
}
|
|
|
|
public AuthorityAttribute( NetPermission permission ) : base( RpcMode.Owner )
|
|
{
|
|
Permission = permission;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies who can invoke an action over the network.
|
|
/// </summary>
|
|
[Expose, Obsolete]
|
|
public enum NetPermission
|
|
{
|
|
/// <summary>
|
|
/// Anyone can invoke this.
|
|
/// </summary>
|
|
Anyone,
|
|
|
|
/// <summary>
|
|
/// Only the host can invoke this.
|
|
/// </summary>
|
|
HostOnly,
|
|
|
|
/// <summary>
|
|
/// Only the owner can invoke this. If the action is static, this works the same way as <see cref="HostOnly"/>.
|
|
/// </summary>
|
|
OwnerOnly
|
|
}
|
|
|
|
public static partial class Rpc
|
|
{
|
|
/// <summary>
|
|
/// The <see cref="Connection"/> that is calling this method.
|
|
/// </summary>
|
|
public static Connection Caller { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The id of the <see cref="Connection"/> that is calling this method.
|
|
/// </summary>
|
|
public static Guid CallerId => Caller.Id;
|
|
|
|
/// <summary>
|
|
/// Whether we're currently being called from a remote <see cref="Connection"/>.
|
|
/// </summary>
|
|
public static bool Calling { get; private set; }
|
|
|
|
internal static Connection.Filter? Filter { get; private set; }
|
|
|
|
internal static DisposeAction<Connection, bool> WithCaller( Connection caller )
|
|
{
|
|
var oldCaller = Caller;
|
|
var oldCalling = Calling;
|
|
|
|
Calling = true;
|
|
Caller = caller;
|
|
|
|
unsafe
|
|
{
|
|
return new DisposeAction<Connection, bool>( &RestoreCaller, oldCaller, oldCalling );
|
|
}
|
|
}
|
|
|
|
static void RestoreCaller( Connection oldCaller, bool oldCalling )
|
|
{
|
|
Calling = oldCalling;
|
|
Caller = oldCaller;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resume a method from an RPC. If the RPC caller is our local connection then we'll
|
|
/// first disable any active filter and restore it afterwards.
|
|
/// </summary>
|
|
/// <param name="m"></param>
|
|
internal static void Resume( WrappedMethod m )
|
|
{
|
|
try
|
|
{
|
|
if ( Caller != Connection.Local )
|
|
{
|
|
m.Resume?.Invoke();
|
|
return;
|
|
}
|
|
|
|
var oldFilter = Filter;
|
|
Filter = null;
|
|
|
|
try
|
|
{
|
|
m.Resume?.Invoke();
|
|
}
|
|
finally
|
|
{
|
|
Filter = oldFilter;
|
|
}
|
|
}
|
|
catch ( Exception e )
|
|
{
|
|
Log.Error( e );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called right before calling an RPC function.
|
|
/// </summary>
|
|
public static void PreCall()
|
|
{
|
|
if ( Calling )
|
|
{
|
|
Calling = false;
|
|
return;
|
|
}
|
|
|
|
Caller = Connection.Local;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filter the recipients of any Rpc called in this scope to only include the specified <see cref="Connection"/> set.
|
|
/// </summary>
|
|
/// <param name="connections">Only send the RPC to these connections.</param>
|
|
public static IDisposable FilterInclude( IEnumerable<Connection> connections )
|
|
{
|
|
if ( Filter.HasValue )
|
|
throw new InvalidOperationException( "An RPC filter is already active" );
|
|
|
|
Filter = new( Connection.Filter.FilterType.Include, connections );
|
|
|
|
return DisposeAction.Create( () =>
|
|
{
|
|
Filter = null;
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filter the recipients of any Rpc called in this scope to only include a <see cref="Connection"/> based on a predicate.
|
|
/// </summary>
|
|
/// <param name="predicate">Only send the RPC to connections that meet the criteria of the predicate.</param>
|
|
public static IDisposable FilterInclude( Predicate<Connection> predicate )
|
|
{
|
|
if ( Filter.HasValue )
|
|
throw new InvalidOperationException( "An RPC filter is already active" );
|
|
|
|
Filter = new( Connection.Filter.FilterType.Include, predicate );
|
|
|
|
return DisposeAction.Create( () =>
|
|
{
|
|
Filter = null;
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filter the recipients of any Rpc called in this scope to only include the specified <see cref="Connection"/>.
|
|
/// </summary>
|
|
/// <param name="connection">Only send the RPC to this connection.</param>
|
|
public static IDisposable FilterInclude( Connection connection )
|
|
{
|
|
if ( Filter.HasValue )
|
|
throw new InvalidOperationException( "An RPC filter is already active" );
|
|
|
|
Filter = new( Connection.Filter.FilterType.Include, c => c == connection );
|
|
|
|
return DisposeAction.Create( () =>
|
|
{
|
|
Filter = null;
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filter the recipients of any Rpc called in this scope to exclude a <see cref="Connection"/> based on a predicate.
|
|
/// </summary>
|
|
/// <param name="predicate">Exclude connections that don't meet the criteria of the predicate from receiving the RPC.</param>
|
|
public static IDisposable FilterExclude( Predicate<Connection> predicate )
|
|
{
|
|
if ( Filter.HasValue )
|
|
throw new InvalidOperationException( "An RPC filter is already active" );
|
|
|
|
Filter = new( Connection.Filter.FilterType.Exclude, predicate );
|
|
|
|
return DisposeAction.Create( () =>
|
|
{
|
|
Filter = null;
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filter the recipients of any Rpc called in this scope to exclude the specified <see cref="Connection"/> set.
|
|
/// </summary>
|
|
/// <param name="connections">Exclude these connections from receiving the RPC.</param>
|
|
public static IDisposable FilterExclude( IEnumerable<Connection> connections )
|
|
{
|
|
if ( Filter.HasValue )
|
|
throw new InvalidOperationException( "An RPC filter is already active" );
|
|
|
|
Filter = new( Connection.Filter.FilterType.Exclude, connections );
|
|
|
|
return DisposeAction.Create( () =>
|
|
{
|
|
Filter = null;
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filter the recipients of any Rpc called in this scope to exclude the specified <see cref="Connection"/>.
|
|
/// </summary>
|
|
/// <param name="connection">Exclude this connection from receiving the RPC.</param>
|
|
public static IDisposable FilterExclude( Connection connection )
|
|
{
|
|
if ( Filter.HasValue )
|
|
throw new InvalidOperationException( "An RPC filter is already active" );
|
|
|
|
Filter = new( Connection.Filter.FilterType.Exclude, c => c == connection );
|
|
|
|
return DisposeAction.Create( () =>
|
|
{
|
|
Filter = null;
|
|
} );
|
|
}
|
|
}
|