summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/basis_universal/image_compress_basisu.cpp3
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml12
-rw-r--r--modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp7
-rw-r--r--modules/fbx/editor/editor_scene_importer_ufbx.cpp19
-rw-r--r--modules/gdscript/gdscript.cpp19
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp13
-rw-r--r--modules/gdscript/gdscript_editor.cpp27
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp4
-rw-r--r--modules/gdscript/gdscript_vm.cpp4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd13
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd15
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out1
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp3
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp12
-rw-r--r--modules/gltf/gltf_document.cpp3
-rw-r--r--modules/interactive_music/audio_stream_interactive.cpp2
-rw-r--r--modules/interactive_music/register_types.cpp6
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp16
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp35
-rw-r--r--modules/openxr/openxr_interface.cpp6
-rw-r--r--modules/squish/image_decompress_squish.cpp5
25 files changed, 150 insertions, 85 deletions
diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp
index 216fa6c9a2..fc1f01ae50 100644
--- a/modules/basis_universal/image_compress_basisu.cpp
+++ b/modules/basis_universal/image_compress_basisu.cpp
@@ -120,7 +120,8 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
Vector<uint32_t> mip_data_padded;
for (int32_t i = 0; i <= image->get_mipmap_count(); i++) {
- int ofs, size, width, height;
+ int64_t ofs, size;
+ int width, height;
image->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height);
const uint8_t *image_mip_data = image_data.ptr() + ofs;
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index ebd1577172..84534fec06 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -51,7 +51,7 @@
<param index="3" name="data" type="int" default="0" />
<description>
Initiates a connection to a foreign [param address] using the specified [param port] and allocating the requested [param channels]. Optional [param data] can be passed during connection in the form of a 32 bit integer.
- [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method.
+ [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] on both ends before calling this method.
</description>
</method>
<method name="create_host">
@@ -61,7 +61,9 @@
<param index="2" name="in_bandwidth" type="int" default="0" />
<param index="3" name="out_bandwidth" type="int" default="0" />
<description>
- Create an ENetHost that will allow up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth].
+ Creates an ENetHost that allows up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth] (if greater than zero).
+ This method binds a random available dynamic UDP port on the host machine at the [i]unspecified[/i] address. Use [method create_host_bound] to specify the address and port.
+ [b]Note:[/b] It is necessary to create a host in both client and server in order to establish a connection.
</description>
</method>
<method name="create_host_bound">
@@ -73,7 +75,8 @@
<param index="4" name="in_bandwidth" type="int" default="0" />
<param index="5" name="out_bandwidth" type="int" default="0" />
<description>
- Create an ENetHost like [method create_host] which is also bound to the given [param bind_address] and [param bind_port].
+ Creates an ENetHost bound to the given [param bind_address] and [param bind_port] that allows up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth] (if greater than zero).
+ [b]Note:[/b] It is necessary to create a host in both client and server in order to establish a connection.
</description>
</method>
<method name="destroy">
@@ -141,8 +144,9 @@
<return type="Array" />
<param index="0" name="timeout" type="int" default="0" />
<description>
- Waits for events on the specified host and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
+ Waits for events on this connection and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
Call this function regularly to handle connections, disconnections, and to receive new packets.
+ [b]Note:[/b] This method must be called on both ends involved in the event (sending and receiving hosts).
</description>
</method>
<method name="socket_send">
diff --git a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
index afb63246e4..daa4db37df 100644
--- a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
+++ b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
@@ -126,10 +126,9 @@ Node *EditorSceneFormatImporterFBX2GLTF::import_scene(const String &p_path, uint
Variant EditorSceneFormatImporterFBX2GLTF::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const HashMap<StringName, Variant> &p_options) {
- if (p_option == "fbx/embedded_image_handling") {
- return false;
- }
- if (p_options.has("fbx/importer") && int(p_options["fbx/importer"]) == EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF && p_option == "fbx/embedded_image_handling") {
+ // Remove all the FBX options except for 'fbx/importer' if the importer is fbx2gltf.
+ // These options are available only for ufbx.
+ if (p_option.begins_with("fbx/") && p_option != "fbx/importer" && p_options.has("fbx/importer") && int(p_options["fbx/importer"]) == EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF) {
return false;
}
return true;
diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp
index fb5e324390..4d5f220539 100644
--- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp
+++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp
@@ -76,9 +76,6 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t
if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) {
state->set_import_as_skeleton_bones(true);
}
- if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) {
- state->set_import_as_skeleton_bones(true);
- }
p_flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
state->set_bake_fps(p_options["animation/fps"]);
Error err = fbx->append_from_file(path, state, p_flags, p_path.get_base_dir());
@@ -93,21 +90,17 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t
Variant EditorSceneFormatImporterUFBX::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const HashMap<StringName, Variant> &p_options) {
- String file_extension = p_path.get_extension().to_lower();
- if (file_extension != "fbx" && p_option.begins_with("fbx/")) {
- return false;
- }
- if ((file_extension != "gltf" && file_extension != "glb") && p_option.begins_with("gltf/")) {
- return false;
- }
return true;
}
void EditorSceneFormatImporterUFBX::get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) {
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX));
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false));
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ // Returns all the options when path is empty because that means it's for the Project Settings.
+ if (p_path.is_empty() || p_path.get_extension().to_lower() == "fbx") {
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ }
}
void EditorSceneFormatImporterUFBX::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 73b1e44db3..eaf2565e69 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1537,10 +1537,14 @@ void GDScript::clear(ClearData *p_clear_data) {
}
}
- RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies();
- for (GDScript *E : must_clear_dependencies) {
- clear_data->scripts.insert(E);
- E->clear(clear_data);
+ // If we're in the process of shutting things down then every single script will be cleared
+ // anyway, so we can safely skip this very costly operation.
+ if (!GDScriptLanguage::singleton->finishing) {
+ RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies();
+ for (GDScript *E : must_clear_dependencies) {
+ clear_data->scripts.insert(E);
+ E->clear(clear_data);
+ }
}
for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
@@ -2246,6 +2250,11 @@ String GDScriptLanguage::get_extension() const {
}
void GDScriptLanguage::finish() {
+ if (finishing) {
+ return;
+ }
+ finishing = true;
+
_call_stack.free();
// Clear the cache before parsing the script_list
@@ -2281,6 +2290,8 @@ void GDScriptLanguage::finish() {
}
script_list.clear();
function_list.clear();
+
+ finishing = false;
}
void GDScriptLanguage::profiling_start() {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index d097cb193b..4e78fbe302 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -411,6 +411,8 @@ class GDScriptLanguage : public ScriptLanguage {
static GDScriptLanguage *singleton;
+ bool finishing = false;
+
Variant *_global_array = nullptr;
Vector<Variant> global_array;
HashMap<StringName, int> globals;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 5469dad3f7..b0ac4aa800 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1064,12 +1064,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Get at (potential) root stack pos, so it can be returned.
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base);
+
if (r_error) {
return GDScriptCodeGenerator::Address();
}
GDScriptCodeGenerator::Address prev_base = base;
+ // In case the base has a setter, don't use the address directly, as we want to call that setter.
+ // So use a temp value instead and call the setter at the end.
+ GDScriptCodeGenerator::Address base_temp;
+ if (base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) {
+ base_temp = codegen.add_temporary(base.type);
+ gen->write_assign(base_temp, base);
+ prev_base = base_temp;
+ }
+
struct ChainInfo {
bool is_named = false;
GDScriptCodeGenerator::Address base;
@@ -1218,6 +1228,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_end_jump_if_shared();
}
}
+ } else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ // Save the temp value back to the base by calling its setter.
+ gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned });
}
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index b58b44973e..b1ffc02e4b 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1521,22 +1521,19 @@ static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value, G
}
if (scr.is_valid()) {
ci.type.script_path = scr->get_path();
+ ci.type.script_type = scr;
+ ci.type.native_type = scr->get_instance_base_type();
+ ci.type.kind = GDScriptParser::DataType::SCRIPT;
if (scr->get_path().ends_with(".gd")) {
- Error err;
- Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(scr->get_path(), GDScriptParserRef::INTERFACE_SOLVED, err);
- if (err == OK) {
+ Ref<GDScriptParserRef> parser = p_context.parser->get_depended_parser_for(scr->get_path());
+ if (parser.is_valid() && parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED) == OK) {
ci.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
ci.type.class_type = parser->get_parser()->get_tree();
ci.type.kind = GDScriptParser::DataType::CLASS;
- p_context.dependent_parsers.push_back(parser);
return ci;
}
}
-
- ci.type.kind = GDScriptParser::DataType::SCRIPT;
- ci.type.script_type = scr;
- ci.type.native_type = scr->get_instance_base_type();
} else {
ci.type.kind = GDScriptParser::DataType::NATIVE;
}
@@ -1811,8 +1808,6 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
if (mb && mb->is_const()) {
bool all_is_const = true;
Vector<Variant> args;
- GDScriptParser::CompletionContext c2 = p_context;
- c2.current_line = call->start_line;
for (int i = 0; all_is_const && i < call->arguments.size(); i++) {
GDScriptCompletionIdentifier arg;
@@ -1849,16 +1844,14 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
}
if (FileAccess::exists(script)) {
- Error err = OK;
- Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err);
- if (err == OK) {
+ Ref<GDScriptParserRef> parser = p_context.parser->get_depended_parser_for(script);
+ if (parser.is_valid() && parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED) == OK) {
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.script_path = script;
r_type.type.class_type = parser->get_parser()->get_tree();
r_type.type.is_constant = false;
r_type.type.kind = GDScriptParser::DataType::CLASS;
r_type.value = Variant();
- p_context.dependent_parsers.push_back(parser);
found = true;
}
}
@@ -2310,9 +2303,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
if (ScriptServer::is_global_class(p_identifier->name)) {
String script = ScriptServer::get_global_class_path(p_identifier->name);
if (script.to_lower().ends_with(".gd")) {
- Error err = OK;
- Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err);
- if (err == OK) {
+ Ref<GDScriptParserRef> parser = p_context.parser->get_depended_parser_for(script);
+ if (parser.is_valid() && parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED) == OK) {
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.script_path = script;
r_type.type.class_type = parser->get_parser()->get_tree();
@@ -2320,7 +2312,6 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
r_type.type.is_constant = false;
r_type.type.kind = GDScriptParser::DataType::CLASS;
r_type.value = Variant();
- p_context.dependent_parsers.push_back(parser);
return true;
}
} else {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 433f767f1e..54bb152f7f 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -260,6 +260,7 @@ void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node
context.current_line = tokenizer->get_cursor_line();
context.current_argument = p_argument;
context.node = p_node;
+ context.parser = this;
completion_context = context;
}
@@ -277,6 +278,7 @@ void GDScriptParser::make_completion_context(CompletionType p_type, Variant::Typ
context.current_suite = current_suite;
context.current_line = tokenizer->get_cursor_line();
context.builtin_type = p_builtin_type;
+ context.parser = this;
completion_context = context;
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 21942222cf..60ee477656 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1314,7 +1314,7 @@ public:
Variant::Type builtin_type = Variant::VARIANT_MAX;
Node *node = nullptr;
Object *base = nullptr;
- List<Ref<GDScriptParserRef>> dependent_parsers;
+ GDScriptParser *parser = nullptr;
};
struct CompletionCall {
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 5b1639e250..404b61fb40 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -574,7 +574,9 @@ GDScriptTokenizer::Token GDScriptTokenizerText::potential_identifier() {
if (len == 1 && _peek(-1) == '_') {
// Lone underscore.
- return make_token(Token::UNDERSCORE);
+ Token token = make_token(Token::UNDERSCORE);
+ token.literal = "_";
+ return token;
}
String name(_start, len);
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 912367764b..5eab8a6306 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -1807,7 +1807,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else if (methodstr == "free") {
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
if (base->is_ref_counted()) {
- err_text = "Attempted to free a reference.";
+ err_text = "Attempted to free a RefCounted object.";
OPCODE_BREAK;
} else if (base->get_type() == Variant::OBJECT) {
err_text = "Attempted to free a locked object (calling or emitting).";
@@ -1898,7 +1898,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else if (methodstr == "free") {
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
if (base->is_ref_counted()) {
- err_text = "Attempted to free a reference.";
+ err_text = "Attempted to free a RefCounted object.";
OPCODE_BREAK;
} else if (base->get_type() == Variant::OBJECT) {
err_text = "Attempted to free a locked object (calling or emitting).";
diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd
new file mode 100644
index 0000000000..9e27a500bf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd
@@ -0,0 +1,13 @@
+# https://github.com/godotengine/godot/issues/85952
+
+var vec: Vector2 = Vector2.ZERO:
+ set(new_vec):
+ prints("setting vec from", vec, "to", new_vec)
+ if new_vec == Vector2(1, 1):
+ vec = new_vec
+
+func test():
+ vec.x = 2
+ vec.y = 2
+
+ prints("vec is", vec)
diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out
new file mode 100644
index 0000000000..31b3b3a3a8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+setting vec from (0, 0) to (2, 0)
+setting vec from (0, 0) to (0, 2)
+vec is (0, 0)
diff --git a/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd
new file mode 100644
index 0000000000..b07c40b6da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd
@@ -0,0 +1,15 @@
+extends Node
+
+func test() -> void:
+ var node1 := Node.new()
+ node1.name = "_"
+ var node2 := Node.new()
+ node2.name = "Child"
+ var node3 := Node.new()
+ node3.name = "Child"
+
+ add_child(node1)
+ node1.add_child(node2)
+ add_child(node3)
+
+ assert(get_node("_/Child") == $_/Child)
diff --git a/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index b474128fd6..f70e440781 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -332,7 +332,8 @@ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_pa
}
void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
- if (p_path.get_extension().to_lower() != "blend") {
+ // Returns all the options when path is empty because that means it's for the Project Settings.
+ if (!p_path.is_empty() && p_path.get_extension().to_lower() != "blend") {
return;
}
#define ADD_OPTION_BOOL(PATH, VALUE) \
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index b38c64de01..ce7e17d361 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -84,8 +84,12 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) {
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1));
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ String file_extension = p_path.get_extension().to_lower();
+ // Returns all the options when path is empty because that means it's for the Project Settings.
+ if (p_path.is_empty() || file_extension == "gltf" || file_extension == "glb") {
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ }
}
void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
@@ -98,10 +102,6 @@ void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringN
Variant EditorSceneFormatImporterGLTF::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const HashMap<StringName, Variant> &p_options) {
- String file_extension = p_path.get_extension().to_lower();
- if ((file_extension != "gltf" && file_extension != "glb") && p_option.begins_with("gltf/")) {
- return false;
- }
return true;
}
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index c0232e6d0c..dff1e62e82 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -789,8 +789,9 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_
ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
uri = uri.uri_decode();
uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows.
+ ERR_FAIL_COND_V_MSG(!FileAccess::exists(uri), ERR_FILE_NOT_FOUND, "glTF: Binary file not found: " + uri);
buffer_data = FileAccess::get_file_as_bytes(uri);
- ERR_FAIL_COND_V_MSG(buffer.is_empty(), ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri);
+ ERR_FAIL_COND_V_MSG(buffer_data.is_empty(), ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri);
}
ERR_FAIL_COND_V(!buffer.has("byteLength"), ERR_PARSE_ERROR);
diff --git a/modules/interactive_music/audio_stream_interactive.cpp b/modules/interactive_music/audio_stream_interactive.cpp
index 01764d66ed..d7762295eb 100644
--- a/modules/interactive_music/audio_stream_interactive.cpp
+++ b/modules/interactive_music/audio_stream_interactive.cpp
@@ -976,6 +976,8 @@ void AudioStreamPlaybackInteractive::switch_to_clip_by_name(const StringName &p_
return;
}
+ ERR_FAIL_COND_MSG(stream.is_null(), "Attempted to switch while not playing back any stream.");
+
for (int i = 0; i < stream->get_clip_count(); i++) {
if (stream->get_clip_name(i) == p_name) {
switch_request = i;
diff --git a/modules/interactive_music/register_types.cpp b/modules/interactive_music/register_types.cpp
index 5baea13f81..6175ea6493 100644
--- a/modules/interactive_music/register_types.cpp
+++ b/modules/interactive_music/register_types.cpp
@@ -42,11 +42,11 @@
void initialize_interactive_music_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
GDREGISTER_CLASS(AudioStreamPlaylist);
- GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackPlaylist);
+ GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackPlaylist);
GDREGISTER_CLASS(AudioStreamInteractive);
- GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackInteractive);
+ GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackInteractive);
GDREGISTER_CLASS(AudioStreamSynchronized);
- GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackSynchronized);
+ GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackSynchronized);
}
#ifdef TOOLS_ENABLED
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 7ac7bd8088..33b0b0d015 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -233,14 +233,14 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
MeshInstance &mi = mesh_instances.write[m_i];
Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height());
sizes.push_back(s);
- atlas_size = atlas_size.max(s + Size2i(2, 2));
+ atlas_size = atlas_size.max(s + Size2i(2, 2).maxi(p_denoiser_range));
}
int max = nearest_power_of_2_templated(atlas_size.width);
max = MAX(max, nearest_power_of_2_templated(atlas_size.height));
if (max > p_max_texture_size) {
- return BAKE_ERROR_LIGHTMAP_TOO_SMALL;
+ return BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE;
}
if (p_step_function) {
@@ -254,19 +254,27 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
int best_atlas_memory = 0x7FFFFFFF;
Vector<Vector3i> best_atlas_offsets;
- //determine best texture array atlas size by bruteforce fitting
+ // Determine best texture array atlas size by bruteforce fitting.
while (atlas_size.x <= p_max_texture_size && atlas_size.y <= p_max_texture_size) {
Vector<Vector2i> source_sizes;
Vector<int> source_indices;
source_sizes.resize(sizes.size());
source_indices.resize(sizes.size());
for (int i = 0; i < source_indices.size(); i++) {
- source_sizes.write[i] = sizes[i] + Vector2i(2, 2).maxi(p_denoiser_range); // Add padding between lightmaps
+ source_sizes.write[i] = sizes[i] + Vector2i(2, 2).maxi(p_denoiser_range); // Add padding between lightmaps.
source_indices.write[i] = i;
}
Vector<Vector3i> atlas_offsets;
atlas_offsets.resize(source_sizes.size());
+ // Ensure the sizes can all fit into a single atlas layer.
+ // This should always happen, and this check is only in place to prevent an infinite loop.
+ for (int i = 0; i < source_sizes.size(); i++) {
+ if (source_sizes[i] > atlas_size) {
+ return BAKE_ERROR_ATLAS_TOO_SMALL;
+ }
+ }
+
int slices = 0;
while (source_sizes.size() > 0) {
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 51e6c3e277..a353073f21 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -248,32 +248,27 @@ void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path
void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) {
Error err = OK;
- action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
- if (err != OK) {
- if ((err == ERR_FILE_NOT_FOUND || err == ERR_CANT_OPEN) && p_create_new_if_missing) {
- action_map.instantiate();
- action_map->create_default_action_sets();
-
- // Save it immediately
- err = ResourceSaver::save(action_map, p_path);
- if (err != OK) {
- // Show warning but continue.
- EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err]));
- } else {
- // Reload so it's cached.
- action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
- if (err != OK) {
- // Show warning but continue.
- EditorNode::get_singleton()->show_warning(vformat(TTR("Error reloading file %s: %s"), edited_path, error_names[err]));
- }
- }
- } else {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->file_exists(p_path)) {
+ action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ if (err != OK) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Error loading %s: %s."), edited_path, error_names[err]));
edited_path = "";
header_label->set_text("");
return;
}
+ } else if (p_create_new_if_missing) {
+ action_map.instantiate();
+ action_map->create_default_action_sets();
+ action_map->set_path(p_path);
+
+ // Save it immediately
+ err = ResourceSaver::save(action_map, p_path);
+ if (err != OK) {
+ // Show warning but continue.
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err]));
+ }
}
edited_path = p_path;
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index fbbc61a91c..cce9c09361 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -651,6 +651,10 @@ bool OpenXRInterface::initialize() {
// make this our primary interface
xr_server->set_primary_interface(this);
+ // Register an additional output with the display server, so rendering won't
+ // be skipped if no windows are visible.
+ DisplayServer::get_singleton()->register_additional_output(this);
+
initialized = true;
return initialized;
@@ -674,6 +678,8 @@ void OpenXRInterface::uninitialize() {
}
}
+ DisplayServer::get_singleton()->unregister_additional_output(this);
+
initialized = false;
}
diff --git a/modules/squish/image_decompress_squish.cpp b/modules/squish/image_decompress_squish.cpp
index fba76621d6..72640cd936 100644
--- a/modules/squish/image_decompress_squish.cpp
+++ b/modules/squish/image_decompress_squish.cpp
@@ -77,10 +77,11 @@ void image_decompress_squish(Image *p_image) {
}
for (int i = 0; i <= mm_count; i++) {
- int src_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0;
+ int64_t src_ofs = 0, mipmap_size = 0;
+ int mipmap_w = 0, mipmap_h = 0;
p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h);
- int dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i);
+ int64_t dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i);
squish::DecompressImage(&wb[dst_ofs], w, h, &rb[src_ofs], squish_flags);
w >>= 1;