diff options
26 files changed, 168 insertions, 61 deletions
diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 553698f8a6..ab30fb1ca3 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -489,7 +489,7 @@ bool ResourceCache::has(const String &p_path) { Resource **res = resources.getptr(p_path); - if (res && (*res)->reference_get_count() == 0) { + if (res && (*res)->get_reference_count() == 0) { // This resource is in the process of being deleted, ignore its existence. (*res)->path_cache = String(); resources.erase(p_path); diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp index cac2400744..50467d795d 100644 --- a/core/object/ref_counted.cpp +++ b/core/object/ref_counted.cpp @@ -48,9 +48,10 @@ void RefCounted::_bind_methods() { ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref); ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference); ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference); + ClassDB::bind_method(D_METHOD("get_reference_count"), &RefCounted::get_reference_count); } -int RefCounted::reference_get_count() const { +int RefCounted::get_reference_count() const { return refcount.get(); } diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h index bd06a84bd8..71790fb825 100644 --- a/core/object/ref_counted.h +++ b/core/object/ref_counted.h @@ -47,7 +47,7 @@ public: bool init_ref(); bool reference(); // returns false if refcount is at zero and didn't get increased bool unreference(); - int reference_get_count() const; + int get_reference_count() const; RefCounted(); ~RefCounted() {} diff --git a/doc/classes/DirAccess.xml b/doc/classes/DirAccess.xml index cb7bf56f11..af498a6519 100644 --- a/doc/classes/DirAccess.xml +++ b/doc/classes/DirAccess.xml @@ -9,11 +9,10 @@ Most of the methods have a static alternative that can be used without creating a [DirAccess]. Static methods only support absolute paths (including [code]res://[/code] and [code]user://[/code]). [codeblock] # Standard - var dir = Directory.new() - dir.open("user://levels") + var dir = DirAccess.open("user://levels") dir.make_dir("world1") # Static - Directory.make_dir_absolute("user://levels/world1") + DirAccess.make_dir_absolute("user://levels/world1") [/codeblock] [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources. Here is an example on how to iterate through the files of a directory: diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index 348347c4ef..c395815117 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -9,7 +9,7 @@ Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec": [codeblocks] [gdscript] - tool + @tool extends EditorImportPlugin func _get_importer_name(): @@ -44,7 +44,7 @@ # Fill the Mesh with data read in "file", left as an exercise to the reader. var filename = save_path + "." + _get_save_extension() - return ResourceSaver.save(filename, mesh) + return ResourceSaver.save(mesh, filename) [/gdscript] [csharp] using Godot; @@ -103,7 +103,7 @@ var mesh = new ArrayMesh(); // Fill the Mesh with data read in "file", left as an exercise to the reader. String filename = savePath + "." + GetSaveExtension(); - return (int)ResourceSaver.Save(filename, mesh); + return (int)ResourceSaver.Save(mesh, filename); } } [/csharp] diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml index 395b094bf2..2bf2accf17 100644 --- a/doc/classes/EditorScenePostImport.xml +++ b/doc/classes/EditorScenePostImport.xml @@ -8,7 +8,7 @@ The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example: [codeblocks] [gdscript] - tool # Needed so it runs in editor. + @tool # Needed so it runs in editor. extends EditorScenePostImport # This sample changes all node names. # Called right after the scene is imported and gets the root node. diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml index 2ff8a7ba2a..dfc04c9cde 100644 --- a/doc/classes/EditorScript.xml +++ b/doc/classes/EditorScript.xml @@ -9,7 +9,7 @@ [b]Example script:[/b] [codeblocks] [gdscript] - tool + @tool extends EditorScript func _run(): diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml index 08986781cd..df10c645ef 100644 --- a/doc/classes/EditorTranslationParserPlugin.xml +++ b/doc/classes/EditorTranslationParserPlugin.xml @@ -11,7 +11,7 @@ Below shows an example of a custom parser that extracts strings from a CSV file to write into a POT. [codeblocks] [gdscript] - tool + @tool extends EditorTranslationParserPlugin func _parse_file(path, msgids, msgids_context_plural): diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml index 89f7dcb4af..0f28081201 100644 --- a/doc/classes/NavigationRegion2D.xml +++ b/doc/classes/NavigationRegion2D.xml @@ -10,6 +10,7 @@ The pathfinding cost of entering this region from another region can be controlled with the [member enter_cost] value. [b]Note:[/b] This value is not added to the path cost when the start position is already inside this region. The pathfinding cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier. + [b]Note:[/b] This node caches changes to its properties, so if you make changes to the underlying region [RID] in [NavigationServer2D], they will not be reflected in this node's properties. </description> <tutorials> </tutorials> diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml index 87e82e7b2e..85f163b3c2 100644 --- a/doc/classes/NavigationRegion3D.xml +++ b/doc/classes/NavigationRegion3D.xml @@ -10,6 +10,7 @@ The cost of entering this region from another region can be controlled with the [member enter_cost] value. [b]Note:[/b] This value is not added to the path cost when the start position is already inside this region. The cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier. + [b]Note:[/b] This node caches changes to its properties, so if you make changes to the underlying region [RID] in [NavigationServer3D], they will not be reflected in this node's properties. </description> <tutorials> </tutorials> diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml index 97595a6984..7ca1d5d60d 100644 --- a/doc/classes/PackedScene.xml +++ b/doc/classes/PackedScene.xml @@ -41,7 +41,7 @@ # Only `node` and `body` are now packed. var result = scene.pack(node) if result == OK: - var error = ResourceSaver.save("res://path/name.tscn", scene) # Or "user://..." + var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..." if error != OK: push_error("An error occurred while saving the scene to disk.") [/gdscript] @@ -63,7 +63,7 @@ Error result = scene.Pack(node); if (result == Error.Ok) { - Error error = ResourceSaver.Save("res://path/name.tscn", scene); // Or "user://..." + Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..." if (error != Error.Ok) { GD.PushError("An error occurred while saving the scene to disk."); diff --git a/doc/classes/RefCounted.xml b/doc/classes/RefCounted.xml index 3daf3534b0..223e572254 100644 --- a/doc/classes/RefCounted.xml +++ b/doc/classes/RefCounted.xml @@ -13,6 +13,12 @@ <link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link> </tutorials> <methods> + <method name="get_reference_count" qualifiers="const"> + <return type="int" /> + <description> + Returns the current reference count. + </description> + </method> <method name="init_ref"> <return type="bool" /> <description> diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index c1761339b2..1e0f45419f 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1009,6 +1009,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { vars_list_root = vars_list->create_item(); + import_settings_data->settings.clear(); import_settings_data->defaults.clear(); for (List<ResourceImporter::ImportOption>::Element *E = options_general.front(); E; E = E->next()) { import_settings_data->defaults[E->get().option.name] = E->get().default_value; diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index 2df951518e..ba11479714 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -622,6 +622,16 @@ void EditorPropertyOTFeatures::update_property() { supported = fd->get_supported_feature_list(); } + if (supported.is_empty()) { + edit->set_text(vformat(TTR("No supported features"))); + if (container) { + set_bottom_editor(nullptr); + memdelete(container); + button_add = nullptr; + container = nullptr; + } + return; + } edit->set_text(vformat(TTR("Features (%d of %d set)"), dict.size(), supported.size())); bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 6fff2ab7cb..0b1e9719b7 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -30,6 +30,7 @@ #include "scene_tree_editor.h" +#include "core/config/project_settings.h" #include "core/object/message_queue.h" #include "core/string/print_string.h" #include "editor/editor_file_system.h" @@ -942,14 +943,16 @@ void SceneTreeEditor::_renamed() { Node *n = get_node(np); ERR_FAIL_COND(!n); - // Empty node names are not allowed, so resets it to previous text and show warning - if (which->get_text(0).strip_edges().is_empty()) { - which->set_text(0, n->get_name()); - EditorNode::get_singleton()->show_warning(TTR("No name provided.")); - return; + String raw_new_name = which->get_text(0); + if (raw_new_name.strip_edges().is_empty()) { + // If name is empty, fallback to class name. + if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) { + raw_new_name = Node::adjust_name_casing(n->get_class()); + } else { + raw_new_name = n->get_class(); + } } - String raw_new_name = which->get_text(0); String new_name = raw_new_name.validate_node_name(); if (new_name != raw_new_name) { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 8fd3626a20..97a1d5c8d8 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1299,7 +1299,7 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, MonoGCHandleData &gchandle = script_binding.gchandle; - int refcount = rc_owner->reference_get_count(); + int refcount = rc_owner->get_reference_count(); if (!script_binding.inited) { return refcount == 0; @@ -1818,7 +1818,7 @@ void CSharpInstance::refcount_incremented() { RefCounted *rc_owner = Object::cast_to<RefCounted>(owner); - if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + if (rc_owner->get_reference_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 // The reference count was increased after the managed side was the only one referencing our owner. // This means the owner is being referenced again by the unmanaged side, // so the owner must hold the managed side alive again to avoid it from being GCed. @@ -1849,7 +1849,7 @@ bool CSharpInstance::refcount_decremented() { RefCounted *rc_owner = Object::cast_to<RefCounted>(owner); - int refcount = rc_owner->reference_get_count(); + int refcount = rc_owner->get_reference_count(); if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 // If owner owner is no longer referenced by the unmanaged side, @@ -1995,7 +1995,7 @@ CSharpInstance::~CSharpInstance() { #ifdef DEBUG_ENABLED // The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope - CRASH_COND(rc_owner->reference_get_count() <= 1); + CRASH_COND(rc_owner->get_reference_count() <= 1); #endif } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs new file mode 100644 index 0000000000..ddde730fa2 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs @@ -0,0 +1,53 @@ +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Godot.SourceGenerators +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class EventHandlerSuffixSuppressor : DiagnosticSuppressor + { + private static readonly SuppressionDescriptor _descriptor = new( + id: "GDSP0001", + suppressedDiagnosticId: "CA1711", + justification: "Signal delegates are used in events so the naming follows the guidelines."); + + public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => + ImmutableArray.Create(_descriptor); + + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (var diagnostic in context.ReportedDiagnostics) + { + AnalyzeDiagnostic(context, diagnostic, context.CancellationToken); + } + } + + private static void AnalyzeDiagnostic(SuppressionAnalysisContext context, Diagnostic diagnostic, CancellationToken cancellationToken = default) + { + var location = diagnostic.Location; + var root = location.SourceTree?.GetRoot(cancellationToken); + var dds = root? + .FindNode(location.SourceSpan) + .DescendantNodesAndSelf() + .OfType<DelegateDeclarationSyntax>() + .FirstOrDefault(); + + if (dds == null) + return; + + var semanticModel = context.GetSemanticModel(dds.SyntaxTree); + var delegateSymbol = semanticModel.GetDeclaredSymbol(dds, cancellationToken); + if (delegateSymbol == null) + return; + + if (delegateSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false)) + { + context.ReportSuppression(Suppression.Create(_descriptor, diagnostic)); + } + } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index de3b6c862a..8de12de23b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -29,7 +29,7 @@ namespace Godot.SourceGenerators { while (symbol != null) { - if (symbol.ContainingAssembly.Name == assemblyName && + if (symbol.ContainingAssembly?.Name == assemblyName && symbol.ToString() == typeFullName) { return true; @@ -47,7 +47,7 @@ namespace Godot.SourceGenerators while (symbol != null) { - if (symbol.ContainingAssembly.Name == "GodotSharp") + if (symbol.ContainingAssembly?.Name == "GodotSharp") return symbol; symbol = symbol.BaseType; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs index f31ded4d77..bd40675fd3 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -124,8 +124,8 @@ namespace Godot.SourceGenerators if (typeKind == TypeKind.Struct) { - if (type.ContainingAssembly.Name == "GodotSharp" && - type.ContainingNamespace.Name == "Godot") + if (type.ContainingAssembly?.Name == "GodotSharp" && + type.ContainingNamespace?.Name == "Godot") { return type switch { @@ -208,9 +208,9 @@ namespace Godot.SourceGenerators if (type.SimpleDerivesFrom(typeCache.GodotObjectType)) return MarshalType.GodotObjectOrDerived; - if (type.ContainingAssembly.Name == "GodotSharp") + if (type.ContainingAssembly?.Name == "GodotSharp") { - switch (type.ContainingNamespace.Name) + switch (type.ContainingNamespace?.Name) { case "Godot": return type switch @@ -220,7 +220,7 @@ namespace Godot.SourceGenerators _ => null }; case "Collections" - when type.ContainingNamespace.FullQualifiedName() == "Godot.Collections": + when type.ContainingNamespace?.FullQualifiedName() == "Godot.Collections": return type switch { { Name: "Dictionary" } => diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index b1e2875a8b..6e8ecb13b1 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -354,10 +354,13 @@ void NavigationPolygon::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); } +///////////////////////////// + void NavigationRegion2D::set_enabled(bool p_enabled) { if (enabled == p_enabled) { return; } + enabled = p_enabled; if (!is_inside_tree()) { @@ -384,35 +387,50 @@ bool NavigationRegion2D::is_enabled() const { } void NavigationRegion2D::set_navigation_layers(uint32_t p_navigation_layers) { - NavigationServer2D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers); + if (navigation_layers == p_navigation_layers) { + return; + } + + navigation_layers = p_navigation_layers; + + NavigationServer2D::get_singleton()->region_set_navigation_layers(region, navigation_layers); } uint32_t NavigationRegion2D::get_navigation_layers() const { - return NavigationServer2D::get_singleton()->region_get_navigation_layers(region); + return navigation_layers; } void NavigationRegion2D::set_navigation_layer_value(int p_layer_number, bool p_value) { ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + uint32_t _navigation_layers = get_navigation_layers(); + if (p_value) { _navigation_layers |= 1 << (p_layer_number - 1); } else { _navigation_layers &= ~(1 << (p_layer_number - 1)); } + set_navigation_layers(_navigation_layers); } bool NavigationRegion2D::get_navigation_layer_value(int p_layer_number) const { ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + return get_navigation_layers() & (1 << (p_layer_number - 1)); } void NavigationRegion2D::set_enter_cost(real_t p_enter_cost) { ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); - enter_cost = MAX(p_enter_cost, 0.0); - NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost); + if (Math::is_equal_approx(enter_cost, p_enter_cost)) { + return; + } + + enter_cost = p_enter_cost; + + NavigationServer2D::get_singleton()->region_set_enter_cost(region, enter_cost); } real_t NavigationRegion2D::get_enter_cost() const { @@ -421,7 +439,12 @@ real_t NavigationRegion2D::get_enter_cost() const { void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) { ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); - travel_cost = MAX(p_travel_cost, 0.0); + if (Math::is_equal_approx(travel_cost, p_travel_cost)) { + return; + } + + travel_cost = p_travel_cost; + NavigationServer2D::get_singleton()->region_set_travel_cost(region, travel_cost); } @@ -433,7 +456,6 @@ RID NavigationRegion2D::get_region_rid() const { return region; } -///////////////////////////// #ifdef TOOLS_ENABLED Rect2 NavigationRegion2D::_edit_get_rect() const { return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2(); diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 893de41a94..c630e20780 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -96,10 +96,10 @@ class NavigationRegion2D : public Node2D { bool enabled = true; RID region; - Ref<NavigationPolygon> navpoly; - + uint32_t navigation_layers = 1; real_t enter_cost = 0.0; real_t travel_cost = 1.0; + Ref<NavigationPolygon> navpoly; void _navpoly_changed(); void _map_changed(RID p_RID); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 16686f4fe6..4e6b37a860 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -62,7 +62,7 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p if (move_and_collide(parameters, result, p_test_only)) { // Create a new instance when the cached reference is invalid or still in use in script. - if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { + if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) { motion_cache.instantiate(); motion_cache->owner = this; } @@ -1544,7 +1544,7 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) { } // Create a new instance when the cached reference is invalid or still in use in script. - if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) { + if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) { slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index bfc4353138..b060d314ba 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -37,6 +37,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) { if (enabled == p_enabled) { return; } + enabled = p_enabled; if (!is_inside_tree()) { @@ -81,35 +82,50 @@ bool NavigationRegion3D::is_enabled() const { } void NavigationRegion3D::set_navigation_layers(uint32_t p_navigation_layers) { - NavigationServer3D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers); + if (navigation_layers == p_navigation_layers) { + return; + } + + navigation_layers = p_navigation_layers; + + NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers); } uint32_t NavigationRegion3D::get_navigation_layers() const { - return NavigationServer3D::get_singleton()->region_get_navigation_layers(region); + return navigation_layers; } void NavigationRegion3D::set_navigation_layer_value(int p_layer_number, bool p_value) { ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + uint32_t _navigation_layers = get_navigation_layers(); + if (p_value) { _navigation_layers |= 1 << (p_layer_number - 1); } else { _navigation_layers &= ~(1 << (p_layer_number - 1)); } + set_navigation_layers(_navigation_layers); } bool NavigationRegion3D::get_navigation_layer_value(int p_layer_number) const { ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + return get_navigation_layers() & (1 << (p_layer_number - 1)); } void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) { ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); - enter_cost = MAX(p_enter_cost, 0.0); - NavigationServer3D::get_singleton()->region_set_enter_cost(region, p_enter_cost); + if (Math::is_equal_approx(enter_cost, p_enter_cost)) { + return; + } + + enter_cost = p_enter_cost; + + NavigationServer3D::get_singleton()->region_set_enter_cost(region, enter_cost); } real_t NavigationRegion3D::get_enter_cost() const { @@ -118,7 +134,12 @@ real_t NavigationRegion3D::get_enter_cost() const { void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) { ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); - travel_cost = MAX(p_travel_cost, 0.0); + if (Math::is_equal_approx(travel_cost, p_travel_cost)) { + return; + } + + travel_cost = p_travel_cost; + NavigationServer3D::get_singleton()->region_set_travel_cost(region, travel_cost); } @@ -130,8 +151,6 @@ RID NavigationRegion3D::get_region_rid() const { return region; } -///////////////////////////// - void NavigationRegion3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 7d16d81d77..660538d314 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -39,10 +39,10 @@ class NavigationRegion3D : public Node3D { bool enabled = true; RID region; - Ref<NavigationMesh> navmesh; - + uint32_t navigation_layers = 1; real_t enter_cost = 0.0; real_t travel_cost = 1.0; + Ref<NavigationMesh> navmesh; Thread bake_thread; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 0eefb45c04..594e94644c 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -100,7 +100,7 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p if (move_and_collide(parameters, result, p_test_only)) { // Create a new instance when the cached reference is invalid or still in use in script. - if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { + if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) { motion_cache.instantiate(); motion_cache->owner = this; } @@ -1797,7 +1797,7 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) { } // Create a new instance when the cached reference is invalid or still in use in script. - if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) { + if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) { slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index da4b8046a5..4e529de8ee 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -769,15 +769,6 @@ public: class GradientTexture1D : public Texture2D { GDCLASS(GradientTexture1D, Texture2D); -public: - struct Point { - float offset = 0.0; - Color color; - bool operator<(const Point &p_ponit) const { - return offset < p_ponit.offset; - } - }; - private: Ref<Gradient> gradient; bool update_pending = false; |