using System.ComponentModel; namespace Sandbox; public static partial class Rpc { /// /// A static RPC call is incoming from the network. Look up the method and call it. /// 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() ) { 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}" ); } } } /// /// Called when a static RPC is called /// [EditorBrowsable( EditorBrowsableState.Never )] public static void OnCallRpc( WrappedMethod m, params object[] argumentList ) { var attribute = m.GetAttribute(); 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 ); } /// /// Does the current caller have permission to invoke the RPC? /// static bool HasStaticPermission( Connection caller, NetFlags permission ) { if ( (permission.Contains( NetFlags.HostOnly ) || permission.Contains( NetFlags.OwnerOnly )) && !caller.IsHost ) return false; return true; } /// /// Do the actual send of the static RPC. /// 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 ); } } }