diff options
Diffstat (limited to 'scene/main')
-rw-r--r-- | scene/main/canvas_layer.cpp | 46 | ||||
-rw-r--r-- | scene/main/canvas_layer.h | 8 | ||||
-rw-r--r-- | scene/main/http_request.cpp | 4 | ||||
-rw-r--r-- | scene/main/http_request.h | 1 | ||||
-rw-r--r-- | scene/main/instance_placeholder.cpp | 25 | ||||
-rw-r--r-- | scene/main/instance_placeholder.h | 2 | ||||
-rw-r--r-- | scene/main/node.cpp | 331 | ||||
-rw-r--r-- | scene/main/node.h | 26 | ||||
-rw-r--r-- | scene/main/resource_preloader.cpp | 3 | ||||
-rw-r--r-- | scene/main/resource_preloader.h | 1 | ||||
-rw-r--r-- | scene/main/scene_tree.cpp | 526 | ||||
-rw-r--r-- | scene/main/scene_tree.h | 48 | ||||
-rwxr-xr-x | scene/main/timer.cpp | 10 | ||||
-rwxr-xr-x | scene/main/timer.h | 3 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 282 | ||||
-rw-r--r-- | scene/main/viewport.h | 24 |
16 files changed, 422 insertions, 918 deletions
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 939de346eb..8414210952 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "canvas_layer.h" #include "viewport.h" @@ -34,7 +35,7 @@ void CanvasLayer::set_layer(int p_xform) { layer = p_xform; if (viewport.is_valid()) - VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas->get_canvas(), layer); + VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer); } int CanvasLayer::get_layer() const { @@ -47,7 +48,7 @@ void CanvasLayer::set_transform(const Transform2D &p_xform) { transform = p_xform; locrotscale_dirty = true; if (viewport.is_valid()) - VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform); + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); } Transform2D CanvasLayer::get_transform() const { @@ -60,7 +61,7 @@ void CanvasLayer::_update_xform() { transform.set_rotation_and_scale(rot, scale); transform.set_origin(ofs); if (viewport.is_valid()) - VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform); + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); } void CanvasLayer::_update_locrotscale() { @@ -132,11 +133,6 @@ Vector2 CanvasLayer::get_scale() const { return scale; } -Ref<World2D> CanvasLayer::get_world_2d() const { - - return canvas; -} - void CanvasLayer::_notification(int p_what) { switch (p_what) { @@ -152,14 +148,14 @@ void CanvasLayer::_notification(int p_what) { ERR_FAIL_COND(!vp); viewport = vp->get_viewport_rid(); - VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas->get_canvas()); - VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas->get_canvas(), layer); - VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform); + VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas); + VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer); + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); } break; case NOTIFICATION_EXIT_TREE: { - VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas->get_canvas()); + VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); } break; @@ -183,7 +179,7 @@ RID CanvasLayer::get_viewport() const { void CanvasLayer::set_custom_viewport(Node *p_viewport) { ERR_FAIL_NULL(p_viewport); if (is_inside_tree()) { - VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas->get_canvas()); + VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); } @@ -204,9 +200,9 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) { viewport = vp->get_viewport_rid(); - VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas->get_canvas()); - VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas->get_canvas(), layer); - VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform); + VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas); + VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer); + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); } } @@ -224,6 +220,10 @@ int CanvasLayer::get_sort_index() { return sort_index++; } +RID CanvasLayer::get_canvas() const { + + return canvas; +} void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer); @@ -247,14 +247,17 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &CanvasLayer::set_custom_viewport); ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport); - ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasLayer::get_world_2d); + ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasLayer::get_canvas); //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasLayer::get_viewport); ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer"); //ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"transform",PROPERTY_HINT_RANGE),"set_transform","get_transform") ; ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation"), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); } CanvasLayer::CanvasLayer() { @@ -264,8 +267,13 @@ CanvasLayer::CanvasLayer() { rot = 0; locrotscale_dirty = false; layer = 1; - canvas = Ref<World2D>(memnew(World2D)); + canvas = VS::get_singleton()->canvas_create(); custom_viewport = NULL; custom_viewport_id = 0; sort_index = 0; } + +CanvasLayer::~CanvasLayer() { + + VS::get_singleton()->free(canvas); +} diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 81d2616cdc..aae23fbb12 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CANVAS_LAYER_H #define CANVAS_LAYER_H @@ -44,7 +45,7 @@ class CanvasLayer : public Node { real_t rot; int layer; Transform2D transform; - Ref<World2D> canvas; + RID canvas; ObjectID custom_viewport_id; // to check validity Viewport *custom_viewport; @@ -80,8 +81,6 @@ public: void set_scale(const Size2 &p_scale); Size2 get_scale() const; - Ref<World2D> get_world_2d() const; - Size2 get_viewport_size() const; RID get_viewport() const; @@ -92,7 +91,10 @@ public: void reset_sort_index(); int get_sort_index(); + RID get_canvas() const; + CanvasLayer(); + ~CanvasLayer(); }; #endif // CANVAS_LAYER_H diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index e99a21fbce..ae21775c55 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "http_request.h" #include "version.h" @@ -120,7 +121,7 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h } if (!has_user_agent) { - headers.push_back("User-Agent: GodotEngine/" + String(VERSION_MKSTRING) + " (" + OS::get_singleton()->get_name() + ")"); + headers.push_back("User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")"); } if (!has_accept) { @@ -523,6 +524,7 @@ void HTTPRequest::_bind_methods() { ClassDB::bind_method(D_METHOD("_redirect_request"), &HTTPRequest::_redirect_request); ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "download_file", PROPERTY_HINT_FILE), "set_download_file", "get_download_file"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads"); ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects"); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 1777a7f8f1..eb5d020bc5 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef HTTPREQUEST_H #define HTTPREQUEST_H diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp index a2c29d8209..1443d5efbf 100644 --- a/scene/main/instance_placeholder.cpp +++ b/scene/main/instance_placeholder.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "instance_placeholder.h" #include "io/resource_loader.h" @@ -51,6 +52,7 @@ bool InstancePlaceholder::_get(const StringName &p_name, Variant &r_ret) const { } return false; } + void InstancePlaceholder::_get_property_list(List<PropertyInfo> *p_list) const { for (const List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) { @@ -72,13 +74,14 @@ String InstancePlaceholder::get_instance_path() const { return path; } -void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene) { - ERR_FAIL_COND(!is_inside_tree()); +Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene> &p_custom_scene) { + + ERR_FAIL_COND_V(!is_inside_tree(), NULL); Node *base = get_parent(); if (!base) - return; + return NULL; Ref<PackedScene> ps; if (p_custom_scene.is_valid()) @@ -87,7 +90,7 @@ void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_s ps = ResourceLoader::load(path, "PackedScene"); if (!ps.is_valid()) - return; + return NULL; Node *scene = ps->instance(); scene->set_name(get_name()); int pos = get_position_in_parent(); @@ -96,11 +99,20 @@ void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_s scene->set(E->get().name, E->get().value); } - queue_delete(); + if (p_replace) { + queue_delete(); + base->remove_child(this); + } - base->remove_child(this); base->add_child(scene); base->move_child(scene, pos); + + return scene; +} + +void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene) { + //Deprecated by + create_instance(true, p_custom_scene); } Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) { @@ -123,6 +135,7 @@ Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) { void InstancePlaceholder::_bind_methods() { ClassDB::bind_method(D_METHOD("get_stored_values", "with_order"), &InstancePlaceholder::get_stored_values, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("create_instance", "replace", "custom_scene"), &InstancePlaceholder::create_instance, DEFVAL(false), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("replace_by_instance", "custom_scene"), &InstancePlaceholder::replace_by_instance, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("get_instance_path"), &InstancePlaceholder::get_instance_path); } diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h index 9b2f1e1168..2158257c93 100644 --- a/scene/main/instance_placeholder.h +++ b/scene/main/instance_placeholder.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef INSTANCE_PLACEHOLDER_H #define INSTANCE_PLACEHOLDER_H @@ -59,6 +60,7 @@ public: Dictionary get_stored_values(bool p_with_order = false); + Node *create_instance(bool p_replace = false, const Ref<PackedScene> &p_custom_scene = Ref<PackedScene>()); void replace_by_instance(const Ref<PackedScene> &p_custom_scene = Ref<PackedScene>()); InstancePlaceholder(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index d82000e3fa..67ee246252 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "node.h" #include "core/core_string_names.h" @@ -135,7 +136,6 @@ void Node::_notification(int p_notification) { get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, NULL, 0); } - //emit_signal(SceneStringNames::get_singleton()->enter_tree); } break; case NOTIFICATION_POSTINITIALIZE: { @@ -179,11 +179,12 @@ void Node::_propagate_ready() { if (data.ready_first) { data.ready_first = false; notification(NOTIFICATION_READY); + emit_signal(SceneStringNames::get_singleton()->ready); } } void Node::_propagate_enter_tree() { - // this needs to happen to all childs before any enter_tree + // this needs to happen to all children before any enter_tree if (data.parent) { data.tree = data.parent->data.tree; @@ -274,7 +275,7 @@ void Node::_propagate_exit_tree() { get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, NULL, 0); } - emit_signal(SceneStringNames::get_singleton()->tree_exited); + emit_signal(SceneStringNames::get_singleton()->tree_exiting); notification(NOTIFICATION_EXIT_TREE, true); if (data.tree) @@ -296,6 +297,8 @@ void Node::_propagate_exit_tree() { data.ready_notified = false; data.tree = NULL; data.depth = -1; + + emit_signal(SceneStringNames::get_singleton()->tree_exited); } void Node::move_child(Node *p_child, int p_pos) { @@ -474,7 +477,7 @@ bool Node::is_network_master() const { ERR_FAIL_COND_V(!is_inside_tree(), false); - return get_tree()->get_network_unique_id() == data.network_master; + return get_multiplayer_api()->get_network_unique_id() == data.network_master; } /***** RPC CONFIG ********/ @@ -664,200 +667,16 @@ Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Va } void Node::rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { - ERR_FAIL_COND(!is_inside_tree()); - - bool skip_rpc = false; - bool call_local_native = false; - bool call_local_script = false; - - if (p_peer_id == 0 || p_peer_id == get_tree()->get_network_unique_id() || (p_peer_id < 0 && p_peer_id != -get_tree()->get_network_unique_id())) { - //check that send mode can use local call - - Map<StringName, RPCMode>::Element *E = data.rpc_methods.find(p_method); - if (E) { - - switch (E->get()) { - - case RPC_MODE_DISABLED: { - //do nothing - } break; - case RPC_MODE_REMOTE: { - //do nothing also, no need to call local - } break; - case RPC_MODE_SYNC: { - //call it, sync always results in call - call_local_native = true; - } break; - case RPC_MODE_MASTER: { - call_local_native = is_network_master(); - if (call_local_native) { - skip_rpc = true; //no other master so.. - } - } break; - case RPC_MODE_SLAVE: { - call_local_native = !is_network_master(); - } break; - } - } - - if (call_local_native) { - // done below - } else if (get_script_instance()) { - //attempt with script - ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rpc_mode(p_method); - - switch (rpc_mode) { - - case ScriptInstance::RPC_MODE_DISABLED: { - //do nothing - } break; - case ScriptInstance::RPC_MODE_REMOTE: { - //do nothing also, no need to call local - } break; - case ScriptInstance::RPC_MODE_SYNC: { - //call it, sync always results in call - call_local_script = true; - } break; - case ScriptInstance::RPC_MODE_MASTER: { - call_local_script = is_network_master(); - if (call_local_script) { - skip_rpc = true; //no other master so.. - } - } break; - case ScriptInstance::RPC_MODE_SLAVE: { - call_local_script = !is_network_master(); - } break; - } - } - } - - if (!skip_rpc) { - get_tree()->_rpc(this, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount); - } - - if (call_local_native) { - Variant::CallError ce; - call(p_method, p_arg, p_argcount, ce); - if (ce.error != Variant::CallError::CALL_OK) { - String error = Variant::get_call_error_text(this, p_method, p_arg, p_argcount, ce); - error = "rpc() aborted in local call: - " + error; - ERR_PRINTS(error); - return; - } - } - - if (call_local_script) { - Variant::CallError ce; - ce.error = Variant::CallError::CALL_OK; - get_script_instance()->call(p_method, p_arg, p_argcount, ce); - if (ce.error != Variant::CallError::CALL_OK) { - String error = Variant::get_call_error_text(this, p_method, p_arg, p_argcount, ce); - error = "rpc() aborted in script local call: - " + error; - ERR_PRINTS(error); - return; - } - } + get_multiplayer_api()->rpcp(this, p_peer_id, p_unreliable, p_method, p_arg, p_argcount); } -/******** RSET *********/ - void Node::rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { - ERR_FAIL_COND(!is_inside_tree()); - - bool skip_rset = false; - - if (p_peer_id == 0 || p_peer_id == get_tree()->get_network_unique_id() || (p_peer_id < 0 && p_peer_id != -get_tree()->get_network_unique_id())) { - //check that send mode can use local call - - bool set_local = false; - - Map<StringName, RPCMode>::Element *E = data.rpc_properties.find(p_property); - if (E) { - - switch (E->get()) { - - case RPC_MODE_DISABLED: { - //do nothing - } break; - case RPC_MODE_REMOTE: { - //do nothing also, no need to call local - } break; - case RPC_MODE_SYNC: { - //call it, sync always results in call - set_local = true; - } break; - case RPC_MODE_MASTER: { - set_local = is_network_master(); - if (set_local) { - skip_rset = true; - } - - } break; - case RPC_MODE_SLAVE: { - set_local = !is_network_master(); - } break; - } - } - - if (set_local) { - bool valid; - set(p_property, p_value, &valid); - - if (!valid) { - String error = "rset() aborted in local set, property not found: - " + String(p_property); - ERR_PRINTS(error); - return; - } - } else if (get_script_instance()) { - //attempt with script - ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rset_mode(p_property); - - switch (rpc_mode) { - - case ScriptInstance::RPC_MODE_DISABLED: { - //do nothing - } break; - case ScriptInstance::RPC_MODE_REMOTE: { - //do nothing also, no need to call local - } break; - case ScriptInstance::RPC_MODE_SYNC: { - //call it, sync always results in call - set_local = true; - } break; - case ScriptInstance::RPC_MODE_MASTER: { - set_local = is_network_master(); - if (set_local) { - skip_rset = true; - } - } break; - case ScriptInstance::RPC_MODE_SLAVE: { - set_local = !is_network_master(); - } break; - } - - if (set_local) { - - bool valid = get_script_instance()->set(p_property, p_value); - - if (!valid) { - String error = "rset() aborted in local script set, property not found: - " + String(p_property); - ERR_PRINTS(error); - return; - } - } - } - } - - if (skip_rset) - return; - - const Variant *vptr = &p_value; - - get_tree()->_rpc(this, p_peer_id, p_unreliable, true, p_property, &vptr, 1); + get_multiplayer_api()->rsetp(this, p_peer_id, p_unreliable, p_property, p_value); } +/******** RSET *********/ void Node::rset(const StringName &p_property, const Variant &p_value) { rsetp(0, false, p_property, p_value); @@ -879,6 +698,30 @@ void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const } //////////// end of rpc +Ref<MultiplayerAPI> Node::get_multiplayer_api() const { + if (multiplayer_api.is_valid()) + return multiplayer_api; + if (!is_inside_tree()) + return Ref<MultiplayerAPI>(); + return get_tree()->get_multiplayer_api(); +} + +Ref<MultiplayerAPI> Node::get_custom_multiplayer_api() const { + return multiplayer_api; +} + +void Node::set_custom_multiplayer_api(Ref<MultiplayerAPI> p_multiplayer_api) { + + multiplayer_api = p_multiplayer_api; +} + +const Map<StringName, Node::RPCMode>::Element *Node::get_node_rpc_mode(const StringName &p_method) { + return data.rpc_methods.find(p_method); +} + +const Map<StringName, Node::RPCMode>::Element *Node::get_node_rset_mode(const StringName &p_property) { + return data.rpc_properties.find(p_property); +} bool Node::can_call_rpc(const StringName &p_method, int p_from) const { @@ -1136,9 +979,23 @@ void Node::_set_name_nocheck(const StringName &p_name) { data.name = p_name; } +String Node::invalid_character = ". : @ / \""; + +bool Node::_validate_node_name(String &p_name) { + String name = p_name; + Vector<String> chars = Node::invalid_character.split(" "); + for (int i = 0; i < chars.size(); i++) { + name = name.replace(chars[i], ""); + } + bool is_valid = name == p_name; + p_name = name; + return is_valid; +} + void Node::set_name(const String &p_name) { - String name = p_name.replace(":", "").replace("/", "").replace("@", ""); + String name = p_name; + _validate_node_name(name); ERR_FAIL_COND(name == ""); data.name = name; @@ -1199,13 +1056,13 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { unique = false; } else { //check if exists - Node **childs = data.children.ptrw(); + Node **children = data.children.ptrw(); int cc = data.children.size(); for (int i = 0; i < cc; i++) { - if (childs[i] == p_child) + if (children[i] == p_child) continue; - if (childs[i]->data.name == p_child->data.name) { + if (children[i]->data.name == p_child->data.name) { unique = false; break; } @@ -1308,7 +1165,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { } /* Notify */ - //recognize childs created in this node constructor + //recognize children created in this node constructor p_child->data.parent_owned = data.in_constructor; add_child_notify(p_child); } @@ -1865,11 +1722,18 @@ bool Node::has_persistent_groups() const { return false; } -void Node::_print_tree(const Node *p_node) { +void Node::_print_tree_pretty(const String prefix, const bool last) { - print_line(String(p_node->get_path_to(this))); - for (int i = 0; i < data.children.size(); i++) - data.children[i]->_print_tree(p_node); + String new_prefix = last ? String::utf8(" ┖╴") : String::utf8(" ┠╴"); + print_line(prefix + new_prefix + String(get_name())); + for (int i = 0; i < data.children.size(); i++) { + new_prefix = last ? String::utf8(" ") : String::utf8(" ┃ "); + data.children[i]->_print_tree_pretty(prefix + new_prefix, i == data.children.size() - 1); + } +} + +void Node::print_tree_pretty() { + _print_tree_pretty("", true); } void Node::print_tree() { @@ -1877,6 +1741,12 @@ void Node::print_tree() { _print_tree(this); } +void Node::_print_tree(const Node *p_node) { + print_line(String(p_node->get_path_to(this))); + for (int i = 0; i < data.children.size(); i++) + data.children[i]->_print_tree(p_node); +} + void Node::_propagate_reverse_notification(int p_notification) { data.blocked++; @@ -2007,7 +1877,7 @@ void Node::set_editable_instance(Node *p_node, bool p_editable) { if (!p_editable) { data.editable_instances.erase(p); // Avoid this flag being needlessly saved; - // also give more visual feedback if editable children is reenabled + // also give more visual feedback if editable children is re-enabled set_display_folded(false); } else { data.editable_instances[p] = true; @@ -2160,15 +2030,18 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const if (name == script_property_name) continue; - Variant value = N->get()->get(name); - // Duplicate dictionaries and arrays, mainly needed for __meta__ - if (value.get_type() == Variant::DICTIONARY) { - value = Dictionary(value).duplicate(); - } else if (value.get_type() == Variant::ARRAY) { - value = Array(value).duplicate(); - } + Variant value = N->get()->get(name).duplicate(true); - current_node->set(name, value); + if (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) { + + Resource *res = Object::cast_to<Resource>(value); + if (res) // Duplicate only if it's a resource + current_node->set(name, res->duplicate()); + + } else { + + current_node->set(name, value); + } } } @@ -2301,13 +2174,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p continue; String name = E->get().name; - Variant value = get(name); - // Duplicate dictionaries and arrays, mainly needed for __meta__ - if (value.get_type() == Variant::DICTIONARY) { - value = Dictionary(value).duplicate(); - } else if (value.get_type() == Variant::ARRAY) { - value = Array(value).duplicate(); - } + Variant value = get(name).duplicate(true); node->set(name, value); } @@ -2490,7 +2357,10 @@ void Node::replace_by(Node *p_node, bool p_keep_data) { Node *child = get_child(0); remove_child(child); - p_node->add_child(child); + if (!child->is_owned_by_parent()) { + // add the custom children to the p_node + p_node->add_child(child); + } } p_node->set_owner(owner); @@ -2711,18 +2581,21 @@ Array Node::_get_children() const { return arr; } -#ifdef TOOLS_ENABLED void Node::set_import_path(const NodePath &p_import_path) { +#ifdef TOOLS_ENABLED data.import_path = p_import_path; +#endif } NodePath Node::get_import_path() const { +#ifdef TOOLS_ENABLED return data.import_path; -} - +#else + return NodePath(); #endif +} static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) { @@ -2825,6 +2698,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip); ClassDB::bind_method(D_METHOD("get_index"), &Node::get_index); ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree); + ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty); ClassDB::bind_method(D_METHOD("set_filename", "filename"), &Node::set_filename); ClassDB::bind_method(D_METHOD("get_filename"), &Node::get_filename); ClassDB::bind_method(D_METHOD("propagate_notification", "what"), &Node::propagate_notification); @@ -2874,15 +2748,15 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("is_network_master"), &Node::is_network_master); + ClassDB::bind_method(D_METHOD("get_multiplayer_api"), &Node::get_multiplayer_api); + ClassDB::bind_method(D_METHOD("get_custom_multiplayer_api"), &Node::get_custom_multiplayer_api); + ClassDB::bind_method(D_METHOD("set_custom_multiplayer_api", "api"), &Node::set_custom_multiplayer_api); ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config); ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config); -#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path); ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path); - ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_import_path", "_get_import_path"); - -#endif + ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path"); { MethodInfo mi; @@ -2940,8 +2814,10 @@ void Node::_bind_methods() { BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANCING); + ADD_SIGNAL(MethodInfo("ready")); ADD_SIGNAL(MethodInfo("renamed")); ADD_SIGNAL(MethodInfo("tree_entered")); + ADD_SIGNAL(MethodInfo("tree_exiting")); ADD_SIGNAL(MethodInfo("tree_exited")); //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/process" ),"set_process","is_processing") ; @@ -2950,7 +2826,12 @@ void Node::_bind_methods() { //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ; ADD_GROUP("Pause", "pause_"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode"); - ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_display_folded", "is_displayed_folded"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded"); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name"); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "multiplayer_api", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer_api"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "custom_multiplayer_api", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer_api", "get_custom_multiplayer_api"); BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::REAL, "delta"))); BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::REAL, "delta"))); diff --git a/scene/main/node.h b/scene/main/node.h index 2aca84324d..b5a956116d 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef NODE_H #define NODE_H @@ -103,7 +104,7 @@ private: StringName name; SceneTree *tree; bool inside_tree; - bool ready_notified; //this is a small hack, so if a node is added during _ready() to the tree, it corretly gets the _ready() notification + bool ready_notified; //this is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification bool ready_first; #ifdef TOOLS_ENABLED NodePath import_path; //path used when imported, used by scene editors to keep tracking @@ -150,6 +151,9 @@ private: NAME_CASING_SNAKE_CASE }; + Ref<MultiplayerAPI> multiplayer_api; + + void _print_tree_pretty(const String prefix, const bool last); void _print_tree(const Node *p_node); Node *_get_node(const NodePath &p_path) const; @@ -186,6 +190,12 @@ private: void _set_tree(SceneTree *p_tree); +#ifdef TOOLS_ENABLED + friend class SceneTreeEditor; +#endif + static String invalid_character; + static bool _validate_node_name(String &p_name); + protected: void _block() { data.blocked++; } void _unblock() { data.blocked--; } @@ -286,6 +296,7 @@ public: int get_index() const; void print_tree(); + void print_tree_pretty(); void set_filename(const String &p_filename); String get_filename() const; @@ -363,16 +374,14 @@ public: void queue_delete(); - //shitty hacks for speed + //hacks for speed static void set_human_readable_collision_renaming(bool p_enabled); static void init_node_hrcr(); void force_parent_owned() { data.parent_owned = true; } //hack to avoid duplicate nodes -#ifdef TOOLS_ENABLED void set_import_path(const NodePath &p_import_path); //path used when imported, used by scene editors to keep tracking NodePath get_import_path() const; -#endif bool is_owned_by_parent() const; @@ -402,15 +411,20 @@ public: void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode void rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode - void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); - void rset(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode void rset_unreliable(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode void rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode void rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode + void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); + Ref<MultiplayerAPI> get_multiplayer_api() const; + Ref<MultiplayerAPI> get_custom_multiplayer_api() const; + void set_custom_multiplayer_api(Ref<MultiplayerAPI> p_multiplayer_api); + const Map<StringName, RPCMode>::Element *get_node_rpc_mode(const StringName &p_method); + const Map<StringName, RPCMode>::Element *get_node_rset_mode(const StringName &p_property); + bool can_call_rpc(const StringName &p_method, int p_from) const; bool can_call_rset(const StringName &p_property, int p_from) const; diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp index 76fa40cc7c..dbe7daa604 100644 --- a/scene/main/resource_preloader.cpp +++ b/scene/main/resource_preloader.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "resource_preloader.h" void ResourcePreloader::_set_resources(const Array &p_data) { @@ -160,7 +161,7 @@ void ResourcePreloader::_bind_methods() { ClassDB::bind_method(D_METHOD("get_resource", "name"), &ResourcePreloader::get_resource); ClassDB::bind_method(D_METHOD("get_resource_list"), &ResourcePreloader::_get_resource_list); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "resources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_resources", "_get_resources"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "resources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_resources", "_get_resources"); } ResourcePreloader::ResourcePreloader() { diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h index 479cde51ae..98c7b21f37 100644 --- a/scene/main/resource_preloader.h +++ b/scene/main/resource_preloader.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RESOURCE_PRELOADER_H #define RESOURCE_PRELOADER_H diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 632d912e43..011087b487 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -27,11 +27,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "scene_tree.h" #include "editor/editor_node.h" #include "io/marshalls.h" #include "io/resource_loader.h" +#include "main/input_default.h" #include "message_queue.h" #include "node.h" #include "os/keyboard.h" @@ -54,6 +56,8 @@ void SceneTreeTimer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left); ClassDB::bind_method(D_METHOD("get_time_left"), &SceneTreeTimer::get_time_left); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_left"), "set_time_left", "get_time_left"); + ADD_SIGNAL(MethodInfo("timeout")); } @@ -481,7 +485,7 @@ bool SceneTree::idle(float p_time) { idle_process_time = p_time; - _network_poll(); + multiplayer_api->poll(); emit_signal("idle_frame"); @@ -495,14 +499,14 @@ bool SceneTree::idle(float p_time) { Size2 win_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); if (win_size != last_screen_size) { + last_screen_size = win_size; + _update_root_rect(); + if (use_font_oversampling) { DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width; DynamicFont::update_oversampling(); } - last_screen_size = win_size; - _update_root_rect(); - emit_signal("screen_resized"); } @@ -612,9 +616,18 @@ void SceneTree::_notification(int p_notification) { } } break; case NOTIFICATION_OS_MEMORY_WARNING: + case NOTIFICATION_WM_MOUSE_ENTER: + case NOTIFICATION_WM_MOUSE_EXIT: case NOTIFICATION_WM_FOCUS_IN: case NOTIFICATION_WM_FOCUS_OUT: { + if (p_notification == NOTIFICATION_WM_FOCUS_IN) { + InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); + if (id) { + id->ensure_touch_mouse_raised(); + } + } + get_root()->propagate_notification(p_notification); } break; case NOTIFICATION_TRANSLATION_CHANGED: { @@ -1192,16 +1205,20 @@ void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, c _update_root_rect(); } -#ifdef TOOLS_ENABLED void SceneTree::set_edited_scene_root(Node *p_node) { +#ifdef TOOLS_ENABLED edited_scene_root = p_node; +#endif } Node *SceneTree::get_edited_scene_root() const { +#ifdef TOOLS_ENABLED return edited_scene_root; -} +#else + return NULL; #endif +} void SceneTree::set_current_scene(Node *p_scene) { @@ -1628,16 +1645,11 @@ Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pa void SceneTree::_network_peer_connected(int p_id) { - connected_peers.insert(p_id); - path_get_cache.insert(p_id, PathGetCache()); - emit_signal("network_peer_connected", p_id); } void SceneTree::_network_peer_disconnected(int p_id) { - connected_peers.erase(p_id); - path_get_cache.erase(p_id); //I no longer need your cache, sorry emit_signal("network_peer_disconnected", p_id); } @@ -1656,466 +1668,70 @@ void SceneTree::_server_disconnected() { emit_signal("server_disconnected"); } -void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer) { - if (network_peer.is_valid()) { - network_peer->disconnect("peer_connected", this, "_network_peer_connected"); - network_peer->disconnect("peer_disconnected", this, "_network_peer_disconnected"); - network_peer->disconnect("connection_succeeded", this, "_connected_to_server"); - network_peer->disconnect("connection_failed", this, "_connection_failed"); - network_peer->disconnect("server_disconnected", this, "_server_disconnected"); - connected_peers.clear(); - path_get_cache.clear(); - path_send_cache.clear(); - last_send_cache_id = 1; +Ref<MultiplayerAPI> SceneTree::get_multiplayer_api() const { + return multiplayer_api; +} + +void SceneTree::set_multiplayer_api(Ref<MultiplayerAPI> p_multiplayer_api) { + ERR_FAIL_COND(!p_multiplayer_api.is_valid()); + + if (multiplayer_api.is_valid()) { + multiplayer_api->disconnect("network_peer_connected", this, "_network_peer_connected"); + multiplayer_api->disconnect("network_peer_disconnected", this, "_network_peer_disconnected"); + multiplayer_api->disconnect("connected_to_server", this, "_connected_to_server"); + multiplayer_api->disconnect("connection_failed", this, "_connection_failed"); + multiplayer_api->disconnect("server_disconnected", this, "_server_disconnected"); } - ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected."); - ERR_FAIL_COND(p_network_peer.is_valid() && p_network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED); + multiplayer_api = p_multiplayer_api; + multiplayer_api->set_root_node(root); - network_peer = p_network_peer; + multiplayer_api->connect("network_peer_connected", this, "_network_peer_connected"); + multiplayer_api->connect("network_peer_disconnected", this, "_network_peer_disconnected"); + multiplayer_api->connect("connected_to_server", this, "_connected_to_server"); + multiplayer_api->connect("connection_failed", this, "_connection_failed"); + multiplayer_api->connect("server_disconnected", this, "_server_disconnected"); +} - if (network_peer.is_valid()) { - network_peer->connect("peer_connected", this, "_network_peer_connected"); - network_peer->connect("peer_disconnected", this, "_network_peer_disconnected"); - network_peer->connect("connection_succeeded", this, "_connected_to_server"); - network_peer->connect("connection_failed", this, "_connection_failed"); - network_peer->connect("server_disconnected", this, "_server_disconnected"); - } +void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer) { + + multiplayer_api->set_network_peer(p_network_peer); +} + +Ref<NetworkedMultiplayerPeer> SceneTree::get_network_peer() const { + + return multiplayer_api->get_network_peer(); } bool SceneTree::is_network_server() const { - ERR_FAIL_COND_V(!network_peer.is_valid(), false); - return network_peer->is_server(); + return multiplayer_api->is_network_server(); } bool SceneTree::has_network_peer() const { - return network_peer.is_valid(); + return multiplayer_api->has_network_peer(); } int SceneTree::get_network_unique_id() const { - ERR_FAIL_COND_V(!network_peer.is_valid(), 0); - return network_peer->get_unique_id(); + return multiplayer_api->get_network_unique_id(); } Vector<int> SceneTree::get_network_connected_peers() const { - ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>()); - - Vector<int> ret; - for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { - ret.push_back(E->get()); - } - return ret; + return multiplayer_api->get_network_connected_peers(); } int SceneTree::get_rpc_sender_id() const { - return rpc_sender_id; + return multiplayer_api->get_rpc_sender_id(); } void SceneTree::set_refuse_new_network_connections(bool p_refuse) { - ERR_FAIL_COND(!network_peer.is_valid()); - network_peer->set_refuse_new_connections(p_refuse); + multiplayer_api->set_refuse_new_network_connections(p_refuse); } bool SceneTree::is_refusing_new_network_connections() const { - - ERR_FAIL_COND_V(!network_peer.is_valid(), false); - - return network_peer->is_refusing_new_connections(); -} - -void SceneTree::_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { - - if (network_peer.is_null()) { - ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); - ERR_FAIL(); - } - - if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { - ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); - ERR_FAIL(); - } - - if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { - ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); - ERR_FAIL(); - } - - if (p_argcount > 255) { - ERR_EXPLAIN("Too many arguments >255."); - ERR_FAIL(); - } - - if (p_to != 0 && !connected_peers.has(ABS(p_to))) { - if (p_to == get_network_unique_id()) { - ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(get_network_unique_id())); - } else { - ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); - } - - ERR_FAIL(); - } - - NodePath from_path = p_from->get_path(); - ERR_FAIL_COND(from_path.is_empty()); - - //see if the path is cached - PathSentCache *psc = path_send_cache.getptr(from_path); - if (!psc) { - //path is not cached, create - path_send_cache[from_path] = PathSentCache(); - psc = path_send_cache.getptr(from_path); - psc->id = last_send_cache_id++; - } - - //create base packet, lots of harcode because it must be tight - - int ofs = 0; - -#define MAKE_ROOM(m_amount) \ - if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); - - //encode type - MAKE_ROOM(1); - packet_cache[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; - ofs += 1; - - //encode ID - MAKE_ROOM(ofs + 4); - encode_uint32(psc->id, &packet_cache[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[ofs]); - ofs += len; - - if (p_set) { - //set argument - Error err = encode_variant(*p_arg[0], NULL, len); - ERR_FAIL_COND(err != OK); - MAKE_ROOM(ofs + len); - encode_variant(*p_arg[0], &packet_cache[ofs], len); - ofs += len; - - } else { - //call arguments - MAKE_ROOM(ofs + 1); - packet_cache[ofs] = p_argcount; - ofs += 1; - for (int i = 0; i < p_argcount; i++) { - Error err = encode_variant(*p_arg[i], NULL, len); - ERR_FAIL_COND(err != OK); - MAKE_ROOM(ofs + len); - encode_variant(*p_arg[i], &packet_cache[ofs], len); - ofs += len; - } - } - - //see if all peers have cached path (is so, call can be fast) - bool has_all_peers = true; - - List<int> peers_to_add; //if one is missing, take note to add it - - for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { - - if (p_to < 0 && E->get() == -p_to) - continue; //continue, excluded - - if (p_to > 0 && E->get() != p_to) - continue; //continue, not for this peer - - Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - - if (!F || F->get() == false) { - //path was not cached, or was cached but is unconfirmed - if (!F) { - //not cached at all, take note - peers_to_add.push_back(E->get()); - } - - has_all_peers = false; - } - } - - //those that need to be added, send a message for this - - for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) { - - //encode function name - CharString pname = String(from_path).utf8(); - int len = encode_cstring(pname.get_data(), NULL); - - Vector<uint8_t> packet; - - packet.resize(1 + 4 + len); - packet[0] = NETWORK_COMMAND_SIMPLIFY_PATH; - encode_uint32(psc->id, &packet[1]); - encode_cstring(pname.get_data(), &packet[5]); - - 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 - } - - //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); - - if (has_all_peers) { - - //they all have verified paths, so send fast - network_peer->set_target_peer(p_to); //to all of you - network_peer->put_packet(packet_cache.ptr(), ofs); //a message with love - } else { - //not all verified path, so send one by one - - //apend path at the end, since we will need it for some packets - CharString pname = String(from_path).utf8(); - int path_len = encode_cstring(pname.get_data(), NULL); - MAKE_ROOM(ofs + path_len); - encode_cstring(pname.get_data(), &packet_cache[ofs]); - - for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { - - if (p_to < 0 && E->get() == -p_to) - continue; //continue, excluded - - if (p_to > 0 && E->get() != p_to) - continue; //continue, not for this peer - - Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - ERR_CONTINUE(!F); //should never happen - - network_peer->set_target_peer(E->get()); //to this one specifically - - if (F->get() == true) { - //this one confirmed path, so use id - encode_uint32(psc->id, &packet_cache[1]); - network_peer->put_packet(packet_cache.ptr(), ofs); - } else { - //this one did not confirm path yet, so use entire path (sorry!) - encode_uint32(0x80000000 | ofs, &packet_cache[1]); //offset to path and flag - network_peer->put_packet(packet_cache.ptr(), ofs + path_len); - } - } - } -} - -void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { - - ERR_FAIL_COND(p_packet_len < 5); - - uint8_t packet_type = p_packet[0]; - - switch (packet_type) { - - case NETWORK_COMMAND_REMOTE_CALL: - case NETWORK_COMMAND_REMOTE_SET: { - - ERR_FAIL_COND(p_packet_len < 5); - uint32_t target = decode_uint32(&p_packet[1]); - - Node *node = NULL; - - if (target & 0x80000000) { - //use full path (not cached yet) - - int ofs = target & 0x7FFFFFFF; - ERR_FAIL_COND(ofs >= p_packet_len); - - String paths; - paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); - - NodePath np = paths; - - node = get_root()->get_node(np); - if (node == NULL) { - ERR_EXPLAIN("Failed to get path from RPC: " + String(np)); - ERR_FAIL_COND(node == NULL); - } - } else { - //use cached path - int id = target; - - Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from); - ERR_FAIL_COND(!E); - - Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id); - ERR_FAIL_COND(!F); - - PathGetCache::NodeInfo *ni = &F->get(); - //do proper caching later - - node = get_root()->get_node(ni->path); - if (node == NULL) { - ERR_EXPLAIN("Failed to get cached path from RPC: " + String(ni->path)); - ERR_FAIL_COND(node == NULL); - } - } - - ERR_FAIL_COND(p_packet_len < 6); - - //detect cstring end - int len_end = 5; - for (; len_end < p_packet_len; len_end++) { - if (p_packet[len_end] == 0) { - break; - } - } - - ERR_FAIL_COND(len_end >= p_packet_len); - - StringName name = String::utf8((const char *)&p_packet[5]); - - if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { - - if (!node->can_call_rpc(name, p_from)) - return; - - int ofs = len_end + 1; - - ERR_FAIL_COND(ofs >= p_packet_len); - - int argc = p_packet[ofs]; - Vector<Variant> args; - Vector<const Variant *> argp; - args.resize(argc); - argp.resize(argc); - - ofs++; - - for (int i = 0; i < argc; i++) { - - ERR_FAIL_COND(ofs >= p_packet_len); - int vlen; - Error err = decode_variant(args[i], &p_packet[ofs], p_packet_len - ofs, &vlen); - ERR_FAIL_COND(err != OK); - //args[i]=p_packet[3+i]; - argp[i] = &args[i]; - ofs += vlen; - } - - Variant::CallError ce; - - node->call(name, (const Variant **)argp.ptr(), argc, ce); - if (ce.error != Variant::CallError::CALL_OK) { - String error = Variant::get_call_error_text(node, name, (const Variant **)argp.ptr(), argc, ce); - error = "RPC - " + error; - ERR_PRINTS(error); - } - - } else { - - if (!node->can_call_rset(name, p_from)) - return; - - int ofs = len_end + 1; - - ERR_FAIL_COND(ofs >= p_packet_len); - - Variant value; - decode_variant(value, &p_packet[ofs], p_packet_len - ofs); - - bool valid; - - node->set(name, value, &valid); - if (!valid) { - String error = "Error setting remote property '" + String(name) + "', not found in object of type " + node->get_class(); - ERR_PRINTS(error); - } - } - - } break; - case NETWORK_COMMAND_SIMPLIFY_PATH: { - - ERR_FAIL_COND(p_packet_len < 5); - int id = decode_uint32(&p_packet[1]); - - String paths; - paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5); - - NodePath path = paths; - - if (!path_get_cache.has(p_from)) { - path_get_cache[p_from] = PathGetCache(); - } - - PathGetCache::NodeInfo ni; - ni.path = path; - ni.instance = 0; - - path_get_cache[p_from].nodes[id] = ni; - - { - //send ack - - //encode path - CharString pname = String(path).utf8(); - int len = encode_cstring(pname.get_data(), NULL); - - Vector<uint8_t> packet; - - packet.resize(1 + len); - packet[0] = NETWORK_COMMAND_CONFIRM_PATH; - encode_cstring(pname.get_data(), &packet[1]); - - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); - network_peer->set_target_peer(p_from); - network_peer->put_packet(packet.ptr(), packet.size()); - } - } break; - case NETWORK_COMMAND_CONFIRM_PATH: { - - String paths; - paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1); - - NodePath path = paths; - - PathSentCache *psc = path_send_cache.getptr(path); - ERR_FAIL_COND(!psc); - - Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from); - ERR_FAIL_COND(!E); - E->get() = true; - } break; - } -} - -void SceneTree::_network_poll() { - - if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) - return; - - network_peer->poll(); - - if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here - return; - - while (network_peer->get_available_packet_count()) { - - int sender = network_peer->get_packet_peer(); - const uint8_t *packet; - int len; - - Error err = network_peer->get_packet(&packet, len); - if (err != OK) { - ERR_PRINT("Error getting packet!"); - } - - rpc_sender_id = sender; - _network_process_packet(sender, packet, len); - rpc_sender_id = 0; - - if (!network_peer.is_valid()) { - break; //it's also possible that a packet or RPC caused a disconnection, so also check here - } - } + return multiplayer_api->is_refusing_new_network_connections(); } void SceneTree::_bind_methods() { @@ -2133,10 +1749,8 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint); ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint); -#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root); ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root); -#endif ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); @@ -2186,7 +1800,10 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene); + ClassDB::bind_method(D_METHOD("set_multiplayer_api", "multiplayer_api"), &SceneTree::set_multiplayer_api); + ClassDB::bind_method(D_METHOD("get_multiplayer_api"), &SceneTree::get_multiplayer_api); ClassDB::bind_method(D_METHOD("set_network_peer", "peer"), &SceneTree::set_network_peer); + ClassDB::bind_method(D_METHOD("get_network_peer"), &SceneTree::get_network_peer); ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server); ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &SceneTree::get_network_connected_peers); @@ -2203,6 +1820,17 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling); ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_font_oversampling"), "set_use_font_oversampling", "is_using_font_oversampling"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "", "get_root"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer_api", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_multiplayer_api", "get_multiplayer_api"); + ADD_SIGNAL(MethodInfo("tree_changed")); ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node"))); ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node"))); @@ -2297,7 +1925,6 @@ SceneTree::SceneTree() { call_lock = 0; root_lock = 0; node_count = 0; - rpc_sender_id = 0; //create with mainloop @@ -2306,6 +1933,9 @@ SceneTree::SceneTree() { if (!root->get_world().is_valid()) root->set_world(Ref<World>(memnew(World))); + // Initialize network state + set_multiplayer_api(Ref<MultiplayerAPI>(memnew(MultiplayerAPI))); + //root->set_world_2d( Ref<World2D>( memnew( World2D ))); root->set_as_audio_listener(true); root->set_as_audio_listener_2d(true); @@ -2350,7 +1980,7 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set("rendering/environment/default_environment", ""); } else { //file was erased, notify user. - ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Environment -> Default Environment) could not be loaded.")); + ERR_PRINTS(RTR("Default Environment as specified in Project Settings (Rendering -> Environment -> Default Environment) could not be loaded.")); } } } @@ -2400,8 +2030,6 @@ SceneTree::SceneTree() { live_edit_root = NodePath("/root"); - last_send_cache_id = 1; - #endif use_font_oversampling = false; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index dab446e226..9c06e4ded3 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -27,10 +27,11 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SCENE_MAIN_LOOP_H #define SCENE_MAIN_LOOP_H -#include "io/networked_multiplayer_peer.h" +#include "io/multiplayer_api.h" #include "os/main_loop.h" #include "os/thread_safe.h" #include "scene/resources/mesh.h" @@ -184,16 +185,8 @@ private: ///network/// - enum NetworkCommands { - NETWORK_COMMAND_REMOTE_CALL, - NETWORK_COMMAND_REMOTE_SET, - NETWORK_COMMAND_SIMPLIFY_PATH, - NETWORK_COMMAND_CONFIRM_PATH, - }; - - Ref<NetworkedMultiplayerPeer> network_peer; + Ref<MultiplayerAPI> multiplayer_api; - Set<int> connected_peers; void _network_peer_connected(int p_id); void _network_peer_disconnected(int p_id); @@ -201,39 +194,9 @@ private: void _connection_failed(); void _server_disconnected(); - int rpc_sender_id; - - //path sent caches - struct PathSentCache { - Map<int, bool> confirmed_peers; - int id; - }; - - HashMap<NodePath, PathSentCache> path_send_cache; - int last_send_cache_id; - - //path get caches - struct PathGetCache { - struct NodeInfo { - NodePath path; - ObjectID instance; - }; - - Map<int, NodeInfo> nodes; - }; - - Map<int, PathGetCache> path_get_cache; - - Vector<uint8_t> packet_cache; - - void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); - void _network_poll(); - static SceneTree *singleton; friend class Node; - void _rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); - void tree_changed(); void node_added(Node *p_node); void node_removed(Node *p_node); @@ -427,10 +390,8 @@ public: //void change_scene(const String& p_path); //Node *get_loaded_scene(); -#ifdef TOOLS_ENABLED void set_edited_scene_root(Node *p_node); Node *get_edited_scene_root() const; -#endif void set_current_scene(Node *p_scene); Node *get_current_scene() const; @@ -449,7 +410,10 @@ public: //network API + Ref<MultiplayerAPI> get_multiplayer_api() const; + void set_multiplayer_api(Ref<MultiplayerAPI> p_multiplayer_api); void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer); + Ref<NetworkedMultiplayerPeer> get_network_peer() const; bool is_network_server() const; bool has_network_peer() const; int get_network_unique_id() const; diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index 90cec07f56..c285694dfa 100755 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "timer.h" #include "engine.h" @@ -106,7 +107,10 @@ bool Timer::has_autostart() const { return autostart; } -void Timer::start() { +void Timer::start(float p_time) { + if (p_time > 0) { + set_wait_time(p_time); + } time_left = wait_time; _set_process(true); } @@ -184,7 +188,7 @@ void Timer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_autostart", "enable"), &Timer::set_autostart); ClassDB::bind_method(D_METHOD("has_autostart"), &Timer::has_autostart); - ClassDB::bind_method(D_METHOD("start"), &Timer::start); + ClassDB::bind_method(D_METHOD("start", "time_sec"), &Timer::start, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("stop"), &Timer::stop); ClassDB::bind_method(D_METHOD("set_paused", "paused"), &Timer::set_paused); @@ -203,6 +207,8 @@ void Timer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.01,4096,0.01"), "set_wait_time", "get_wait_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", 0), "set_paused", "is_paused"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_left", PROPERTY_HINT_NONE, "", 0), "", "get_time_left"); BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE); diff --git a/scene/main/timer.h b/scene/main/timer.h index 8c15e2eac7..2f42252a7e 100755 --- a/scene/main/timer.h +++ b/scene/main/timer.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TIMER_H #define TIMER_H @@ -63,7 +64,7 @@ public: void set_autostart(bool p_start); bool has_autostart() const; - void start(); + void start(float p_time = -1); void stop(); void set_paused(bool p_paused); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 78706ee14a..295f131db3 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "viewport.h" #include "os/input.h" @@ -180,6 +181,7 @@ public: Viewport::GUI::GUI() { mouse_focus = NULL; + mouse_click_grabber = NULL; mouse_focus_button = -1; key_focus = NULL; mouse_over = NULL; @@ -187,16 +189,16 @@ Viewport::GUI::GUI() { tooltip = NULL; tooltip_popup = NULL; tooltip_label = NULL; + subwindow_visibility_dirty = false; subwindow_order_dirty = false; } ///////////////////////////////////// + void Viewport::_update_stretch_transform() { if (size_override_stretch && size_override) { - //print_line("sive override size "+size_override_size); - //print_line("rect size "+size); stretch_transform = Transform2D(); Size2 scale = size / (size_override_size + size_override_margin * 2); stretch_transform.scale(scale); @@ -210,114 +212,6 @@ void Viewport::_update_stretch_transform() { _update_global_transform(); } -void Viewport::_update_rect() { - - if (!is_inside_tree()) - return; - - /*if (!render_target && parent_control) { - - Control *c = parent_control; - - rect.pos=Point2(); - rect.size=c->get_size(); - }*/ - /* - VisualServer::ViewportRect vr; - vr.x=rect.pos.x; - vr.y=rect.pos.y; - - if (render_target) { - vr.x=0; - vr.y=0; - } - vr.width=rect.size.width; - vr.height=rect.size.height; - - VisualServer::get_singleton()->viewport_set_rect(viewport,vr); - last_vp_rect=rect; - - if (canvas_item.is_valid()) { - VisualServer::get_singleton()->canvas_item_set_custom_rect(canvas_item,true,rect); - } - - emit_signal("size_changed"); - texture->emit_changed(); -*/ -} - -void Viewport::_parent_resized() { - - _update_rect(); -} - -void Viewport::_parent_draw() { -} - -void Viewport::_parent_visibility_changed() { - - /* - if (parent_control) { - - Control *c = parent_control; - VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,c->is_visible_in_tree()); - - _update_listener(); - _update_listener_2d(); - } -*/ -} - -void Viewport::_vp_enter_tree() { - - /* if (parent_control) { - - Control *cparent=parent_control; - RID parent_ci = cparent->get_canvas_item(); - ERR_FAIL_COND(!parent_ci.is_valid()); - canvas_item = VisualServer::get_singleton()->canvas_item_create(); - - VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,parent_ci); - VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false); - //VisualServer::get_singleton()->canvas_item_attach_viewport(canvas_item,viewport); - parent_control->connect("resized",this,"_parent_resized"); - parent_control->connect("visibility_changed",this,"_parent_visibility_changed"); - } else if (!parent){ - - //VisualServer::get_singleton()->viewport_attach_to_screen(viewport,0); - - } -*/ -} - -void Viewport::_vp_exit_tree() { - - /* - if (parent_control) { - - parent_control->disconnect("resized",this,"_parent_resized"); - } - - if (parent_control) { - - parent_control->disconnect("visibility_changed",this,"_parent_visibility_changed"); - } - - if (canvas_item.is_valid()) { - - VisualServer::get_singleton()->free(canvas_item); - canvas_item=RID(); - - } - - if (!parent) { - - VisualServer::get_singleton()->viewport_detach(viewport); - - } -*/ -} - void Viewport::update_worlds() { if (!is_inside_tree()) @@ -375,7 +269,6 @@ void Viewport::_notification(int p_what) { _update_listener(); _update_listener_2d(); - _update_rect(); find_world_2d()->_register_viewport(this, Rect2()); @@ -428,6 +321,11 @@ void Viewport::_notification(int p_what) { first->make_current(); } #endif + + // Enable processing for tooltips, collision debugging, physics object picking, etc. + set_process_internal(true); + set_physics_process_internal(true); + } break; case NOTIFICATION_EXIT_TREE: { @@ -435,11 +333,6 @@ void Viewport::_notification(int p_what) { if (world_2d.is_valid()) world_2d->_remove_viewport(this); - /* - if (!render_target) - _vp_exit_tree(); - */ - VisualServer::get_singleton()->viewport_set_scenario(viewport, RID()); // SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID()); VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas); @@ -460,15 +353,18 @@ void Viewport::_notification(int p_what) { VS::get_singleton()->viewport_set_active(viewport, false); } break; - case NOTIFICATION_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PROCESS: { if (gui.tooltip_timer >= 0) { - gui.tooltip_timer -= get_physics_process_delta_time(); + gui.tooltip_timer -= get_process_delta_time(); if (gui.tooltip_timer < 0) { _gui_show_tooltip(); } } + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) { VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug); @@ -678,6 +574,20 @@ void Viewport::_notification(int p_what) { } } break; + case SceneTree::NOTIFICATION_WM_FOCUS_OUT: { + if (gui.mouse_focus) { + //if mouse is being pressed, send a release event + Ref<InputEventMouseButton> mb; + mb.instance(); + mb->set_position(gui.mouse_focus->get_local_mouse_position()); + mb->set_global_position(gui.mouse_focus->get_local_mouse_position()); + mb->set_button_index(gui.mouse_focus_button); + mb->set_pressed(false); + Control *c = gui.mouse_focus; + gui.mouse_focus = NULL; + c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); + } + } break; } } @@ -703,7 +613,6 @@ void Viewport::set_size(const Size2 &p_size) { size = p_size.floor(); VS::get_singleton()->viewport_set_size(viewport, size.width, size.height); - _update_rect(); _update_stretch_transform(); emit_signal("size_changed"); @@ -1152,7 +1061,7 @@ void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vecto size_override_size = p_size; } size_override_margin = p_margin; - _update_rect(); + _update_stretch_transform(); emit_signal("size_changed"); } @@ -1171,9 +1080,6 @@ void Viewport::set_size_override_stretch(bool p_enable) { return; size_override_stretch = p_enable; - if (size_override) { - _update_rect(); - } _update_stretch_transform(); } @@ -1346,6 +1252,24 @@ void Viewport::warp_mouse(const Vector2 &p_pos) { Input::get_singleton()->warp_mouse_position(gpos); } +void Viewport::_gui_prepare_subwindows() { + + if (gui.subwindow_visibility_dirty) { + + gui.subwindows.clear(); + for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) { + if (E->get()->is_visible_in_tree()) { + gui.subwindows.push_back(E->get()); + } + } + + gui.subwindow_visibility_dirty = false; + gui.subwindow_order_dirty = true; + } + + _gui_sort_subwindows(); +} + void Viewport::_gui_sort_subwindows() { if (!gui.subwindow_order_dirty) @@ -1488,7 +1412,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu Control *Viewport::_gui_find_control(const Point2 &p_global) { - _gui_sort_subwindows(); + _gui_prepare_subwindows(); for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) { @@ -1909,7 +1833,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (!over) { - OS::get_singleton()->set_cursor_shape(OS::CURSOR_ARROW); + OS::get_singleton()->set_cursor_shape((OS::CursorShape)Input::get_singleton()->get_default_cursor_shape()); return; } @@ -2030,6 +1954,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Ref<InputEventGesture> gesture_event = p_event; if (gesture_event.is_valid()) { + gui.key_event_accepted = false; + _gui_cancel_tooltip(); Size2 pos = gesture_event->get_position(); @@ -2122,6 +2048,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { top->notification(Control::NOTIFICATION_MODAL_CLOSE); top->_modal_stack_remove(); top->hide(); + // Close modal, set input as handled + get_tree()->set_input_as_handled(); + return; } } @@ -2183,8 +2112,14 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) { List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) { - gui.subwindow_order_dirty = true; - return gui.subwindows.push_back(p_control); + p_control->connect("visibility_changed", this, "_subwindow_visibility_changed"); + + if (p_control->is_visible_in_tree()) { + gui.subwindow_order_dirty = true; + gui.subwindows.push_back(p_control); + } + + return gui.all_known_subwindows.push_back(p_control); } void Viewport::_gui_set_subwindow_order_dirty() { @@ -2258,9 +2193,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) { p_control->set_position(gui.last_mouse_pos); p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport p_control->raise(); - if (gui.drag_preview) { - memdelete(gui.drag_preview); - } + gui.drag_preview = p_control; } @@ -2271,7 +2204,17 @@ void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) { void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) { - gui.subwindows.erase(SI); + ERR_FAIL_COND(!SI); + + Control *control = SI->get(); + + control->disconnect("visibility_changed", this, "_subwindow_visibility_changed"); + + List<Control *>::Element *E = gui.subwindows.find(control); + if (E) + gui.subwindows.erase(E); + + gui.all_known_subwindows.erase(SI); } void Viewport::_gui_unfocus_control(Control *p_control) { @@ -2298,7 +2241,7 @@ void Viewport::_gui_hid_control(Control *p_control) { */ if (gui.key_focus == p_control) - gui.key_focus = NULL; + _gui_remove_focus(); if (gui.mouse_over == p_control) gui.mouse_over = NULL; if (gui.tooltip == p_control) @@ -2369,19 +2312,16 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) { else p_control->_modal_set_prev_focus_owner(0); - if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus)) { + if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) { Ref<InputEventMouseButton> mb; mb.instance(); mb->set_position(gui.mouse_focus->get_local_mouse_position()); mb->set_global_position(gui.mouse_focus->get_local_mouse_position()); mb->set_button_index(gui.mouse_focus_button); mb->set_pressed(false); - gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); - - //if (gui.mouse_over == gui.mouse_focus) { - // gui.mouse_focus->notification(Control::NOTIFICATION_MOUSE_EXIT); - //} + Control *c = gui.mouse_focus; gui.mouse_focus = NULL; + c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); } return gui.modal_stack.back(); @@ -2394,9 +2334,22 @@ Control *Viewport::_gui_get_focus_owner() { void Viewport::_gui_grab_click_focus(Control *p_control) { + gui.mouse_click_grabber = p_control; + call_deferred("_post_gui_grab_click_focus"); +} + +void Viewport::_post_gui_grab_click_focus() { + + Control *focus_grabber = gui.mouse_click_grabber; + if (!focus_grabber) { + // Redundant grab requests were made + return; + } + gui.mouse_click_grabber = NULL; + if (gui.mouse_focus) { - if (gui.mouse_focus == p_control) + if (gui.mouse_focus == focus_grabber) return; Ref<InputEventMouseButton> mb; mb.instance(); @@ -2407,9 +2360,9 @@ void Viewport::_gui_grab_click_focus(Control *p_control) { mb->set_position(click); mb->set_button_index(gui.mouse_focus_button); mb->set_pressed(false); - gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb); + gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); - gui.mouse_focus = p_control; + gui.mouse_focus = focus_grabber; gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse(); click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos); mb->set_position(click); @@ -2512,9 +2465,14 @@ Rect2 Viewport::get_attach_to_screen_rect() const { void Viewport::set_physics_object_picking(bool p_enable) { physics_object_picking = p_enable; - set_physics_process(physics_object_picking); - if (!physics_object_picking) + if (!physics_object_picking) { physics_picking_events.clear(); + } +} + +bool Viewport::get_physics_object_picking() { + + return physics_object_picking; } Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const { @@ -2528,11 +2486,6 @@ Vector2 Viewport::get_camera_rect_size() const { return size; } -bool Viewport::get_physics_object_picking() { - - return physics_object_picking; -} - bool Viewport::gui_has_modal_stack() const { return gui.modal_stack.size(); @@ -2557,6 +2510,16 @@ bool Viewport::is_3d_disabled() const { return disable_3d; } +void Viewport::set_keep_3d_linear(bool p_keep_3d_linear) { + keep_3d_linear = p_keep_3d_linear; + VS::get_singleton()->viewport_set_keep_3d_linear(viewport, keep_3d_linear); +} + +bool Viewport::get_keep_3d_linear() const { + + return keep_3d_linear; +} + Variant Viewport::gui_get_drag_data() const { return gui.drag_data; } @@ -2672,9 +2635,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background); ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background); - ClassDB::bind_method(D_METHOD("_parent_visibility_changed"), &Viewport::_parent_visibility_changed); - - ClassDB::bind_method(D_METHOD("_parent_resized"), &Viewport::_parent_resized); ClassDB::bind_method(D_METHOD("_vp_input"), &Viewport::_vp_input); ClassDB::bind_method(D_METHOD("_vp_input_text", "text"), &Viewport::_vp_input_text); ClassDB::bind_method(D_METHOD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input); @@ -2743,8 +2703,12 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d); ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled); + ClassDB::bind_method(D_METHOD("set_keep_3d_linear", "keep_3d_linear"), &Viewport::set_keep_3d_linear); + ClassDB::bind_method(D_METHOD("get_keep_3d_linear"), &Viewport::get_keep_3d_linear); + ClassDB::bind_method(D_METHOD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip); ClassDB::bind_method(D_METHOD("_gui_remove_focus"), &Viewport::_gui_remove_focus); + ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus); ClassDB::bind_method(D_METHOD("set_shadow_atlas_size", "size"), &Viewport::set_shadow_atlas_size); ClassDB::bind_method(D_METHOD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size); @@ -2755,17 +2719,20 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv); ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv); + ClassDB::bind_method(D_METHOD("_subwindow_visibility_changed"), &Viewport::_subwindow_visibility_changed); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world"); - //ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world_2d",PROPERTY_HINT_RESOURCE_TYPE,"World2D"), "set_world_2d", "get_world_2d") ; + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background"); ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x"), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "get_hdr"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear"); ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); ADD_GROUP("Render Target", "render_target_"); @@ -2786,6 +2753,8 @@ void Viewport::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_1", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 1); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_2", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 2); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_3", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 3); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_canvas_transform", "get_canvas_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform"); ADD_SIGNAL(MethodInfo("size_changed")); @@ -2832,6 +2801,13 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME); } +void Viewport::_subwindow_visibility_changed() { + + // unfortunately, we don't know the sender, i.e. which subwindow changed; + // so we have to check them all. + gui.subwindow_visibility_dirty = true; +} + Viewport::Viewport() { world_2d = Ref<World2D>(memnew(World2D)); @@ -2886,6 +2862,7 @@ Viewport::Viewport() { disable_input = false; disable_3d = false; + keep_3d_linear = false; //window tooltip gui.tooltip_timer = -1; @@ -2898,6 +2875,7 @@ Viewport::Viewport() { gui.drag_preview = NULL; gui.drag_attempted = false; gui.canvas_sort_index = 0; + gui.roots_order_dirty = false; msaa = MSAA_DISABLED; hdr = true; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 92c53a7ab8..363414bbad 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -1,4 +1,3 @@ - /*************************************************************************/ /* viewport.h */ /*************************************************************************/ @@ -28,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VIEWPORT_H #define VIEWPORT_H @@ -206,12 +206,6 @@ private: void _test_new_mouseover(ObjectID new_collider); Map<ObjectID, uint64_t> physics_2d_mouseover; - void _update_rect(); - - void _parent_resized(); - void _parent_draw(); - void _parent_visibility_changed(); - Ref<World2D> world_2d; Ref<World> world; Ref<World> own_world; @@ -232,6 +226,7 @@ private: void _update_global_transform(); bool disable_3d; + bool keep_3d_linear; UpdateMode update_mode; RID texture_rid; uint32_t texture_flags; @@ -254,6 +249,7 @@ private: bool key_event_accepted; Control *mouse_focus; + Control *mouse_click_grabber; int mouse_focus_button; Control *key_focus; Control *mouse_over; @@ -271,7 +267,9 @@ private: List<Control *> modal_stack; Transform2D focus_inv_xform; bool subwindow_order_dirty; - List<Control *> subwindows; + bool subwindow_visibility_dirty; + List<Control *> subwindows; // visible subwindows + List<Control *> all_known_subwindows; bool roots_order_dirty; List<Control *> roots; int canvas_sort_index; //for sorting items with canvas as root @@ -282,6 +280,7 @@ private: bool disable_input; void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input); + void _gui_prepare_subwindows(); void _gui_sort_subwindows(); void _gui_sort_roots(); void _gui_sort_modal_stack(); @@ -294,9 +293,6 @@ private: _FORCE_INLINE_ Transform2D _get_input_pre_xform() const; - void _vp_enter_tree(); - void _vp_exit_tree(); - void _vp_input(const Ref<InputEvent> &p_ev); void _vp_input_text(const String &p_text); void _vp_unhandled_input(const Ref<InputEvent> &p_ev); @@ -332,6 +328,7 @@ private: bool _gui_control_has_focus(const Control *p_control); void _gui_control_grab_focus(Control *p_control); void _gui_grab_click_focus(Control *p_control); + void _post_gui_grab_click_focus(); void _gui_accept_event(); Control *_gui_get_focus_owner(); @@ -440,6 +437,9 @@ public: void set_disable_3d(bool p_disable); bool is_3d_disabled() const; + void set_keep_3d_linear(bool p_keep_3d_linear); + bool get_keep_3d_linear() const; + void set_attach_to_screen_rect(const Rect2 &p_rect); Rect2 get_attach_to_screen_rect() const; @@ -470,6 +470,8 @@ public: void set_snap_controls_to_pixels(bool p_enable); bool is_snap_controls_to_pixels_enabled() const; + void _subwindow_visibility_changed(); + Viewport(); ~Viewport(); }; |