C#: New RPCAttribute

Replace old RPC attributes with a new single `RPCAttribute` which works
like the GDScript `@rpc` annotation.
This commit is contained in:
Raul Santos 2022-07-07 03:13:41 +02:00
parent 76d0a99707
commit 8131358b71
No known key found for this signature in database
GPG Key ID: B532473AE3A803E4
7 changed files with 76 additions and 41 deletions

View File

@ -3063,16 +3063,11 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
Vector<GDMonoMethod *> methods = top->get_all_methods();
for (int i = 0; i < methods.size(); i++) {
if (!methods[i]->is_static()) {
Multiplayer::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]);
if (Multiplayer::RPC_MODE_DISABLED != mode) {
Multiplayer::RPCConfig nd;
nd.name = methods[i]->get_name();
nd.rpc_mode = mode;
// TODO Transfer mode, channel
nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
nd.channel = 0;
if (-1 == p_script->rpc_functions.find(nd)) {
p_script->rpc_functions.push_back(nd);
Multiplayer::RPCConfig rpc_config = p_script->_member_get_rpc_config(methods[i]);
if (rpc_config.rpc_mode != Multiplayer::RPC_MODE_DISABLED) {
// RPC annotations can only be used once per method
if (p_script->rpc_functions.find(rpc_config) == -1) {
p_script->rpc_functions.push_back(rpc_config);
}
}
}
@ -3507,15 +3502,19 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
return -1;
}
Multiplayer::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const {
if (p_member->has_attribute(CACHED_CLASS(AnyPeerAttribute))) {
return Multiplayer::RPC_MODE_ANY_PEER;
}
if (p_member->has_attribute(CACHED_CLASS(AuthorityAttribute))) {
return Multiplayer::RPC_MODE_AUTHORITY;
Multiplayer::RPCConfig CSharpScript::_member_get_rpc_config(IMonoClassMember *p_member) const {
Multiplayer::RPCConfig rpc_config;
MonoObject *rpc_attribute = p_member->get_attribute(CACHED_CLASS(RPCAttribute));
if (rpc_attribute != nullptr) {
rpc_config.name = p_member->get_name();
rpc_config.rpc_mode = (Multiplayer::RPCMode)CACHED_PROPERTY(RPCAttribute, Mode)->get_int_value(rpc_attribute);
rpc_config.call_local = CACHED_PROPERTY(RPCAttribute, CallLocal)->get_bool_value(rpc_attribute);
rpc_config.transfer_mode = (Multiplayer::TransferMode)CACHED_PROPERTY(RPCAttribute, TransferMode)->get_int_value(rpc_attribute);
rpc_config.channel = CACHED_PROPERTY(RPCAttribute, TransferChannel)->get_int_value(rpc_attribute);
}
return Multiplayer::RPC_MODE_DISABLED;
return rpc_config;
}
const Vector<Multiplayer::RPCConfig> CSharpScript::get_rpc_methods() const {

View File

@ -179,7 +179,7 @@ private:
static void update_script_class_info(Ref<CSharpScript> p_script);
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
Multiplayer::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
Multiplayer::RPCConfig _member_get_rpc_config(IMonoClassMember *p_member) const;
protected:
static void _bind_methods();

View File

@ -0,0 +1,43 @@
using System;
namespace Godot
{
/// <summary>
/// Attribute that changes the RPC mode for the annotated <c>method</c> to the given <see cref="Mode"/>,
/// optionally specifying the <see cref="TransferMode"/> and <see cref="TransferChannel"/> (on supported peers).
/// See <see cref="RPCMode"/> and <see cref="TransferMode"/>. By default, methods are not exposed to networking
/// (and RPCs).
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class RPCAttribute : Attribute
{
/// <summary>
/// RPC mode for the annotated method.
/// </summary>
public RPCMode Mode { get; } = RPCMode.Disabled;
/// <summary>
/// If the method will also be called locally; otherwise, it is only called remotely.
/// </summary>
public bool CallLocal { get; set; } = false;
/// <summary>
/// Transfer mode for the annotated method.
/// </summary>
public TransferMode TransferMode { get; set; } = TransferMode.Reliable;
/// <summary>
/// Transfer channel for the annotated mode.
/// </summary>
public int TransferChannel { get; set; } = 0;
/// <summary>
/// Constructs a <see cref="RPCAttribute"/> instance.
/// </summary>
/// <param name="mode">The RPC mode to use.</param>
public RPCAttribute(RPCMode mode = RPCMode.Authority)
{
Mode = mode;
}
}
}

View File

@ -1,16 +0,0 @@
using System;
namespace Godot
{
/// <summary>
/// Constructs a new AnyPeerAttribute instance. Members with the AnyPeerAttribute are given authority over their own player.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AnyPeerAttribute : Attribute { }
/// <summary>
/// Constructs a new AuthorityAttribute instance. Members with the AuthorityAttribute are given authority over the game.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AuthorityAttribute : Attribute { }
}

View File

@ -18,7 +18,7 @@
<Compile Include="Core\Attributes\DisableGodotGeneratorsAttribute.cs" />
<Compile Include="Core\Attributes\ExportAttribute.cs" />
<Compile Include="Core\Attributes\GodotMethodAttribute.cs" />
<Compile Include="Core\Attributes\RPCAttributes.cs" />
<Compile Include="Core\Attributes\RPCAttribute.cs" />
<Compile Include="Core\Attributes\ScriptPathAttribute.cs" />
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />

View File

@ -140,8 +140,11 @@ void CachedData::clear_godot_api_cache() {
field_ExportAttribute_hintString = nullptr;
class_SignalAttribute = nullptr;
class_ToolAttribute = nullptr;
class_AnyPeerAttribute = nullptr;
class_AuthorityAttribute = nullptr;
class_RPCAttribute = nullptr;
property_RPCAttribute_Mode = nullptr;
property_RPCAttribute_CallLocal = nullptr;
property_RPCAttribute_TransferMode = nullptr;
property_RPCAttribute_TransferChannel = nullptr;
class_GodotMethodAttribute = nullptr;
field_GodotMethodAttribute_methodName = nullptr;
class_ScriptPathAttribute = nullptr;
@ -268,8 +271,11 @@ void update_godot_api_cache() {
CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
CACHE_CLASS_AND_CHECK(AnyPeerAttribute, GODOT_API_CLASS(AnyPeerAttribute));
CACHE_CLASS_AND_CHECK(AuthorityAttribute, GODOT_API_CLASS(AuthorityAttribute));
CACHE_CLASS_AND_CHECK(RPCAttribute, GODOT_API_CLASS(RPCAttribute));
CACHE_PROPERTY_AND_CHECK(RPCAttribute, Mode, CACHED_CLASS(RPCAttribute)->get_property("Mode"));
CACHE_PROPERTY_AND_CHECK(RPCAttribute, CallLocal, CACHED_CLASS(RPCAttribute)->get_property("CallLocal"));
CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferMode, CACHED_CLASS(RPCAttribute)->get_property("TransferMode"));
CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferChannel, CACHED_CLASS(RPCAttribute)->get_property("TransferChannel"));
CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));

View File

@ -111,8 +111,11 @@ struct CachedData {
GDMonoField *field_ExportAttribute_hintString = nullptr;
GDMonoClass *class_SignalAttribute = nullptr;
GDMonoClass *class_ToolAttribute = nullptr;
GDMonoClass *class_AnyPeerAttribute = nullptr;
GDMonoClass *class_AuthorityAttribute = nullptr;
GDMonoClass *class_RPCAttribute = nullptr;
GDMonoProperty *property_RPCAttribute_Mode = nullptr;
GDMonoProperty *property_RPCAttribute_CallLocal = nullptr;
GDMonoProperty *property_RPCAttribute_TransferMode = nullptr;
GDMonoProperty *property_RPCAttribute_TransferChannel = nullptr;
GDMonoClass *class_GodotMethodAttribute = nullptr;
GDMonoField *field_GodotMethodAttribute_methodName = nullptr;
GDMonoClass *class_ScriptPathAttribute = nullptr;