Files
sbox-public/engine/Sandbox.Engine/Scene/Networking/Rpc.StaticRpc.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

121 lines
3.3 KiB
C#

using System.ComponentModel;
namespace Sandbox;
public static partial class Rpc
{
/// <summary>
/// A static RPC call is incoming from the network. Look up the method and call it.
/// </summary>
internal static void IncomingStaticRpcMsg( StaticRpcMsg message, Connection source )
{
NetworkDebugSystem.Current?.Record( NetworkDebugSystem.MessageType.Rpc, message );
if ( Game.TypeLibrary.GetMemberByIdent( message.MethodIdentity ) is not MethodDescription method )
{
throw new( $"Unknown Static RPC type for method with identity '{message.MethodIdentity}'" );
}
if ( !method.HasAttribute<RpcAttribute>() )
{
source.Kick( "Unauthorized RPC" );
return;
}
NetworkDebugSystem.Current?.Track( $"{method.TypeDescription.FullName}.{method.Name}", message );
using ( WithCaller( source ) )
{
try
{
method.Invoke( null, message.Arguments );
}
catch ( Exception e )
{
Log.Error( e, $"Error calling RPC '{method.TypeDescription.FullName}.{method.Name}' - {e.Message}" );
}
}
}
/// <summary>
/// Called when a static RPC is called
/// </summary>
[EditorBrowsable( EditorBrowsableState.Never )]
public static void OnCallRpc( WrappedMethod m, params object[] argumentList )
{
var attribute = m.GetAttribute<RpcAttribute>();
if ( attribute is null ) return;
//
// Send over network
//
if ( !Calling && Networking.IsActive )
{
SendStaticRpc( m, argumentList, attribute );
}
// Was filtered out
if ( Filter.HasValue && !Filter.Value.IsRecipient( Connection.Local ) ) return;
// Was not included in the filter
if ( attribute.Mode == RpcMode.Owner && !Networking.IsHost ) return;
if ( attribute.Mode == RpcMode.Host && !Networking.IsHost ) return;
PreCall();
// Can they even call this shit
if ( !HasStaticPermission( Caller ?? Connection.Local, attribute.Flags ) ) return;
Resume( m );
}
/// <summary>
/// Does the current caller have permission to invoke the RPC?
/// </summary>
static bool HasStaticPermission( Connection caller, NetFlags permission )
{
if ( (permission.Contains( NetFlags.HostOnly ) || permission.Contains( NetFlags.OwnerOnly )) && !caller.IsHost )
return false;
return true;
}
/// <summary>
/// Do the actual send of the static RPC.
/// </summary>
private static void SendStaticRpc( WrappedMethod m, object[] argumentList, RpcAttribute attribute )
{
var networkSystem = SceneNetworkSystem.Instance;
if ( networkSystem is null )
{
Log.Warning( "SceneNetworkSystem.Instance is null when sending RPC" );
return;
}
//
// To everyone
//
if ( attribute.Mode == RpcMode.Broadcast )
{
var msg = new StaticRpcMsg { MethodIdentity = m.MethodIdentity, Arguments = argumentList };
networkSystem.Broadcast( msg, Filter, attribute.Flags );
return;
}
//
// To the host (statics can't have an owner)
//
if ( attribute.Mode is RpcMode.Owner or RpcMode.Host )
{
if ( Networking.IsHost ) return; // don't send to ourselves
var targetId = Connection.Host?.Id ?? Guid.Empty;
if ( targetId == Connection.Local.Id ) return; // don't send to ourselves
if ( targetId == Guid.Empty ) return; // don't send to no-one
var msg = new StaticRpcMsg { MethodIdentity = m.MethodIdentity, Arguments = argumentList };
networkSystem.Send( targetId, msg, attribute.Flags );
}
}
}