Optmized data sent during RPC and RSet calls.

- Now is sent the method ID rather the full function name.
- The passed IDs (Node and Method) are compressed so to use less possible space.
- The variant (INT and BOOL) is now encoded and compressed so to use much less data.
- Optimized RPCMode retrieval for GDScript functions.
- Added checksum to assert the methods are the same across peers.

This work has been kindly sponsored by IMVU.
This commit is contained in:
Andrea Catania 2020-02-12 11:51:50 +01:00
parent 70dd7f4e1a
commit eb07e87981
19 changed files with 1580 additions and 292 deletions

View file

@ -30,6 +30,8 @@
#include "visual_script.h"
#include <stdint.h>
#include "core/core_string_names.h"
#include "core/os/os.h"
#include "core/project_settings.h"
@ -1102,6 +1104,60 @@ bool VisualScript::are_subnodes_edited() const {
}
#endif
Vector<ScriptNetData> VisualScript::get_rpc_methods() const {
return rpc_functions;
}
uint16_t VisualScript::get_rpc_method_id(const StringName &p_method) const {
for (int i = 0; i < rpc_functions.size(); i++) {
if (rpc_functions[i].name == p_method) {
return i;
}
}
return UINT16_MAX;
}
StringName VisualScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
return rpc_functions[p_rpc_method_id].name;
}
MultiplayerAPI::RPCMode VisualScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
return rpc_functions[p_rpc_method_id].mode;
}
MultiplayerAPI::RPCMode VisualScript::get_rpc_mode(const StringName &p_method) const {
return get_rpc_mode_by_id(get_rpc_method_id(p_method));
}
Vector<ScriptNetData> VisualScript::get_rset_properties() const {
return rpc_variables;
}
uint16_t VisualScript::get_rset_property_id(const StringName &p_variable) const {
for (int i = 0; i < rpc_variables.size(); i++) {
if (rpc_variables[i].name == p_variable) {
return i;
}
}
return UINT16_MAX;
}
StringName VisualScript::get_rset_property(const uint16_t p_rset_property_id) const {
ERR_FAIL_COND_V(p_rset_property_id >= rpc_variables.size(), StringName());
return rpc_variables[p_rset_property_id].name;
}
MultiplayerAPI::RPCMode VisualScript::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const {
ERR_FAIL_COND_V(p_rset_variable_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
return rpc_functions[p_rset_variable_id].mode;
}
MultiplayerAPI::RPCMode VisualScript::get_rset_mode(const StringName &p_variable) const {
return get_rset_mode_by_id(get_rset_property_id(p_variable));
}
void VisualScript::_set_data(const Dictionary &p_data) {
Dictionary d = p_data;
@ -1206,6 +1262,30 @@ void VisualScript::_set_data(const Dictionary &p_data) {
is_tool_script = d["is_tool_script"];
else
is_tool_script = false;
// Takes all the rpc methods
rpc_functions.clear();
rpc_variables.clear();
for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
if (E->get().function_id >= 0 && E->get().nodes.find(E->get().function_id)) {
Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
if (vsf.is_valid()) {
if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
ScriptNetData nd;
nd.name = E->key();
nd.mode = vsf->get_rpc_mode();
if (rpc_functions.find(nd) == -1) {
rpc_functions.push_back(nd);
}
}
}
}
}
// Visual script doesn't have rset :(
// Sort so we are 100% that they are always the same.
rpc_functions.sort_custom<SortNetData>();
}
Dictionary VisualScript::_get_data() const {
@ -2043,31 +2123,44 @@ Ref<Script> VisualScriptInstance::get_script() const {
return script;
}
Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const {
return script->get_rpc_methods();
}
uint16_t VisualScriptInstance::get_rpc_method_id(const StringName &p_method) const {
return script->get_rpc_method_id(p_method);
}
StringName VisualScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
return script->get_rpc_method(p_rpc_method_id);
}
MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
return script->get_rpc_mode_by_id(p_rpc_method_id);
}
MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
return script->get_rpc_mode(p_method);
}
if (p_method == script->get_default_func())
return MultiplayerAPI::RPC_MODE_DISABLED;
Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const {
return script->get_rset_properties();
}
const Map<StringName, VisualScript::Function>::Element *E = script->functions.find(p_method);
if (!E) {
return MultiplayerAPI::RPC_MODE_DISABLED;
}
uint16_t VisualScriptInstance::get_rset_property_id(const StringName &p_variable) const {
return script->get_rset_property_id(p_variable);
}
if (E->get().function_id >= 0 && E->get().nodes.has(E->get().function_id)) {
StringName VisualScriptInstance::get_rset_property(const uint16_t p_rset_property_id) const {
return script->get_rset_property(p_rset_property_id);
}
Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
if (vsf.is_valid()) {
return vsf->get_rpc_mode();
}
}
return MultiplayerAPI::RPC_MODE_DISABLED;
MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const {
return script->get_rset_mode_by_id(p_rset_variable_id);
}
MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const {
return MultiplayerAPI::RPC_MODE_DISABLED;
return script->get_rset_mode(p_variable);
}
void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {