[Net] Single rpc annotation. "sync" no longer part of mode.
- Move the "sync" property for RPCs to RPCConfig.
- Unify GDScript annotations into a single one:
- `@rpc(master)` # default
- `@rpc(puppet)`
- `@rpc(any)` # former `@remote`
- Implement three additional `@rpc` options:
- The second parameter is the "sync" option (which also calls the
function locally when RPCing). One of "sync", "nosync".
- The third parameter is the transfer mode (reliable, unreliable,
ordered).
- The third parameter is the channel (unused for now).
This commit is contained in:
parent
8b1c60c1a3
commit
ddb68f76ff
17 changed files with 72 additions and 127 deletions
|
|
@ -1165,15 +1165,11 @@ void GDScript::_init_rpc_methods_properties() {
|
|||
while (cscript) {
|
||||
// RPC Methods
|
||||
for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) {
|
||||
if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||
MultiplayerAPI::RPCConfig nd;
|
||||
nd.name = E->key();
|
||||
nd.rpc_mode = E->get()->get_rpc_mode();
|
||||
// TODO
|
||||
nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
|
||||
nd.channel = 0;
|
||||
if (-1 == rpc_functions.find(nd)) {
|
||||
rpc_functions.push_back(nd);
|
||||
MultiplayerAPI::RPCConfig config = E->get()->get_rpc_config();
|
||||
if (config.rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||
config.name = E->get()->get_name();
|
||||
if (rpc_functions.find(config) == -1) {
|
||||
rpc_functions.push_back(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ class GDScript : public Script {
|
|||
int index = 0;
|
||||
StringName setter;
|
||||
StringName getter;
|
||||
MultiplayerAPI::RPCMode rpc_mode;
|
||||
GDScriptDataType data_type;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ void GDScriptByteCodeGenerator::end_parameters() {
|
|||
function->default_arguments.reverse();
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) {
|
||||
void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) {
|
||||
function = memnew(GDScriptFunction);
|
||||
debug_stack = EngineDebugger::is_active();
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName
|
|||
|
||||
function->_static = p_static;
|
||||
function->return_type = p_return_type;
|
||||
function->rpc_mode = p_rpc_mode;
|
||||
function->rpc_config = p_rpc_config;
|
||||
function->_argument_count = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ public:
|
|||
virtual void start_block() override;
|
||||
virtual void end_block() override;
|
||||
|
||||
virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) override;
|
||||
virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) override;
|
||||
virtual GDScriptFunction *write_end() override;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public:
|
|||
virtual void start_block() = 0;
|
||||
virtual void end_block() = 0;
|
||||
|
||||
virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) = 0;
|
||||
virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) = 0;
|
||||
virtual GDScriptFunction *write_end() = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
|
|
|||
|
|
@ -1859,7 +1859,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
|
|||
|
||||
StringName func_name;
|
||||
bool is_static = false;
|
||||
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
|
||||
MultiplayerAPI::RPCConfig rpc_config;
|
||||
GDScriptDataType return_type;
|
||||
return_type.has_type = true;
|
||||
return_type.kind = GDScriptDataType::BUILTIN;
|
||||
|
|
@ -1872,7 +1872,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
|
|||
func_name = "<anonymous lambda>";
|
||||
}
|
||||
is_static = p_func->is_static;
|
||||
rpc_mode = p_func->rpc_mode;
|
||||
rpc_config = p_func->rpc_config;
|
||||
return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
|
||||
} else {
|
||||
if (p_for_ready) {
|
||||
|
|
@ -1883,7 +1883,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
|
|||
}
|
||||
|
||||
codegen.function_name = func_name;
|
||||
codegen.generator->write_start(p_script, func_name, is_static, rpc_mode, return_type);
|
||||
codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type);
|
||||
|
||||
int optional_parameters = 0;
|
||||
|
||||
|
|
@ -2088,7 +2088,7 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
|
|||
return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script);
|
||||
}
|
||||
|
||||
codegen.generator->write_start(p_script, func_name, false, p_variable->rpc_mode, return_type);
|
||||
codegen.generator->write_start(p_script, func_name, false, MultiplayerAPI::RPCConfig(), return_type);
|
||||
|
||||
if (p_is_setter) {
|
||||
uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype()));
|
||||
|
|
@ -2268,7 +2268,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
|
|||
}
|
||||
break;
|
||||
}
|
||||
minfo.rpc_mode = variable->rpc_mode;
|
||||
minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script);
|
||||
|
||||
PropertyInfo prop_info = minfo.data_type;
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ private:
|
|||
|
||||
int _initial_line = 0;
|
||||
bool _static = false;
|
||||
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
|
||||
MultiplayerAPI::RPCConfig rpc_config;
|
||||
|
||||
GDScript *_script = nullptr;
|
||||
|
||||
|
|
@ -592,7 +592,7 @@ public:
|
|||
void disassemble(const Vector<String> &p_code_lines) const;
|
||||
#endif
|
||||
|
||||
_FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; }
|
||||
_FORCE_INLINE_ MultiplayerAPI::RPCConfig get_rpc_config() const { return rpc_config; }
|
||||
GDScriptFunction();
|
||||
~GDScriptFunction();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -168,12 +168,7 @@ GDScriptParser::GDScriptParser() {
|
|||
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
|
||||
register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
|
||||
// Networking.
|
||||
register_annotation(MethodInfo("@remote"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_REMOTE>);
|
||||
register_annotation(MethodInfo("@master"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTER>);
|
||||
register_annotation(MethodInfo("@puppet"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPET>);
|
||||
register_annotation(MethodInfo("@remotesync"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_REMOTESYNC>);
|
||||
register_annotation(MethodInfo("@mastersync"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTERSYNC>);
|
||||
register_annotation(MethodInfo("@puppetsync"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPETSYNC>);
|
||||
register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTER>, 4, true);
|
||||
// TODO: Warning annotations.
|
||||
}
|
||||
|
||||
|
|
@ -3430,27 +3425,60 @@ template <MultiplayerAPI::RPCMode t_mode>
|
|||
bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Node *p_node) {
|
||||
ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE && p_node->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to variables and functions.)", p_annotation->name));
|
||||
|
||||
switch (p_node->type) {
|
||||
case Node::VARIABLE: {
|
||||
VariableNode *variable = static_cast<VariableNode *>(p_node);
|
||||
if (variable->rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||
push_error(R"(RPC annotations can only be used once per variable.)", p_annotation);
|
||||
MultiplayerAPI::RPCConfig rpc_config;
|
||||
rpc_config.rpc_mode = t_mode;
|
||||
for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) {
|
||||
if (i == 0) {
|
||||
String mode = p_annotation->resolved_arguments[i].operator String();
|
||||
if (mode == "any") {
|
||||
rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_REMOTE;
|
||||
} else if (mode == "master") {
|
||||
rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_MASTER;
|
||||
} else if (mode == "puppet") {
|
||||
rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_PUPPET;
|
||||
} else {
|
||||
push_error(R"(Invalid RPC mode. Must be one of: 'any', 'master', or 'puppet')", p_annotation);
|
||||
return false;
|
||||
}
|
||||
variable->rpc_mode = t_mode;
|
||||
break;
|
||||
} else if (i == 1) {
|
||||
String sync = p_annotation->resolved_arguments[i].operator String();
|
||||
if (sync == "sync") {
|
||||
rpc_config.sync = true;
|
||||
} else if (sync == "nosync") {
|
||||
rpc_config.sync = false;
|
||||
} else {
|
||||
push_error(R"(Invalid RPC sync mode. Must be one of: 'sync' or 'nosync')", p_annotation);
|
||||
return false;
|
||||
}
|
||||
} else if (i == 2) {
|
||||
String mode = p_annotation->resolved_arguments[i].operator String();
|
||||
if (mode == "reliable") {
|
||||
rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
|
||||
} else if (mode == "unreliable") {
|
||||
rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE;
|
||||
} else if (mode == "ordered") {
|
||||
rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED;
|
||||
} else {
|
||||
push_error(R"(Invalid RPC transfer mode. Must be one of: 'reliable', 'unreliable', 'ordered')", p_annotation);
|
||||
return false;
|
||||
}
|
||||
} else if (i == 3) {
|
||||
rpc_config.channel = p_annotation->resolved_arguments[i].operator int();
|
||||
}
|
||||
}
|
||||
switch (p_node->type) {
|
||||
case Node::FUNCTION: {
|
||||
FunctionNode *function = static_cast<FunctionNode *>(p_node);
|
||||
if (function->rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||
if (function->rpc_config.rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||
push_error(R"(RPC annotations can only be used once per function.)", p_annotation);
|
||||
return false;
|
||||
}
|
||||
function->rpc_mode = t_mode;
|
||||
function->rpc_config = rpc_config;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false; // Unreachable.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -729,7 +729,7 @@ public:
|
|||
SuiteNode *body = nullptr;
|
||||
bool is_static = false;
|
||||
bool is_coroutine = false;
|
||||
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
|
||||
MultiplayerAPI::RPCConfig rpc_config;
|
||||
MethodInfo info;
|
||||
LambdaNode *source_lambda = nullptr;
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
@ -1117,7 +1117,6 @@ public:
|
|||
bool exported = false;
|
||||
bool onready = false;
|
||||
PropertyInfo export_info;
|
||||
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
|
||||
int assignments = 0;
|
||||
int usages = 0;
|
||||
bool use_conversion_assign = false;
|
||||
|
|
|
|||
|
|
@ -695,7 +695,9 @@ Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::Functio
|
|||
ERR_FAIL_NULL_V(p_func, func);
|
||||
func["name"] = p_func->identifier->name;
|
||||
func["return_type"] = p_func->get_datatype().to_string();
|
||||
func["rpc_mode"] = p_func->rpc_mode;
|
||||
func["rpc_mode"] = p_func->rpc_config.rpc_mode;
|
||||
func["rpc_transfer_mode"] = p_func->rpc_config.transfer_mode;
|
||||
func["rpc_transfer_channel"] = p_func->rpc_config.channel;
|
||||
Array parameters;
|
||||
for (int i = 0; i < p_func->parameters.size(); i++) {
|
||||
Dictionary arg;
|
||||
|
|
|
|||
|
|
@ -3472,15 +3472,6 @@ MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_m
|
|||
if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute))) {
|
||||
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||
}
|
||||
if (p_member->has_attribute(CACHED_CLASS(RemoteSyncAttribute))) {
|
||||
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||
}
|
||||
if (p_member->has_attribute(CACHED_CLASS(MasterSyncAttribute))) {
|
||||
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
||||
}
|
||||
if (p_member->has_attribute(CACHED_CLASS(PuppetSyncAttribute))) {
|
||||
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
||||
}
|
||||
|
||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,12 @@ using System;
|
|||
|
||||
namespace Godot
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class RemoteAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class MasterAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class PuppetAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class RemoteSyncAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class MasterSyncAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class PuppetSyncAttribute : Attribute {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,9 +143,6 @@ void CachedData::clear_godot_api_cache() {
|
|||
class_RemoteAttribute = nullptr;
|
||||
class_MasterAttribute = nullptr;
|
||||
class_PuppetAttribute = nullptr;
|
||||
class_RemoteSyncAttribute = nullptr;
|
||||
class_MasterSyncAttribute = nullptr;
|
||||
class_PuppetSyncAttribute = nullptr;
|
||||
class_GodotMethodAttribute = nullptr;
|
||||
field_GodotMethodAttribute_methodName = nullptr;
|
||||
class_ScriptPathAttribute = nullptr;
|
||||
|
|
@ -272,9 +269,6 @@ void update_godot_api_cache() {
|
|||
CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
|
||||
CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
|
||||
CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute));
|
||||
CACHE_CLASS_AND_CHECK(RemoteSyncAttribute, GODOT_API_CLASS(RemoteSyncAttribute));
|
||||
CACHE_CLASS_AND_CHECK(MasterSyncAttribute, GODOT_API_CLASS(MasterSyncAttribute));
|
||||
CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute));
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -114,9 +114,6 @@ struct CachedData {
|
|||
GDMonoClass *class_RemoteAttribute;
|
||||
GDMonoClass *class_MasterAttribute;
|
||||
GDMonoClass *class_PuppetAttribute;
|
||||
GDMonoClass *class_RemoteSyncAttribute;
|
||||
GDMonoClass *class_MasterSyncAttribute;
|
||||
GDMonoClass *class_PuppetSyncAttribute;
|
||||
GDMonoClass *class_GodotMethodAttribute;
|
||||
GDMonoField *field_GodotMethodAttribute_methodName;
|
||||
GDMonoClass *class_ScriptPathAttribute;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue