summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/func_ref.cpp9
-rw-r--r--core/hashfuncs.h3
-rw-r--r--core/io/marshalls.cpp9
-rw-r--r--core/io/multiplayer_api.cpp497
-rw-r--r--core/io/multiplayer_api.h24
-rw-r--r--core/method_ptrcall.h16
-rw-r--r--core/object.cpp9
-rw-r--r--core/object.h7
-rw-r--r--core/object_id.h32
-rw-r--r--core/reference.cpp9
-rw-r--r--core/script_language.cpp9
-rw-r--r--core/script_language.h45
-rw-r--r--core/type_info.h10
-rw-r--r--core/variant.cpp13
-rw-r--r--core/variant.h4
-rw-r--r--doc/classes/BaseMaterial3D.xml188
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp30
-rw-r--r--editor/dictionary_property_edit.cpp1
-rw-r--r--editor/editor_data.cpp14
-rw-r--r--editor/editor_node.cpp8
-rw-r--r--editor/editor_properties.cpp10
-rw-r--r--editor/editor_sectioned_inspector.cpp3
-rw-r--r--editor/inspector_dock.cpp12
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp7
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp30
-rw-r--r--editor/property_editor.cpp8
-rw-r--r--editor/property_selector.cpp12
-rw-r--r--editor/script_editor_debugger.cpp13
-rw-r--r--modules/bullet/area_bullet.cpp6
-rw-r--r--modules/bullet/area_bullet.h3
-rw-r--r--modules/bullet/bullet_physics_server.cpp14
-rw-r--r--modules/bullet/bullet_physics_server.h4
-rw-r--r--modules/bullet/collision_object_bullet.cpp2
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp4
-rw-r--r--modules/bullet/space_bullet.cpp2
-rw-r--r--modules/gdnative/gdnative/gdnative.cpp2
-rw-r--r--modules/gdnative/gdnative/string.cpp7
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp28
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp342
-rw-r--r--modules/gdnative/nativescript/nativescript.h29
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp32
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h9
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp105
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h17
-rw-r--r--modules/gdnavigation/gd_navigation_server.cpp2
-rw-r--r--modules/gdnavigation/rvo_agent.cpp8
-rw-r--r--modules/gdscript/gdscript.cpp155
-rw-r--r--modules/gdscript/gdscript.h23
-rw-r--r--modules/gdscript/gdscript_function.cpp6
-rw-r--r--modules/gdscript/gdscript_functions.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp2
-rw-r--r--modules/mono/csharp_script.cpp219
-rw-r--r--modules/mono/csharp_script.h28
-rw-r--r--modules/mono/signal_awaiter_utils.cpp9
-rw-r--r--modules/visual_script/visual_script.cpp133
-rw-r--r--modules/visual_script/visual_script.h23
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp6
-rw-r--r--platform/x11/os_x11.cpp5
-rw-r--r--scene/2d/area_2d.cpp4
-rw-r--r--scene/2d/area_2d.h4
-rw-r--r--scene/2d/camera_2d.cpp4
-rw-r--r--scene/2d/canvas_item.cpp2
-rw-r--r--scene/2d/collision_object_2d.cpp4
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/2d/polygon_2d.cpp4
-rw-r--r--scene/2d/ray_cast_2d.cpp6
-rw-r--r--scene/2d/remote_transform_2d.cpp7
-rw-r--r--scene/3d/area.cpp4
-rw-r--r--scene/3d/area.h4
-rw-r--r--scene/3d/physics_body.cpp4
-rw-r--r--scene/3d/ray_cast.cpp6
-rw-r--r--scene/3d/remote_transform.cpp7
-rw-r--r--scene/3d/skeleton.cpp12
-rw-r--r--scene/3d/skeleton.h2
-rw-r--r--scene/animation/animation_player.cpp2
-rw-r--r--scene/animation/animation_player.h10
-rw-r--r--scene/animation/animation_tree.cpp9
-rw-r--r--scene/animation/animation_tree.h1
-rw-r--r--scene/gui/control.cpp13
-rw-r--r--scene/gui/tree.cpp2
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/canvas_layer.cpp4
-rw-r--r--scene/main/node.cpp128
-rw-r--r--scene/main/node.h31
-rw-r--r--scene/main/viewport.cpp32
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--servers/physics/area_sw.cpp10
-rw-r--r--servers/physics/area_sw.h4
-rw-r--r--servers/physics/body_sw.cpp4
-rw-r--r--servers/physics/body_sw.h2
-rw-r--r--servers/physics/collision_object_sw.cpp2
-rw-r--r--servers/physics/physics_server_sw.cpp14
-rw-r--r--servers/physics/physics_server_sw.h4
-rw-r--r--servers/physics/space_sw.cpp8
-rw-r--r--servers/physics_2d/area_2d_sw.cpp10
-rw-r--r--servers/physics_2d/area_2d_sw.h4
-rw-r--r--servers/physics_2d/body_2d_sw.cpp4
-rw-r--r--servers/physics_2d/body_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp2
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp22
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h8
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h8
-rw-r--r--servers/physics_2d/space_2d_sw.cpp8
-rw-r--r--servers/physics_2d/space_2d_sw.h2
-rw-r--r--servers/physics_2d_server.cpp2
-rw-r--r--servers/physics_2d_server.h12
-rw-r--r--servers/physics_server.h6
-rw-r--r--servers/visual/rasterizer_rd/shader_compiler_rd.cpp30
-rw-r--r--servers/visual/shader_language.cpp238
-rw-r--r--servers/visual/shader_language.h18
-rw-r--r--servers/visual/visual_server_scene.cpp6
-rw-r--r--servers/visual/visual_server_scene.h3
114 files changed, 2411 insertions, 601 deletions
diff --git a/core/func_ref.cpp b/core/func_ref.cpp
index 2dffb30bab..e20188c813 100644
--- a/core/func_ref.cpp
+++ b/core/func_ref.cpp
@@ -32,7 +32,7 @@
Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
- if (id == 0) {
+ if (id.is_null()) {
r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return Variant();
}
@@ -48,7 +48,7 @@ Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Variant::Call
Variant FuncRef::call_funcv(const Array &p_args) {
- ERR_FAIL_COND_V(id == 0, Variant());
+ ERR_FAIL_COND_V(id.is_null(), Variant());
Object *obj = ObjectDB::get_instance(id);
@@ -69,7 +69,7 @@ void FuncRef::set_function(const StringName &p_func) {
}
bool FuncRef::is_valid() const {
- if (id == 0)
+ if (id.is_null())
return false;
Object *obj = ObjectDB::get_instance(id);
@@ -95,6 +95,5 @@ void FuncRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_valid"), &FuncRef::is_valid);
}
-FuncRef::FuncRef() :
- id(0) {
+FuncRef::FuncRef() {
}
diff --git a/core/hashfuncs.h b/core/hashfuncs.h
index 647e8a40b2..d6cf04e560 100644
--- a/core/hashfuncs.h
+++ b/core/hashfuncs.h
@@ -34,10 +34,10 @@
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "core/node_path.h"
+#include "core/object_id.h"
#include "core/string_name.h"
#include "core/typedefs.h"
#include "core/ustring.h"
-
/**
* Hashing functions
*/
@@ -137,6 +137,7 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
+ static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); }
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index e847a9cf0c..fdce9db2a0 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -53,8 +53,7 @@ ObjectID EncodedObjectAsID::get_object_id() const {
return id;
}
-EncodedObjectAsID::EncodedObjectAsID() :
- id(0) {
+EncodedObjectAsID::EncodedObjectAsID() {
}
#define _S(a) ((int32_t)a)
@@ -386,11 +385,11 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
if (type & ENCODE_FLAG_OBJECT_AS_ID) {
//this _is_ allowed
ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
- ObjectID val = decode_uint64(buf);
+ ObjectID val = ObjectID(decode_uint64(buf));
if (r_len)
(*r_len) += 8;
- if (val == 0) {
+ if (val.is_null()) {
r_variant = (Object *)NULL;
} else {
Ref<EncodedObjectAsID> obj_as_id;
@@ -1129,7 +1128,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
Object *obj = p_variant;
- ObjectID id = 0;
+ ObjectID id;
if (obj && ObjectDB::instance_validate(obj)) {
id = obj->get_instance_id();
}
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index fbed460a4e..ce641dd0f5 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -32,6 +32,7 @@
#include "core/io/marshalls.h"
#include "scene/main/node.h"
+#include <stdint.h>
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
@@ -180,7 +181,8 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
#endif
- uint8_t packet_type = p_packet[0];
+ // Extract the `packet_type` from the LSB three bits:
+ uint8_t packet_type = p_packet[0] & 7;
switch (packet_type) {
@@ -197,31 +199,80 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
case NETWORK_COMMAND_REMOTE_CALL:
case NETWORK_COMMAND_REMOTE_SET: {
- ERR_FAIL_COND_MSG(p_packet_len < 6, "Invalid packet received. Size too small.");
-
- Node *node = _process_get_node(p_from, p_packet, p_packet_len);
+ // Extract packet meta
+ int packet_min_size = 1;
+ int name_id_offset = 1;
+ ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small.");
+ // Compute the meta size, which depends on the compression level.
+ int node_id_compression = (p_packet[0] & 24) >> 3;
+ int name_id_compression = (p_packet[0] & 32) >> 5;
+
+ switch (node_id_compression) {
+ case NETWORK_NODE_ID_COMPRESSION_8:
+ packet_min_size += 1;
+ name_id_offset += 1;
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_16:
+ packet_min_size += 2;
+ name_id_offset += 2;
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_32:
+ packet_min_size += 4;
+ name_id_offset += 4;
+ break;
+ default:
+ ERR_FAIL_MSG("Was not possible to extract the node id compression mode.");
+ }
+ switch (name_id_compression) {
+ case NETWORK_NAME_ID_COMPRESSION_8:
+ packet_min_size += 1;
+ break;
+ case NETWORK_NAME_ID_COMPRESSION_16:
+ packet_min_size += 2;
+ break;
+ default:
+ ERR_FAIL_MSG("Was not possible to extract the name id compression mode.");
+ }
+ ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small.");
+ uint32_t node_target = 0;
+ switch (node_id_compression) {
+ case NETWORK_NODE_ID_COMPRESSION_8:
+ node_target = p_packet[1];
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_16:
+ node_target = decode_uint16(p_packet + 1);
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_32:
+ node_target = decode_uint32(p_packet + 1);
+ break;
+ default:
+ // Unreachable, checked before.
+ CRASH_NOW();
+ }
+ Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len);
ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found.");
- // Detect cstring end.
- int len_end = 5;
- for (; len_end < p_packet_len; len_end++) {
- if (p_packet[len_end] == 0) {
+ uint16_t name_id = 0;
+ switch (name_id_compression) {
+ case NETWORK_NAME_ID_COMPRESSION_8:
+ name_id = p_packet[name_id_offset];
break;
- }
+ case NETWORK_NAME_ID_COMPRESSION_16:
+ name_id = decode_uint16(p_packet + name_id_offset);
+ break;
+ default:
+ // Unreachable, checked before.
+ CRASH_NOW();
}
- ERR_FAIL_COND_MSG(len_end >= p_packet_len, "Invalid packet received. Size too small.");
-
- StringName name = String::utf8((const char *)&p_packet[5]);
-
if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
- _process_rpc(node, name, p_from, p_packet, p_packet_len, len_end + 1);
+ _process_rpc(node, name_id, p_from, p_packet, p_packet_len, packet_min_size);
} else {
- _process_rset(node, name, p_from, p_packet, p_packet_len, len_end + 1);
+ _process_rset(node, name_id, p_from, p_packet, p_packet_len, packet_min_size);
}
} break;
@@ -233,15 +284,14 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
}
-Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int p_packet_len) {
+Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len) {
- uint32_t target = decode_uint32(&p_packet[1]);
Node *node = NULL;
- if (target & 0x80000000) {
+ if (p_node_target & 0x80000000) {
// Use full path (not cached yet).
- int ofs = target & 0x7FFFFFFF;
+ int ofs = p_node_target & 0x7FFFFFFF;
ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, NULL, "Invalid packet received. Size smaller than declared.");
@@ -256,7 +306,7 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
ERR_PRINT("Failed to get path from RPC: " + String(np) + ".");
} else {
// Use cached path.
- int id = target;
+ int id = p_node_target;
Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
ERR_FAIL_COND_V_MSG(!E, NULL, "Invalid packet received. Requests invalid peer cache.");
@@ -274,21 +324,21 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
return node;
}
-void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
+void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
// Check that remote can call the RPC on this node.
- RPCMode rpc_mode = RPC_MODE_DISABLED;
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_name);
- if (E) {
- rpc_mode = E->get();
- } else if (p_node->get_script_instance()) {
- rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name);
+ StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
+ RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id);
+ if (name == StringName() && p_node->get_script_instance()) {
+ name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id);
+ rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id);
}
+ ERR_FAIL_COND(name == StringName());
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
- ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
int argc = p_packet[p_offset];
Vector<Variant> args;
@@ -311,7 +361,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
int vlen;
- Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ Error err = _decode_and_decompress_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument.");
argp.write[i] = &args[i];
@@ -320,29 +370,29 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
Variant::CallError ce;
- p_node->call(p_name, (const Variant **)argp.ptr(), argc, ce);
+ p_node->call(name, (const Variant **)argp.ptr(), argc, ce);
if (ce.error != Variant::CallError::CALL_OK) {
- String error = Variant::get_call_error_text(p_node, p_name, (const Variant **)argp.ptr(), argc, ce);
+ String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce);
error = "RPC - " + error;
ERR_PRINT(error);
}
}
-void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
+void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
// Check that remote can call the RSET on this node.
- RPCMode rset_mode = RPC_MODE_DISABLED;
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_name);
- if (E) {
- rset_mode = E->get();
- } else if (p_node->get_script_instance()) {
- rset_mode = p_node->get_script_instance()->get_rset_mode(p_name);
+ StringName name = p_node->get_node_rset_property(p_rpc_property_id);
+ RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id);
+ if (name == StringName() && p_node->get_script_instance()) {
+ name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id);
+ rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id);
}
+ ERR_FAIL_COND(name == StringName());
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
- ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
#ifdef DEBUG_ENABLED
if (profiling) {
@@ -353,26 +403,33 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
#endif
Variant value;
- Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value.");
bool valid;
- p_node->set(p_name, value, &valid);
+ p_node->set(name, value, &valid);
if (!valid) {
- String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class() + ".";
+ String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + ".";
ERR_PRINT(error);
}
}
void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
- ERR_FAIL_COND_MSG(p_packet_len < 5, "Invalid packet received. Size too small.");
- int id = decode_uint32(&p_packet[1]);
+ ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small.");
+ int ofs = 1;
+
+ String methods_md5;
+ methods_md5.parse_utf8((const char *)(p_packet + ofs), 32);
+ ofs += 33;
+
+ int id = decode_uint32(&p_packet[ofs]);
+ ofs += 4;
String paths;
- paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5);
+ paths.parse_utf8((const char *)(p_packet + ofs), p_packet_len - ofs);
NodePath path = paths;
@@ -380,9 +437,15 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
path_get_cache[p_from] = PathGetCache();
}
+ Node *node = root_node->get_node(path);
+ ERR_FAIL_COND(node == NULL);
+ const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5;
+ if (valid_rpc_checksum == false) {
+ ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
+ }
+
PathGetCache::NodeInfo ni;
ni.path = path;
- ni.instance = 0;
path_get_cache[p_from].nodes[id] = ni;
@@ -392,9 +455,10 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
Vector<uint8_t> packet;
- packet.resize(1 + len);
+ packet.resize(1 + 1 + len);
packet.write[0] = NETWORK_COMMAND_CONFIRM_PATH;
- encode_cstring(pname.get_data(), &packet.write[1]);
+ packet.write[1] = valid_rpc_checksum;
+ encode_cstring(pname.get_data(), &packet.write[2]);
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
network_peer->set_target_peer(p_from);
@@ -403,13 +467,19 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
- ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small.");
+ ERR_FAIL_COND_MSG(p_packet_len < 3, "Invalid packet received. Size too small.");
+
+ const bool valid_rpc_checksum = p_packet[1];
String paths;
- paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1);
+ paths.parse_utf8((const char *)&p_packet[2], p_packet_len - 2);
NodePath path = paths;
+ if (valid_rpc_checksum == false) {
+ ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
+ }
+
PathSentCache *psc = path_send_cache.getptr(path);
ERR_FAIL_COND_MSG(!psc, "Invalid packet received. Tries to confirm a path which was not found in cache.");
@@ -418,7 +488,7 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet,
E->get() = true;
}
-bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int p_target) {
+bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target) {
bool has_all_peers = true;
List<int> peers_to_add; // If one is missing, take note to add it.
@@ -443,31 +513,192 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int
}
}
- // Those that need to be added, send a message for this.
+ if (peers_to_add.size() > 0) {
- for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
+ // Those that need to be added, send a message for this.
// Encode function name.
- CharString pname = String(p_path).utf8();
- int len = encode_cstring(pname.get_data(), NULL);
+ const CharString path = String(p_path).utf8();
+ const int path_len = encode_cstring(path.get_data(), NULL);
+
+ // Extract MD5 from rpc methods list.
+ const String methods_md5 = p_node->get_rpc_md5();
+ const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder.
Vector<uint8_t> packet;
+ packet.resize(1 + 4 + path_len + methods_md5_len);
+ int ofs = 0;
+
+ packet.write[ofs] = NETWORK_COMMAND_SIMPLIFY_PATH;
+ ofs += 1;
+
+ ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]);
+
+ ofs += encode_uint32(psc->id, &packet.write[ofs]);
+
+ ofs += encode_cstring(path.get_data(), &packet.write[ofs]);
- packet.resize(1 + 4 + len);
- packet.write[0] = NETWORK_COMMAND_SIMPLIFY_PATH;
- encode_uint32(psc->id, &packet.write[1]);
- encode_cstring(pname.get_data(), &packet.write[5]);
+ for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
- network_peer->set_target_peer(E->get()); // To all of you.
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
- network_peer->put_packet(packet.ptr(), packet.size());
+ network_peer->set_target_peer(E->get()); // To all of you.
+ network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->put_packet(packet.ptr(), packet.size());
- psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed.
+ psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed.
+ }
}
return has_all_peers;
}
+// The variant is compressed and encoded; The first byte contains all the meta
+// information and the format is:
+// - The first LSB 5 bits are used for the variant type.
+// - The next two bits are used to store the encoding mode.
+// - The most significant is used to store the boolean value.
+#define VARIANT_META_TYPE_MASK 0x1F
+#define VARIANT_META_EMODE_MASK 0x60
+#define VARIANT_META_BOOL_MASK 0x80
+#define ENCODE_8 0 << 5
+#define ENCODE_16 1 << 5
+#define ENCODE_32 2 << 5
+#define ENCODE_64 3 << 5
+Error MultiplayerAPI::_encode_and_compress_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
+
+ // Unreachable because `VARIANT_MAX` == 27 and `ENCODE_VARIANT_MASK` == 31
+ CRASH_COND(p_variant.get_type() > VARIANT_META_TYPE_MASK);
+
+ uint8_t *buf = r_buffer;
+ r_len = 0;
+ uint8_t encode_mode = 0;
+
+ switch (p_variant.get_type()) {
+ case Variant::BOOL: {
+ if (buf) {
+ // We still have 1 free bit in the meta, so let's use it.
+ buf[0] = (p_variant.operator bool()) ? (1 << 7) : 0;
+ buf[0] |= encode_mode | p_variant.get_type();
+ }
+ r_len += 1;
+ } break;
+ case Variant::INT: {
+ if (buf) {
+ // Reserve the first byte for the meta.
+ buf += 1;
+ }
+ r_len += 1;
+ int64_t val = p_variant;
+ if (val <= (int64_t)INT8_MAX && val >= (int64_t)INT8_MIN) {
+ // Use 8 bit
+ encode_mode = ENCODE_8;
+ if (buf) {
+ buf[0] = val;
+ }
+ r_len += 1;
+ } else if (val <= (int64_t)INT16_MAX && val >= (int64_t)INT16_MIN) {
+ // Use 16 bit
+ encode_mode = ENCODE_16;
+ if (buf) {
+ encode_uint16(val, buf);
+ }
+ r_len += 2;
+ } else if (val <= (int64_t)INT32_MAX && val >= (int64_t)INT32_MIN) {
+ // Use 32 bit
+ encode_mode = ENCODE_32;
+ if (buf) {
+ encode_uint32(val, buf);
+ }
+ r_len += 4;
+ } else {
+ // Use 64 bit
+ encode_mode = ENCODE_64;
+ if (buf) {
+ encode_uint64(val, buf);
+ }
+ r_len += 8;
+ }
+ // Store the meta
+ if (buf) {
+ buf -= 1;
+ buf[0] = encode_mode | p_variant.get_type();
+ }
+ } break;
+ default:
+ // Any other case is not yet compressed.
+ Error err = encode_variant(p_variant, r_buffer, r_len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ if (err != OK)
+ return err;
+ if (r_buffer) {
+ // The first byte is not used by the marshaling, so store the type
+ // so we know how to decompress and decode this variant.
+ r_buffer[0] = p_variant.get_type();
+ }
+ }
+
+ return OK;
+}
+Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len) {
+
+ const uint8_t *buf = p_buffer;
+ int len = p_len;
+
+ ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA);
+ uint8_t type = buf[0] & VARIANT_META_TYPE_MASK;
+ uint8_t encode_mode = buf[0] & VARIANT_META_EMODE_MASK;
+
+ ERR_FAIL_COND_V(type >= Variant::VARIANT_MAX, ERR_INVALID_DATA);
+
+ switch (type) {
+ case Variant::BOOL: {
+ bool val = (buf[0] & VARIANT_META_BOOL_MASK) > 0;
+ r_variant = val;
+ if (r_len)
+ *r_len = 1;
+ } break;
+ case Variant::INT: {
+ buf += 1;
+ len -= 1;
+ if (r_len)
+ *r_len = 1;
+ if (encode_mode == ENCODE_8) {
+ // 8 bits.
+ ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA);
+ int8_t val = buf[0];
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 1;
+ } else if (encode_mode == ENCODE_16) {
+ // 16 bits.
+ ERR_FAIL_COND_V(len < 2, ERR_INVALID_DATA);
+ int16_t val = decode_uint16(buf);
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 2;
+ } else if (encode_mode == ENCODE_32) {
+ // 32 bits.
+ ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+ int32_t val = decode_uint32(buf);
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 4;
+ } else {
+ // 64 bits.
+ ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
+ int64_t val = decode_uint64(buf);
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 8;
+ }
+ } break;
+ default:
+ Error err = decode_variant(r_variant, p_buffer, p_len, r_len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ if (err != OK)
+ return err;
+ }
+
+ return OK;
+}
+
void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree.");
@@ -496,6 +727,9 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
psc->id = last_send_cache_id++;
}
+ // See if all peers have cached path (if so, call can be fast).
+ const bool has_all_peers = _send_confirm_path(p_from, from_path, psc, p_to);
+
// Create base packet, lots of hardcode because it must be tight.
int ofs = 0;
@@ -503,45 +737,125 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
#define MAKE_ROOM(m_amount) \
if (packet_cache.size() < m_amount) packet_cache.resize(m_amount);
- // Encode type.
+ // Encode meta.
+ // The meta is composed by a single byte that contains (starting from the least segnificant bit):
+ // - `NetworkCommands` in the first three bits.
+ // - `NetworkNodeIdCompression` in the next 2 bits.
+ // - `NetworkNameIdCompression` in the next 1 bit.
+ // - So we still have the last two bits free!
+ uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
+ uint8_t node_id_compression = UINT8_MAX;
+ uint8_t name_id_compression = UINT8_MAX;
+
MAKE_ROOM(1);
- packet_cache.write[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
+ // The meta is composed along the way, so just set 0 for now.
+ packet_cache.write[0] = 0;
ofs += 1;
- // Encode ID.
- MAKE_ROOM(ofs + 4);
- encode_uint32(psc->id, &(packet_cache.write[ofs]));
- ofs += 4;
-
- // Encode function name.
- CharString name = String(p_name).utf8();
- int len = encode_cstring(name.get_data(), NULL);
- MAKE_ROOM(ofs + len);
- encode_cstring(name.get_data(), &(packet_cache.write[ofs]));
- ofs += len;
+ // Encode Node ID.
+ if (has_all_peers) {
+ // Compress the node ID only if all the target peers already know it.
+ if (psc->id >= 0 && psc->id <= 255) {
+ // We can encode the id in 1 byte
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(psc->id);
+ ofs += 1;
+ } else if (psc->id >= 0 && psc->id <= 65535) {
+ // We can encode the id in 2 bytes
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(static_cast<uint16_t>(psc->id), &(packet_cache.write[ofs]));
+ ofs += 2;
+ } else {
+ // Too big, let's use 4 bytes.
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
+ MAKE_ROOM(ofs + 4);
+ encode_uint32(psc->id, &(packet_cache.write[ofs]));
+ ofs += 4;
+ }
+ } else {
+ // The targets doesn't know the node yet, so we need to use 32 bits int.
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
+ MAKE_ROOM(ofs + 4);
+ encode_uint32(psc->id, &(packet_cache.write[ofs]));
+ ofs += 4;
+ }
if (p_set) {
+
+ // Take the rpc property ID
+ uint16_t property_id = p_from->get_node_rset_property_id(p_name);
+ if (property_id == UINT16_MAX && p_from->get_script_instance()) {
+ property_id = p_from->get_script_instance()->get_rset_property_id(p_name);
+ }
+ ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". this can happen only if this property is not marked as `remote`.");
+
+ if (property_id <= UINT8_MAX) {
+ // The ID fits in 1 byte
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(property_id);
+ ofs += 1;
+ } else {
+ // The ID is larger, let's use 2 bytes
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(property_id, &(packet_cache.write[ofs]));
+ ofs += 2;
+ }
+
// Set argument.
- Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ int len(0);
+ Error err = _encode_and_compress_variant(*p_arg[0], NULL, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ _encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len);
ofs += len;
} else {
+ // Take the rpc method ID
+ uint16_t method_id = p_from->get_node_rpc_method_id(p_name);
+ if (method_id == UINT16_MAX && p_from->get_script_instance()) {
+ method_id = p_from->get_script_instance()->get_rpc_method_id(p_name);
+ }
+ ERR_FAIL_COND_MSG(method_id == UINT16_MAX, "Unable to take the `method_id` for the function:" + p_name + ". this can happen only if this method is not marked as `remote`.");
+
+ if (method_id <= UINT8_MAX) {
+ // The ID fits in 1 byte
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(method_id);
+ ofs += 1;
+ } else {
+ // The ID is larger, let's use 2 bytes
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(method_id, &(packet_cache.write[ofs]));
+ ofs += 2;
+ }
+
// Call arguments.
MAKE_ROOM(ofs + 1);
packet_cache.write[ofs] = p_argcount;
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
- Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ int len(0);
+ Error err = _encode_and_compress_variant(*p_arg[i], NULL, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
ofs += len;
}
}
+ ERR_FAIL_COND(command_type > 7);
+ ERR_FAIL_COND(node_id_compression > 3);
+ ERR_FAIL_COND(name_id_compression > 1);
+
+ // We can now set the meta
+ packet_cache.write[0] = command_type + (node_id_compression << 3) + (name_id_compression << 5);
+
#ifdef DEBUG_ENABLED
if (profiling) {
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
@@ -550,9 +864,6 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
}
#endif
- // See if all peers have cached path (is so, call can be fast).
- bool has_all_peers = _send_confirm_path(from_path, psc, p_to);
-
// Take chance and set transfer mode, since all send methods will use it.
network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
@@ -562,6 +873,9 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
network_peer->set_target_peer(p_to); // To all of you.
network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love.
} else {
+ // Unreachable because the node ID is never compressed if the peers doesn't know it.
+ CRASH_COND(node_id_compression != NETWORK_NODE_ID_COMPRESSION_32);
+
// Not all verified path, so send one by one.
// Append path at the end, since we will need it for some packets.
@@ -647,16 +961,14 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
// Check that send mode can use local call.
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_method);
- if (E) {
- call_local_native = _should_call_local(E->get(), is_master, skip_rpc);
- }
+ RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method);
+ call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc);
if (call_local_native) {
// Done below.
} else if (p_node->get_script_instance()) {
// Attempt with script.
- RPCMode rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method);
+ rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method);
call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc);
}
}
@@ -719,11 +1031,8 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
// Check that send mode can use local call.
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property);
- if (E) {
-
- set_local = _should_call_local(E->get(), is_master, skip_rset);
- }
+ RPCMode rpc_mode = p_node->get_node_rset_mode(p_property);
+ set_local = _should_call_local(rpc_mode, is_master, skip_rset);
if (set_local) {
bool valid;
@@ -740,7 +1049,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
} else if (p_node->get_script_instance()) {
// Attempt with script.
- RPCMode rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property);
+ rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property);
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index c9f127b6b2..6672cfe155 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -98,23 +98,37 @@ protected:
void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
void _process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len);
void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len);
- Node *_process_get_node(int p_from, const uint8_t *p_packet, int p_packet_len);
- void _process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
- void _process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
+ Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len);
+ void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
+ void _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len);
void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount);
- bool _send_confirm_path(NodePath p_path, PathSentCache *psc, int p_target);
+ bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target);
+
+ Error _encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len);
+ Error _decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len);
public:
enum NetworkCommands {
- NETWORK_COMMAND_REMOTE_CALL,
+ NETWORK_COMMAND_REMOTE_CALL = 0,
NETWORK_COMMAND_REMOTE_SET,
NETWORK_COMMAND_SIMPLIFY_PATH,
NETWORK_COMMAND_CONFIRM_PATH,
NETWORK_COMMAND_RAW,
};
+ enum NetworkNodeIdCompression {
+ NETWORK_NODE_ID_COMPRESSION_8 = 0,
+ NETWORK_NODE_ID_COMPRESSION_16,
+ NETWORK_NODE_ID_COMPRESSION_32,
+ };
+
+ enum NetworkNameIdCompression {
+ NETWORK_NAME_ID_COMPRESSION_8 = 0,
+ NETWORK_NAME_ID_COMPRESSION_16,
+ };
+
enum RPCMode {
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h
index 0f2458d982..118970de80 100644
--- a/core/method_ptrcall.h
+++ b/core/method_ptrcall.h
@@ -32,6 +32,7 @@
#define METHOD_PTRCALL_H
#include "core/math/transform_2d.h"
+#include "core/object_id.h"
#include "core/typedefs.h"
#include "core/variant.h"
@@ -167,6 +168,21 @@ struct PtrToArg<const T *> {
}
};
+//this is for ObjectID
+
+template <>
+struct PtrToArg<ObjectID> {
+ _FORCE_INLINE_ static const ObjectID convert(const void *p_ptr) {
+
+ return ObjectID(*reinterpret_cast<const uint64_t *>(p_ptr));
+ }
+
+ _FORCE_INLINE_ static void encode(const ObjectID &p_val, void *p_ptr) {
+
+ *((uint64_t *)p_ptr) = p_val;
+ }
+};
+
//this is for the special cases used by Variant
#define MAKE_VECARG(m_type) \
diff --git a/core/object.cpp b/core/object.cpp
index 937b1ae8d4..dc1dc2c41f 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -1916,7 +1916,6 @@ Object::Object() {
_class_ptr = NULL;
_block_signals = false;
_predelete_ok = 0;
- _instance_id = 0;
_instance_id = ObjectDB::add_instance(this);
_can_translate = true;
_is_queued_for_deletion = false;
@@ -1972,7 +1971,7 @@ Object::~Object() {
}
ObjectDB::remove_instance(this);
- _instance_id = 0;
+ _instance_id = ObjectID();
_predelete_ok = 2;
if (!ScriptServer::are_languages_finished()) {
@@ -1995,14 +1994,14 @@ void postinitialize_handler(Object *p_object) {
}
HashMap<ObjectID, Object *> ObjectDB::instances;
-ObjectID ObjectDB::instance_counter = 1;
+uint64_t ObjectDB::instance_counter = 1;
HashMap<Object *, ObjectID, ObjectDB::ObjectPtrHash> ObjectDB::instance_checks;
ObjectID ObjectDB::add_instance(Object *p_object) {
- ERR_FAIL_COND_V(p_object->get_instance_id() != 0, 0);
+ ERR_FAIL_COND_V(p_object->get_instance_id().is_valid(), ObjectID());
rw_lock->write_lock();
- ObjectID instance_id = ++instance_counter;
+ ObjectID instance_id = ObjectID(++instance_counter);
instances[instance_id] = p_object;
instance_checks[p_object] = instance_id;
diff --git a/core/object.h b/core/object.h
index 865c155764..312fe07a17 100644
--- a/core/object.h
+++ b/core/object.h
@@ -34,6 +34,7 @@
#include "core/hash_map.h"
#include "core/list.h"
#include "core/map.h"
+#include "core/object_id.h"
#include "core/os/rw_lock.h"
#include "core/set.h"
#include "core/variant.h"
@@ -89,6 +90,7 @@ enum PropertyHint {
PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send
PROPERTY_HINT_NODE_PATH_VALID_TYPES,
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
+ PROPERTY_HINT_INT_IS_OBJECTID,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -397,7 +399,6 @@ public: \
private:
class ScriptInstance;
-typedef uint64_t ObjectID;
class Object {
public:
@@ -452,7 +453,7 @@ private:
_id(p_id),
method(p_method) {
}
- Target() { _id = 0; }
+ Target() { _id = ObjectID(); }
};
struct Slot {
@@ -775,7 +776,7 @@ class ObjectDB {
static HashMap<ObjectID, Object *> instances;
static HashMap<Object *, ObjectID, ObjectPtrHash> instance_checks;
- static ObjectID instance_counter;
+ static uint64_t instance_counter;
friend class Object;
friend void unregister_core_types();
diff --git a/core/object_id.h b/core/object_id.h
new file mode 100644
index 0000000000..f0ff2a24f5
--- /dev/null
+++ b/core/object_id.h
@@ -0,0 +1,32 @@
+#ifndef OBJECT_ID_H
+#define OBJECT_ID_H
+
+#include "core/typedefs.h"
+
+// Class to store an object ID (int64)
+// needs to be compatile with int64 because this is what Variant uses
+// Also, need to be explicitly only castable to 64 bits integer types
+// to avoid bugs due to loss of precision
+
+class ObjectID {
+ uint64_t id = 0;
+
+public:
+ _ALWAYS_INLINE_ bool is_valid() const { return id != 0; }
+ _ALWAYS_INLINE_ bool is_null() const { return id == 0; }
+ _ALWAYS_INLINE_ operator uint64_t() const { return id; }
+ _ALWAYS_INLINE_ operator int64_t() const { return id; }
+
+ _ALWAYS_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
+ _ALWAYS_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
+ _ALWAYS_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
+
+ _ALWAYS_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
+ _ALWAYS_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
+
+ _ALWAYS_INLINE_ ObjectID() {}
+ _ALWAYS_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
+ _ALWAYS_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
+};
+
+#endif // OBJECT_ID_H
diff --git a/core/reference.cpp b/core/reference.cpp
index b24b2a3ec0..5c211fe301 100644
--- a/core/reference.cpp
+++ b/core/reference.cpp
@@ -113,7 +113,7 @@ Reference::~Reference() {
Variant WeakRef::get_ref() const {
- if (ref == 0)
+ if (ref.is_null())
return Variant();
Object *obj = ObjectDB::get_instance(ref);
@@ -129,16 +129,15 @@ Variant WeakRef::get_ref() const {
}
void WeakRef::set_obj(Object *p_object) {
- ref = p_object ? p_object->get_instance_id() : 0;
+ ref = p_object ? p_object->get_instance_id() : ObjectID();
}
void WeakRef::set_ref(const REF &p_ref) {
- ref = p_ref.is_valid() ? p_ref->get_instance_id() : 0;
+ ref = p_ref.is_valid() ? p_ref->get_instance_id() : ObjectID();
}
-WeakRef::WeakRef() :
- ref(0) {
+WeakRef::WeakRef() {
}
void WeakRef::_bind_methods() {
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 7392e7a0af..1149feac38 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -32,6 +32,7 @@
#include "core/core_string_names.h"
#include "core/project_settings.h"
+#include <stdint.h>
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
int ScriptServer::_language_count = 0;
@@ -644,6 +645,14 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam
return Variant();
}
+uint16_t PlaceHolderScriptInstance::get_rpc_method_id(const StringName &p_method) const {
+ return UINT16_MAX;
+}
+
+uint16_t PlaceHolderScriptInstance::get_rset_property_id(const StringName &p_method) const {
+ return UINT16_MAX;
+}
+
PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
owner(p_owner),
language(p_language),
diff --git a/core/script_language.h b/core/script_language.h
index 22f83080bc..788f5d6976 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -40,6 +40,21 @@ class ScriptLanguage;
typedef void (*ScriptEditRequestFunction)(const String &p_path);
+struct ScriptNetData {
+ StringName name;
+ MultiplayerAPI::RPCMode mode;
+ bool operator==(ScriptNetData const &p_other) const {
+ return name == p_other.name;
+ }
+};
+
+struct SortNetData {
+ StringName::AlphCompare compare;
+ bool operator()(const ScriptNetData &p_a, const ScriptNetData &p_b) const {
+ return compare(p_a.name, p_b.name);
+ }
+};
+
class ScriptServer {
enum {
@@ -154,6 +169,18 @@ public:
virtual bool is_placeholder_fallback_enabled() const { return false; }
+ virtual Vector<ScriptNetData> get_rpc_methods() const = 0;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const = 0;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const = 0;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const = 0;
+ virtual uint16_t get_rset_property_id(const StringName &p_property) const = 0;
+ virtual StringName get_rset_property(const uint16_t p_rset_property_id) const = 0;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const = 0;
+ virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
+
Script() {}
};
@@ -195,7 +222,16 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid);
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid);
+ virtual Vector<ScriptNetData> get_rpc_methods() const = 0;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0;
+ virtual StringName get_rpc_method(uint16_t p_id) const = 0;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const = 0;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const = 0;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const = 0;
+ virtual StringName get_rset_property(uint16_t p_id) const = 0;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const = 0;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
virtual ScriptLanguage *get_language() = 0;
@@ -409,7 +445,16 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL);
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = NULL);
+ virtual Vector<ScriptNetData> get_rpc_methods() const { return Vector<ScriptNetData>(); }
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(uint16_t p_id) const { return StringName(); }
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
+
+ virtual Vector<ScriptNetData> get_rset_properties() const { return Vector<ScriptNetData>(); }
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(uint16_t p_id) const { return StringName(); }
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
diff --git a/core/type_info.h b/core/type_info.h
index 68bc1cc554..b9e5b61a6a 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -187,6 +187,16 @@ struct GetTypeInfo<const RefPtr &> {
}
};
+//objectID
+template <>
+struct GetTypeInfo<ObjectID> {
+ static const Variant::Type VARIANT_TYPE = Variant::INT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_OBJECTID);
+ }
+};
+
//for variant
template <>
struct GetTypeInfo<Variant> {
diff --git a/core/variant.cpp b/core/variant.cpp
index f4e4cd5341..0f04710d13 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -1248,6 +1248,14 @@ Variant::operator uint64_t() const {
}
}
+Variant::operator ObjectID() const {
+ if (type == INT) {
+ return ObjectID(_data._int);
+ } else {
+ return ObjectID();
+ }
+}
+
#ifdef NEED_LONG_INT
Variant::operator signed long() const {
@@ -2193,6 +2201,11 @@ Variant::Variant(double p_double) {
_data._real = p_double;
}
+Variant::Variant(const ObjectID &p_id) {
+ type = INT;
+ _data._int = p_id;
+}
+
Variant::Variant(const StringName &p_string) {
type = STRING;
diff --git a/core/variant.h b/core/variant.h
index 06be914408..d8007f9e12 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -44,6 +44,7 @@
#include "core/math/transform_2d.h"
#include "core/math/vector3.h"
#include "core/node_path.h"
+#include "core/object_id.h"
#include "core/pool_vector.h"
#include "core/ref_ptr.h"
#include "core/rid.h"
@@ -177,6 +178,8 @@ public:
operator unsigned long() const;
#endif
+ operator ObjectID() const;
+
operator CharType() const;
operator float() const;
operator double() const;
@@ -248,6 +251,7 @@ public:
Variant(uint64_t p_int);
Variant(float p_float);
Variant(double p_double);
+ Variant(const ObjectID &p_id);
Variant(const String &p_string);
Variant(const StringName &p_string);
Variant(const char *const p_cstring);
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index 740a388149..f0730a0f58 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BaseMaterial3D" inherits="Material" version="4.0">
<brief_description>
+ Default 3D rendering material.
</brief_description>
<description>
+ This provides a default material with a wide variety of rendering features and properties without the need to write shader code. See the tutorial below for details.
</description>
<tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/spatial_material.html</link>
</tutorials>
<methods>
<method name="get_feature" qualifiers="const">
@@ -13,6 +16,7 @@
<argument index="0" name="feature" type="int" enum="BaseMaterial3D.Feature">
</argument>
<description>
+ Returns [code]true[/code], if the specified [enum Feature] is enabled.
</description>
</method>
<method name="get_flag" qualifiers="const">
@@ -21,6 +25,7 @@
<argument index="0" name="flag" type="int" enum="BaseMaterial3D.Flags">
</argument>
<description>
+ Returns [code]true[/code], if the specified flag is enabled. See [enum Flags] enumerator for options.
</description>
</method>
<method name="get_texture" qualifiers="const">
@@ -29,6 +34,7 @@
<argument index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam">
</argument>
<description>
+ Returns the [Texture] associated with the specified [enum TextureParam].
</description>
</method>
<method name="set_feature">
@@ -39,6 +45,7 @@
<argument index="1" name="enable" type="bool">
</argument>
<description>
+ If [code]true[/code], enables the specified [enum Feature]. Many features that are available in [BaseMaterial3D]s need to be enabled before use. This way the cost for using the feature is only incurred when specified. Features can also be enabled by setting the corresponding member to [code]true[/code].
</description>
</method>
<method name="set_flag">
@@ -49,6 +56,7 @@
<argument index="1" name="enable" type="bool">
</argument>
<description>
+ If [code]true[/code], enables the specified flag. Flags are optional behavior that can be turned on and off. Only one flag can be enabled at a time with this function, the flag enumerators cannot be bit-masked together to enable or disable multiple flags at once. Flags can also be enabled by setting the corresponding member to [code]true[/code]. See [enum Flags] enumerator for options.
</description>
</method>
<method name="set_texture">
@@ -64,88 +72,131 @@
</methods>
<members>
<member name="albedo_color" type="Color" setter="set_albedo" getter="get_albedo" default="Color( 1, 1, 1, 1 )">
+ The material's base color.
</member>
<member name="albedo_tex_force_srgb" type="bool" setter="set_flag" getter="get_flag" default="false">
+ Forces a conversion of the [member albedo_texture] from sRGB space to linear space.
</member>
<member name="albedo_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture to multiply by [member albedo_color]. Used for basic texturing of objects.
</member>
<member name="alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold">
+ Threshold at which the alpha scissor will discard values.
</member>
<member name="anisotropy" type="float" setter="set_anisotropy" getter="get_anisotropy">
+ The strength of the anisotropy effect.
</member>
<member name="anisotropy_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], anisotropy is enabled. Changes the shape of the specular blob and aligns it to tangent space. Mesh tangents are needed for this to work. If the mesh does not contain tangents the anisotropy effect will appear broken.
</member>
<member name="anisotropy_flowmap" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that offsets the tangent map for anisotropy calculations.
</member>
<member name="ao_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], ambient occlusion is enabled. Ambient occlusion darkens areas based on the [member ao_texture].
</member>
<member name="ao_light_affect" type="float" setter="set_ao_light_affect" getter="get_ao_light_affect">
+ Amount that ambient occlusion affects lighting from lights. If [code]0[/code], ambient occlusion only affects ambient light. If [code]1[/code], ambient occlusion affects lights just as much as it affects ambient light. This can be used to impact the strength of the ambient occlusion effect, but typically looks unrealistic.
</member>
<member name="ao_on_uv2" type="bool" setter="set_flag" getter="get_flag">
+ If [code]true[/code], use [code]UV2[/code] coordinates to look up from the [member ao_texture].
</member>
<member name="ao_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that defines the amount of ambient occlusion for a given point on the object.
</member>
<member name="ao_texture_channel" type="int" setter="set_ao_texture_channel" getter="get_ao_texture_channel" enum="BaseMaterial3D.TextureChannel">
+ Specifies the channel of the [member ao_texture] in which the ambient occlusion information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use.
</member>
<member name="billboard_keep_scale" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise the scale is lost when billboarding. Only applies when [member billboard_mode] is [constant BILLBOARD_ENABLED].
</member>
<member name="billboard_mode" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="BaseMaterial3D.BillboardMode" default="0">
+ Controls how the object faces the camera. See [enum BillboardMode].
</member>
<member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="BaseMaterial3D.BlendMode" default="0">
+ The material's blend mode.
+ [b]Note:[/b] Values other than [code]Mix[/code] force the object into the transparent pipeline. See [enum BlendMode].
</member>
<member name="clearcoat" type="float" setter="set_clearcoat" getter="get_clearcoat">
+ Sets the strength of the clearcoat effect. Setting to [code]0[/code] looks the same as disabling the clearcoat effect.
</member>
<member name="clearcoat_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], clearcoat rendering is enabled. Adds a secondary transparent pass to the lighting calculation resulting in an added specular blob. This makes materials appear as if they have a clear layer on them that can be either glossy or rough.
</member>
<member name="clearcoat_gloss" type="float" setter="set_clearcoat_gloss" getter="get_clearcoat_gloss">
+ Sets the roughness of the clearcoat pass. A higher value results in a smoother clearcoat while a lower value results in a rougher clearcoat.
</member>
<member name="clearcoat_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that defines the strength of the clearcoat effect and the glossiness of the clearcoat. Strength is specified in the red channel while glossiness is specified in the green channel.
</member>
<member name="cull_mode" type="int" setter="set_cull_mode" getter="get_cull_mode" enum="BaseMaterial3D.CullMode" default="0">
+ Which side of the object is not drawn when backfaces are rendered. See [enum CullMode].
</member>
- <member name="depth_draw" type="int" setter="set_depth_draw_mode" getter="get_depth_draw_mode" enum="BaseMaterial3D.DepthDrawMode" default="0">
+ <member name="depth_draw_mode" type="int" setter="set_depth_draw_mode" getter="get_depth_draw_mode" enum="BaseMaterial3D.DepthDrawMode" default="0">
+ Determines when depth rendering takes place. See [enum DepthDrawMode]. See also [member transparency].
</member>
<member name="detail_albedo" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that specifies the color of the detail overlay.
</member>
<member name="detail_blend_mode" type="int" setter="set_detail_blend_mode" getter="get_detail_blend_mode" enum="BaseMaterial3D.BlendMode">
+ Specifies how the [member detail_albedo] should blend with the current [code]ALBEDO[/code]. See [enum BlendMode] for options.
</member>
<member name="detail_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], enables the detail overlay. Detail is a second texture that gets mixed over the surface of the object based on [member detail_mask]. This can be used to add variation to objects, or to blend between two different albedo/normal textures.
</member>
<member name="detail_mask" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to specify how the detail textures get blended with the base textures.
</member>
<member name="detail_normal" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that specifies the per-pixel normal of the detail overlay.
</member>
<member name="detail_uv_layer" type="int" setter="set_detail_uv" getter="get_detail_uv" enum="BaseMaterial3D.DetailUV">
+ Specifies whether to use [code]UV[/code] or [code]UV2[/code] for the detail layer. See [enum DetailUV] for options.
</member>
<member name="diffuse_mode" type="int" setter="set_diffuse_mode" getter="get_diffuse_mode" enum="BaseMaterial3D.DiffuseMode" default="0">
+ The algorithm used for diffuse light scattering. See [enum DiffuseMode].
</member>
<member name="disable_ambient_light" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the object receives no ambient light.
</member>
<member name="disable_receive_shadows" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the object receives no shadow that would otherwise be cast onto it.
</member>
<member name="distance_fade_max_distance" type="float" setter="set_distance_fade_max_distance" getter="get_distance_fade_max_distance">
+ Distance at which the object fades fully and is no longer visible.
</member>
<member name="distance_fade_min_distance" type="float" setter="set_distance_fade_min_distance" getter="get_distance_fade_min_distance">
+ Distance at which the object starts to fade. If the object is less than this distance away it will appear normal.
</member>
<member name="distance_fade_mode" type="int" setter="set_distance_fade" getter="get_distance_fade" enum="BaseMaterial3D.DistanceFadeMode" default="0">
+ Specifies which type of fade to use. Can be any of the [enum DistanceFadeMode]s.
</member>
<member name="emission" type="Color" setter="set_emission" getter="get_emission">
+ The emitted light's color. See [member emission_enabled].
</member>
<member name="emission_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [GIProbe] is used and this object is used in baked lighting.
</member>
<member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy">
+ The emitted light's strength. See [member emission_enabled].
</member>
<member name="emission_on_uv2" type="bool" setter="set_flag" getter="get_flag">
+ Use [code]UV2[/code] to read from the [member emission_texture].
</member>
<member name="emission_operator" type="int" setter="set_emission_operator" getter="get_emission_operator" enum="BaseMaterial3D.EmissionOperator">
+ Sets how [member emission] interacts with [member emission_texture]. Can either add or multiply. See [enum EmissionOperator] for options.
</member>
<member name="emission_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that specifies how much surface emits light at a given point.
</member>
<member name="fixed_size" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the object is rendered at the same size regardless of distance.
</member>
<member name="grow" type="bool" setter="set_grow_enabled" getter="is_grow_enabled" default="false">
+ If [code]true[/code], enables the vertex grow setting. See [member grow_amount].
</member>
<member name="grow_amount" type="float" setter="set_grow" getter="get_grow" default="0.0">
+ Grows object vertices in the direction of their normals.
</member>
<member name="heightmap_deep_parallax" type="bool" setter="set_heightmap_deep_parallax" getter="is_heightmap_deep_parallax_enabled">
</member>
@@ -166,144 +217,212 @@
<member name="heightmap_texture" type="Texture2D" setter="set_texture" getter="get_texture">
</member>
<member name="metallic" type="float" setter="set_metallic" getter="get_metallic" default="0.0">
+ A high value makes the material appear more like a metal. Non-metals use their albedo as the diffuse color and add diffuse to the specular reflection. With non-metals, the reflection appears on top of the albedo color. Metals use their albedo as a multiplier to the specular reflection and set the diffuse color to black resulting in a tinted reflection. Materials work better when fully metal or fully non-metal, values between [code]0[/code] and [code]1[/code] should only be used for blending between metal and non-metal sections. To alter the amount of reflection use [member roughness].
</member>
<member name="metallic_specular" type="float" setter="set_specular" getter="get_specular" default="0.5">
+ Sets the size of the specular lobe. The specular lobe is the bright spot that is reflected from light sources.
+ [b]Note:[/b] unlike [member metallic], this is not energy-conserving, so it should be left at [code]0.5[/code] in most cases. See also [member roughness].
</member>
<member name="metallic_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to specify metallic for an object. This is multiplied by [member metallic].
</member>
<member name="metallic_texture_channel" type="int" setter="set_metallic_texture_channel" getter="get_metallic_texture_channel" enum="BaseMaterial3D.TextureChannel" default="0">
+ Specifies the channel of the [member metallic_texture] in which the metallic information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use.
</member>
<member name="no_depth_test" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], depth testing is disabled and the object will be drawn in render order.
</member>
<member name="normal_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], normal mapping is enabled.
</member>
<member name="normal_scale" type="float" setter="set_normal_scale" getter="get_normal_scale">
+ The strength of the normal map's effect.
</member>
<member name="normal_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to specify the normal at a given pixel. The [code]normal_texture[/code] only uses the red and green channels. The normal read from [code]normal_texture[/code] is oriented around the surface normal provided by the [Mesh].
</member>
<member name="orm_texture" type="Texture2D" setter="set_texture" getter="get_texture">
</member>
<member name="particles_anim_h_frames" type="int" setter="set_particles_anim_h_frames" getter="get_particles_anim_h_frames">
+ The number of horizontal frames in the particle sprite sheet. Only enabled when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode].
</member>
<member name="particles_anim_loop" type="bool" setter="set_particles_anim_loop" getter="get_particles_anim_loop">
+ If [code]true[/code], particle animations are looped. Only enabled when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode].
</member>
<member name="particles_anim_v_frames" type="int" setter="set_particles_anim_v_frames" getter="get_particles_anim_v_frames">
+ The number of vertical frames in the particle sprite sheet. Only enabled when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode].
</member>
<member name="point_size" type="float" setter="set_point_size" getter="get_point_size" default="1.0">
+ The point size in pixels. See [member use_point_size].
</member>
<member name="proximity_fade_distance" type="float" setter="set_proximity_fade_distance" getter="get_proximity_fade_distance">
+ Distance over which the fade effect takes place. The larger the distance the longer it takes for an object to fade.
</member>
<member name="proximity_fade_enable" type="bool" setter="set_proximity_fade" getter="is_proximity_fade_enabled" default="false">
+ If [code]true[/code], the proximity fade effect is enabled. The proximity fade effect fades out each pixel based on its distance to another object.
</member>
<member name="refraction_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], the refraction effect is enabled. Distorts transparency based on light from behind the object.
</member>
<member name="refraction_scale" type="float" setter="set_refraction" getter="get_refraction">
+ The strength of the refraction effect.
</member>
<member name="refraction_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture that controls the strength of the refraction per-pixel. Multiplied by [member refraction_scale].
</member>
<member name="refraction_texture_channel" type="int" setter="set_refraction_texture_channel" getter="get_refraction_texture_channel" enum="BaseMaterial3D.TextureChannel">
+ Specifies the channel of the [member ao_texture] in which the ambient occlusion information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use.
</member>
<member name="rim" type="float" setter="set_rim" getter="get_rim">
+ Sets the strength of the rim lighting effect.
</member>
<member name="rim_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], rim effect is enabled. Rim lighting increases the brightness at glancing angles on an object.
</member>
<member name="rim_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to set the strength of the rim lighting effect per-pixel. Multiplied by [member rim].
</member>
<member name="rim_tint" type="float" setter="set_rim_tint" getter="get_rim_tint">
+ The amount of to blend light and albedo color when rendering rim effect. If [code]0[/code] the light color is used, while [code]1[/code] means albedo color is used. An intermediate value generally works best.
</member>
<member name="roughness" type="float" setter="set_roughness" getter="get_roughness" default="1.0">
+ Surface reflection. A value of [code]0[/code] represents a perfect mirror while a value of [code]1[/code] completely blurs the reflection. See also [member metallic].
</member>
<member name="roughness_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to control the roughness per-pixel. Multiplied by [member roughness].
</member>
<member name="roughness_texture_channel" type="int" setter="set_roughness_texture_channel" getter="get_roughness_texture_channel" enum="BaseMaterial3D.TextureChannel" default="0">
+ Specifies the channel of the [member ao_texture] in which the ambient occlusion information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use.
</member>
<member name="shading_mode" type="int" setter="set_shading_mode" getter="get_shading_mode" enum="BaseMaterial3D.ShadingMode" default="1">
</member>
<member name="shadow_to_opacity" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], enables the "shadow to opacity" render mode where lighting modifies the alpha so shadowed areas are opaque and non-shadowed areas are transparent. Useful for overlaying shadows onto a camera feed in AR.
</member>
<member name="specular_mode" type="int" setter="set_specular_mode" getter="get_specular_mode" enum="BaseMaterial3D.SpecularMode" default="0">
+ The method for rendering the specular blob. See [enum SpecularMode].
</member>
<member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges.
</member>
<member name="subsurf_scatter_strength" type="float" setter="set_subsurface_scattering_strength" getter="get_subsurface_scattering_strength">
+ The strength of the subsurface scattering effect.
</member>
<member name="subsurf_scatter_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to control the subsurface scattering strength. Stored in the red texture channel. Multiplied by [member subsurf_scatter_strength].
</member>
<member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="BaseMaterial3D.TextureFilter" default="3">
+ Filter flags for the texture. See [enum TextureFilter] for options.
</member>
<member name="texture_repeat" type="bool" setter="set_flag" getter="get_flag" default="true">
+ Repeat flags for the texture. See [enum TextureFilter] for options.
</member>
<member name="transmission" type="Color" setter="set_transmission" getter="get_transmission">
+ The color used by the transmission effect. Represents the light passing through an object.
</member>
<member name="transmission_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], the transmission effect is enabled.
</member>
<member name="transmission_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Texture used to control the transmission effect per-pixel. Added to [member transmission].
</member>
<member name="transparency" type="int" setter="set_transparency" getter="get_transparency" enum="BaseMaterial3D.Transparency" default="0">
+ If [code]true[/code], transparency is enabled on the body. See also [member blend_mode].
</member>
<member name="use_point_size" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], render point size can be changed.
+ [b]Note:[/b] this is only effective for objects whose geometry is point-based rather than triangle-based. See also [member point_size].
</member>
<member name="uv1_offset" type="Vector3" setter="set_uv1_offset" getter="get_uv1_offset" default="Vector3( 0, 0, 0 )">
+ How much to offset the [code]UV[/code] coordinates. This amount will be added to [code]UV[/code] in the vertex function. This can be used to offset a texture.
</member>
<member name="uv1_scale" type="Vector3" setter="set_uv1_scale" getter="get_uv1_scale" default="Vector3( 1, 1, 1 )">
+ How much to scale the [code]UV[/code] coordinates. This is multiplied by [code]UV[/code] in the vertex function.
</member>
<member name="uv1_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], instead of using [code]UV[/code] textures will use a triplanar texture lookup to determine how to apply textures. Triplanar uses the orientation of the object's surface to blend between texture coordinates. It reads from the source texture 3 times, once for each axis and then blends between the results based on how closely the pixel aligns with each axis. This is often used for natural features to get a realistic blend of materials. Because triplanar texturing requires many more texture reads per-pixel it is much slower than normal UV texturing. Additionally, because it is blending the texture between the three axes, it is unsuitable when you are trying to achieve crisp texturing.
</member>
<member name="uv1_triplanar_sharpness" type="float" setter="set_uv1_triplanar_blend_sharpness" getter="get_uv1_triplanar_blend_sharpness" default="1.0">
+ A lower number blends the texture more softly while a higher number blends the texture more sharply.
</member>
<member name="uv1_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], triplanar mapping for [code]UV[/code] is calculated in world space rather than object local space. See also [member uv1_triplanar].
</member>
<member name="uv2_offset" type="Vector3" setter="set_uv2_offset" getter="get_uv2_offset" default="Vector3( 0, 0, 0 )">
+ How much to offset the [code]UV2[/code] coordinates. This amount will be added to [code]UV2[/code] in the vertex function. This can be used to offset a texture.
</member>
<member name="uv2_scale" type="Vector3" setter="set_uv2_scale" getter="get_uv2_scale" default="Vector3( 1, 1, 1 )">
+ How much to scale the [code]UV2[/code] coordinates. This is multiplied by [code]UV2[/code] in the vertex function.
</member>
<member name="uv2_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], instead of using [code]UV2[/code] textures will use a triplanar texture lookup to determine how to apply textures. Triplanar uses the orientation of the object's surface to blend between texture coordinates. It reads from the source texture 3 times, once for each axis and then blends between the results based on how closely the pixel aligns with each axis. This is often used for natural features to get a realistic blend of materials. Because triplanar texturing requires many more texture reads per-pixel it is much slower than normal UV texturing. Additionally, because it is blending the texture between the three axes, it is unsuitable when you are trying to achieve crisp texturing.
</member>
<member name="uv2_triplanar_sharpness" type="float" setter="set_uv2_triplanar_blend_sharpness" getter="get_uv2_triplanar_blend_sharpness" default="1.0">
+ A lower number blends the texture more softly while a higher number blends the texture more sharply.
</member>
<member name="uv2_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], triplanar mapping for [code]UV2[/code] is calculated in world space rather than object local space. See also [member uv2_triplanar].
</member>
<member name="vertex_color_is_srgb" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the model's vertex colors are processed as sRGB mode.
</member>
<member name="vertex_color_use_as_albedo" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the vertex color is used as albedo color.
</member>
</members>
<constants>
<constant name="TEXTURE_ALBEDO" value="0" enum="TextureParam">
+ Texture specifying per-pixel color.
</constant>
<constant name="TEXTURE_METALLIC" value="1" enum="TextureParam">
+ Texture specifying per-pixel metallic value.
</constant>
<constant name="TEXTURE_ROUGHNESS" value="2" enum="TextureParam">
+ Texture specifying per-pixel roughness value.
</constant>
<constant name="TEXTURE_EMISSION" value="3" enum="TextureParam">
+ Texture specifying per-pixel emission color.
</constant>
<constant name="TEXTURE_NORMAL" value="4" enum="TextureParam">
+ Texture specifying per-pixel normal vector.
</constant>
<constant name="TEXTURE_RIM" value="5" enum="TextureParam">
+ Texture specifying per-pixel rim value.
</constant>
<constant name="TEXTURE_CLEARCOAT" value="6" enum="TextureParam">
+ Texture specifying per-pixel clearcoat value.
</constant>
<constant name="TEXTURE_FLOWMAP" value="7" enum="TextureParam">
+ Texture specifying per-pixel flowmap direction for use with [member anisotropy].
</constant>
<constant name="TEXTURE_AMBIENT_OCCLUSION" value="8" enum="TextureParam">
+ Texture specifying per-pixel ambient occlusion value.
</constant>
<constant name="TEXTURE_HEIGHTMAP" value="9" enum="TextureParam">
+ Texture specifying per-pixel height.
</constant>
<constant name="TEXTURE_SUBSURFACE_SCATTERING" value="10" enum="TextureParam">
+ Texture specifying per-pixel subsurface scattering.
</constant>
<constant name="TEXTURE_TRANSMISSION" value="11" enum="TextureParam">
+ Texture specifying per-pixel transmission color.
</constant>
<constant name="TEXTURE_REFRACTION" value="12" enum="TextureParam">
+ Texture specifying per-pixel refraction strength.
</constant>
<constant name="TEXTURE_DETAIL_MASK" value="13" enum="TextureParam">
+ Texture specifying per-pixel detail mask blending value.
</constant>
<constant name="TEXTURE_DETAIL_ALBEDO" value="14" enum="TextureParam">
+ Texture specifying per-pixel detail color.
</constant>
<constant name="TEXTURE_DETAIL_NORMAL" value="15" enum="TextureParam">
+ Texture specifying per-pixel detail normal.
</constant>
<constant name="TEXTURE_ORM" value="16" enum="TextureParam">
</constant>
<constant name="TEXTURE_MAX" value="17" enum="TextureParam">
+ Represents the size of the [enum TextureParam] enum.
</constant>
<constant name="TEXTURE_FILTER_NEAREST" value="0" enum="TextureFilter">
</constant>
@@ -320,8 +439,10 @@
<constant name="TEXTURE_FILTER_MAX" value="6" enum="TextureFilter">
</constant>
<constant name="DETAIL_UV_1" value="0" enum="DetailUV">
+ Use [code]UV[/code] with the detail texture.
</constant>
<constant name="DETAIL_UV_2" value="1" enum="DetailUV">
+ Use [code]UV2[/code] with the detail texture.
</constant>
<constant name="TRANSPARENCY_DISABLED" value="0" enum="Transparency">
</constant>
@@ -342,136 +463,201 @@
<constant name="SHADING_MODE_MAX" value="3" enum="ShadingMode">
</constant>
<constant name="FEATURE_EMISSION" value="0" enum="Feature">
+ Constant for setting [member emission_enabled].
</constant>
<constant name="FEATURE_NORMAL_MAPPING" value="1" enum="Feature">
+ Constant for setting [member normal_enabled].
</constant>
<constant name="FEATURE_RIM" value="2" enum="Feature">
+ Constant for setting [member rim_enabled].
</constant>
<constant name="FEATURE_CLEARCOAT" value="3" enum="Feature">
+ Constant for setting [member clearcoat_enabled].
</constant>
<constant name="FEATURE_ANISOTROPY" value="4" enum="Feature">
+ Constant for setting [member anisotropy_enabled].
</constant>
<constant name="FEATURE_AMBIENT_OCCLUSION" value="5" enum="Feature">
+ Constant for setting [member ao_enabled].
</constant>
<constant name="FEATURE_HEIGHT_MAPPING" value="6" enum="Feature">
</constant>
<constant name="FEATURE_SUBSURACE_SCATTERING" value="7" enum="Feature">
+ Constant for setting [member subsurf_scatter_enabled].
</constant>
<constant name="FEATURE_TRANSMISSION" value="8" enum="Feature">
+ Constant for setting [member transmission_enabled].
</constant>
<constant name="FEATURE_REFRACTION" value="9" enum="Feature">
+ Constant for setting [member refraction_enabled].
</constant>
<constant name="FEATURE_DETAIL" value="10" enum="Feature">
+ Constant for setting [member detail_enabled].
</constant>
<constant name="FEATURE_MAX" value="11" enum="Feature">
+ Represents the size of the [enum Feature] enum.
</constant>
<constant name="BLEND_MODE_MIX" value="0" enum="BlendMode">
+ Default blend mode. The color of the object is blended over the background based on the object's alpha value.
</constant>
<constant name="BLEND_MODE_ADD" value="1" enum="BlendMode">
+ The color of the object is added to the background.
</constant>
<constant name="BLEND_MODE_SUB" value="2" enum="BlendMode">
+ The color of the object is subtracted from the background.
</constant>
<constant name="BLEND_MODE_MUL" value="3" enum="BlendMode">
+ The color of the object is multiplied by the background.
</constant>
<constant name="DEPTH_DRAW_OPAQUE_ONLY" value="0" enum="DepthDrawMode">
+ Default depth draw mode. Depth is drawn only for opaque objects.
</constant>
<constant name="DEPTH_DRAW_ALWAYS" value="1" enum="DepthDrawMode">
+ Depth draw is calculated for both opaque and transparent objects.
</constant>
<constant name="DEPTH_DRAW_DISABLED" value="2" enum="DepthDrawMode">
+ No depth draw.
</constant>
<constant name="CULL_BACK" value="0" enum="CullMode">
+ Default cull mode. The back of the object is culled when not visible.
</constant>
<constant name="CULL_FRONT" value="1" enum="CullMode">
+ The front of the object is culled when not visible.
</constant>
<constant name="CULL_DISABLED" value="2" enum="CullMode">
+ No culling is performed.
</constant>
<constant name="FLAG_DISABLE_DEPTH_TEST" value="0" enum="Flags">
+ Disables the depth test, so this object is drawn on top of all others. However, objects drawn after it in the draw order may cover it.
</constant>
<constant name="FLAG_ALBEDO_FROM_VERTEX_COLOR" value="1" enum="Flags">
+ Set [code]ALBEDO[/code] to the per-vertex color specified in the mesh.
</constant>
<constant name="FLAG_SRGB_VERTEX_COLOR" value="2" enum="Flags">
+ Vertex color is in sRGB space and needs to be converted to linear. Only applies in the GLES3 renderer.
</constant>
<constant name="FLAG_USE_POINT_SIZE" value="3" enum="Flags">
+ Uses point size to alter the size of primitive points. Also changes the albedo texture lookup to use [code]POINT_COORD[/code] instead of [code]UV[/code].
</constant>
<constant name="FLAG_FIXED_SIZE" value="4" enum="Flags">
+ Object is scaled by depth so that it always appears the same size on screen.
</constant>
<constant name="FLAG_BILLBOARD_KEEP_SCALE" value="5" enum="Flags">
+ Shader will keep the scale set for the mesh. Otherwise the scale is lost when billboarding. Only applies when [member billboard_mode] is [constant BILLBOARD_ENABLED].
</constant>
<constant name="FLAG_UV1_USE_TRIPLANAR" value="6" enum="Flags">
+ Use triplanar texture lookup for all texture lookups that would normally use [code]UV[/code].
</constant>
<constant name="FLAG_UV2_USE_TRIPLANAR" value="7" enum="Flags">
+ Use triplanar texture lookup for all texture lookups that would normally use [code]UV2[/code].
</constant>
<constant name="FLAG_UV1_USE_WORLD_TRIPLANAR" value="8" enum="Flags">
+ Use triplanar texture lookup for all texture lookups that would normally use [code]UV[/code].
</constant>
<constant name="FLAG_UV2_USE_WORLD_TRIPLANAR" value="9" enum="Flags">
+ Use triplanar texture lookup for all texture lookups that would normally use [code]UV2[/code].
</constant>
<constant name="FLAG_AO_ON_UV2" value="10" enum="Flags">
+ Use [code]UV2[/code] coordinates to look up from the [member ao_texture].
</constant>
<constant name="FLAG_EMISSION_ON_UV2" value="11" enum="Flags">
+ Use [code]UV2[/code] coordinates to look up from the [member emission_texture].
</constant>
<constant name="FLAG_ALBEDO_TEXTURE_FORCE_SRGB" value="12" enum="Flags">
+ Forces the shader to convert albedo from sRGB space to linear space.
</constant>
<constant name="FLAG_DONT_RECEIVE_SHADOWS" value="13" enum="Flags">
+ Disables receiving shadows from other objects.
</constant>
<constant name="FLAG_DISABLE_AMBIENT_LIGHT" value="14" enum="Flags">
+ Disables receiving ambient light.
</constant>
<constant name="FLAG_USE_SHADOW_TO_OPACITY" value="15" enum="Flags">
+ Enables the shadow to opacity feature.
</constant>
<constant name="FLAG_USE_TEXTURE_REPEAT" value="16" enum="Flags">
</constant>
<constant name="FLAG_INVERT_HEIGHTMAP" value="17" enum="Flags">
+ Invert values read from a depth texture to convert them to height values (heightmap).
</constant>
<constant name="FLAG_MAX" value="18" enum="Flags">
+ Represents the size of the [enum Flags] enum.
</constant>
<constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode">
+ Default diffuse scattering algorithm.
</constant>
<constant name="DIFFUSE_LAMBERT" value="1" enum="DiffuseMode">
+ Diffuse scattering ignores roughness.
</constant>
<constant name="DIFFUSE_LAMBERT_WRAP" value="2" enum="DiffuseMode">
+ Extends Lambert to cover more than 90 degrees when roughness increases.
</constant>
<constant name="DIFFUSE_OREN_NAYAR" value="3" enum="DiffuseMode">
+ Attempts to use roughness to emulate microsurfacing.
</constant>
<constant name="DIFFUSE_TOON" value="4" enum="DiffuseMode">
+ Uses a hard cut for lighting, with smoothing affected by roughness.
</constant>
<constant name="SPECULAR_SCHLICK_GGX" value="0" enum="SpecularMode">
+ Default specular blob.
</constant>
<constant name="SPECULAR_BLINN" value="1" enum="SpecularMode">
+ Older specular algorithm, included for compatibility.
</constant>
<constant name="SPECULAR_PHONG" value="2" enum="SpecularMode">
+ Older specular algorithm, included for compatibility.
</constant>
<constant name="SPECULAR_TOON" value="3" enum="SpecularMode">
+ Toon blob which changes size based on roughness.
</constant>
<constant name="SPECULAR_DISABLED" value="4" enum="SpecularMode">
+ No specular blob.
</constant>
<constant name="BILLBOARD_DISABLED" value="0" enum="BillboardMode">
+ Billboard mode is disabled.
</constant>
<constant name="BILLBOARD_ENABLED" value="1" enum="BillboardMode">
+ The object's Z axis will always face the camera.
</constant>
<constant name="BILLBOARD_FIXED_Y" value="2" enum="BillboardMode">
+ The object's X axis will always face the camera.
</constant>
<constant name="BILLBOARD_PARTICLES" value="3" enum="BillboardMode">
+ Used for particle systems when assigned to [Particles] and [CPUParticles] nodes. Enables [code]particles_anim_*[/code] properties.
+ The [member ParticlesMaterial.anim_speed] or [member CPUParticles.anim_speed] should also be set to a positive value for the animation to play.
</constant>
<constant name="TEXTURE_CHANNEL_RED" value="0" enum="TextureChannel">
+ Used to read from the red channel of a texture.
</constant>
<constant name="TEXTURE_CHANNEL_GREEN" value="1" enum="TextureChannel">
+ Used to read from the green channel of a texture.
</constant>
<constant name="TEXTURE_CHANNEL_BLUE" value="2" enum="TextureChannel">
+ Used to read from the blue channel of a texture.
</constant>
<constant name="TEXTURE_CHANNEL_ALPHA" value="3" enum="TextureChannel">
+ Used to read from the alpha channel of a texture.
</constant>
<constant name="TEXTURE_CHANNEL_GRAYSCALE" value="4" enum="TextureChannel">
+ Currently unused.
</constant>
<constant name="EMISSION_OP_ADD" value="0" enum="EmissionOperator">
+ Adds the emission color to the color from the emission texture.
</constant>
<constant name="EMISSION_OP_MULTIPLY" value="1" enum="EmissionOperator">
+ Multiplies the emission color by the color from the emission texture.
</constant>
<constant name="DISTANCE_FADE_DISABLED" value="0" enum="DistanceFadeMode">
+ Do not use distance fade.
</constant>
<constant name="DISTANCE_FADE_PIXEL_ALPHA" value="1" enum="DistanceFadeMode">
+ Smoothly fades the object out based on each pixel's distance from the camera using the alpha channel.
</constant>
<constant name="DISTANCE_FADE_PIXEL_DITHER" value="2" enum="DistanceFadeMode">
+ Smoothly fades the object out based on each pixel's distance from the camera using a dither approach. Dithering discards pixels based on a set pattern to smoothly fade without enabling transparency. On certain hardware this can be faster than [constant DISTANCE_FADE_PIXEL_ALPHA].
</constant>
<constant name="DISTANCE_FADE_OBJECT_DITHER" value="3" enum="DistanceFadeMode">
+ Smoothly fades the object out based on the object's distance from the camera using a dither approach. Dithering discards pixels based on a set pattern to smoothly fade without enabling transparency. On certain hardware this can be faster than [constant DISTANCE_FADE_PIXEL_ALPHA].
</constant>
</constants>
</class>
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 08047935bd..620fcdbdca 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -332,6 +332,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
struct_code += " ";
struct_code += m->name;
+ if (m->array_size > 0) {
+ struct_code += "[";
+ struct_code += itos(m->array_size);
+ struct_code += "]";
+ }
struct_code += ";\n";
}
struct_code += "}";
@@ -558,6 +563,26 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
}
} break;
+ case SL::Node::TYPE_ARRAY_CONSTRUCT: {
+ SL::ArrayConstructNode *arr_con_node = (SL::ArrayConstructNode *)p_node;
+ int sz = arr_con_node->initializer.size();
+ if (acnode->datatype == SL::TYPE_STRUCT) {
+ code += _mkid(arr_con_node->struct_name);
+ } else {
+ code += _typestr(arr_con_node->datatype);
+ }
+ code += "[";
+ code += itos(arr_con_node->initializer.size());
+ code += "]";
+ code += "(";
+ for (int i = 0; i < sz; i++) {
+ code += _dump_node_code(arr_con_node->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (i != sz - 1) {
+ code += ", ";
+ }
+ }
+ code += ")";
+ } break;
case SL::Node::TYPE_ARRAY_DECLARATION: {
SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node;
@@ -898,6 +923,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ".";
code += member_node->name;
+ if (member_node->index_expression != NULL) {
+ code += "[";
+ code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "]";
+ }
} break;
}
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
index bb01fadb72..82db639379 100644
--- a/editor/dictionary_property_edit.cpp
+++ b/editor/dictionary_property_edit.cpp
@@ -190,5 +190,4 @@ bool DictionaryPropertyEdit::_get(const StringName &p_name, Variant &r_ret) cons
}
DictionaryPropertyEdit::DictionaryPropertyEdit() {
- obj = 0;
}
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index d7c610f109..5cb7720170 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -156,8 +156,8 @@ bool EditorHistory::is_history_obj_inspector_only(int p_obj) const {
}
ObjectID EditorHistory::get_history_obj(int p_obj) const {
- ERR_FAIL_INDEX_V(p_obj, history.size(), 0);
- ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), 0);
+ ERR_FAIL_INDEX_V(p_obj, history.size(), ObjectID());
+ ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), ObjectID());
return history[p_obj].path[history[p_obj].level].object;
}
@@ -204,12 +204,12 @@ bool EditorHistory::is_current_inspector_only() const {
ObjectID EditorHistory::get_current() {
if (current < 0 || current >= history.size())
- return 0;
+ return ObjectID();
History &h = history.write[current];
Object *obj = ObjectDB::get_instance(h.path[h.level].object);
if (!obj)
- return 0;
+ return ObjectID();
return obj->get_instance_id();
}
@@ -226,15 +226,15 @@ int EditorHistory::get_path_size() const {
ObjectID EditorHistory::get_path_object(int p_index) const {
if (current < 0 || current >= history.size())
- return 0;
+ return ObjectID();
const History &h = history[current];
- ERR_FAIL_INDEX_V(p_index, h.path.size(), 0);
+ ERR_FAIL_INDEX_V(p_index, h.path.size(), ObjectID());
Object *obj = ObjectDB::get_instance(h.path[p_index].object);
if (!obj)
- return 0;
+ return ObjectID();
return obj->get_instance_id();
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 4440a747be..a6172faeaa 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1558,7 +1558,7 @@ void EditorNode::_dialog_action(String p_file) {
save_resource_in_path(saving_resource, p_file);
saving_resource = Ref<Resource>();
ObjectID current = editor_history.get_current();
- Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL;
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
ERR_FAIL_COND(!current_obj);
current_obj->_change_notify();
} break;
@@ -1711,7 +1711,7 @@ void EditorNode::push_item(Object *p_object, const String &p_property, bool p_in
return;
}
- uint32_t id = p_object->get_instance_id();
+ ObjectID id = p_object->get_instance_id();
if (id != editor_history.get_current()) {
if (p_inspector_only) {
@@ -1767,8 +1767,8 @@ static bool overrides_external_editor(Object *p_object) {
void EditorNode::_edit_current() {
- uint32_t current = editor_history.get_current();
- Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL;
+ ObjectID current = editor_history.get_current();
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
bool inspector_only = editor_history.is_current_inspector_only();
this->current = current_obj;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 0794940cb1..905e928c5a 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -388,13 +388,13 @@ void EditorPropertyMember::_property_select() {
} else if (hint == MEMBER_METHOD_OF_INSTANCE) {
- Object *instance = ObjectDB::get_instance(hint_text.to_int64());
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (instance)
selector->select_method_from_instance(instance, current);
} else if (hint == MEMBER_METHOD_OF_SCRIPT) {
- Object *obj = ObjectDB::get_instance(hint_text.to_int64());
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (Object::cast_to<Script>(obj)) {
selector->select_method_from_script(Object::cast_to<Script>(obj), current);
}
@@ -420,13 +420,13 @@ void EditorPropertyMember::_property_select() {
} else if (hint == MEMBER_PROPERTY_OF_INSTANCE) {
- Object *instance = ObjectDB::get_instance(hint_text.to_int64());
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (instance)
selector->select_property_from_instance(instance, current);
} else if (hint == MEMBER_PROPERTY_OF_SCRIPT) {
- Object *obj = ObjectDB::get_instance(hint_text.to_int64());
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (Object::cast_to<Script>(obj)) {
selector->select_property_from_script(Object::cast_to<Script>(obj), current);
}
@@ -858,7 +858,7 @@ void EditorPropertyObjectID::update_property() {
type = "Object";
ObjectID id = get_edited_object()->get(get_edited_property());
- if (id != 0) {
+ if (id.is_valid()) {
edit->set_text(type + " ID: " + itos(id));
edit->set_disabled(false);
edit->set_icon(EditorNode::get_singleton()->get_class_icon(type));
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index 2090c12c91..c4a84bfcdc 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -177,7 +177,7 @@ String SectionedInspector::get_full_item_path(const String &p_item) {
void SectionedInspector::edit(Object *p_object) {
if (!p_object) {
- obj = 0;
+ obj = ObjectID();
sections->clear();
filter->set_edited(NULL);
@@ -308,7 +308,6 @@ EditorInspector *SectionedInspector::get_inspector() {
}
SectionedInspector::SectionedInspector() :
- obj(0),
sections(memnew(Tree)),
filter(memnew(SectionedInspectorFilter)),
inspector(memnew(EditorInspector)),
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index c681cdd033..954a941a96 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -166,8 +166,8 @@ void InspectorDock::_resource_file_selected(String p_file) {
}
void InspectorDock::_save_resource(bool save_as) const {
- uint32_t current = EditorNode::get_singleton()->get_editor_history()->get_current();
- Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL;
+ ObjectID current = EditorNode::get_singleton()->get_editor_history()->get_current();
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -180,8 +180,8 @@ void InspectorDock::_save_resource(bool save_as) const {
}
void InspectorDock::_unref_resource() const {
- uint32_t current = EditorNode::get_singleton()->get_editor_history()->get_current();
- Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL;
+ ObjectID current = EditorNode::get_singleton()->get_editor_history()->get_current();
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -191,8 +191,8 @@ void InspectorDock::_unref_resource() const {
}
void InspectorDock::_copy_resource() const {
- uint32_t current = EditorNode::get_singleton()->get_editor_history()->get_current();
- Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL;
+ ObjectID current = EditorNode::get_singleton()->get_editor_history()->get_current();
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index 8dc7e4638d..a729c90160 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -59,7 +59,7 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) {
path = tree->get_meta("_tree_edit_path");
edit_path(path);
} else {
- current_root = 0;
+ current_root = ObjectID();
}
}
@@ -128,7 +128,7 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) {
}
}
} else {
- current_root = 0;
+ current_root = ObjectID();
edited_path = button_path;
}
@@ -151,7 +151,7 @@ void AnimationTreeEditor::_about_to_show_root() {
void AnimationTreeEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
- ObjectID root = 0;
+ ObjectID root;
if (tree && tree->get_tree_root().is_valid()) {
root = tree->get_tree_root()->get_instance_id();
}
@@ -242,7 +242,6 @@ AnimationTreeEditor::AnimationTreeEditor() {
add_child(memnew(HSeparator));
- current_root = 0;
singleton = this;
editor_base = memnew(PanelContainer);
editor_base->set_v_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 27ba518f01..f7a3b50052 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -3659,7 +3659,7 @@ bool CanvasItemEditor::_build_bones_list(Node *p_node) {
// Add a last bone if the Bone2D has no Bone2D child
BoneKey bk;
bk.from = canvas_item->get_instance_id();
- bk.to = 0;
+ bk.to = ObjectID();
if (!bone_list.has(bk)) {
BoneList b;
b.length = 0;
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 88376f6ce6..cf6c8feaed 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -252,7 +252,7 @@ void SpatialEditorViewport::_clear_selected() {
void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single, bool p_allow_locked) {
- if (!clicked)
+ if (clicked.is_null())
return;
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked));
@@ -309,7 +309,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
Set<Ref<EditorSpatialGizmo> > found_gizmos;
Node *edited_scene = get_tree()->get_edited_scene_root();
- ObjectID closest = 0;
+ ObjectID closest;
Node *item = NULL;
float closest_dist = 1e20;
int selected_handle = -1;
@@ -356,7 +356,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
}
if (!item)
- return 0;
+ return ObjectID();
if (!editor_selection->is_selected(item) || (r_gizmo_handle && selected_handle >= 0)) {
@@ -850,9 +850,9 @@ void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
clicked = selection_results[0].item->get_instance_id();
selection_results.clear();
- if (clicked) {
+ if (clicked.is_valid()) {
_select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != SpatialEditor::TOOL_MODE_LIST_SELECT);
- clicked = 0;
+ clicked = ObjectID();
}
} else if (!selection_results.empty()) {
@@ -1095,7 +1095,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (_gizmo_select(_edit.mouse_pos))
break;
- clicked = 0;
+ clicked = ObjectID();
clicked_includes_current = false;
if ((spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
@@ -1139,7 +1139,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked_wants_append = b->get_shift();
- if (!clicked) {
+ if (clicked.is_null()) {
if (!clicked_wants_append)
_clear_selected();
@@ -1150,7 +1150,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
cursor.region_end = b->get_position();
}
- if (clicked && gizmo_handle >= 0) {
+ if (clicked.is_valid() && gizmo_handle >= 0) {
Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked));
if (spa) {
@@ -1175,10 +1175,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.gizmo = Ref<EditorSpatialGizmo>();
break;
}
- if (clicked) {
+ if (clicked.is_valid()) {
_select_clicked(clicked_wants_append, true);
// Processing was deferred.
- clicked = 0;
+ clicked = ObjectID();
}
if (cursor.region_select) {
@@ -1279,7 +1279,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
} else if (nav_scheme == NAVIGATION_MODO && m->get_alt()) {
nav_mode = NAVIGATION_ORBIT;
} else {
- if (clicked) {
+ if (clicked.is_valid()) {
if (!clicked_includes_current) {
@@ -1288,7 +1288,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
_compute_edit(_edit.mouse_pos);
- clicked = 0;
+ clicked = ObjectID();
_edit.mode = TRANSFORM_TRANSLATE;
}
@@ -2945,9 +2945,9 @@ void SpatialEditorViewport::_selection_result_pressed(int p_result) {
clicked = selection_results[p_result].item->get_instance_id();
- if (clicked) {
+ if (clicked.is_valid()) {
_select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != SpatialEditor::TOOL_MODE_LIST_SELECT);
- clicked = 0;
+ clicked = ObjectID();
}
}
@@ -3581,7 +3581,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
editor_data = editor->get_scene_tree_dock()->get_editor_data();
editor_selection = editor->get_editor_selection();
undo_redo = editor->get_undo_redo();
- clicked = 0;
+
clicked_includes_current = false;
orthogonal = false;
lock_rotation = false;
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 63f0b02a40..1691ce3a63 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -639,7 +639,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
MAKE_PROPSELECT
- Object *instance = ObjectDB::get_instance(hint_text.to_int64());
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (instance)
property_select->select_method_from_instance(instance, v);
updating = false;
@@ -648,7 +648,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_METHOD_OF_SCRIPT) {
MAKE_PROPSELECT
- Object *obj = ObjectDB::get_instance(hint_text.to_int64());
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (Object::cast_to<Script>(obj)) {
property_select->select_method_from_script(Object::cast_to<Script>(obj), v);
}
@@ -688,7 +688,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
MAKE_PROPSELECT
- Object *instance = ObjectDB::get_instance(hint_text.to_int64());
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (instance)
property_select->select_property_from_instance(instance, v);
@@ -698,7 +698,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
MAKE_PROPSELECT
- Object *obj = ObjectDB::get_instance(hint_text.to_int64());
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
if (Object::cast_to<Script>(obj)) {
property_select->select_property_from_script(Object::cast_to<Script>(obj), v);
}
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index fdb1ce3e62..1de5099c4a 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -404,7 +404,7 @@ void PropertySelector::select_method_from_base_type(const String &p_base, const
base_type = p_base;
selected = p_current;
type = Variant::NIL;
- script = 0;
+ script = ObjectID();
properties = false;
instance = NULL;
virtuals_only = p_virtuals_only;
@@ -437,7 +437,7 @@ void PropertySelector::select_method_from_basic_type(Variant::Type p_type, const
base_type = "";
selected = p_current;
type = p_type;
- script = 0;
+ script = ObjectID();
properties = false;
instance = NULL;
virtuals_only = false;
@@ -453,7 +453,7 @@ void PropertySelector::select_method_from_instance(Object *p_instance, const Str
base_type = p_instance->get_class();
selected = p_current;
type = Variant::NIL;
- script = 0;
+ script = ObjectID();
{
Ref<Script> scr = p_instance->get_script();
if (scr.is_valid())
@@ -474,7 +474,7 @@ void PropertySelector::select_property_from_base_type(const String &p_base, cons
base_type = p_base;
selected = p_current;
type = Variant::NIL;
- script = 0;
+ script = ObjectID();
properties = true;
instance = NULL;
virtuals_only = false;
@@ -509,7 +509,7 @@ void PropertySelector::select_property_from_basic_type(Variant::Type p_type, con
base_type = "";
selected = p_current;
type = p_type;
- script = 0;
+ script = ObjectID();
properties = true;
instance = NULL;
virtuals_only = false;
@@ -525,7 +525,7 @@ void PropertySelector::select_property_from_instance(Object *p_instance, const S
base_type = "";
selected = p_current;
type = Variant::NIL;
- script = 0;
+ script = ObjectID();
properties = true;
instance = p_instance;
virtuals_only = false;
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 3aec50528f..2b28aa87a3 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -172,7 +172,7 @@ public:
}
String get_title() {
- if (remote_object_id)
+ if (remote_object_id.is_valid())
return TTR("Remote ") + String(type_name) + ": " + itos(remote_object_id);
else
return "<null>";
@@ -197,7 +197,6 @@ public:
}
ScriptEditorDebuggerInspectedObject() {
- remote_object_id = 0;
}
};
@@ -302,7 +301,7 @@ void ScriptEditorDebugger::_scene_tree_selected() {
return;
}
- inspected_object_id = item->get_metadata(0);
+ inspected_object_id = item->get_metadata(0).operator ObjectID();
Array msg;
msg.push_back("inspect_object");
@@ -434,7 +433,7 @@ int ScriptEditorDebugger::_update_scene_tree(TreeItem *parent, const Array &node
TreeItem *item = inspect_scene_tree->create_item(parent);
item->set_text(0, item_text);
item->set_tooltip(0, TTR("Type:") + " " + item_type);
- ObjectID id = ObjectID(nodes[current_index + 3]);
+ ObjectID id = nodes[current_index + 3].operator ObjectID();
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(nodes[current_index + 2], "");
if (icon.is_valid()) {
item->set_icon(0, icon);
@@ -1107,7 +1106,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
int frame_size = 6;
for (int i = 0; i < p_data.size(); i += frame_size) {
MultiplayerAPI::ProfilingInfo pi;
- pi.node = p_data[i + 0];
+ pi.node = p_data[i + 0].operator ObjectID();
pi.node_path = p_data[i + 1];
pi.incoming_rpc = p_data[i + 2];
pi.incoming_rset = p_data[i + 3];
@@ -1253,7 +1252,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
inspect_edited_object_timeout -= get_process_delta_time();
if (inspect_edited_object_timeout < 0) {
inspect_edited_object_timeout = EditorSettings::get_singleton()->get("debugger/remote_inspect_refresh_interval");
- if (inspected_object_id) {
+ if (inspected_object_id.is_valid()) {
if (ScriptEditorDebuggerInspectedObject *obj = Object::cast_to<ScriptEditorDebuggerInspectedObject>(ObjectDB::get_instance(editor->get_editor_history()->get_current()))) {
if (obj->remote_object_id == inspected_object_id) {
//take the chance and re-inspect selected object
@@ -2486,7 +2485,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
auto_switch_remote_scene_tree = EDITOR_DEF("debugger/auto_switch_to_remote_scene_tree", false);
inspect_scene_tree_timeout = EDITOR_DEF("debugger/remote_scene_tree_refresh_interval", 1.0);
inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2);
- inspected_object_id = 0;
+ inspected_object_id = ObjectID();
updating_scene_tree = false;
}
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index 8d03a99556..7806145390 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -107,7 +107,7 @@ void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer:
Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id);
if (!areaGodoObject) {
- event.event_callback_id = 0;
+ event.event_callback_id = ObjectID();
return;
}
@@ -279,7 +279,7 @@ void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, co
ev.event_callback_method = p_method;
/// Set if monitoring
- if (eventsCallbacks[0].event_callback_id || eventsCallbacks[1].event_callback_id) {
+ if (eventsCallbacks[0].event_callback_id.is_valid() || eventsCallbacks[1].event_callback_id.is_valid()) {
set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA);
} else {
set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA));
@@ -287,7 +287,7 @@ void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, co
}
bool AreaBullet::has_event_callback(Type p_callbackObjectType) {
- return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id;
+ return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id.is_valid();
}
void AreaBullet::on_enter_area(AreaBullet *p_area) {
diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h
index f770c63bcc..18888c6725 100644
--- a/modules/bullet/area_bullet.h
+++ b/modules/bullet/area_bullet.h
@@ -50,8 +50,7 @@ public:
ObjectID event_callback_id;
StringName event_callback_method;
- InOutEventCallback() :
- event_callback_id(0) {}
+ InOutEventCallback() {}
};
enum OverlapState {
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index fceb5d2b4b..89868babc6 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -359,7 +359,7 @@ void BulletPhysicsServer::area_attach_object_instance_id(RID p_area, ObjectID p_
ObjectID BulletPhysicsServer::area_get_object_instance_id(RID p_area) const {
if (space_owner.owns(p_area)) {
- return 0;
+ return ObjectID();
}
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND_V(!area, ObjectID());
@@ -428,14 +428,14 @@ void BulletPhysicsServer::area_set_monitor_callback(RID p_area, Object *p_receiv
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+ area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
void BulletPhysicsServer::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+ area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
void BulletPhysicsServer::area_set_ray_pickable(RID p_area, bool p_enable) {
@@ -569,16 +569,16 @@ void BulletPhysicsServer::body_clear_shapes(RID p_body) {
body->remove_all_shapes();
}
-void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, uint32_t p_id) {
+void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
CollisionObjectBullet *body = get_collisin_object(p_body);
ERR_FAIL_COND(!body);
body->set_instance_id(p_id);
}
-uint32_t BulletPhysicsServer::body_get_object_instance_id(RID p_body) const {
+ObjectID BulletPhysicsServer::body_get_object_instance_id(RID p_body) const {
CollisionObjectBullet *body = get_collisin_object(p_body);
- ERR_FAIL_COND_V(!body, 0);
+ ERR_FAIL_COND_V(!body, ObjectID());
return body->get_instance_id();
}
@@ -844,7 +844,7 @@ bool BulletPhysicsServer::body_is_omitting_force_integration(RID p_body) const {
void BulletPhysicsServer::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(0), p_method, p_udata);
+ body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
}
void BulletPhysicsServer::body_set_ray_pickable(RID p_body, bool p_enable) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 22032d32e3..6ea9a7a974 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -189,8 +189,8 @@ public:
virtual void body_clear_shapes(RID p_body);
// Used for Rigid and Soft Bodies
- virtual void body_attach_object_instance_id(RID p_body, uint32_t p_id);
- virtual uint32_t body_get_object_instance_id(RID p_body) const;
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_object_instance_id(RID p_body) const;
virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable);
virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const;
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index c916c65d2b..5b7e7281e4 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -90,7 +90,7 @@ void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_s
CollisionObjectBullet::CollisionObjectBullet(Type p_type) :
RIDBullet(),
type(p_type),
- instance_id(0),
+ instance_id(ObjectID()),
collisionLayer(0),
collisionMask(0),
collisionsEnabled(true),
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 6e54d10abf..20467e3ef3 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -112,7 +112,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo
result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
result.rid = gObj->get_self();
result.collider_id = gObj->get_instance_id();
- result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id);
+ result.collider = result.collider_id.is_null() ? NULL : ObjectDB::get_instance(result.collider_id);
++count;
return 1; // not used by bullet
@@ -220,7 +220,7 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con
}
result.collider_id = colObj->get_instance_id();
- result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id);
+ result.collider = result.collider_id.is_null() ? NULL : ObjectDB::get_instance(result.collider_id);
result.rid = colObj->get_self();
++m_count;
}
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index dfc9647813..e5804fbde8 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -366,7 +366,7 @@ void RigidBodyBullet::dispatch_callbacks() {
Object *obj = ObjectDB::get_instance(force_integration_callback->id);
if (!obj) {
// Remove integration callback
- set_force_integration_callback(0, StringName());
+ set_force_integration_callback(ObjectID(), StringName());
} else {
const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata };
@@ -395,7 +395,7 @@ void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const String
force_integration_callback = NULL;
}
- if (p_id != 0) {
+ if (p_id.is_valid()) {
force_integration_callback = memnew(ForceIntegrationCallback);
force_integration_callback->id = p_id;
force_integration_callback->method = p_method;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 69f3d1b393..0e4c4b4731 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -108,7 +108,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
r_result.shape = btResult.m_shapeId;
r_result.rid = gObj->get_self();
r_result.collider_id = gObj->get_instance_id();
- r_result.collider = 0 == r_result.collider_id ? NULL : ObjectDB::get_instance(r_result.collider_id);
+ r_result.collider = r_result.collider_id.is_null() ? NULL : ObjectDB::get_instance(r_result.collider_id);
} else {
WARN_PRINT("The raycast performed has hit a collision object that is not part of Godot scene, please check it.");
}
diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp
index 06334556d9..119bb80659 100644
--- a/modules/gdnative/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative/gdnative.cpp
@@ -171,7 +171,7 @@ bool GDAPI godot_is_instance_valid(const godot_object *p_object) {
}
godot_object GDAPI *godot_instance_from_id(godot_int p_instance_id) {
- return (godot_object *)ObjectDB::get_instance((ObjectID)p_instance_id);
+ return (godot_object *)ObjectDB::get_instance(ObjectID((uint64_t)p_instance_id));
}
void *godot_get_class_tag(const godot_string_name *p_class) {
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 414b9b9eaf..59901f6139 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -250,7 +250,12 @@ godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, co
keys.write[i] = (*keys_proxy)[i];
}
- return self->findmk(keys, p_from, r_key);
+ int key;
+ int ret = self->findmk(keys, p_from, &key);
+ if (r_key) {
+ *r_key = key;
+ }
+ return ret;
}
godot_int GDAPI godot_string_findn(const godot_string *p_self, godot_string p_what) {
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index e19e675344..f953206a34 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -36,6 +36,7 @@
#include "core/project_settings.h"
#include "core/variant.h"
#include "gdnative/gdnative.h"
+#include <stdint.h>
#include "nativescript.h"
@@ -67,6 +68,14 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char
if (classes->has(p_base)) {
desc.base_data = &(*classes)[p_base];
desc.base_native_type = desc.base_data->base_native_type;
+
+ const NativeScriptDesc *b = desc.base_data;
+ while (b) {
+ desc.rpc_count += b->rpc_count;
+ desc.rset_count += b->rset_count;
+ b = b->base_data;
+ }
+
} else {
desc.base_data = NULL;
desc.base_native_type = p_base;
@@ -87,10 +96,20 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
desc.destroy_func = p_destroy_func;
desc.is_tool = true;
desc.base = p_base;
+ desc.rpc_count = 0;
+ desc.rset_count = 0;
if (classes->has(p_base)) {
desc.base_data = &(*classes)[p_base];
desc.base_native_type = desc.base_data->base_native_type;
+
+ const NativeScriptDesc *b = desc.base_data;
+ while (b) {
+ desc.rpc_count += b->rpc_count;
+ desc.rset_count += b->rset_count;
+ b = b->base_data;
+ }
+
} else {
desc.base_data = NULL;
desc.base_native_type = p_base;
@@ -109,6 +128,11 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha
NativeScriptDesc::Method method;
method.method = p_method;
method.rpc_mode = p_attr.rpc_type;
+ method.rpc_method_id = UINT16_MAX;
+ if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) {
+ method.rpc_method_id = E->get().rpc_count;
+ E->get().rpc_count += 1;
+ }
method.info = MethodInfo(p_function_name);
E->get().methods.insert(p_function_name, method);
@@ -125,6 +149,10 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c
property.default_value = *(Variant *)&p_attr->default_value;
property.getter = p_get_func;
property.rset_mode = p_attr->rset_type;
+ if (p_attr->rset_type != GODOT_METHOD_RPC_MODE_DISABLED) {
+ property.rset_property_id = E->get().rset_count;
+ E->get().rset_count += 1;
+ }
property.setter = p_set_func;
property.info = PropertyInfo((Variant::Type)p_attr->type,
p_path,
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 8b06af6c7b..df85155ff5 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -30,6 +30,8 @@
#include "nativescript.h"
+#include <stdint.h>
+
#include "gdnative/gdnative.h"
#include "core/core_string_names.h"
@@ -402,6 +404,262 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
}
+Vector<ScriptNetData> NativeScript::get_rpc_methods() const {
+
+ Vector<ScriptNetData> v;
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
+ if (E->get().rpc_mode != GODOT_METHOD_RPC_MODE_DISABLED) {
+ ScriptNetData nd;
+ nd.name = E->key();
+ nd.mode = MultiplayerAPI::RPCMode(E->get().rpc_mode);
+ v.push_back(nd);
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return v;
+}
+
+uint16_t NativeScript::get_rpc_method_id(const StringName &p_method) const {
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
+ if (E) {
+ return E->get().rpc_method_id;
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return UINT16_MAX;
+}
+
+StringName NativeScript::get_rpc_method(uint16_t p_id) const {
+ ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName());
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
+ if (E->get().rpc_method_id == p_id) {
+ return E->key();
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return StringName();
+}
+
+MultiplayerAPI::RPCMode NativeScript::get_rpc_mode_by_id(uint16_t p_id) const {
+
+ ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED);
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
+ if (E->get().rpc_method_id == p_id) {
+ switch (E->get().rpc_mode) {
+ case GODOT_METHOD_RPC_MODE_DISABLED:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ case GODOT_METHOD_RPC_MODE_REMOTE:
+ return MultiplayerAPI::RPC_MODE_REMOTE;
+ case GODOT_METHOD_RPC_MODE_MASTER:
+ return MultiplayerAPI::RPC_MODE_MASTER;
+ case GODOT_METHOD_RPC_MODE_PUPPET:
+ return MultiplayerAPI::RPC_MODE_PUPPET;
+ case GODOT_METHOD_RPC_MODE_REMOTESYNC:
+ return MultiplayerAPI::RPC_MODE_REMOTESYNC;
+ case GODOT_METHOD_RPC_MODE_MASTERSYNC:
+ return MultiplayerAPI::RPC_MODE_MASTERSYNC;
+ case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
+ return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
+ default:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ }
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
+MultiplayerAPI::RPCMode NativeScript::get_rpc_mode(const StringName &p_method) const {
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
+ if (E) {
+ switch (E->get().rpc_mode) {
+ case GODOT_METHOD_RPC_MODE_DISABLED:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ case GODOT_METHOD_RPC_MODE_REMOTE:
+ return MultiplayerAPI::RPC_MODE_REMOTE;
+ case GODOT_METHOD_RPC_MODE_MASTER:
+ return MultiplayerAPI::RPC_MODE_MASTER;
+ case GODOT_METHOD_RPC_MODE_PUPPET:
+ return MultiplayerAPI::RPC_MODE_PUPPET;
+ case GODOT_METHOD_RPC_MODE_REMOTESYNC:
+ return MultiplayerAPI::RPC_MODE_REMOTESYNC;
+ case GODOT_METHOD_RPC_MODE_MASTERSYNC:
+ return MultiplayerAPI::RPC_MODE_MASTERSYNC;
+ case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
+ return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
+ default:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
+Vector<ScriptNetData> NativeScript::get_rset_properties() const {
+ Vector<ScriptNetData> v;
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
+ if (E.get().rset_mode != GODOT_METHOD_RPC_MODE_DISABLED) {
+ ScriptNetData nd;
+ nd.name = E.key();
+ nd.mode = MultiplayerAPI::RPCMode(E.get().rset_mode);
+ v.push_back(nd);
+ }
+ }
+ script_data = script_data->base_data;
+ }
+
+ return v;
+}
+
+uint16_t NativeScript::get_rset_property_id(const StringName &p_variable) const {
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
+ if (E) {
+ return E.get().rset_property_id;
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return UINT16_MAX;
+}
+
+StringName NativeScript::get_rset_property(uint16_t p_id) const {
+ ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName());
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
+ if (E.get().rset_property_id == p_id) {
+ return E.key();
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return StringName();
+}
+
+MultiplayerAPI::RPCMode NativeScript::get_rset_mode_by_id(uint16_t p_id) const {
+
+ ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED);
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
+ if (E.get().rset_property_id == p_id) {
+ switch (E.get().rset_mode) {
+ case GODOT_METHOD_RPC_MODE_DISABLED:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ case GODOT_METHOD_RPC_MODE_REMOTE:
+ return MultiplayerAPI::RPC_MODE_REMOTE;
+ case GODOT_METHOD_RPC_MODE_MASTER:
+ return MultiplayerAPI::RPC_MODE_MASTER;
+ case GODOT_METHOD_RPC_MODE_PUPPET:
+ return MultiplayerAPI::RPC_MODE_PUPPET;
+ case GODOT_METHOD_RPC_MODE_REMOTESYNC:
+ return MultiplayerAPI::RPC_MODE_REMOTESYNC;
+ case GODOT_METHOD_RPC_MODE_MASTERSYNC:
+ return MultiplayerAPI::RPC_MODE_MASTERSYNC;
+ case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
+ return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
+ default:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ }
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
+MultiplayerAPI::RPCMode NativeScript::get_rset_mode(const StringName &p_variable) const {
+
+ NativeScriptDesc *script_data = get_script_desc();
+
+ while (script_data) {
+
+ OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
+ if (E) {
+ switch (E.get().rset_mode) {
+ case GODOT_METHOD_RPC_MODE_DISABLED:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ case GODOT_METHOD_RPC_MODE_REMOTE:
+ return MultiplayerAPI::RPC_MODE_REMOTE;
+ case GODOT_METHOD_RPC_MODE_MASTER:
+ return MultiplayerAPI::RPC_MODE_MASTER;
+ case GODOT_METHOD_RPC_MODE_PUPPET:
+ return MultiplayerAPI::RPC_MODE_PUPPET;
+ case GODOT_METHOD_RPC_MODE_REMOTESYNC:
+ return MultiplayerAPI::RPC_MODE_REMOTESYNC;
+ case GODOT_METHOD_RPC_MODE_MASTERSYNC:
+ return MultiplayerAPI::RPC_MODE_MASTERSYNC;
+ case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
+ return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
+ default:
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ }
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
String NativeScript::get_class_documentation() const {
NativeScriptDesc *script_data = get_script_desc();
@@ -803,72 +1061,44 @@ Ref<Script> NativeScriptInstance::get_script() const {
return script;
}
-MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const {
-
- NativeScriptDesc *script_data = GET_SCRIPT_DESC();
-
- while (script_data) {
+Vector<ScriptNetData> NativeScriptInstance::get_rpc_methods() const {
+ return script->get_rpc_methods();
+}
- Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
- if (E) {
- switch (E->get().rpc_mode) {
- case GODOT_METHOD_RPC_MODE_DISABLED:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- case GODOT_METHOD_RPC_MODE_REMOTE:
- return MultiplayerAPI::RPC_MODE_REMOTE;
- case GODOT_METHOD_RPC_MODE_MASTER:
- return MultiplayerAPI::RPC_MODE_MASTER;
- case GODOT_METHOD_RPC_MODE_PUPPET:
- return MultiplayerAPI::RPC_MODE_PUPPET;
- case GODOT_METHOD_RPC_MODE_REMOTESYNC:
- return MultiplayerAPI::RPC_MODE_REMOTESYNC;
- case GODOT_METHOD_RPC_MODE_MASTERSYNC:
- return MultiplayerAPI::RPC_MODE_MASTERSYNC;
- case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
- return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
- default:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- }
+uint16_t NativeScriptInstance::get_rpc_method_id(const StringName &p_method) const {
+ return script->get_rpc_method_id(p_method);
+}
- script_data = script_data->base_data;
- }
+StringName NativeScriptInstance::get_rpc_method(uint16_t p_id) const {
+ return script->get_rpc_method(p_id);
+}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const {
+ return script->get_rpc_mode_by_id(p_id);
}
-MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
+MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const {
+ return script->get_rpc_mode(p_method);
+}
- NativeScriptDesc *script_data = GET_SCRIPT_DESC();
+Vector<ScriptNetData> NativeScriptInstance::get_rset_properties() const {
+ return script->get_rset_properties();
+}
- while (script_data) {
+uint16_t NativeScriptInstance::get_rset_property_id(const StringName &p_variable) const {
+ return script->get_rset_property_id(p_variable);
+}
- OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
- if (E) {
- switch (E.get().rset_mode) {
- case GODOT_METHOD_RPC_MODE_DISABLED:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- case GODOT_METHOD_RPC_MODE_REMOTE:
- return MultiplayerAPI::RPC_MODE_REMOTE;
- case GODOT_METHOD_RPC_MODE_MASTER:
- return MultiplayerAPI::RPC_MODE_MASTER;
- case GODOT_METHOD_RPC_MODE_PUPPET:
- return MultiplayerAPI::RPC_MODE_PUPPET;
- case GODOT_METHOD_RPC_MODE_REMOTESYNC:
- return MultiplayerAPI::RPC_MODE_REMOTESYNC;
- case GODOT_METHOD_RPC_MODE_MASTERSYNC:
- return MultiplayerAPI::RPC_MODE_MASTERSYNC;
- case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
- return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
- default:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- }
+StringName NativeScriptInstance::get_rset_property(uint16_t p_id) const {
+ return script->get_rset_property(p_id);
+}
- script_data = script_data->base_data;
- }
+MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode_by_id(uint16_t p_id) const {
+ return script->get_rset_mode_by_id(p_id);
+}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
+ return script->get_rset_mode(p_variable);
}
ScriptLanguage *NativeScriptInstance::get_language() {
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index cf787e1f6a..2ff08e32cd 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -54,6 +54,7 @@ struct NativeScriptDesc {
godot_instance_method method;
MethodInfo info;
int rpc_mode;
+ uint16_t rpc_method_id;
String documentation;
};
struct Property {
@@ -62,6 +63,7 @@ struct NativeScriptDesc {
PropertyInfo info;
Variant default_value;
int rset_mode;
+ uint16_t rset_property_id;
String documentation;
};
@@ -70,7 +72,9 @@ struct NativeScriptDesc {
String documentation;
};
+ uint16_t rpc_count;
Map<StringName, Method> methods;
+ uint16_t rset_count;
OrderedHashMap<StringName, Property> properties;
Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
StringName base;
@@ -86,7 +90,9 @@ struct NativeScriptDesc {
bool is_tool;
inline NativeScriptDesc() :
+ rpc_count(0),
methods(),
+ rset_count(0),
properties(),
signals_(),
base(),
@@ -174,6 +180,18 @@ public:
virtual void get_script_method_list(List<MethodInfo> *p_list) const;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+
String get_class_documentation() const;
String get_method_documentation(const StringName &p_method) const;
String get_signal_documentation(const StringName &p_signal_name) const;
@@ -210,8 +228,19 @@ public:
virtual void notification(int p_notification);
String to_string(bool *r_valid);
virtual Ref<Script> get_script() const;
+
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+
virtual ScriptLanguage *get_language();
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 0d6dac3268..26a1d5f47a 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -93,10 +93,42 @@ void PluginScriptInstance::notification(int p_notification) {
_desc->notification(_data, p_notification);
}
+Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const {
+ return _script->get_rpc_methods();
+}
+
+uint16_t PluginScriptInstance::get_rpc_method_id(const StringName &p_variable) const {
+ return _script->get_rpc_method_id(p_variable);
+}
+
+StringName PluginScriptInstance::get_rpc_method(uint16_t p_id) const {
+ return _script->get_rpc_method(p_id);
+}
+
+MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const {
+ return _script->get_rpc_mode_by_id(p_id);
+}
+
MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const {
return _script->get_rpc_mode(p_method);
}
+Vector<ScriptNetData> PluginScriptInstance::get_rset_properties() const {
+ return _script->get_rset_properties();
+}
+
+uint16_t PluginScriptInstance::get_rset_property_id(const StringName &p_variable) const {
+ return _script->get_rset_property_id(p_variable);
+}
+
+StringName PluginScriptInstance::get_rset_property(uint16_t p_id) const {
+ return _script->get_rset_property(p_id);
+}
+
+MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode_by_id(uint16_t p_id) const {
+ return _script->get_rset_mode_by_id(p_id);
+}
+
MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const {
return _script->get_rset_mode(p_variable);
}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index dc1229a44d..154bebd72a 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -76,7 +76,16 @@ public:
void set_path(const String &p_path);
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(uint16_t p_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
virtual void refcount_incremented();
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index cc5bdee0a1..c370062262 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -34,6 +34,8 @@
#include "pluginscript_instance.h"
#include "pluginscript_script.h"
+#include <stdint.h>
+
#ifdef DEBUG_ENABLED
#define __ASSERT_SCRIPT_REASON "Cannot retrieve PluginScript class for this script, is your code correct?"
#define ASSERT_SCRIPT_VALID() \
@@ -298,18 +300,31 @@ Error PluginScript::reload(bool p_keep_state) {
_member_lines[*key] = (*members)[*key];
}
Array *methods = (Array *)&manifest.methods;
+ _rpc_methods.clear();
+ _rpc_variables.clear();
+ if (_ref_base_parent.is_valid()) {
+ _rpc_methods = _ref_base_parent->get_rpc_methods();
+ _rpc_variables = _ref_base_parent->get_rset_properties();
+ }
for (int i = 0; i < methods->size(); ++i) {
Dictionary v = (*methods)[i];
MethodInfo mi = MethodInfo::from_dict(v);
_methods_info[mi.name] = mi;
// rpc_mode is passed as an optional field and is not part of MethodInfo
Variant var = v["rpc_mode"];
- if (var == Variant()) {
- _methods_rpc_mode[mi.name] = MultiplayerAPI::RPC_MODE_DISABLED;
- } else {
- _methods_rpc_mode[mi.name] = MultiplayerAPI::RPCMode(int(var));
+ if (var != Variant()) {
+ ScriptNetData nd;
+ nd.name = mi.name;
+ nd.mode = MultiplayerAPI::RPCMode(int(var));
+ if (_rpc_methods.find(nd) == -1) {
+ _rpc_methods.push_back(nd);
+ }
}
}
+
+ // Sort so we are 100% that they are always the same.
+ _rpc_methods.sort_custom<SortNetData>();
+
Array *signals = (Array *)&manifest.signals;
for (int i = 0; i < signals->size(); ++i) {
Variant v = (*signals)[i];
@@ -324,13 +339,19 @@ Error PluginScript::reload(bool p_keep_state) {
_properties_default_values[pi.name] = v["default_value"];
// rset_mode is passed as an optional field and is not part of PropertyInfo
Variant var = v["rset_mode"];
- if (var == Variant()) {
- _methods_rpc_mode[pi.name] = MultiplayerAPI::RPC_MODE_DISABLED;
- } else {
- _methods_rpc_mode[pi.name] = MultiplayerAPI::RPCMode(int(var));
+ if (var != Variant()) {
+ ScriptNetData nd;
+ nd.name = pi.name;
+ nd.mode = MultiplayerAPI::RPCMode(int(var));
+ if (_rpc_variables.find(nd) == -1) {
+ _rpc_variables.push_back(nd);
+ }
}
}
+ // Sort so we are 100% that they are always the same.
+ _rpc_variables.sort_custom<SortNetData>();
+
#ifdef TOOLS_ENABLED
/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
@@ -455,24 +476,70 @@ int PluginScript::get_member_line(const StringName &p_member) const {
return -1;
}
-MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const {
+Vector<ScriptNetData> PluginScript::get_rpc_methods() const {
+ return _rpc_methods;
+}
+
+uint16_t PluginScript::get_rpc_method_id(const StringName &p_method) const {
+ ASSERT_SCRIPT_VALID_V(UINT16_MAX);
+ for (int i = 0; i < _rpc_methods.size(); i++) {
+ if (_rpc_methods[i].name == p_method) {
+ return i;
+ }
+ }
+ return UINT16_MAX;
+}
+
+StringName PluginScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
+ ASSERT_SCRIPT_VALID_V(StringName());
+ if (p_rpc_method_id >= _rpc_methods.size())
+ return StringName();
+ return _rpc_methods[p_rpc_method_id].name;
+}
+
+MultiplayerAPI::RPCMode PluginScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
- const Map<StringName, MultiplayerAPI::RPCMode>::Element *e = _methods_rpc_mode.find(p_method);
- if (e != NULL) {
- return e->get();
- } else {
+ if (p_rpc_method_id >= _rpc_methods.size())
return MultiplayerAPI::RPC_MODE_DISABLED;
+ return _rpc_methods[p_rpc_method_id].mode;
+}
+
+MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const {
+ ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
+ return get_rpc_mode_by_id(get_rpc_method_id(p_method));
+}
+
+Vector<ScriptNetData> PluginScript::get_rset_properties() const {
+ return _rpc_variables;
+}
+
+uint16_t PluginScript::get_rset_property_id(const StringName &p_property) const {
+ ASSERT_SCRIPT_VALID_V(UINT16_MAX);
+ for (int i = 0; i < _rpc_variables.size(); i++) {
+ if (_rpc_variables[i].name == p_property) {
+ return i;
+ }
}
+ return UINT16_MAX;
}
-MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const {
+StringName PluginScript::get_rset_property(const uint16_t p_rset_property_id) const {
+ ASSERT_SCRIPT_VALID_V(StringName());
+ if (p_rset_property_id >= _rpc_variables.size())
+ return StringName();
+ return _rpc_variables[p_rset_property_id].name;
+}
+
+MultiplayerAPI::RPCMode PluginScript::get_rset_mode_by_id(const uint16_t p_rset_property_id) const {
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
- const Map<StringName, MultiplayerAPI::RPCMode>::Element *e = _variables_rset_mode.find(p_variable);
- if (e != NULL) {
- return e->get();
- } else {
+ if (p_rset_property_id >= _rpc_variables.size())
return MultiplayerAPI::RPC_MODE_DISABLED;
- }
+ return _rpc_variables[p_rset_property_id].mode;
+}
+
+MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const {
+ ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
+ return get_rset_mode_by_id(get_rset_property_id(p_variable));
}
PluginScript::PluginScript() :
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index f67c88c794..f6bca8a9cb 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -60,8 +60,8 @@ private:
Map<StringName, PropertyInfo> _properties_info;
Map<StringName, MethodInfo> _signals_info;
Map<StringName, MethodInfo> _methods_info;
- Map<StringName, MultiplayerAPI::RPCMode> _variables_rset_mode;
- Map<StringName, MultiplayerAPI::RPCMode> _methods_rpc_mode;
+ Vector<ScriptNetData> _rpc_methods;
+ Vector<ScriptNetData> _rpc_variables;
Set<Object *> _instances;
//exported members
@@ -118,8 +118,17 @@ public:
virtual int get_member_line(const StringName &p_member) const;
- MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
- MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_property) const;
+ virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
PluginScript();
void init(PluginScriptLanguage *language);
diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/gdnavigation/gd_navigation_server.cpp
index ddfb3c10fa..2780e2a931 100644
--- a/modules/gdnavigation/gd_navigation_server.cpp
+++ b/modules/gdnavigation/gd_navigation_server.cpp
@@ -374,7 +374,7 @@ COMMAND_4(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_
RvoAgent *agent = agent_owner.getornull(p_agent);
ERR_FAIL_COND(agent == NULL);
- agent->set_callback(p_receiver == NULL ? 0 : p_receiver->get_instance_id(), p_method, p_udata);
+ agent->set_callback(p_receiver == NULL ? ObjectID() : p_receiver->get_instance_id(), p_method, p_udata);
if (agent->get_map()) {
if (p_receiver == NULL) {
diff --git a/modules/gdnavigation/rvo_agent.cpp b/modules/gdnavigation/rvo_agent.cpp
index eb66eb3a05..4d19bc15af 100644
--- a/modules/gdnavigation/rvo_agent.cpp
+++ b/modules/gdnavigation/rvo_agent.cpp
@@ -38,7 +38,7 @@
RvoAgent::RvoAgent() :
map(NULL) {
- callback.id = ObjectID(0);
+ callback.id = ObjectID();
}
void RvoAgent::set_map(NavMap *p_map) {
@@ -62,16 +62,16 @@ void RvoAgent::set_callback(ObjectID p_id, const StringName p_method, const Vari
}
bool RvoAgent::has_callback() const {
- return callback.id != 0;
+ return callback.id.is_valid();
}
void RvoAgent::dispatch_callback() {
- if (callback.id == 0) {
+ if (callback.id.is_null()) {
return;
}
Object *obj = ObjectDB::get_instance(callback.id);
if (obj == NULL) {
- callback.id = ObjectID(0);
+ callback.id = ObjectID();
}
Variant::CallError responseCallError;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index a255b92257..e4da60b5b9 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -30,6 +30,8 @@
#include "gdscript.h"
+#include <stdint.h>
+
#include "core/core_string_names.h"
#include "core/engine.h"
#include "core/global_constants.h"
@@ -610,6 +612,53 @@ Error GDScript::reload(bool p_keep_state) {
_set_subclass_path(E->get(), path);
}
+ // Copy the base rpc methods so we don't mask their IDs.
+ rpc_functions.clear();
+ rpc_variables.clear();
+ if (base.is_valid()) {
+ rpc_functions = base->rpc_functions;
+ rpc_variables = base->rpc_variables;
+ }
+
+ GDScript *cscript = this;
+ Map<StringName, Ref<GDScript> >::Element *sub_E = subclasses.front();
+ 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) {
+ ScriptNetData nd;
+ nd.name = E->key();
+ nd.mode = E->get()->get_rpc_mode();
+ if (-1 == rpc_functions.find(nd)) {
+ rpc_functions.push_back(nd);
+ }
+ }
+ }
+ // RSet
+ for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) {
+ if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
+ ScriptNetData nd;
+ nd.name = E->key();
+ nd.mode = E->get().rpc_mode;
+ if (-1 == rpc_variables.find(nd)) {
+ rpc_variables.push_back(nd);
+ }
+ }
+ }
+
+ if (cscript != this)
+ sub_E = sub_E->next();
+
+ if (sub_E)
+ cscript = sub_E->get().ptr();
+ else
+ cscript = NULL;
+ }
+
+ // Sort so we are 100% that they are always the same.
+ rpc_functions.sort_custom<SortNetData>();
+ rpc_variables.sort_custom<SortNetData>();
+
return OK;
}
@@ -635,6 +684,60 @@ void GDScript::get_members(Set<StringName> *p_members) {
}
}
+Vector<ScriptNetData> GDScript::get_rpc_methods() const {
+ return rpc_functions;
+}
+
+uint16_t GDScript::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 GDScript::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 GDScript::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 GDScript::get_rpc_mode(const StringName &p_method) const {
+ return get_rpc_mode_by_id(get_rpc_method_id(p_method));
+}
+
+Vector<ScriptNetData> GDScript::get_rset_properties() const {
+ return rpc_variables;
+}
+
+uint16_t GDScript::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 GDScript::get_rset_property(const uint16_t p_rset_member_id) const {
+ ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName());
+ return rpc_variables[p_rset_member_id].name;
+}
+
+MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
+ ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
+ return rpc_functions[p_rset_member_id].mode;
+}
+
+MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const {
+ return get_rset_mode_by_id(get_rset_property_id(p_variable));
+}
+
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
GDScript *top = this;
@@ -1291,40 +1394,44 @@ ScriptLanguage *GDScriptInstance::get_language() {
return GDScriptLanguage::get_singleton();
}
-MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const {
+Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const {
+ return script->get_rpc_methods();
+}
- const GDScript *cscript = script.ptr();
+uint16_t GDScriptInstance::get_rpc_method_id(const StringName &p_method) const {
+ return script->get_rpc_method_id(p_method);
+}
- while (cscript) {
- const Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.find(p_method);
- if (E) {
+StringName GDScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
+ return script->get_rpc_method(p_rpc_method_id);
+}
- if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
- return E->get()->get_rpc_mode();
- }
- }
- cscript = cscript->_base;
- }
+MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
+ return script->get_rpc_mode_by_id(p_rpc_method_id);
+}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const {
+ return script->get_rpc_mode(p_method);
}
-MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const {
+Vector<ScriptNetData> GDScriptInstance::get_rset_properties() const {
+ return script->get_rset_properties();
+}
- const GDScript *cscript = script.ptr();
+uint16_t GDScriptInstance::get_rset_property_id(const StringName &p_variable) const {
+ return script->get_rset_property_id(p_variable);
+}
- while (cscript) {
- const Map<StringName, GDScript::MemberInfo>::Element *E = cscript->member_indices.find(p_variable);
- if (E) {
+StringName GDScriptInstance::get_rset_property(const uint16_t p_rset_member_id) const {
+ return script->get_rset_property(p_rset_member_id);
+}
- if (E->get().rpc_mode) {
- return E->get().rpc_mode;
- }
- }
- cscript = cscript->_base;
- }
+MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
+ return script->get_rset_mode_by_id(p_rset_member_id);
+}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const {
+ return script->get_rset_mode(p_variable);
}
void GDScriptInstance::reload_members() {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 4ae52238ce..4af574cd9d 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -85,6 +85,8 @@ class GDScript : public Script {
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
Map<StringName, Ref<GDScript> > subclasses;
Map<StringName, Vector<StringName> > _signals;
+ Vector<ScriptNetData> rpc_functions;
+ Vector<ScriptNetData> rpc_variables;
#ifdef TOOLS_ENABLED
@@ -213,6 +215,18 @@ public:
virtual void get_constants(Map<StringName, Variant> *p_constants);
virtual void get_members(Set<StringName> *p_members);
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(const uint16_t p_variable_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+
#ifdef TOOLS_ENABLED
virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
#endif
@@ -264,7 +278,16 @@ public:
void reload_members();
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(const uint16_t p_variable_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
GDScriptInstance();
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 452b1933eb..7392bbc10a 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1274,7 +1274,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->state.script = Ref<GDScript>(_script);
gdfs->state.ip = ip + ipofs;
gdfs->state.line = line;
- gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_id() : 0;
+ gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_id() : ObjectID();
//gdfs->state.result_pos=ip+ipofs-1;
gdfs->state.defarg = defarg;
gdfs->state.instance = p_instance;
@@ -1829,7 +1829,7 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
if (p_extended_check) {
//class instance gone?
- if (state.instance_id && !ObjectDB::get_instance(state.instance_id))
+ if (state.instance_id.is_valid() && !ObjectDB::get_instance(state.instance_id))
return false;
}
@@ -1839,7 +1839,7 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
Variant GDScriptFunctionState::resume(const Variant &p_arg) {
ERR_FAIL_COND_V(!function, Variant());
- if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
+ if (state.instance_id.is_valid() && !ObjectDB::get_instance(state.instance_id)) {
#ifdef DEBUG_ENABLED
ERR_FAIL_V_MSG(Variant(), "Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line));
#else
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 37cefa0d52..1a5087eb4d 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -1367,7 +1367,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
break;
}
- uint32_t id = *p_args[0];
+ ObjectID id = *p_args[0];
r_ret = ObjectDB::get_instance(id);
} break;
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 0572c5f746..d5723fd20f 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -321,6 +321,8 @@ Variant GDScriptTextDocument::hover(const Dictionary &p_params) {
lsp::Hover hover;
hover.contents = symbol->render();
+ hover.range.start = params.position;
+ hover.range.end = params.position;
return hover.to_json();
} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 2847f3b414..10bc3dcb49 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -31,6 +31,7 @@
#include "csharp_script.h"
#include <mono/metadata/threads.h>
+#include <stdint.h>
#include "core/io/json.h"
#include "core/os/file_access.h"
@@ -161,11 +162,11 @@ void CSharpLanguage::finish() {
#ifdef DEBUG_ENABLED
for (Map<ObjectID, int>::Element *E = unsafe_object_references.front(); E; E = E->next()) {
- const ObjectID &id = E->get();
+ const ObjectID &id = E->key();
Object *obj = ObjectDB::get_instance(id);
if (obj) {
- ERR_PRINT("Leaked unsafe reference to object: " + obj->get_class() + ":" + itos(id));
+ ERR_PRINT("Leaked unsafe reference to object: " + obj->to_string());
} else {
ERR_PRINT("Leaked unsafe reference to deleted object: " + itos(id));
}
@@ -1979,67 +1980,44 @@ bool CSharpInstance::refcount_decremented() {
return ref_dying;
}
-MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p_member) const {
-
- if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute)))
- return MultiplayerAPI::RPC_MODE_REMOTE;
- if (p_member->has_attribute(CACHED_CLASS(MasterAttribute)))
- return MultiplayerAPI::RPC_MODE_MASTER;
- if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute)))
- return MultiplayerAPI::RPC_MODE_PUPPET;
- if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute)))
- 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(SyncAttribute)))
- 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;
+Vector<ScriptNetData> CSharpInstance::get_rpc_methods() const {
+ return script->get_rpc_methods();
+}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+uint16_t CSharpInstance::get_rpc_method_id(const StringName &p_method) const {
+ return script->get_rpc_method_id(p_method);
}
-MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
+StringName CSharpInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
+ return script->get_rpc_method(p_rpc_method_id);
+}
- GD_MONO_SCOPE_THREAD_ATTACH;
+MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
+ return script->get_rpc_mode_by_id(p_rpc_method_id);
+}
- GDMonoClass *top = script->script_class;
+MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
+ return script->get_rpc_mode(p_method);
+}
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_fetched_method_unknown_params(p_method);
+Vector<ScriptNetData> CSharpInstance::get_rset_properties() const {
+ return script->get_rset_properties();
+}
- if (method && !method->is_static())
- return _member_get_rpc_mode(method);
+uint16_t CSharpInstance::get_rset_property_id(const StringName &p_variable) const {
+ return script->get_rset_property_id(p_variable);
+}
- top = top->get_parent_class();
- }
+StringName CSharpInstance::get_rset_property(const uint16_t p_rset_member_id) const {
+ return script->get_rset_property(p_rset_member_id);
+}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
+ return script->get_rset_mode_by_id(p_rset_member_id);
}
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoField *field = top->get_field(p_variable);
-
- if (field && !field->is_static())
- return _member_get_rpc_mode(field);
-
- GDMonoProperty *property = top->get_property(p_variable);
-
- if (property && !property->is_static())
- return _member_get_rpc_mode(property);
-
- top = top->get_parent_class();
- }
-
- return MultiplayerAPI::RPC_MODE_DISABLED;
+ return script->get_rset_mode(p_variable);
}
void CSharpInstance::notification(int p_notification) {
@@ -3251,6 +3229,69 @@ Error CSharpScript::reload(bool p_keep_state) {
_update_exports();
}
+ rpc_functions.clear();
+ rpc_variables.clear();
+
+ GDMonoClass *top = script_class;
+ while (top && top != native) {
+ {
+ Vector<GDMonoMethod *> methods = top->get_all_methods();
+ for (int i = 0; i < methods.size(); i++) {
+ if (!methods[i]->is_static()) {
+ MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(methods[i]);
+ if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
+ ScriptNetData nd;
+ nd.name = methods[i]->get_name();
+ nd.mode = mode;
+ if (-1 == rpc_functions.find(nd)) {
+ rpc_functions.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
+ {
+ Vector<GDMonoField *> fields = top->get_all_fields();
+ for (int i = 0; i < fields.size(); i++) {
+ if (!fields[i]->is_static()) {
+ MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(fields[i]);
+ if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
+ ScriptNetData nd;
+ nd.name = fields[i]->get_name();
+ nd.mode = mode;
+ if (-1 == rpc_variables.find(nd)) {
+ rpc_variables.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
+ {
+ Vector<GDMonoProperty *> properties = top->get_all_properties();
+ for (int i = 0; i < properties.size(); i++) {
+ if (!properties[i]->is_static()) {
+ MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(properties[i]);
+ if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
+ ScriptNetData nd;
+ nd.name = properties[i]->get_name();
+ nd.mode = mode;
+ if (-1 == rpc_variables.find(nd)) {
+ rpc_variables.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+
+ // Sort so we are 100% that they are always the same.
+ rpc_functions.sort_custom<SortNetData>();
+ rpc_variables.sort_custom<SortNetData>();
+
return OK;
}
@@ -3324,6 +3365,82 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
return -1;
}
+MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const {
+
+ if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute)))
+ return MultiplayerAPI::RPC_MODE_REMOTE;
+ if (p_member->has_attribute(CACHED_CLASS(MasterAttribute)))
+ return MultiplayerAPI::RPC_MODE_MASTER;
+ if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute)))
+ return MultiplayerAPI::RPC_MODE_PUPPET;
+ if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute)))
+ 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(SyncAttribute)))
+ 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;
+}
+
+Vector<ScriptNetData> CSharpScript::get_rpc_methods() const {
+ return rpc_functions;
+}
+
+uint16_t CSharpScript::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 CSharpScript::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 CSharpScript::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 CSharpScript::get_rpc_mode(const StringName &p_method) const {
+ return get_rpc_mode_by_id(get_rpc_method_id(p_method));
+}
+
+Vector<ScriptNetData> CSharpScript::get_rset_properties() const {
+ return rpc_variables;
+}
+
+uint16_t CSharpScript::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 CSharpScript::get_rset_property(const uint16_t p_rset_member_id) const {
+ ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName());
+ return rpc_variables[p_rset_member_id].name;
+}
+
+MultiplayerAPI::RPCMode CSharpScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
+ ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
+ return rpc_functions[p_rset_member_id].mode;
+}
+
+MultiplayerAPI::RPCMode CSharpScript::get_rset_mode(const StringName &p_variable) const {
+ return get_rset_mode_by_id(get_rset_property_id(p_variable));
+}
+
Error CSharpScript::load_source_code(const String &p_path) {
Error ferr = read_all_file_utf8(p_path, source);
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index f244bc4119..32a5b30c18 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -113,6 +113,9 @@ class CSharpScript : public Script {
Map<StringName, Vector<Argument> > _signals;
bool signals_invalidated;
+ Vector<ScriptNetData> rpc_functions;
+ Vector<ScriptNetData> rpc_variables;
+
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
@@ -146,6 +149,8 @@ class CSharpScript : public Script {
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
+ MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
+
protected:
static void _bind_methods();
@@ -187,6 +192,18 @@ public:
virtual int get_member_line(const StringName &p_member) const;
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(const uint16_t p_variable_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+
#ifdef TOOLS_ENABLED
virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
#endif
@@ -232,8 +249,6 @@ class CSharpInstance : public ScriptInstance {
void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
- MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
-
void get_properties_state_for_reloading(List<Pair<StringName, Variant> > &r_state);
public:
@@ -265,7 +280,16 @@ public:
virtual void refcount_incremented();
virtual bool refcount_decremented();
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
+ virtual StringName get_rset_property(const uint16_t p_variable_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
virtual void notification(int p_notification);
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index d3226762ea..b85d5f2fd9 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -68,7 +68,7 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p
Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(conn_target_id && !ObjectDB::get_instance(conn_target_id), Variant(),
+ ERR_FAIL_COND_V_MSG(conn_target_id.is_valid() && !ObjectDB::get_instance(conn_target_id), Variant(),
"Resumed after await, but class instance is gone.");
#endif
@@ -116,12 +116,7 @@ void SignalAwaiterHandle::_bind_methods() {
}
SignalAwaiterHandle::SignalAwaiterHandle(MonoObject *p_managed) :
- MonoGCHandle(MonoGCHandle::new_strong_handle(p_managed), STRONG_HANDLE) {
-
-#ifdef DEBUG_ENABLED
- conn_target_id = 0;
-#endif
-}
+ MonoGCHandle(MonoGCHandle::new_strong_handle(p_managed), STRONG_HANDLE) {}
SignalAwaiterHandle::~SignalAwaiterHandle() {
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index c591e3b5c2..e712190344 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -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;
}
-MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
+Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const {
+ return script->get_rpc_methods();
+}
- if (p_method == script->get_default_func())
- return MultiplayerAPI::RPC_MODE_DISABLED;
+uint16_t VisualScriptInstance::get_rpc_method_id(const StringName &p_method) const {
+ return script->get_rpc_method_id(p_method);
+}
- const Map<StringName, VisualScript::Function>::Element *E = script->functions.find(p_method);
- if (!E) {
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
+StringName VisualScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
+ return script->get_rpc_method(p_rpc_method_id);
+}
- if (E->get().function_id >= 0 && E->get().nodes.has(E->get().function_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);
+}
- Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
- if (vsf.is_valid()) {
+MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
+ return script->get_rpc_mode(p_method);
+}
- return vsf->get_rpc_mode();
- }
- }
+Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const {
+ return script->get_rset_properties();
+}
- 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);
}
-MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const {
+StringName VisualScriptInstance::get_rset_property(const uint16_t p_rset_property_id) const {
+ return script->get_rset_property(p_rset_property_id);
+}
- 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 script->get_rset_mode(p_variable);
}
void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {
@@ -2321,8 +2414,8 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(instance_id && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone.");
- ERR_FAIL_COND_V_MSG(script_id && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone.");
+ ERR_FAIL_COND_V_MSG(instance_id.is_valid() && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone.");
+ ERR_FAIL_COND_V_MSG(script_id.is_valid() && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone.");
#endif
@@ -2383,8 +2476,8 @@ Variant VisualScriptFunctionState::resume(Array p_args) {
ERR_FAIL_COND_V(function == StringName(), Variant());
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(instance_id && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone.");
- ERR_FAIL_COND_V_MSG(script_id && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone.");
+ ERR_FAIL_COND_V_MSG(instance_id.is_valid() && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone.");
+ ERR_FAIL_COND_V_MSG(script_id.is_valid() && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone.");
#endif
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 9305226dc6..d3569bb040 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -245,6 +245,8 @@ private:
Map<StringName, Function> functions;
Map<StringName, Variable> variables;
Map<StringName, Vector<Argument> > custom_signals;
+ Vector<ScriptNetData> rpc_functions;
+ Vector<ScriptNetData> rpc_variables;
Map<Object *, VisualScriptInstance *> instances;
@@ -362,6 +364,18 @@ public:
virtual int get_member_line(const StringName &p_member) const;
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_property) const;
+ virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+
#ifdef TOOLS_ENABLED
virtual bool are_subnodes_edited() const;
#endif
@@ -441,7 +455,16 @@ public:
virtual ScriptLanguage *get_language();
+ virtual Vector<ScriptNetData> get_rpc_methods() const;
+ virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
+ virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
+ virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
+
+ virtual Vector<ScriptNetData> get_rset_properties() const;
+ virtual uint16_t get_rset_property_id(const StringName &p_property) const;
+ virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
+ virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
VisualScriptInstance();
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index e629175094..e8c02a41c4 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -529,7 +529,6 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_
base_type = p_base;
selected = p_current;
type = Variant::NIL;
- script = 0;
properties = false;
instance = NULL;
virtuals_only = p_virtuals_only;
@@ -554,7 +553,6 @@ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, c
base_type = p_base;
selected = p_current;
type = Variant::NIL;
- script = 0;
properties = true;
visual_script_generic = false;
instance = NULL;
@@ -601,7 +599,6 @@ void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type,
base_type = "";
selected = p_current;
type = p_type;
- script = 0;
properties = true;
visual_script_generic = false;
instance = NULL;
@@ -623,7 +620,6 @@ void VisualScriptPropertySelector::select_from_action(const String &p_type, cons
base_type = p_type;
selected = p_current;
type = Variant::NIL;
- script = 0;
properties = false;
visual_script_generic = false;
instance = NULL;
@@ -645,7 +641,6 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons
base_type = p_basetype;
selected = p_current;
type = Variant::NIL;
- script = 0;
properties = true;
visual_script_generic = false;
instance = p_instance;
@@ -667,7 +662,6 @@ void VisualScriptPropertySelector::select_from_visual_script(const String &p_bas
base_type = p_base;
selected = "";
type = Variant::NIL;
- script = 0;
properties = true;
visual_script_generic = true;
instance = NULL;
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 338194fcae..1fd91ec3c1 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -240,6 +240,11 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and GLES2 support checks, driver selection and fallback
video_driver_index = p_video_driver;
+#ifndef _MSC_VER
+#warning Forcing vulkan video driver because OpenGL not implemented yet
+#endif
+ video_driver_index = VIDEO_DRIVER_VULKAN;
+
print_verbose("Driver: " + String(get_video_driver_name(video_driver_index)) + " [" + itos(video_driver_index) + "]");
//!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 8302ba5336..b661db2e52 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -148,7 +148,7 @@ void Area2D::_body_exit_tree(ObjectID p_id) {
}
}
-void Area2D::_body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape) {
+void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {
bool body_in = p_status == Physics2DServer::AREA_BODY_ADDED;
ObjectID objid = p_instance;
@@ -251,7 +251,7 @@ void Area2D::_area_exit_tree(ObjectID p_id) {
}
}
-void Area2D::_area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape) {
+void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) {
bool area_in = p_status == Physics2DServer::AREA_BODY_ADDED;
ObjectID objid = p_instance;
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index 6d9386c535..c5e6635412 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -62,7 +62,7 @@ private:
bool monitorable;
bool locked;
- void _body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape);
+ void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape);
void _body_enter_tree(ObjectID p_id);
void _body_exit_tree(ObjectID p_id);
@@ -94,7 +94,7 @@ private:
Map<ObjectID, BodyState> body_map;
- void _area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape);
+ void _area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape);
void _area_enter_tree(ObjectID p_id);
void _area_exit_tree(ObjectID p_id);
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index e9f8c5dff2..7ec770597e 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -608,7 +608,7 @@ void Camera2D::set_custom_viewport(Node *p_viewport) {
if (custom_viewport) {
custom_viewport_id = custom_viewport->get_instance_id();
} else {
- custom_viewport_id = 0;
+ custom_viewport_id = ObjectID();
}
if (is_inside_tree()) {
@@ -795,7 +795,7 @@ Camera2D::Camera2D() {
smoothing_enabled = false;
limit_smoothing_enabled = false;
custom_viewport = NULL;
- custom_viewport_id = 0;
+
process_mode = CAMERA2D_PROCESS_IDLE;
smoothing = 5.0;
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index eff58a4fb3..aca0c4c959 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -997,7 +997,7 @@ ObjectID CanvasItem::get_canvas_layer_instance_id() const {
if (canvas_layer) {
return canvas_layer->get_instance_id();
} else {
- return 0;
+ return ObjectID();
}
}
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 3e9e63a7f0..4af2e846f7 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -95,9 +95,9 @@ void CollisionObject2D::_notification(int p_what) {
case NOTIFICATION_EXIT_CANVAS: {
if (area)
- Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, 0);
+ Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, ObjectID());
else
- Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, 0);
+ Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID());
} break;
}
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index d42bd6adaf..d1fe5caf7e 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1544,7 +1544,7 @@ Object *KinematicCollision2D::get_local_shape() const {
Object *KinematicCollision2D::get_collider() const {
- if (collision.collider) {
+ if (collision.collider.is_valid()) {
return ObjectDB::get_instance(collision.collider);
}
@@ -1608,7 +1608,7 @@ void KinematicCollision2D::_bind_methods() {
}
KinematicCollision2D::KinematicCollision2D() {
- collision.collider = 0;
+
collision.collider_shape = 0;
collision.local_shape = 0;
owner = NULL;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index dc953b2d7d..ba5b7d29e7 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -108,7 +108,7 @@ void Polygon2D::_notification(int p_what) {
skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton));
}
- ObjectID new_skeleton_id = 0;
+ ObjectID new_skeleton_id;
if (skeleton_node) {
VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton());
@@ -734,7 +734,7 @@ Polygon2D::Polygon2D() {
color = Color(1, 1, 1);
rect_cache_dirty = true;
internal_vertices = 0;
- current_skeleton_id = 0;
+
specular_color = Color(1, 1, 1, 1);
shininess = 1.0;
}
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 3252e02e38..fd6e0aebcc 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -78,7 +78,7 @@ bool RayCast2D::is_colliding() const {
}
Object *RayCast2D::get_collider() const {
- if (against == 0)
+ if (against.is_null())
return NULL;
return ObjectDB::get_instance(against);
@@ -225,7 +225,7 @@ void RayCast2D::_update_raycast_state() {
against_shape = rr.shape;
} else {
collided = false;
- against = 0;
+ against = ObjectID();
against_shape = 0;
}
}
@@ -339,7 +339,7 @@ void RayCast2D::_bind_methods() {
RayCast2D::RayCast2D() {
enabled = false;
- against = 0;
+
collided = false;
against_shape = 0;
collision_mask = 1;
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index 53072f942d..ec50f5f922 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -33,7 +33,7 @@
void RemoteTransform2D::_update_cache() {
- cache = 0;
+ cache = ObjectID();
if (has_node(remote_node)) {
Node *node = get_node(remote_node);
if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
@@ -49,7 +49,7 @@ void RemoteTransform2D::_update_remote() {
if (!is_inside_tree())
return;
- if (!cache)
+ if (cache.is_null())
return;
Node2D *n = Object::cast_to<Node2D>(ObjectDB::get_instance(cache));
@@ -119,7 +119,7 @@ void RemoteTransform2D::_notification(int p_what) {
if (!is_inside_tree())
break;
- if (cache) {
+ if (cache.is_valid()) {
_update_remote();
}
@@ -225,6 +225,5 @@ RemoteTransform2D::RemoteTransform2D() {
update_remote_rotation = true;
update_remote_scale = true;
- cache = 0;
set_notify_transform(true);
}
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 67f57a1aa3..62908e2b0f 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -147,7 +147,7 @@ void Area::_body_exit_tree(ObjectID p_id) {
}
}
-void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape) {
+void Area::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {
bool body_in = p_status == PhysicsServer::AREA_BODY_ADDED;
ObjectID objid = p_instance;
@@ -340,7 +340,7 @@ void Area::_area_exit_tree(ObjectID p_id) {
}
}
-void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape) {
+void Area::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) {
bool area_in = p_status == PhysicsServer::AREA_BODY_ADDED;
ObjectID objid = p_instance;
diff --git a/scene/3d/area.h b/scene/3d/area.h
index ca66f41f60..7fe61430fa 100644
--- a/scene/3d/area.h
+++ b/scene/3d/area.h
@@ -62,7 +62,7 @@ private:
bool monitorable;
bool locked;
- void _body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape);
+ void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape);
void _body_enter_tree(ObjectID p_id);
void _body_exit_tree(ObjectID p_id);
@@ -94,7 +94,7 @@ private:
Map<ObjectID, BodyState> body_map;
- void _area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape);
+ void _area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape);
void _area_enter_tree(ObjectID p_id);
void _area_exit_tree(ObjectID p_id);
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index fbfd372272..5d5cb4dfce 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1493,7 +1493,7 @@ Object *KinematicCollision::get_local_shape() const {
Object *KinematicCollision::get_collider() const {
- if (collision.collider) {
+ if (collision.collider.is_valid()) {
return ObjectDB::get_instance(collision.collider);
}
@@ -1557,7 +1557,7 @@ void KinematicCollision::_bind_methods() {
}
KinematicCollision::KinematicCollision() {
- collision.collider = 0;
+
collision.collider_shape = 0;
collision.local_shape = 0;
owner = NULL;
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index 0c976b9fb1..be1426f13c 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -80,7 +80,7 @@ bool RayCast::is_colliding() const {
}
Object *RayCast::get_collider() const {
- if (against == 0)
+ if (against.is_null())
return NULL;
return ObjectDB::get_instance(against);
@@ -219,7 +219,7 @@ void RayCast::_update_raycast_state() {
against_shape = rr.shape;
} else {
collided = false;
- against = 0;
+ against = ObjectID();
against_shape = 0;
}
}
@@ -393,7 +393,7 @@ void RayCast::_clear_debug_shape() {
RayCast::RayCast() {
enabled = false;
- against = 0;
+
collided = false;
against_shape = 0;
collision_mask = 1;
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
index 983af7a9ec..9ef43647ba 100644
--- a/scene/3d/remote_transform.cpp
+++ b/scene/3d/remote_transform.cpp
@@ -31,7 +31,7 @@
#include "remote_transform.h"
void RemoteTransform::_update_cache() {
- cache = 0;
+ cache = ObjectID();
if (has_node(remote_node)) {
Node *node = get_node(remote_node);
if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
@@ -47,7 +47,7 @@ void RemoteTransform::_update_remote() {
if (!is_inside_tree())
return;
- if (!cache)
+ if (cache.is_null())
return;
Spatial *n = Object::cast_to<Spatial>(ObjectDB::get_instance(cache));
@@ -114,7 +114,7 @@ void RemoteTransform::_notification(int p_what) {
if (!is_inside_tree())
break;
- if (cache) {
+ if (cache.is_valid()) {
_update_remote();
}
@@ -219,6 +219,5 @@ RemoteTransform::RemoteTransform() {
update_remote_rotation = true;
update_remote_scale = true;
- cache = 0;
set_notify_transform(true);
}
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 3e4cd54664..aa5c439f8a 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -138,7 +138,7 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const {
else if (what == "bound_children") {
Array children;
- for (const List<uint32_t>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) {
+ for (const List<ObjectID>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->get());
ERR_CONTINUE(!obj);
@@ -302,7 +302,7 @@ void Skeleton::_notification(int p_what) {
b.global_pose_override_amount = 0.0;
}
- for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
+ for (List<ObjectID>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->get());
ERR_CONTINUE(!obj);
@@ -505,9 +505,9 @@ void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) {
ERR_FAIL_NULL(p_node);
ERR_FAIL_INDEX(p_bone, bones.size());
- uint32_t id = p_node->get_instance_id();
+ ObjectID id = p_node->get_instance_id();
- for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
+ for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
if (E->get() == id)
return; // already here
@@ -520,14 +520,14 @@ void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) {
ERR_FAIL_NULL(p_node);
ERR_FAIL_INDEX(p_bone, bones.size());
- uint32_t id = p_node->get_instance_id();
+ ObjectID id = p_node->get_instance_id();
bones.write[p_bone].nodes_bound.erase(id);
}
void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const {
ERR_FAIL_INDEX(p_bone, bones.size());
- for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
+ for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->get());
ERR_CONTINUE(!obj);
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index 9599510850..b42c2112e3 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -99,7 +99,7 @@ private:
PhysicalBone *cache_parent_physical_bone;
#endif // _3D_DISABLED
- List<uint32_t> nodes_bound;
+ List<ObjectID> nodes_bound;
Bone() {
parent = -1;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 7ec7037dd7..740dad9a1a 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -249,7 +249,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
Vector<StringName> leftover_path;
Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path);
ERR_CONTINUE_MSG(!child, "On Animation: '" + p_anim->name + "', couldn't resolve track: '" + String(a->track_get_path(i)) + "'."); // couldn't find the child node
- uint32_t id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
+ ObjectID id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
int bone_idx = -1;
if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton>(child)) {
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 06f762e63e..48829b02b9 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -159,17 +159,15 @@ private:
struct TrackNodeCacheKey {
- uint32_t id;
+ ObjectID id;
int bone_idx;
inline bool operator<(const TrackNodeCacheKey &p_right) const {
- if (id < p_right.id)
- return true;
- else if (id > p_right.id)
- return false;
- else
+ if (id == p_right.id)
return bone_idx < p_right.bone_idx;
+ else
+ return id < p_right.id;
}
};
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index c28f8dc824..a08cc0927b 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -767,7 +767,7 @@ void AnimationTree::_process_graph(float p_delta) {
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
- ObjectID current_animation_player = 0;
+ ObjectID current_animation_player;
if (player) {
current_animation_player = player->get_instance_id();
@@ -775,7 +775,7 @@ void AnimationTree::_process_graph(float p_delta) {
if (last_animation_player != current_animation_player) {
- if (last_animation_player) {
+ if (last_animation_player.is_valid()) {
Object *old_player = ObjectDB::get_instance(last_animation_player);
if (old_player) {
old_player->disconnect("caches_cleared", this, "_clear_caches");
@@ -1296,7 +1296,7 @@ void AnimationTree::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
_clear_caches();
- if (last_animation_player) {
+ if (last_animation_player.is_valid()) {
Object *player = ObjectDB::get_instance(last_animation_player);
if (player) {
@@ -1304,7 +1304,7 @@ void AnimationTree::_notification(int p_what) {
}
}
} else if (p_what == NOTIFICATION_ENTER_TREE) {
- if (last_animation_player) {
+ if (last_animation_player.is_valid()) {
Object *player = ObjectDB::get_instance(last_animation_player);
if (player) {
@@ -1584,7 +1584,6 @@ AnimationTree::AnimationTree() {
process_pass = 1;
started = true;
properties_dirty = true;
- last_animation_player = 0;
}
AnimationTree::~AnimationTree() {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 0a8dc8109f..8769e2c61d 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -187,7 +187,6 @@ private:
setup_pass = 0;
process_pass = 0;
object = NULL;
- object_id = 0;
}
virtual ~TrackCache() {}
};
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index be211504a6..b7bc2f9c9e 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -705,12 +705,12 @@ void Control::set_drag_forwarding(Control *p_target) {
if (p_target)
data.drag_owner = p_target->get_instance_id();
else
- data.drag_owner = 0;
+ data.drag_owner = ObjectID();
}
Variant Control::get_drag_data(const Point2 &p_point) {
- if (data.drag_owner) {
+ if (data.drag_owner.is_valid()) {
Object *obj = ObjectDB::get_instance(data.drag_owner);
if (obj) {
Control *c = Object::cast_to<Control>(obj);
@@ -732,7 +732,7 @@ Variant Control::get_drag_data(const Point2 &p_point) {
bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
- if (data.drag_owner) {
+ if (data.drag_owner.is_valid()) {
Object *obj = ObjectDB::get_instance(data.drag_owner);
if (obj) {
Control *c = Object::cast_to<Control>(obj);
@@ -753,7 +753,7 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
}
void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
- if (data.drag_owner) {
+ if (data.drag_owner.is_valid()) {
Object *obj = ObjectDB::get_instance(data.drag_owner);
if (obj) {
Control *c = Object::cast_to<Control>(obj);
@@ -2224,7 +2224,7 @@ void Control::_modal_stack_remove() {
get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner);
- data.modal_prev_focus_owner = 0;
+ data.modal_prev_focus_owner = ObjectID();
}
void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign) {
@@ -3110,7 +3110,7 @@ Control::Control() {
data.rotation = 0;
data.parent_canvas_item = NULL;
data.scale = Vector2(1, 1);
- data.drag_owner = 0;
+
data.modal_frame = 0;
data.block_minimum_size_adjust = false;
data.disable_visibility_clip = false;
@@ -3125,7 +3125,6 @@ Control::Control() {
data.margin[i] = 0;
}
data.focus_mode = FOCUS_NONE;
- data.modal_prev_focus_owner = 0;
}
Control::~Control() {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 7bfe060065..08835be9fd 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1399,7 +1399,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
} break;
case TreeItem::CELL_MODE_CUSTOM: {
- if (p_item->cells[i].custom_draw_obj) {
+ if (p_item->cells[i].custom_draw_obj.is_valid()) {
Object *cdo = ObjectDB::get_instance(p_item->cells[i].custom_draw_obj);
if (cdo)
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 2072d0fd13..b58f937c57 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -112,7 +112,7 @@ private:
Cell() {
- custom_draw_obj = 0;
+ custom_draw_obj = ObjectID();
custom_button = false;
mode = TreeItem::CELL_MODE_STRING;
min = 0;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 4ae018a79a..04cf5c6338 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -200,7 +200,7 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
if (custom_viewport) {
custom_viewport_id = custom_viewport->get_instance_id();
} else {
- custom_viewport_id = 0;
+ custom_viewport_id = ObjectID();
}
if (is_inside_tree()) {
@@ -327,7 +327,7 @@ CanvasLayer::CanvasLayer() {
layer = 1;
canvas = VS::get_singleton()->canvas_create();
custom_viewport = NULL;
- custom_viewport_id = 0;
+
sort_index = 0;
follow_viewport = false;
follow_viewport_scale = 1.0;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 761fe3f90f..6a7971ddb3 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -30,6 +30,8 @@
#include "node.h"
+#include <stdint.h>
+
#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
#include "core/message_queue.h"
@@ -498,22 +500,38 @@ bool Node::is_network_master() const {
/***** RPC CONFIG ********/
-void Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
+uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
- if (p_mode == MultiplayerAPI::RPC_MODE_DISABLED) {
- data.rpc_methods.erase(p_method);
+ uint16_t mid = get_node_rpc_method_id(p_method);
+ if (mid == UINT16_MAX) {
+ // It's new
+ NetData nd;
+ nd.name = p_method;
+ nd.mode = p_mode;
+ data.rpc_methods.push_back(nd);
+ return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
} else {
- data.rpc_methods[p_method] = p_mode;
- };
+ int c_mid = (~(1 << 15)) & mid;
+ data.rpc_methods.write[c_mid].mode = p_mode;
+ return mid;
+ }
}
-void Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
+uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
- if (p_mode == MultiplayerAPI::RPC_MODE_DISABLED) {
- data.rpc_properties.erase(p_property);
+ uint16_t pid = get_node_rset_property_id(p_property);
+ if (pid == UINT16_MAX) {
+ // It's new
+ NetData nd;
+ nd.name = p_property;
+ nd.mode = p_mode;
+ data.rpc_properties.push_back(nd);
+ return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
} else {
- data.rpc_properties[p_property] = p_mode;
- };
+ int c_pid = (~(1 << 15)) & pid;
+ data.rpc_properties.write[c_pid].mode = p_mode;
+ return pid;
+ }
}
/***** RPC FUNCTIONS ********/
@@ -731,12 +749,94 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
multiplayer = p_multiplayer;
}
-const Map<StringName, MultiplayerAPI::RPCMode>::Element *Node::get_node_rpc_mode(const StringName &p_method) {
- return data.rpc_methods.find(p_method);
+uint16_t Node::get_node_rpc_method_id(const StringName &p_method) const {
+ for (int i = 0; i < data.rpc_methods.size(); i++) {
+ if (data.rpc_methods[i].name == p_method) {
+ // Returns `i` with the high bit set to 1 so we know that this id comes
+ // from the node and not the script.
+ return i | (1 << 15);
+ }
+ }
+ return UINT16_MAX;
+}
+
+StringName Node::get_node_rpc_method(const uint16_t p_rpc_method_id) const {
+ // Make sure this is a node generated ID.
+ if (((1 << 15) & p_rpc_method_id) > 0) {
+ int mid = (~(1 << 15)) & p_rpc_method_id;
+ if (mid < data.rpc_methods.size())
+ return data.rpc_methods[mid].name;
+ }
+ return StringName();
+}
+
+MultiplayerAPI::RPCMode Node::get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
+ // Make sure this is a node generated ID.
+ if (((1 << 15) & p_rpc_method_id) > 0) {
+ int mid = (~(1 << 15)) & p_rpc_method_id;
+ if (mid < data.rpc_methods.size())
+ return data.rpc_methods[mid].mode;
+ }
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
+MultiplayerAPI::RPCMode Node::get_node_rpc_mode(const StringName &p_method) const {
+ return get_node_rpc_mode_by_id(get_node_rpc_method_id(p_method));
}
-const Map<StringName, MultiplayerAPI::RPCMode>::Element *Node::get_node_rset_mode(const StringName &p_property) {
- return data.rpc_properties.find(p_property);
+uint16_t Node::get_node_rset_property_id(const StringName &p_property) const {
+ for (int i = 0; i < data.rpc_properties.size(); i++) {
+ if (data.rpc_properties[i].name == p_property) {
+ // Returns `i` with the high bit set to 1 so we know that this id comes
+ // from the node and not the script.
+ return i | (1 << 15);
+ }
+ }
+ return UINT16_MAX;
+}
+
+StringName Node::get_node_rset_property(const uint16_t p_rset_property_id) const {
+ // Make sure this is a node generated ID.
+ if (((1 << 15) & p_rset_property_id) > 0) {
+ int mid = (~(1 << 15)) & p_rset_property_id;
+ if (mid < data.rpc_properties.size())
+ return data.rpc_properties[mid].name;
+ }
+ return StringName();
+}
+
+MultiplayerAPI::RPCMode Node::get_node_rset_mode_by_id(const uint16_t p_rset_property_id) const {
+ if (((1 << 15) & p_rset_property_id) > 0) {
+ int mid = (~(1 << 15)) & p_rset_property_id;
+ if (mid < data.rpc_properties.size())
+ return data.rpc_properties[mid].mode;
+ }
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
+MultiplayerAPI::RPCMode Node::get_node_rset_mode(const StringName &p_property) const {
+ return get_node_rset_mode_by_id(get_node_rset_property_id(p_property));
+}
+
+String Node::get_rpc_md5() const {
+ String rpc_list;
+ for (int i = 0; i < data.rpc_methods.size(); i += 1) {
+ rpc_list += String(data.rpc_methods[i].name);
+ }
+ for (int i = 0; i < data.rpc_properties.size(); i += 1) {
+ rpc_list += String(data.rpc_properties[i].name);
+ }
+ if (get_script_instance()) {
+ Vector<ScriptNetData> rpc = get_script_instance()->get_rpc_methods();
+ for (int i = 0; i < rpc.size(); i += 1) {
+ rpc_list += String(rpc[i].name);
+ }
+ rpc = get_script_instance()->get_rset_properties();
+ for (int i = 0; i < rpc.size(); i += 1) {
+ rpc_list += String(rpc[i].name);
+ }
+ }
+ return rpc_list.md5_text();
}
bool Node::can_process_notification(int p_what) const {
diff --git a/scene/main/node.h b/scene/main/node.h
index 6f5544d654..02c828e8ff 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -85,6 +85,11 @@ private:
GroupData() { persistent = false; }
};
+ struct NetData {
+ StringName name;
+ MultiplayerAPI::RPCMode mode;
+ };
+
struct Data {
String filename;
@@ -118,8 +123,8 @@ private:
Node *pause_owner;
int network_master;
- Map<StringName, MultiplayerAPI::RPCMode> rpc_methods;
- Map<StringName, MultiplayerAPI::RPCMode> rpc_properties;
+ Vector<NetData> rpc_methods;
+ Vector<NetData> rpc_properties;
// variables used to properly sort the node when processing, ignored otherwise
//should move all the stuff below to bits
@@ -427,8 +432,8 @@ public:
int get_network_master() const;
bool is_network_master() const;
- void rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
- void rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
+ uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
+ uint16_t rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
void rpc(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
void rpc_unreliable(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
@@ -446,8 +451,22 @@ public:
Ref<MultiplayerAPI> get_multiplayer() const;
Ref<MultiplayerAPI> get_custom_multiplayer() const;
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
- const Map<StringName, MultiplayerAPI::RPCMode>::Element *get_node_rpc_mode(const StringName &p_method);
- const Map<StringName, MultiplayerAPI::RPCMode>::Element *get_node_rset_mode(const StringName &p_property);
+
+ /// Returns the rpc method ID, otherwise UINT32_MAX
+ uint16_t get_node_rpc_method_id(const StringName &p_method) const;
+ StringName get_node_rpc_method(const uint16_t p_rpc_method_id) const;
+ MultiplayerAPI::RPCMode get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
+ MultiplayerAPI::RPCMode get_node_rpc_mode(const StringName &p_method) const;
+
+ /// Returns the rpc property ID, otherwise UINT32_MAX
+ uint16_t get_node_rset_property_id(const StringName &p_property) const;
+ StringName get_node_rset_property(const uint16_t p_rset_property_id) const;
+ MultiplayerAPI::RPCMode get_node_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
+ MultiplayerAPI::RPCMode get_node_rset_mode(const StringName &p_property) const;
+
+ /// Can be used to check if the rpc methods and the rset properties are the
+ /// same across the peers.
+ String get_rpc_md5() const;
Node();
~Node();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index dad2ec4010..748a713110 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -412,7 +412,7 @@ void Viewport::_notification(int p_what) {
#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
CollisionObject *last_object = NULL;
- ObjectID last_id = 0;
+ ObjectID last_id;
#endif
PhysicsDirectSpaceState::RayResult result;
Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
@@ -532,7 +532,7 @@ void Viewport::_notification(int p_what) {
} else {
// This Viewport's builtin canvas
canvas_transform = get_canvas_transform();
- canvas_layer_id = 0;
+ canvas_layer_id = ObjectID();
}
Vector2 point = canvas_transform.affine_inverse().xform(pos);
@@ -540,7 +540,7 @@ void Viewport::_notification(int p_what) {
int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
for (int i = 0; i < rc; i++) {
- if (res[i].collider_id && res[i].collider) {
+ if (res[i].collider_id.is_valid() && res[i].collider) {
CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
if (co) {
bool send_event = true;
@@ -594,18 +594,18 @@ void Viewport::_notification(int p_what) {
#ifndef _3D_DISABLED
bool captured = false;
- if (physics_object_capture != 0) {
+ if (physics_object_capture.is_valid()) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture));
if (co && camera) {
_collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0);
captured = true;
if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) {
- physics_object_capture = 0;
+ physics_object_capture = ObjectID();
}
} else {
- physics_object_capture = 0;
+ physics_object_capture = ObjectID();
}
}
@@ -613,7 +613,7 @@ void Viewport::_notification(int p_what) {
//none
} else if (pos == last_pos) {
- if (last_id) {
+ if (last_id.is_valid()) {
if (ObjectDB::get_instance(last_id) && last_object) {
//good, exists
_collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape);
@@ -633,7 +633,7 @@ void Viewport::_notification(int p_what) {
if (space) {
bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
- ObjectID new_collider = 0;
+ ObjectID new_collider;
if (col) {
CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
@@ -651,7 +651,7 @@ void Viewport::_notification(int p_what) {
if (is_mouse && new_collider != physics_object_over) {
- if (physics_object_over) {
+ if (physics_object_over.is_valid()) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
if (co) {
@@ -659,7 +659,7 @@ void Viewport::_notification(int p_what) {
}
}
- if (new_collider) {
+ if (new_collider.is_valid()) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
if (co) {
@@ -2504,7 +2504,7 @@ void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, Object
gui.modal_stack.erase(MI);
- if (p_prev_focus_owner) {
+ if (p_prev_focus_owner.is_valid()) {
// for previous window in stack, pass the focus so it feels more
// natural
@@ -2701,14 +2701,15 @@ void Viewport::_drop_physics_mouseover() {
}
#ifndef _3D_DISABLED
- if (physics_object_over) {
+ if (physics_object_over.is_valid()) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
if (co) {
co->_mouse_exit();
}
}
- physics_object_over = physics_object_capture = 0;
+ physics_object_over = ObjectID();
+ physics_object_capture = ObjectID();
#endif
}
@@ -2718,7 +2719,7 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
if (gui.key_focus)
p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id());
else
- p_control->_modal_set_prev_focus_owner(0);
+ p_control->_modal_set_prev_focus_owner(ObjectID());
if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
@@ -3334,8 +3335,6 @@ Viewport::Viewport() {
update_mode = UPDATE_WHEN_VISIBLE;
physics_object_picking = false;
- physics_object_capture = 0;
- physics_object_over = 0;
physics_has_last_mousepos = false;
physics_last_mousepos = Vector2(Math_INF, Math_INF);
@@ -3385,7 +3384,6 @@ Viewport::Viewport() {
physics_last_mouse_state.mouse_mask = 0;
local_input_handled = false;
handle_input_locally = true;
- physics_last_id = 0; //ensures first time there will be a check
default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index b8c396062a..1255bb8a87 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -2225,7 +2225,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
ADD_GROUP("Shading", "");
diff --git a/servers/physics/area_sw.cpp b/servers/physics/area_sw.cpp
index 398849edb8..1016afcaba 100644
--- a/servers/physics/area_sw.cpp
+++ b/servers/physics/area_sw.cpp
@@ -175,7 +175,7 @@ void AreaSW::set_monitorable(bool p_monitorable) {
void AreaSW::call_queries() {
- if (monitor_callback_id && !monitored_bodies.empty()) {
+ if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) {
Variant res[5];
Variant *resptr[5];
@@ -185,7 +185,7 @@ void AreaSW::call_queries() {
Object *obj = ObjectDB::get_instance(monitor_callback_id);
if (!obj) {
monitored_bodies.clear();
- monitor_callback_id = 0;
+ monitor_callback_id = ObjectID();
return;
}
@@ -207,7 +207,7 @@ void AreaSW::call_queries() {
monitored_bodies.clear();
- if (area_monitor_callback_id && !monitored_areas.empty()) {
+ if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) {
Variant res[5];
Variant *resptr[5];
@@ -217,7 +217,7 @@ void AreaSW::call_queries() {
Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
if (!obj) {
monitored_areas.clear();
- area_monitor_callback_id = 0;
+ area_monitor_callback_id = ObjectID();
return;
}
@@ -257,8 +257,6 @@ AreaSW::AreaSW() :
linear_damp = 0.1;
priority = 0;
set_ray_pickable(false);
- monitor_callback_id = 0;
- area_monitor_callback_id = 0;
monitorable = false;
}
diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h
index 846243a133..4da2b00d20 100644
--- a/servers/physics/area_sw.h
+++ b/servers/physics/area_sw.h
@@ -111,10 +111,10 @@ public:
//_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
void set_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
+ _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); }
void set_area_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); }
_FORCE_INLINE_ void add_body_to_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
index 64e07e1155..b71c9772df 100644
--- a/servers/physics/body_sw.cpp
+++ b/servers/physics/body_sw.cpp
@@ -709,7 +709,7 @@ void BodySW::call_queries() {
Object *obj = ObjectDB::get_instance(fi_callback->id);
if (!obj) {
- set_force_integration_callback(0, StringName());
+ set_force_integration_callback(ObjectID(), StringName());
} else {
const Variant *vp[2] = { &v, &fi_callback->udata };
@@ -749,7 +749,7 @@ void BodySW::set_force_integration_callback(ObjectID p_id, const StringName &p_m
fi_callback = NULL;
}
- if (p_id != 0) {
+ if (p_id.is_valid()) {
fi_callback = memnew(ForceIntegrationCallback);
fi_callback->id = p_id;
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
index ee4dd0b310..d712b09878 100644
--- a/servers/physics/body_sw.h
+++ b/servers/physics/body_sw.h
@@ -451,7 +451,7 @@ public:
return body->contacts[p_contact_idx].collider_pos;
}
virtual ObjectID get_contact_collider_id(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
return body->contacts[p_contact_idx].collider_instance_id;
}
virtual int get_contact_collider_shape(int p_contact_idx) const {
diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp
index cdae26078c..3cabf75ab6 100644
--- a/servers/physics/collision_object_sw.cpp
+++ b/servers/physics/collision_object_sw.cpp
@@ -232,7 +232,7 @@ CollisionObjectSW::CollisionObjectSW(Type p_type) :
_static = true;
type = p_type;
space = NULL;
- instance_id = 0;
+
collision_layer = 1;
collision_mask = 1;
ray_pickable = true;
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index cd6fc6c0a5..6024e9ab7f 100644
--- a/servers/physics/physics_server_sw.cpp
+++ b/servers/physics/physics_server_sw.cpp
@@ -374,7 +374,7 @@ ObjectID PhysicsServerSW::area_get_object_instance_id(RID p_area) const {
p_area = space->get_default_area()->get_self();
}
AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, 0);
+ ERR_FAIL_COND_V(!area, ObjectID());
return area->get_instance_id();
}
@@ -446,7 +446,7 @@ void PhysicsServerSW::area_set_monitor_callback(RID p_area, Object *p_receiver,
AreaSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+ area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
void PhysicsServerSW::area_set_ray_pickable(RID p_area, bool p_enable) {
@@ -470,7 +470,7 @@ void PhysicsServerSW::area_set_area_monitor_callback(RID p_area, Object *p_recei
AreaSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+ area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
/* BODY API */
@@ -665,7 +665,7 @@ uint32_t PhysicsServerSW::body_get_collision_mask(RID p_body) const {
return body->get_collision_mask();
}
-void PhysicsServerSW::body_attach_object_instance_id(RID p_body, uint32_t p_id) {
+void PhysicsServerSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
BodySW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -673,10 +673,10 @@ void PhysicsServerSW::body_attach_object_instance_id(RID p_body, uint32_t p_id)
body->set_instance_id(p_id);
};
-uint32_t PhysicsServerSW::body_get_object_instance_id(RID p_body) const {
+ObjectID PhysicsServerSW::body_get_object_instance_id(RID p_body) const {
BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
+ ERR_FAIL_COND_V(!body, ObjectID());
return body->get_instance_id();
};
@@ -934,7 +934,7 @@ void PhysicsServerSW::body_set_force_integration_callback(RID p_body, Object *p_
BodySW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(0), p_method, p_udata);
+ body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
}
void PhysicsServerSW::body_set_ray_pickable(RID p_body, bool p_enable) {
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index 37ebfb09c0..459c7688f0 100644
--- a/servers/physics/physics_server_sw.h
+++ b/servers/physics/physics_server_sw.h
@@ -177,8 +177,8 @@ public:
virtual void body_remove_shape(RID p_body, int p_shape_idx);
virtual void body_clear_shapes(RID p_body);
- virtual void body_attach_object_instance_id(RID p_body, uint32_t p_id);
- virtual uint32_t body_get_object_instance_id(RID p_body) const;
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_object_instance_id(RID p_body) const;
virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable);
virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const;
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index 49e1a57879..03dca8b9ec 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -80,7 +80,7 @@ int PhysicsDirectSpaceStateSW::intersect_point(const Vector3 &p_point, ShapeResu
continue;
r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id != 0)
+ if (r_results[cc].collider_id.is_valid())
r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
else
r_results[cc].collider = NULL;
@@ -159,7 +159,7 @@ bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3 &p_from, const Vecto
return false;
r_result.collider_id = res_obj->get_instance_id();
- if (r_result.collider_id != 0)
+ if (r_result.collider_id.is_valid())
r_result.collider = ObjectDB::get_instance(r_result.collider_id);
else
r_result.collider = NULL;
@@ -208,7 +208,7 @@ int PhysicsDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transfo
if (r_results) {
r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id != 0)
+ if (r_results[cc].collider_id.is_valid())
r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
else
r_results[cc].collider = NULL;
@@ -705,7 +705,7 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
//but is it right? who knows at this point..
if (r_result) {
- r_result->collider_id = 0;
+ r_result->collider_id = ObjectID();
r_result->collider_shape = 0;
}
AABB body_aabb;
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
index 6f09041af8..c67d870b2a 100644
--- a/servers/physics_2d/area_2d_sw.cpp
+++ b/servers/physics_2d/area_2d_sw.cpp
@@ -175,7 +175,7 @@ void Area2DSW::set_monitorable(bool p_monitorable) {
void Area2DSW::call_queries() {
- if (monitor_callback_id && !monitored_bodies.empty()) {
+ if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) {
Variant res[5];
Variant *resptr[5];
@@ -185,7 +185,7 @@ void Area2DSW::call_queries() {
Object *obj = ObjectDB::get_instance(monitor_callback_id);
if (!obj) {
monitored_bodies.clear();
- monitor_callback_id = 0;
+ monitor_callback_id = ObjectID();
return;
}
@@ -207,7 +207,7 @@ void Area2DSW::call_queries() {
monitored_bodies.clear();
- if (area_monitor_callback_id && !monitored_areas.empty()) {
+ if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) {
Variant res[5];
Variant *resptr[5];
@@ -217,7 +217,7 @@ void Area2DSW::call_queries() {
Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
if (!obj) {
monitored_areas.clear();
- area_monitor_callback_id = 0;
+ area_monitor_callback_id = ObjectID();
return;
}
@@ -258,8 +258,6 @@ Area2DSW::Area2DSW() :
angular_damp = 1.0;
linear_damp = 0.1;
priority = 0;
- monitor_callback_id = 0;
- area_monitor_callback_id = 0;
monitorable = false;
}
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h
index 31bc0f6f23..54ffd9763d 100644
--- a/servers/physics_2d/area_2d_sw.h
+++ b/servers/physics_2d/area_2d_sw.h
@@ -110,10 +110,10 @@ public:
//_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
void set_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
+ _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); }
void set_area_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); }
_FORCE_INLINE_ void add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index b973fa75a9..4de52cacbd 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -610,7 +610,7 @@ void Body2DSW::call_queries() {
Object *obj = ObjectDB::get_instance(fi_callback->id);
if (!obj) {
- set_force_integration_callback(0, StringName());
+ set_force_integration_callback(ObjectID(), StringName());
} else {
Variant::CallError ce;
if (fi_callback->callback_udata.get_type() != Variant::NIL) {
@@ -653,7 +653,7 @@ void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p
fi_callback = NULL;
}
- if (p_id != 0) {
+ if (p_id.is_valid()) {
fi_callback = memnew(ForceIntegrationCallback);
fi_callback->id = p_id;
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 06cc447526..ea07b8260c 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -400,7 +400,7 @@ public:
return body->contacts[p_contact_idx].collider_pos;
}
virtual ObjectID get_contact_collider_id(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
return body->contacts[p_contact_idx].collider_instance_id;
}
virtual int get_contact_collider_shape(int p_contact_idx) const {
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 85f7b8467a..8fb3296be6 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -267,8 +267,6 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) :
_static = true;
type = p_type;
space = NULL;
- instance_id = 0;
- canvas_instance_id = 0;
collision_mask = 1;
collision_layer = 1;
pickable = true;
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index 65873d9612..aa374aa6bc 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -470,7 +470,7 @@ ObjectID Physics2DServerSW::area_get_object_instance_id(RID p_area) const {
p_area = space->get_default_area()->get_self();
}
Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, 0);
+ ERR_FAIL_COND_V(!area, ObjectID());
return area->get_instance_id();
}
@@ -491,7 +491,7 @@ ObjectID Physics2DServerSW::area_get_canvas_instance_id(RID p_area) const {
p_area = space->get_default_area()->get_self();
}
Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, 0);
+ ERR_FAIL_COND_V(!area, ObjectID());
return area->get_canvas_instance_id();
}
@@ -570,7 +570,7 @@ void Physics2DServerSW::area_set_monitor_callback(RID p_area, Object *p_receiver
Area2DSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+ area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
void Physics2DServerSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
@@ -578,7 +578,7 @@ void Physics2DServerSW::area_set_area_monitor_callback(RID p_area, Object *p_rec
Area2DSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+ area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
/* BODY API */
@@ -756,7 +756,7 @@ Physics2DServerSW::CCDMode Physics2DServerSW::body_get_continuous_collision_dete
return body->get_continuous_collision_detection_mode();
}
-void Physics2DServerSW::body_attach_object_instance_id(RID p_body, uint32_t p_id) {
+void Physics2DServerSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -764,15 +764,15 @@ void Physics2DServerSW::body_attach_object_instance_id(RID p_body, uint32_t p_id
body->set_instance_id(p_id);
};
-uint32_t Physics2DServerSW::body_get_object_instance_id(RID p_body) const {
+ObjectID Physics2DServerSW::body_get_object_instance_id(RID p_body) const {
Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
+ ERR_FAIL_COND_V(!body, ObjectID());
return body->get_instance_id();
};
-void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, uint32_t p_id) {
+void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -780,10 +780,10 @@ void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, uint32_t p_id
body->set_canvas_instance_id(p_id);
};
-uint32_t Physics2DServerSW::body_get_canvas_instance_id(RID p_body) const {
+ObjectID Physics2DServerSW::body_get_canvas_instance_id(RID p_body) const {
Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
+ ERR_FAIL_COND_V(!body, ObjectID());
return body->get_canvas_instance_id();
};
@@ -1025,7 +1025,7 @@ void Physics2DServerSW::body_set_force_integration_callback(RID p_body, Object *
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(0), p_method, p_udata);
+ body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
}
bool Physics2DServerSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 6a636bb72a..a95a2ea0dd 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -195,11 +195,11 @@ public:
virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled);
virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin);
- virtual void body_attach_object_instance_id(RID p_body, uint32_t p_id);
- virtual uint32_t body_get_object_instance_id(RID p_body) const;
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_object_instance_id(RID p_body) const;
- virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_id);
- virtual uint32_t body_get_canvas_instance_id(RID p_body) const;
+ virtual void body_attach_canvas_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_canvas_instance_id(RID p_body) const;
virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode);
virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
index 6bd0a09de5..9a01344390 100644
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -199,11 +199,11 @@ public:
FUNC2(body_remove_shape, RID, int);
FUNC1(body_clear_shapes, RID);
- FUNC2(body_attach_object_instance_id, RID, uint32_t);
- FUNC1RC(uint32_t, body_get_object_instance_id, RID);
+ FUNC2(body_attach_object_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, body_get_object_instance_id, RID);
- FUNC2(body_attach_canvas_instance_id, RID, uint32_t);
- FUNC1RC(uint32_t, body_get_canvas_instance_id, RID);
+ FUNC2(body_attach_canvas_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, body_get_canvas_instance_id, RID);
FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID);
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 150fda4322..83bcae4607 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -91,7 +91,7 @@ int Physics2DDirectSpaceStateSW::_intersect_point_impl(const Vector2 &p_point, S
continue;
r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id != 0)
+ if (r_results[cc].collider_id.is_valid())
r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
r_results[cc].rid = col_obj->get_self();
r_results[cc].shape = shape_idx;
@@ -182,7 +182,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vec
return false;
r_result.collider_id = res_obj->get_instance_id();
- if (r_result.collider_id != 0)
+ if (r_result.collider_id.is_valid())
r_result.collider = ObjectDB::get_instance(r_result.collider_id);
r_result.normal = res_normal;
r_result.metadata = res_obj->get_shape_metadata(res_shape);
@@ -226,7 +226,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Trans
continue;
r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id != 0)
+ if (r_results[cc].collider_id.is_valid())
r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
r_results[cc].rid = col_obj->get_self();
r_results[cc].shape = shape_idx;
@@ -697,7 +697,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//but is it right? who knows at this point..
if (r_result) {
- r_result->collider_id = 0;
+ r_result->collider_id = ObjectID();
r_result->collider_shape = 0;
}
Rect2 body_aabb;
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index ba068e9a37..919c65d849 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -45,7 +45,7 @@ class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState {
GDCLASS(Physics2DDirectSpaceStateSW, Physics2DDirectSpaceState);
- int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0);
+ int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = ObjectID());
public:
Space2DSW *space;
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index 71e3bf8ae8..925af52eeb 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -523,7 +523,7 @@ void Physics2DTestMotionResult::_bind_methods() {
Physics2DTestMotionResult::Physics2DTestMotionResult() {
colliding = false;
- result.collider_id = 0;
+
result.collider_shape = 0;
}
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 40c58ecac5..c923ef16b7 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -149,7 +149,7 @@ class Physics2DDirectSpaceState : public Object {
Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
Array _intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0);
+ Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = ObjectID());
Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
@@ -404,11 +404,11 @@ public:
virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
virtual void body_clear_shapes(RID p_body) = 0;
- virtual void body_attach_object_instance_id(RID p_body, uint32_t p_id) = 0;
- virtual uint32_t body_get_object_instance_id(RID p_body) const = 0;
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) = 0;
+ virtual ObjectID body_get_object_instance_id(RID p_body) const = 0;
- virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_id) = 0;
- virtual uint32_t body_get_canvas_instance_id(RID p_body) const = 0;
+ virtual void body_attach_canvas_instance_id(RID p_body, ObjectID p_id) = 0;
+ virtual ObjectID body_get_canvas_instance_id(RID p_body) const = 0;
enum CCDMode {
CCD_MODE_DISABLED,
@@ -509,7 +509,7 @@ public:
MotionResult() {
collision_local_shape = 0;
collider_shape = 0;
- collider_id = 0;
+ collider_id = ObjectID();
}
};
diff --git a/servers/physics_server.h b/servers/physics_server.h
index 6a66763b2f..f1388c8758 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -385,8 +385,8 @@ public:
virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) = 0;
- virtual void body_attach_object_instance_id(RID p_body, uint32_t p_id) = 0;
- virtual uint32_t body_get_object_instance_id(RID p_body) const = 0;
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) = 0;
+ virtual ObjectID body_get_object_instance_id(RID p_body) const = 0;
virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) = 0;
virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const = 0;
@@ -495,7 +495,7 @@ public:
Variant collider_metadata;
MotionResult() {
collision_local_shape = 0;
- collider_id = 0;
+ collider_id = ObjectID();
collider_shape = 0;
}
};
diff --git a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
index 851deb367f..b2cbac8a09 100644
--- a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
+++ b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
@@ -390,6 +390,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
struct_code += " ";
struct_code += m->name;
+ if (m->array_size > 0) {
+ struct_code += "[";
+ struct_code += itos(m->array_size);
+ struct_code += "]";
+ }
struct_code += ";\n";
}
struct_code += "}";
@@ -701,6 +706,26 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
} break;
+ case SL::Node::TYPE_ARRAY_CONSTRUCT: {
+ SL::ArrayConstructNode *acnode = (SL::ArrayConstructNode *)p_node;
+ int sz = acnode->initializer.size();
+ if (acnode->datatype == SL::TYPE_STRUCT) {
+ code += _mkid(acnode->struct_name);
+ } else {
+ code += _typestr(acnode->datatype);
+ }
+ code += "[";
+ code += itos(acnode->initializer.size());
+ code += "]";
+ code += "(";
+ for (int i = 0; i < sz; i++) {
+ code += _dump_node_code(acnode->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (i != sz - 1) {
+ code += ", ";
+ }
+ }
+ code += ")";
+ } break;
case SL::Node::TYPE_ARRAY_DECLARATION: {
SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node;
@@ -1000,6 +1025,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
case SL::Node::TYPE_MEMBER: {
SL::MemberNode *mnode = (SL::MemberNode *)p_node;
code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
+ if (mnode->index_expression != NULL) {
+ code += "[";
+ code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "]";
+ }
} break;
}
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index c2bdc6d7e4..2a0492709c 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -3200,17 +3200,159 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
func->arguments.push_back(funcname);
for (int i = 0; i < pstruct->members.size(); i++) {
- Node *nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!nexpr) {
- return NULL;
- }
- Node *node = pstruct->members[i];
+ Node *nexpr;
- if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
- String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
- String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
- _set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
- return NULL;
+ if (pstruct->members[i]->array_size != 0) {
+
+ DataType type = pstruct->members[i]->get_datatype();
+ String struct_name = pstruct->members[i]->struct_name;
+ int array_size = pstruct->members[i]->array_size;
+
+ DataType type2;
+ String struct_name2 = "";
+ int array_size2 = 0;
+
+ bool auto_size = false;
+
+ tk = _get_token();
+
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ auto_size = true;
+ } else {
+
+ if (shader->structs.has(tk.text)) {
+ type2 = TYPE_STRUCT;
+ struct_name2 = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for array");
+ return NULL;
+ }
+ type2 = get_token_datatype(tk.type);
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos2 = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ array_size2 = array_size;
+ tk = _get_token();
+ } else {
+ _set_tkpos(pos2);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
+ _set_error("Expected single integer constant > 0");
+ return NULL;
+ }
+
+ ConstantNode *cnode = (ConstantNode *)n;
+ if (cnode->values.size() == 1) {
+ array_size2 = cnode->values[0].sint;
+ if (array_size2 <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return NULL;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return NULL;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return NULL;
+ } else {
+ tk = _get_token();
+ }
+ }
+ } else {
+ _set_error("Expected '['");
+ return NULL;
+ }
+
+ if (type != type2 || struct_name != struct_name2 || array_size != array_size2) {
+ String error_str = "Cannot convert from '";
+ if (type2 == TYPE_STRUCT) {
+ error_str += struct_name2;
+ } else {
+ error_str += get_datatype_name(type2);
+ }
+ error_str += "[";
+ error_str += itos(array_size2);
+ error_str += "]'";
+ error_str += " to '";
+ if (type == TYPE_STRUCT) {
+ error_str += struct_name;
+ } else {
+ error_str += get_datatype_name(type);
+ }
+ error_str += "[";
+ error_str += itos(array_size);
+ error_str += "]'";
+ _set_error(error_str);
+ return NULL;
+ }
+ }
+
+ ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
+ an->datatype = type;
+ an->struct_name = struct_name;
+
+ if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
+ while (true) {
+
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n) {
+ return NULL;
+ }
+
+ if (type != n->get_datatype() || struct_name != n->get_datatype_name()) {
+ _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'");
+ return NULL;
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ an->initializer.push_back(n);
+ continue;
+ } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) {
+ an->initializer.push_back(n);
+ break;
+ } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) {
+ an->initializer.push_back(n);
+ break;
+ } else {
+ if (auto_size)
+ _set_error("Expected '}' or ','");
+ else
+ _set_error("Expected ')' or ','");
+ return NULL;
+ }
+ }
+ if (an->initializer.size() != array_size) {
+ _set_error("Array size mismatch");
+ return NULL;
+ }
+ } else {
+ _set_error("Expected array initialization!");
+ return NULL;
+ }
+
+ nexpr = an;
+ } else {
+ nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!nexpr) {
+ return NULL;
+ }
+ Node *node = pstruct->members[i];
+ if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
+ String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
+ String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
+ _set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
+ return NULL;
+ }
}
if (i + 1 < pstruct->members.size()) {
@@ -3463,7 +3605,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = varname;
}
}
-
} else if (tk.type == TK_OP_ADD) {
continue; //this one does nothing
} else if (tk.type == TK_OP_SUB || tk.type == TK_OP_NOT || tk.type == TK_OP_BIT_INVERT || tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
@@ -3482,7 +3623,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.push_back(e);
continue;
-
} else {
_set_error("Expected expression, found: " + get_token_text(tk));
return NULL;
@@ -3526,6 +3666,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bool ok = true;
DataType member_type = TYPE_VOID;
StringName member_struct_name = "";
+ int array_size = 0;
switch (dt) {
case TYPE_STRUCT: {
ok = false;
@@ -3535,6 +3676,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) {
if (String(E->get()->name) == member_name) {
member_type = E->get()->datatype;
+ array_size = E->get()->array_size;
if (member_type == TYPE_STRUCT) {
member_struct_name = E->get()->struct_name;
}
@@ -3673,8 +3815,52 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn->datatype = member_type;
mn->base_struct_name = st;
mn->struct_name = member_struct_name;
+ mn->array_size = array_size;
mn->name = ident;
mn->owner = expr;
+ if (array_size > 0) {
+
+ tk = _get_token();
+ if (tk.type == TK_PERIOD) {
+ _set_error("Nested array length() is not yet implemented");
+ return NULL;
+ } else if (tk.type == TK_BRACKET_OPEN) {
+
+ Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!index_expression)
+ return NULL;
+
+ if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
+ _set_error("Only integer expressions are allowed for indexing");
+ return NULL;
+ }
+
+ if (index_expression->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cnode = (ConstantNode *)index_expression;
+ if (cnode) {
+ if (!cnode->values.empty()) {
+ int value = cnode->values[0].sint;
+ if (value < 0 || value >= array_size) {
+ _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1));
+ return NULL;
+ }
+ }
+ }
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return NULL;
+ }
+ mn->index_expression = index_expression;
+
+ } else {
+ _set_error("Expected '[' or '.'");
+ return NULL;
+ }
+ }
+
expr = mn;
//todo
@@ -3769,7 +3955,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
break;
default: {
- _set_error("Object of type '" + get_datatype_name(expr->get_datatype()) + "' can't be indexed");
+ _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
return NULL;
}
}
@@ -5353,11 +5539,33 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
member->datatype = type;
member->struct_name = struct_name;
member->name = tk.text;
- st_node->members.push_back(member);
tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ tk = _get_token();
+ if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
+ member->array_size = (int)tk.constant;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ st_node->members.push_back(member);
+
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
+ _set_error("Expected ']' or ';'");
return ERR_PARSE_ERROR;
}
member_count++;
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index 4d474086a6..aac5795e85 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -332,6 +332,7 @@ public:
TYPE_MEMBER,
TYPE_ARRAY,
TYPE_ARRAY_DECLARATION,
+ TYPE_ARRAY_CONSTRUCT,
TYPE_STRUCT,
};
@@ -427,6 +428,17 @@ public:
is_const(false) {}
};
+ struct ArrayConstructNode : public Node {
+ DataType datatype;
+ String struct_name;
+ Vector<Node *> initializer;
+
+ ArrayConstructNode() :
+ Node(TYPE_ARRAY_CONSTRUCT),
+ datatype(TYPE_VOID) {
+ }
+ };
+
struct ArrayDeclarationNode : public Node {
DataPrecision precision;
DataType datatype;
@@ -520,9 +532,11 @@ public:
StringName base_struct_name;
DataPrecision precision;
DataType datatype;
+ int array_size;
StringName struct_name;
StringName name;
Node *owner;
+ Node *index_expression;
virtual DataType get_datatype() const { return datatype; }
virtual String get_datatype_name() const { return String(struct_name); }
@@ -531,7 +545,9 @@ public:
Node(TYPE_MEMBER),
basetype(TYPE_VOID),
datatype(TYPE_VOID),
- owner(NULL) {}
+ array_size(0),
+ owner(NULL),
+ index_expression(NULL) {}
};
struct StructNode : public Node {
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 0df8853f12..61c885cba3 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -805,7 +805,7 @@ Vector<ObjectID> VisualServerScene::instances_cull_aabb(const AABB &p_aabb, RID
Instance *instance = cull[i];
ERR_CONTINUE(!instance);
- if (instance->object_id == 0)
+ if (instance->object_id.is_null())
continue;
instances.push_back(instance->object_id);
@@ -827,7 +827,7 @@ Vector<ObjectID> VisualServerScene::instances_cull_ray(const Vector3 &p_from, co
for (int i = 0; i < culled; i++) {
Instance *instance = cull[i];
ERR_CONTINUE(!instance);
- if (instance->object_id == 0)
+ if (instance->object_id.is_null())
continue;
instances.push_back(instance->object_id);
@@ -851,7 +851,7 @@ Vector<ObjectID> VisualServerScene::instances_cull_convex(const Vector<Plane> &p
Instance *instance = cull[i];
ERR_CONTINUE(!instance);
- if (instance->object_id == 0)
+ if (instance->object_id.is_null())
continue;
instances.push_back(instance->object_id);
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index a811e8b27a..8dbd60d3ff 100644
--- a/servers/visual/visual_server_scene.h
+++ b/servers/visual/visual_server_scene.h
@@ -162,7 +162,7 @@ public:
AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better?
float extra_margin;
- uint32_t object_id;
+ ObjectID object_id;
float lod_begin;
float lod_end;
@@ -203,7 +203,6 @@ public:
extra_margin = 0;
- object_id = 0;
visible = true;
lod_begin = 0;