diff options
Diffstat (limited to 'scene')
25 files changed, 288 insertions, 51 deletions
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index b527a72de6..7b9f7e14ca 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -50,6 +50,7 @@ void Joint2D::_disconnect_signals() { void Joint2D::_body_exit_tree() { _disconnect_signals(); _update_joint(true); + update_configuration_warnings(); } void Joint2D::_update_joint(bool p_only_free) { @@ -64,7 +65,6 @@ void Joint2D::_update_joint(bool p_only_free) { if (p_only_free || !is_inside_tree()) { PhysicsServer2D::get_singleton()->joint_clear(joint); warning = String(); - update_configuration_warnings(); return; } diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index daa6d83867..00082b321e 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -37,6 +37,9 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent2D::get_rid); + ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationAgent2D::set_avoidance_enabled); + ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationAgent2D::get_avoidance_enabled); + ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent2D::set_target_desired_distance); ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent2D::get_target_desired_distance); @@ -82,6 +85,7 @@ void NavigationAgent2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigable_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigable_layers", "get_navigable_layers"); ADD_SIGNAL(MethodInfo("path_changed")); @@ -97,7 +101,7 @@ void NavigationAgent2D::_notification(int p_what) { if (agent_parent != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); - NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); + set_avoidance_enabled(avoidance_enabled); } set_physics_process_internal(true); } break; @@ -150,6 +154,19 @@ NavigationAgent2D::~NavigationAgent2D() { agent = RID(); // Pointless } +void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) { + avoidance_enabled = p_enabled; + if (avoidance_enabled) { + NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); + } else { + NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done"); + } +} + +bool NavigationAgent2D::get_avoidance_enabled() const { + return avoidance_enabled; +} + void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) { bool layers_changed = navigable_layers != p_layers; navigable_layers = p_layers; @@ -268,7 +285,7 @@ TypedArray<String> NavigationAgent2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node2D>(get_parent())) { - warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D node.")); + warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D inheriting parent node.")); } return warnings; diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 2a401190d0..5ab4cdba5d 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -43,6 +43,7 @@ class NavigationAgent2D : public Node { RID agent; RID map_before_pause; + bool avoidance_enabled = false; uint32_t navigable_layers = 1; real_t target_desired_distance = 1.0; @@ -78,6 +79,9 @@ public: return agent; } + void set_avoidance_enabled(bool p_enabled); + bool get_avoidance_enabled() const; + void set_navigable_layers(uint32_t p_layers); uint32_t get_navigable_layers() const; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index f2eb2cef2d..8008512546 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -582,7 +582,7 @@ void GPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime,View Depth"), "set_draw_order", "get_draw_order"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,Z-Billboard,Y to Velocity,Z-Billboard + Y to Velocity"), "set_transform_align", "get_transform_align"); ADD_GROUP("Trails", "trail_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length"); diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index c22e3f6d91..b6fc83e599 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -49,6 +49,7 @@ void Joint3D::_disconnect_signals() { void Joint3D::_body_exit_tree() { _disconnect_signals(); _update_joint(true); + update_configuration_warnings(); } void Joint3D::_update_joint(bool p_only_free) { @@ -65,7 +66,6 @@ void Joint3D::_update_joint(bool p_only_free) { if (p_only_free || !is_inside_tree()) { PhysicsServer3D::get_singleton()->joint_clear(joint); warning = String(); - update_configuration_warnings(); return; } diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index 2d7da48ab1..78da22a0c3 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -788,6 +788,11 @@ Ref<Font> Label3D::get_font() const { } Ref<Font> Label3D::_get_font_or_default() const { + if (theme_font.is_valid()) { + theme_font->disconnect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + theme_font.unref(); + } + if (font_override.is_valid() && font_override->get_data_count() > 0) { return font_override; } @@ -799,7 +804,12 @@ Ref<Font> Label3D::_get_font_or_default() const { for (const StringName &E : theme_types) { if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (f.is_valid()) { + theme_font = f; + theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + } + return f; } } } @@ -811,13 +821,23 @@ Ref<Font> Label3D::_get_font_or_default() const { for (const StringName &E : theme_types) { if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (f.is_valid()) { + theme_font = f; + theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + } + return f; } } } // If they don't exist, use any type to return the default/empty value. - return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + if (f.is_valid()) { + theme_font = f; + theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + } + return f; } void Label3D::set_font_size(int p_size) { diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h index f57797a247..62f4c3fe96 100644 --- a/scene/3d/label_3d.h +++ b/scene/3d/label_3d.h @@ -96,6 +96,7 @@ private: int font_size = 16; Ref<Font> font_override; + mutable Ref<Font> theme_font; Color modulate = Color(1, 1, 1, 1); Point2 lbl_offset; int outline_render_priority = -1; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index fb19479eb9..88f676d031 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -35,6 +35,9 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent3D::get_rid); + ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationAgent3D::set_avoidance_enabled); + ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationAgent3D::get_avoidance_enabled); + ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance); ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance); @@ -88,6 +91,7 @@ void NavigationAgent3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m/s"), "set_max_speed", "get_max_speed"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigable_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigable_layers", "get_navigable_layers"); ADD_SIGNAL(MethodInfo("path_changed")); @@ -103,7 +107,7 @@ void NavigationAgent3D::_notification(int p_what) { if (agent_parent != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map()); - NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); + set_avoidance_enabled(avoidance_enabled); } set_physics_process_internal(true); } break; @@ -157,6 +161,19 @@ NavigationAgent3D::~NavigationAgent3D() { agent = RID(); // Pointless } +void NavigationAgent3D::set_avoidance_enabled(bool p_enabled) { + avoidance_enabled = p_enabled; + if (avoidance_enabled) { + NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); + } else { + NavigationServer3D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done"); + } +} + +bool NavigationAgent3D::get_avoidance_enabled() const { + return avoidance_enabled; +} + void NavigationAgent3D::set_navigable_layers(uint32_t p_layers) { bool layers_changed = navigable_layers != p_layers; navigable_layers = p_layers; @@ -283,7 +300,7 @@ TypedArray<String> NavigationAgent3D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node3D>(get_parent())) { - warnings.push_back(RTR("The NavigationAgent3D can be used only under a spatial node.")); + warnings.push_back(RTR("The NavigationAgent3D can be used only under a Node3D inheriting parent node.")); } return warnings; diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 6a88bd13e2..28bcffd5b4 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -43,6 +43,7 @@ class NavigationAgent3D : public Node { RID agent; RID map_before_pause; + bool avoidance_enabled = false; uint32_t navigable_layers = 1; real_t target_desired_distance = 1.0; @@ -80,6 +81,9 @@ public: return agent; } + void set_avoidance_enabled(bool p_enabled); + bool get_avoidance_enabled() const; + void set_navigable_layers(uint32_t p_layers); uint32_t get_navigable_layers() const; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 39849a0b00..fcc4548929 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -551,7 +551,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } } - // time left must always be 1 because the end node don't lenght to compute + // time left must always be 1 because the end node don't length to compute if (p_state_machine->end_node != current) { rem = 1; } else { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 903e7a26a1..db78b4adb6 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -836,6 +836,7 @@ void Control::_notification(int p_notification) { } } else { data.minimum_size_valid = false; + _update_minimum_size(); _size_changed(); } } break; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 050c510a96..0f74c9c357 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2452,17 +2452,17 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { if (p_word) { int column = caret.column; // Check for the case "<word><space><caret>" and ignore the space. - // No need to check for column being 0 since it is cheked above. + // No need to check for column being 0 since it is checked above. if (is_whitespace(text[caret.line][caret.column - 1])) { column -= 1; } // Get a list with the indices of the word bounds of the given text line. const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid()); if (words.is_empty() || column <= words[0]) { - // If "words" is empty, meaning no words are left, we can remove everything until the begining of the line. + // If "words" is empty, meaning no words are left, we can remove everything until the beginning of the line. column = 0; } else { - // Otherwise search for the first word break that is smaller than the index from we're currentlu deleteing + // Otherwise search for the first word break that is smaller than the index from which we're currently deleting. for (int i = words.size() - 2; i >= 0; i = i - 2) { if (words[i] < column) { column = words[i]; diff --git a/scene/multiplayer/multiplayer_spawner.cpp b/scene/multiplayer/multiplayer_spawner.cpp index a9b9ffa989..ddd01d0a43 100644 --- a/scene/multiplayer/multiplayer_spawner.cpp +++ b/scene/multiplayer/multiplayer_spawner.cpp @@ -35,12 +35,106 @@ #include "scene/main/window.h" #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED +/* This is editor only */ +bool MultiplayerSpawner::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "_spawnable_scene_count") { + spawnable_scenes.resize(p_value); + notify_property_list_changed(); + return true; + } else { + String ns = p_name; + if (ns.begins_with("scenes/")) { + uint32_t index = ns.get_slicec('/', 1).to_int(); + ERR_FAIL_UNSIGNED_INDEX_V(index, spawnable_scenes.size(), false); + spawnable_scenes[index].path = p_value; + return true; + } + } + return false; +} + +bool MultiplayerSpawner::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "_spawnable_scene_count") { + r_ret = spawnable_scenes.size(); + return true; + } else { + String ns = p_name; + if (ns.begins_with("scenes/")) { + uint32_t index = ns.get_slicec('/', 1).to_int(); + ERR_FAIL_UNSIGNED_INDEX_V(index, spawnable_scenes.size(), false); + r_ret = spawnable_scenes[index].path; + return true; + } + } + return false; +} + +void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::INT, "_spawnable_scene_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Scenes,scenes/")); + List<String> exts; + ResourceLoader::get_recognized_extensions_for_type("PackedScene", &exts); + String ext_hint; + for (const String &E : exts) { + if (!ext_hint.is_empty()) { + ext_hint += ","; + } + ext_hint += "*." + E; + } + for (uint32_t i = 0; i < spawnable_scenes.size(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, "scenes/" + itos(i), PROPERTY_HINT_FILE, ext_hint, PROPERTY_USAGE_EDITOR)); + } +} +#endif +void MultiplayerSpawner::add_spawnable_scene(const String &p_path) { + SpawnableScene sc; + sc.path = p_path; + if (Engine::get_singleton()->is_editor_hint()) { + ERR_FAIL_COND(!FileAccess::exists(p_path)); + } else { + sc.cache = ResourceLoader::load(p_path); + ERR_FAIL_COND_MSG(sc.cache.is_null(), "Invalid spawnable scene: " + p_path); + } + spawnable_scenes.push_back(sc); +} +int MultiplayerSpawner::get_spawnable_scene_count() const { + return spawnable_scenes.size(); +} +String MultiplayerSpawner::get_spawnable_scene(int p_idx) const { + return spawnable_scenes[p_idx].path; +} +void MultiplayerSpawner::clear_spawnable_scenes() { + spawnable_scenes.clear(); +} + +Vector<String> MultiplayerSpawner::_get_spawnable_scenes() const { + Vector<String> ss; + ss.resize(spawnable_scenes.size()); + for (int i = 0; i < ss.size(); i++) { + ss.write[i] = spawnable_scenes[i].path; + } + return ss; +} + +void MultiplayerSpawner::_set_spawnable_scenes(const Vector<String> &p_scenes) { + clear_spawnable_scenes(); + for (int i = 0; i < p_scenes.size(); i++) { + add_spawnable_scene(p_scenes[i]); + } +} + void MultiplayerSpawner::_bind_methods() { - ClassDB::bind_method(D_METHOD("spawn", "data"), &MultiplayerSpawner::spawn, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("add_spawnable_scene", "path"), &MultiplayerSpawner::add_spawnable_scene); + ClassDB::bind_method(D_METHOD("get_spawnable_scene_count"), &MultiplayerSpawner::get_spawnable_scene_count); + ClassDB::bind_method(D_METHOD("get_spawnable_scene", "path"), &MultiplayerSpawner::get_spawnable_scene); + ClassDB::bind_method(D_METHOD("clear_spawnable_scenes"), &MultiplayerSpawner::clear_spawnable_scenes); + + ClassDB::bind_method(D_METHOD("_get_spawnable_scenes"), &MultiplayerSpawner::_get_spawnable_scenes); + ClassDB::bind_method(D_METHOD("_set_spawnable_scenes", "scenes"), &MultiplayerSpawner::_set_spawnable_scenes); - ClassDB::bind_method(D_METHOD("get_spawnable_scenes"), &MultiplayerSpawner::get_spawnable_scenes); - ClassDB::bind_method(D_METHOD("set_spawnable_scenes", "scenes"), &MultiplayerSpawner::set_spawnable_scenes); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "replication", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_spawnable_scenes", "get_spawnable_scenes"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_spawnable_scenes", PROPERTY_HINT_NONE, "", (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL)), "_set_spawnable_scenes", "_get_spawnable_scenes"); + + ClassDB::bind_method(D_METHOD("spawn", "data"), &MultiplayerSpawner::spawn, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("get_spawn_path"), &MultiplayerSpawner::get_spawn_path); ClassDB::bind_method(D_METHOD("set_spawn_path", "path"), &MultiplayerSpawner::set_spawn_path); @@ -118,7 +212,7 @@ void MultiplayerSpawner::_node_added(Node *p_node) { if (!parent || p_node->get_parent() != parent) { return; } - int id = get_scene_id(p_node->get_scene_file_path()); + int id = find_spawnable_scene_index_from_path(p_node->get_scene_file_path()); if (id == INVALID_ID) { return; } @@ -136,14 +230,6 @@ bool MultiplayerSpawner::is_auto_spawning() const { return auto_spawn; } -TypedArray<PackedScene> MultiplayerSpawner::get_spawnable_scenes() { - return spawnable_scenes; -} - -void MultiplayerSpawner::set_spawnable_scenes(TypedArray<PackedScene> p_scenes) { - spawnable_scenes = p_scenes; -} - NodePath MultiplayerSpawner::get_spawn_path() const { return spawn_path; } @@ -175,18 +261,16 @@ void MultiplayerSpawner::_node_exit(ObjectID p_id) { } } -int MultiplayerSpawner::get_scene_id(const String &p_scene) const { - for (int i = 0; i < spawnable_scenes.size(); i++) { - Ref<PackedScene> ps = spawnable_scenes[i]; - ERR_CONTINUE(ps.is_null()); - if (ps->get_path() == p_scene) { +int MultiplayerSpawner::find_spawnable_scene_index_from_path(const String &p_scene) const { + for (uint32_t i = 0; i < spawnable_scenes.size(); i++) { + if (spawnable_scenes[i].path == p_scene) { return i; } } return INVALID_ID; } -int MultiplayerSpawner::get_spawn_id(const ObjectID &p_id) const { +int MultiplayerSpawner::find_spawnable_scene_index_from_object(const ObjectID &p_id) const { const SpawnInfo *info = tracked_nodes.getptr(p_id); return info ? info->id : INVALID_ID; } @@ -198,8 +282,8 @@ const Variant MultiplayerSpawner::get_spawn_argument(const ObjectID &p_id) const Node *MultiplayerSpawner::instantiate_scene(int p_id) { ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!"); - ERR_FAIL_INDEX_V(p_id, spawnable_scenes.size(), nullptr); - Ref<PackedScene> scene = spawnable_scenes[p_id]; + ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_id, spawnable_scenes.size(), nullptr); + Ref<PackedScene> scene = spawnable_scenes[p_id].cache; ERR_FAIL_COND_V(scene.is_null(), nullptr); return scene->instantiate(); } diff --git a/scene/multiplayer/multiplayer_spawner.h b/scene/multiplayer/multiplayer_spawner.h index 8fbc9c4803..e8abe702a0 100644 --- a/scene/multiplayer/multiplayer_spawner.h +++ b/scene/multiplayer/multiplayer_spawner.h @@ -33,6 +33,7 @@ #include "scene/main/node.h" +#include "core/templates/local_vector.h" #include "core/variant/typed_array.h" #include "scene/resources/packed_scene.h" #include "scene/resources/scene_replication_config.h" @@ -46,7 +47,13 @@ public: }; private: - TypedArray<PackedScene> spawnable_scenes; + struct SpawnableScene { + String path; + Ref<PackedScene> cache; + }; + + LocalVector<SpawnableScene> spawnable_scenes; + HashSet<ResourceUID::ID> spawnable_ids; NodePath spawn_path; @@ -71,14 +78,26 @@ private: void _node_exit(ObjectID p_id); void _node_ready(ObjectID p_id); + Vector<String> _get_spawnable_scenes() const; + void _set_spawnable_scenes(const Vector<String> &p_scenes); + protected: static void _bind_methods(); void _notification(int p_what); +#ifdef TOOLS_ENABLED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; +#endif public: Node *get_spawn_node() const { return spawn_node.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)) : nullptr; } - TypedArray<PackedScene> get_spawnable_scenes(); - void set_spawnable_scenes(TypedArray<PackedScene> p_scenes); + + void add_spawnable_scene(const String &p_path); + int get_spawnable_scene_count() const; + String get_spawnable_scene(int p_idx) const; + void clear_spawnable_scenes(); + NodePath get_spawn_path() const; void set_spawn_path(const NodePath &p_path); uint32_t get_spawn_limit() const { return spawn_limit; } @@ -87,8 +106,8 @@ public: void set_auto_spawning(bool p_enabled); const Variant get_spawn_argument(const ObjectID &p_id) const; - int get_spawn_id(const ObjectID &p_id) const; - int get_scene_id(const String &p_path) const; + int find_spawnable_scene_index_from_object(const ObjectID &p_id) const; + int find_spawnable_scene_index_from_path(const String &p_path) const; Node *spawn(const Variant &p_data = Variant()); Node *instantiate_custom(const Variant &p_data); Node *instantiate_scene(int p_idx); diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp index 33e845a7a3..34d5abf9f6 100644 --- a/scene/multiplayer/multiplayer_synchronizer.cpp +++ b/scene/multiplayer/multiplayer_synchronizer.cpp @@ -96,7 +96,7 @@ void MultiplayerSynchronizer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config); ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "congiruation", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); } void MultiplayerSynchronizer::_notification(int p_what) { diff --git a/scene/multiplayer/multiplayer_synchronizer.h b/scene/multiplayer/multiplayer_synchronizer.h index e856745379..f61ef459da 100644 --- a/scene/multiplayer/multiplayer_synchronizer.h +++ b/scene/multiplayer/multiplayer_synchronizer.h @@ -40,7 +40,7 @@ class MultiplayerSynchronizer : public Node { private: Ref<SceneReplicationConfig> replication_config; - NodePath root_path; + NodePath root_path = NodePath(".."); // Start with parent, like with AnimationPlayer. uint64_t interval_msec = 0; static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop); diff --git a/scene/multiplayer/scene_replication_interface.cpp b/scene/multiplayer/scene_replication_interface.cpp index 19c69adb4a..e4715ceb88 100644 --- a/scene/multiplayer/scene_replication_interface.cpp +++ b/scene/multiplayer/scene_replication_interface.cpp @@ -167,7 +167,7 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p uint32_t nid = rep_state->ensure_net_id(oid); // Prepare custom arg and scene_id - uint8_t scene_id = p_spawner->get_spawn_id(oid); + uint8_t scene_id = p_spawner->find_spawnable_scene_index_from_object(oid); bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID; Variant spawn_arg = p_spawner->get_spawn_argument(oid); int spawn_arg_size = 0; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index f795e0ffd0..b90f396110 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -544,7 +544,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has Variant value = p_node->get(name); if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) { - // Was this missing resource overriden? If so do not save the old value. + // Was this missing resource overridden? If so do not save the old value. Ref<Resource> ures = value; if (ures.is_null()) { value = missing_resource_properties[E.name]; @@ -613,7 +613,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has if (states_stack.is_empty() && !is_editable_instance) { //this node is not part of an instancing process, so save the type if (missing_node != nullptr) { - // Its a missing node (type non existant on load). + // It's a missing node (type non existent on load). nd.type = _nm_get_string(missing_node->get_original_class(), name_map); } else { nd.type = _nm_get_string(p_node->get_class(), name_map); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 4d83f8772e..36f5f92085 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -2229,17 +2229,27 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con } } else if (points[j].z == TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC) { // Cubic Bezier arc. + int32_t cur = j; int32_t next1 = (j == end) ? start : (j + 1); int32_t next2 = (next1 == end) ? start : (next1 + 1); int32_t prev = (j == start) ? end : (j - 1); // There must be exactly two OFF points and two ON points for each cubic arc. + if (points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON) { + cur = (cur == 0) ? end : cur - 1; + next1 = (next1 == 0) ? end : next1 - 1; + next2 = (next2 == 0) ? end : next2 - 1; + prev = (prev == 0) ? end : prev - 1; + } else { + j++; + } ERR_FAIL_COND_MSG(points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, prev)); + ERR_FAIL_COND_MSG(points[cur].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, cur)); ERR_FAIL_COND_MSG(points[next1].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, next1)); ERR_FAIL_COND_MSG(points[next2].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, next2)); Vector2 p0 = Vector2(points[prev].x, points[prev].y); - Vector2 p1 = Vector2(points[j].x, points[j].y); + Vector2 p1 = Vector2(points[cur].x, points[cur].y); Vector2 p2 = Vector2(points[next1].x, points[next1].y); Vector2 p3 = Vector2(points[next2].x, points[next2].y); @@ -2257,7 +2267,6 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con polygon.push_back(ContourPoint(p, false)); t += step; } - i++; } else { ERR_FAIL_MSG(vformat("Unknown point tag at %d:%d", i, j)); } @@ -2393,6 +2402,10 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { Vector2 offset_pre = offset; for (int i = 0; i < gl_size; i++) { + if (glyphs[i].index == 0) { + offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; + continue; + } if (glyphs[i].font_rid != RID()) { uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id()); hash = hash_djb2_one_32(glyphs[i].index, hash); @@ -2448,6 +2461,10 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { int32_t p_idx = 0; int32_t i_idx = 0; for (int i = 0; i < gl_size; i++) { + if (glyphs[i].index == 0) { + offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; + continue; + } if (glyphs[i].font_rid != RID()) { uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id()); hash = hash_djb2_one_32(glyphs[i].index, hash); @@ -2587,7 +2604,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { } if (p_size == 0) { - // If empty, add single trinagle to suppress errors. + // If empty, add single triangle to suppress errors. vertices.push_back(Vector3()); normals.push_back(Vector3()); uvs.push_back(Vector2()); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 72d66ee4f5..9d586c6f03 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1891,7 +1891,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso } if (PE->get().type == Variant::OBJECT && missing_resource_properties.has(PE->get().name)) { - // Was this missing resource overriden? If so do not save the old value. + // Was this missing resource overridden? If so do not save the old value. Ref<Resource> ures = value; if (ures.is_null()) { value = missing_resource_properties[PE->get().name]; diff --git a/scene/resources/scene_replication_config.cpp b/scene/resources/scene_replication_config.cpp index 2acc0f1922..4aea04bf87 100644 --- a/scene/resources/scene_replication_config.cpp +++ b/scene/resources/scene_replication_config.cpp @@ -124,6 +124,15 @@ void SceneReplicationConfig::remove_property(const NodePath &p_path) { properties.erase(p_path); } +bool SceneReplicationConfig::has_property(const NodePath &p_path) const { + for (int i = 0; i < properties.size(); i++) { + if (properties[i].name == p_path) { + return true; + } + } + return false; +} + int SceneReplicationConfig::property_get_index(const NodePath &p_path) const { for (int i = 0; i < properties.size(); i++) { if (properties[i].name == p_path) { @@ -178,6 +187,7 @@ void SceneReplicationConfig::property_set_sync(const NodePath &p_path, bool p_en void SceneReplicationConfig::_bind_methods() { ClassDB::bind_method(D_METHOD("get_properties"), &SceneReplicationConfig::get_properties); ClassDB::bind_method(D_METHOD("add_property", "path", "index"), &SceneReplicationConfig::add_property, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("has_property", "path"), &SceneReplicationConfig::has_property); ClassDB::bind_method(D_METHOD("remove_property", "path"), &SceneReplicationConfig::remove_property); ClassDB::bind_method(D_METHOD("property_get_index", "path"), &SceneReplicationConfig::property_get_index); ClassDB::bind_method(D_METHOD("property_get_spawn", "path"), &SceneReplicationConfig::property_get_spawn); diff --git a/scene/resources/scene_replication_config.h b/scene/resources/scene_replication_config.h index b791be9414..ab3658d2a7 100644 --- a/scene/resources/scene_replication_config.h +++ b/scene/resources/scene_replication_config.h @@ -73,6 +73,7 @@ public: void add_property(const NodePath &p_path, int p_index = -1); void remove_property(const NodePath &p_path); + bool has_property(const NodePath &p_path) const; int property_get_index(const NodePath &p_path) const; bool property_get_spawn(const NodePath &p_path); diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index fc1e610e98..92efe3ce6f 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -83,5 +83,5 @@ void SphereShape3D::_bind_methods() { SphereShape3D::SphereShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) { - set_radius(1.0); + set_radius(0.5); } diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index 20887dd092..8f77378ef4 100644 --- a/scene/resources/sphere_shape_3d.h +++ b/scene/resources/sphere_shape_3d.h @@ -35,7 +35,7 @@ class SphereShape3D : public Shape3D { GDCLASS(SphereShape3D, Shape3D); - float radius = 1.0f; + float radius = 0.5f; protected: static void _bind_methods(); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 18bb0ff01d..47bb1b264c 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -910,6 +910,48 @@ void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_c return; } VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(p_new_class)); + VisualShaderNode *prev_vsn = g->nodes[p_id].node.ptr(); + + // Update connection data. + for (int i = 0; i < vsn->get_output_port_count(); i++) { + if (i < prev_vsn->get_output_port_count()) { + if (prev_vsn->is_output_port_connected(i)) { + vsn->set_output_port_connected(i, true); + } + + if (prev_vsn->is_output_port_expandable(i) && prev_vsn->_is_output_port_expanded(i) && vsn->is_output_port_expandable(i)) { + vsn->_set_output_port_expanded(i, true); + + int component_count = 0; + switch (prev_vsn->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_VECTOR_2D: + component_count = 2; + break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: + component_count = 3; + break; + case VisualShaderNode::PORT_TYPE_VECTOR_4D: + component_count = 4; + break; + default: + break; + } + + for (int j = 0; j < component_count; j++) { + int sub_port = i + 1 + j; + + if (prev_vsn->is_output_port_connected(sub_port)) { + vsn->set_output_port_connected(sub_port, true); + } + } + + i += component_count; + } + } else { + break; + } + } + vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update)); g->nodes[p_id].node = Ref<VisualShaderNode>(vsn); |