diff options
Diffstat (limited to 'modules')
271 files changed, 4352 insertions, 1853 deletions
diff --git a/modules/SCsub b/modules/SCsub index 6fb2aa67f4..739c5de0b5 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -1,6 +1,6 @@ #!/usr/bin/env python -import modules_builders +import methods import os Import("env") @@ -12,15 +12,51 @@ env_modules.Append(CPPDEFINES=["GODOT_MODULE"]) Export("env_modules") -# Header with MODULE_*_ENABLED defines. -env.Depends("modules_enabled.gen.h", Value(env.module_list)) -env.CommandNoCache( - "modules_enabled.gen.h", - Value(env.module_list), - env.Run(modules_builders.generate_modules_enabled), + +def register_module_types_builder(target, source, env): + modules = source[0].read() + mod_inc = "\n".join([f'#include "{p}/register_types.h"' for p in modules.values()]) + mod_init = "\n".join( + [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tinitialize_{n}_module(p_level);\n#endif" for n in modules.keys()] + ) + mod_uninit = "\n".join( + [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tuninitialize_{n}_module(p_level);\n#endif" for n in modules.keys()] + ) + with methods.generated_wrapper(target) as file: + file.write( + f"""\ +#include "register_module_types.h" + +#include "modules/modules_enabled.gen.h" + +{mod_inc} + +void initialize_modules(ModuleInitializationLevel p_level) {{ +{mod_init} +}} + +void uninitialize_modules(ModuleInitializationLevel p_level) {{ +{mod_uninit} +}} +""" + ) + + +register_module_types = env.CommandNoCache( + "register_module_types.gen.cpp", env.Value(env.modules_detected), env.Run(register_module_types_builder) ) +# Header with MODULE_*_ENABLED defines. +def modules_enabled_builder(target, source, env): + with methods.generated_wrapper(target) as file: + for module in source[0].read(): + file.write(f"#define MODULE_{module.upper()}_ENABLED\n") + + +env.CommandNoCache("modules_enabled.gen.h", env.Value(env.module_list), env.Run(modules_enabled_builder)) + + vs_sources = [] test_headers = [] # libmodule_<name>.a for each active module. @@ -47,18 +83,19 @@ for name, path in env.module_list.items(): # Generate header to be included in `tests/test_main.cpp` to run module-specific tests. if env["tests"]: - env.Depends("modules_tests.gen.h", test_headers) - env.CommandNoCache( - "modules_tests.gen.h", - test_headers, - env.Run(modules_builders.generate_modules_tests), - ) + + def modules_tests_builder(target, source, env): + with methods.generated_wrapper(target) as file: + for header in source: + file.write('#include "{}"\n'.format(os.path.normpath(header.path).replace("\\", "/"))) + + env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder)) # libmodules.a with only register_module_types. # Must be last so that all libmodule_<name>.a libraries are on the right side # in the linker command. env.modules_sources = [] -env_modules.add_source_files(env.modules_sources, "register_module_types.gen.cpp") +env_modules.add_source_files(env.modules_sources, register_module_types) lib = env_modules.add_library("modules", env.modules_sources) env.Prepend(LIBS=[lib]) if env["vsproj"]: diff --git a/modules/astcenc/image_compress_astcenc.cpp b/modules/astcenc/image_compress_astcenc.cpp index 31df83efae..499cf739c4 100644 --- a/modules/astcenc/image_compress_astcenc.cpp +++ b/modules/astcenc/image_compress_astcenc.cpp @@ -41,7 +41,7 @@ void _compress_astc(Image *r_img, Image::ASTCFormat p_format) { // TODO: See how to handle lossy quality. Image::Format img_format = r_img->get_format(); - if (img_format >= Image::FORMAT_DXT1) { + if (Image::is_format_compressed(img_format)) { return; // Do not compress, already compressed. } @@ -132,7 +132,10 @@ void _compress_astc(Image *r_img, Image::ASTCFormat p_format) { int dst_mip_w, dst_mip_h; int dst_ofs = Image::get_image_mipmap_offset_and_dimensions(width, height, target_format, i, dst_mip_w, dst_mip_h); // Ensure that mip offset is a multiple of 8 (etcpak expects uint64_t pointer). - ERR_FAIL_COND(dst_ofs % 8 != 0); + if (unlikely(dst_ofs % 8 != 0)) { + astcenc_context_free(context); + ERR_FAIL_MSG("astcenc: Mip offset is not a multiple of 8."); + } uint8_t *dest_mip_write = (uint8_t *)&dest_write[dst_ofs]; // Compress image. diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp index 72e7977eef..d8ef1c0414 100644 --- a/modules/basis_universal/image_compress_basisu.cpp +++ b/modules/basis_universal/image_compress_basisu.cpp @@ -96,17 +96,74 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha } break; } + // Copy the source image data with mipmaps into BasisU. { - // Encode the image with mipmaps. + const int orig_width = image->get_width(); + const int orig_height = image->get_height(); + + bool is_res_div_4 = (orig_width % 4 == 0) && (orig_height % 4 == 0); + + // Image's resolution rounded up to the nearest values divisible by 4. + int next_width = orig_width <= 2 ? orig_width : (orig_width + 3) & ~3; + int next_height = orig_height <= 2 ? orig_height : (orig_height + 3) & ~3; + Vector<uint8_t> image_data = image->get_data(); basisu::vector<basisu::image> basisu_mipmaps; + // Buffer for storing padded mipmap data. + Vector<uint32_t> mip_data_padded; + for (int32_t i = 0; i <= image->get_mipmap_count(); i++) { int ofs, size, width, height; image->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height); + const uint8_t *image_mip_data = image_data.ptr() + ofs; + + // Pad the mipmap's data if its resolution isn't divisible by 4. + if (image->has_mipmaps() && !is_res_div_4 && (width > 2 && height > 2) && (width != next_width || height != next_height)) { + // Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data. + const uint32_t *mip_src_data = reinterpret_cast<const uint32_t *>(image_mip_data); + + // Reserve space in the padded buffer. + mip_data_padded.resize(next_width * next_height); + uint32_t *data_padded_ptr = mip_data_padded.ptrw(); + + // Pad mipmap to the nearest block by smearing. + int x = 0, y = 0; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + data_padded_ptr[next_width * y + x] = mip_src_data[width * y + x]; + } + + // First, smear in x. + for (; x < next_width; x++) { + data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - 1]; + } + } + + // Then, smear in y. + for (; y < next_height; y++) { + for (x = 0; x < next_width; x++) { + data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - next_width]; + } + } + + // Override the image_mip_data pointer with our temporary Vector. + image_mip_data = reinterpret_cast<const uint8_t *>(mip_data_padded.ptr()); + + // Override the mipmap's properties. + width = next_width; + height = next_height; + size = mip_data_padded.size() * 4; + } + + // Get the next mipmap's resolution. + next_width /= 2; + next_height /= 2; + + // Copy the source mipmap's data to a BasisU image. basisu::image basisu_image(width, height); - memcpy(basisu_image.get_ptr(), image_data.ptr() + ofs, size); + memcpy(basisu_image.get_ptr(), image_mip_data, size); if (i == 0) { params.m_source_images.push_back(basisu_image); @@ -132,10 +189,10 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha // Copy the encoded data to the buffer. { - uint8_t *w = basisu_data.ptrw(); - *(uint32_t *)w = decompress_format; + uint8_t *wb = basisu_data.ptrw(); + *(uint32_t *)wb = decompress_format; - memcpy(w + 4, basisu_out.get_ptr(), basisu_out.size()); + memcpy(wb + 4, basisu_out.get_ptr(), basisu_out.size()); } return basisu_data; @@ -238,12 +295,11 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { uint8_t *dst = out_data.ptrw(); memset(dst, 0, out_data.size()); - uint32_t mip_count = Image::get_image_required_mipmaps(basisu_info.m_orig_width, basisu_info.m_orig_height, image_format); - for (uint32_t i = 0; i <= mip_count; i++) { + for (uint32_t i = 0; i < basisu_info.m_total_levels; i++) { basist::basisu_image_level_info basisu_level; transcoder.get_image_level_info(src_ptr, src_size, basisu_level, 0, i); - uint32_t mip_block_or_pixel_count = image_format >= Image::FORMAT_DXT1 ? basisu_level.m_total_blocks : basisu_level.m_orig_width * basisu_level.m_orig_height; + uint32_t mip_block_or_pixel_count = Image::is_format_compressed(image_format) ? basisu_level.m_total_blocks : basisu_level.m_orig_width * basisu_level.m_orig_height; int ofs = Image::get_image_mipmap_offset(basisu_info.m_width, basisu_info.m_height, image_format, i); bool result = transcoder.transcode_image_level(src_ptr, src_size, 0, i, dst + ofs, mip_block_or_pixel_count, basisu_format); diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 878664bb9c..a4a3c768e9 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -852,7 +852,7 @@ int CSGBrushOperation::Build2DFaces::_add_vertex(const Vertex2D &p_vertex) { } void CSGBrushOperation::Build2DFaces::_add_vertex_idx_sorted(Vector<int> &r_vertex_indices, int p_new_vertex_index) { - if (p_new_vertex_index >= 0 && r_vertex_indices.find(p_new_vertex_index) == -1) { + if (p_new_vertex_index >= 0 && !r_vertex_indices.has(p_new_vertex_index)) { ERR_FAIL_COND_MSG(p_new_vertex_index >= vertices.size(), "Invalid vertex index."); // The first vertex. @@ -1098,7 +1098,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s }; // Check if edge has already been processed. - if (processed_edges.find(edge_points_and_uvs) != -1) { + if (processed_edges.has(edge_points_and_uvs)) { continue; } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 7c93fbf081..8d2847ab1a 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -1824,13 +1824,13 @@ CSGBrush *CSGPolygon3D::_build_brush() { Path3D *current_path = Object::cast_to<Path3D>(get_node_or_null(path_node)); if (path != current_path) { if (path) { - path->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited)); + path->disconnect(SceneStringName(tree_exited), callable_mp(this, &CSGPolygon3D::_path_exited)); path->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed)); path->set_update_callback(Callable()); } path = current_path; if (path) { - path->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited)); + path->connect(SceneStringName(tree_exited), callable_mp(this, &CSGPolygon3D::_path_exited)); path->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed)); path->set_update_callback(callable_mp(this, &CSGPolygon3D::_path_changed)); } @@ -2140,7 +2140,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { void CSGPolygon3D::_notification(int p_what) { if (p_what == NOTIFICATION_EXIT_TREE) { if (path) { - path->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited)); + path->disconnect(SceneStringName(tree_exited), callable_mp(this, &CSGPolygon3D::_path_exited)); path->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed)); path = nullptr; } diff --git a/modules/csg/editor/csg_gizmos.h b/modules/csg/editor/csg_gizmos.h index 6281db0a21..de19b33e7d 100644 --- a/modules/csg/editor/csg_gizmos.h +++ b/modules/csg/editor/csg_gizmos.h @@ -35,7 +35,7 @@ #include "../csg_shape.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" class Gizmo3DHelper; diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index e9a7009d7c..7335315c51 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -142,7 +142,7 @@ static void _digest_job_queue(void *p_job_queue, uint32_t p_index) { } void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) { - if (p_image->get_format() >= Image::FORMAT_BPTC_RGBA) { + if (p_image->is_compressed()) { return; //do not compress, already compressed } int w = p_image->get_width(); diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml index 5ca1ec2228..5795dd8976 100644 --- a/modules/enet/doc_classes/ENetConnection.xml +++ b/modules/enet/doc_classes/ENetConnection.xml @@ -151,7 +151,7 @@ <param index="1" name="destination_port" type="int" /> <param index="2" name="packet" type="PackedByteArray" /> <description> - Sends a [param packet] toward a destination from the address and port currently bound by this ENetConnection instance. + Sends a [param packet] toward a destination from the address and port currently bound by this ENetConnection instance. This is useful as it serves to establish entries in NAT routing tables on all devices between this bound instance and the public facing internet, allowing a prospective client's connection packets to be routed backward through the NAT device(s) between the public internet and this host. This requires forward knowledge of a prospective client's address and communication port as seen by the public internet - after any NAT devices have handled their connection request. This information can be obtained by a [url=https://en.wikipedia.org/wiki/STUN]STUN[/url] service, and must be handed off to your host by an entity that is not the prospective client. This will never work for a client behind a Symmetric NAT due to the nature of the Symmetric NAT routing algorithm, as their IP and Port cannot be known beforehand. </description> diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index 910c4ed242..6f87a398c7 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -124,9 +124,9 @@ Error ENetMultiplayerPeer::add_mesh_peer(int p_id, Ref<ENetConnection> p_host) { ERR_FAIL_COND_V_MSG(active_mode != MODE_MESH, ERR_UNCONFIGURED, "The multiplayer instance is not configured as a mesh. Call 'create_mesh' first."); List<Ref<ENetPacketPeer>> host_peers; p_host->get_peers(host_peers); - ERR_FAIL_COND_V_MSG(host_peers.size() != 1 || host_peers[0]->get_state() != ENetPacketPeer::STATE_CONNECTED, ERR_INVALID_PARAMETER, "The provided host must have exactly one peer in the connected state."); + ERR_FAIL_COND_V_MSG(host_peers.size() != 1 || host_peers.front()->get()->get_state() != ENetPacketPeer::STATE_CONNECTED, ERR_INVALID_PARAMETER, "The provided host must have exactly one peer in the connected state."); hosts[p_id] = p_host; - peers[p_id] = host_peers[0]; + peers[p_id] = host_peers.front()->get(); emit_signal(SNAME("peer_connected"), p_id); return OK; } diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp index dcd73101c2..4ce0cf50d9 100644 --- a/modules/etcpak/image_compress_etcpak.cpp +++ b/modules/etcpak/image_compress_etcpak.cpp @@ -92,7 +92,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img) { uint64_t start_time = OS::get_singleton()->get_ticks_msec(); Image::Format img_format = r_img->get_format(); - if (img_format >= Image::FORMAT_DXT1) { + if (Image::is_format_compressed(img_format)) { return; // Do not compress, already compressed. } if (img_format > Image::FORMAT_RGBA8) { diff --git a/modules/fbx/fbx_document.cpp b/modules/fbx/fbx_document.cpp index 5f94a80566..1361e871de 100644 --- a/modules/fbx/fbx_document.cpp +++ b/modules/fbx/fbx_document.cpp @@ -217,6 +217,16 @@ static ufbx_skin_deformer *_find_skin_deformer(ufbx_skin_cluster *p_cluster) { return nullptr; } +static String _find_element_name(ufbx_element *p_element) { + if (p_element->name.length > 0) { + return FBXDocument::_as_string(p_element->name); + } else if (p_element->instances.count > 0) { + return _find_element_name(&p_element->instances[0]->element); + } else { + return ""; + } +} + struct ThreadPoolFBX { struct Group { ufbx_thread_pool_context ctx = {}; @@ -693,10 +703,7 @@ Error FBXDocument::_parse_meshes(Ref<FBXState> p_state) { // Find the first imported skin deformer for (ufbx_skin_deformer *fbx_skin : fbx_mesh->skin_deformers) { - if (!p_state->skin_indices.has(fbx_skin->typed_id)) { - continue; - } - GLTFSkinIndex skin_i = p_state->skin_indices[fbx_skin->typed_id]; + GLTFSkinIndex skin_i = p_state->original_skin_indices[fbx_skin->typed_id]; if (skin_i < 0) { continue; } @@ -2029,7 +2036,7 @@ Error FBXDocument::_parse(Ref<FBXState> p_state, String p_path, Ref<FileAccess> opts.space_conversion = UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY; if (!p_state->get_allow_geometry_helper_nodes()) { opts.geometry_transform_handling = UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK; - opts.inherit_mode_handling = UFBX_INHERIT_MODE_HANDLING_IGNORE; + opts.inherit_mode_handling = UFBX_INHERIT_MODE_HANDLING_COMPENSATE_NO_FALLBACK; } else { opts.geometry_transform_handling = UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES; opts.inherit_mode_handling = UFBX_INHERIT_MODE_HANDLING_COMPENSATE; @@ -2071,6 +2078,32 @@ Error FBXDocument::_parse(Ref<FBXState> p_state, String p_path, Ref<FileAccess> ERR_FAIL_V_MSG(ERR_PARSE_ERROR, err_buf); } + const int max_warning_count = 10; + int warning_count[UFBX_WARNING_TYPE_COUNT] = {}; + int ignored_warning_count = 0; + for (const ufbx_warning &warning : p_state->scene->metadata.warnings) { + if (warning_count[warning.type]++ < max_warning_count) { + if (warning.count > 1) { + WARN_PRINT(vformat("FBX: ufbx warning: %s (x%d)", _as_string(warning.description), (int)warning.count)); + } else { + String element_name; + if (warning.element_id != UFBX_NO_INDEX) { + element_name = _find_element_name(p_state->scene->elements[warning.element_id]); + } + if (!element_name.is_empty()) { + WARN_PRINT(vformat("FBX: ufbx warning in '%s': %s", element_name, _as_string(warning.description))); + } else { + WARN_PRINT(vformat("FBX: ufbx warning: %s", _as_string(warning.description))); + } + } + } else { + ignored_warning_count++; + } + } + if (ignored_warning_count > 0) { + WARN_PRINT(vformat("FBX: ignored %d further ufbx warnings", ignored_warning_count)); + } + err = _parse_fbx_state(p_state, p_path); ERR_FAIL_COND_V(err != OK, err); @@ -2341,7 +2374,7 @@ Error FBXDocument::_parse_skins(Ref<FBXState> p_state) { HashMap<GLTFNodeIndex, bool> joint_mapping; for (const ufbx_skin_deformer *fbx_skin : fbx_scene->skin_deformers) { - if (fbx_skin->clusters.count == 0) { + if (fbx_skin->clusters.count == 0 || fbx_skin->weights.count == 0) { p_state->skin_indices.push_back(-1); continue; } @@ -2387,8 +2420,9 @@ Error FBXDocument::_parse_skins(Ref<FBXState> p_state) { } } } + p_state->original_skin_indices = p_state->skin_indices.duplicate(); Error err = SkinTool::_asset_parse_skins( - p_state->skin_indices.duplicate(), + p_state->original_skin_indices, p_state->skins.duplicate(), p_state->nodes.duplicate(), p_state->skin_indices, diff --git a/modules/fbx/fbx_state.h b/modules/fbx/fbx_state.h index d10550c228..e52f47e0db 100644 --- a/modules/fbx/fbx_state.h +++ b/modules/fbx/fbx_state.h @@ -53,6 +53,7 @@ class FBXState : public GLTFState { HashMap<Pair<uint64_t, uint64_t>, GLTFTextureIndex, PairHash<uint64_t, uint64_t>> albedo_transparency_textures; Vector<GLTFSkinIndex> skin_indices; + Vector<GLTFSkinIndex> original_skin_indices; HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_fbx_skeleton; HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_fbx_skin; HashSet<String> unique_mesh_names; // Not in GLTFState because GLTFState prefixes mesh names with the scene name (or _) diff --git a/modules/gdscript/README.md b/modules/gdscript/README.md index 865475d37d..a4367b39ff 100644 --- a/modules/gdscript/README.md +++ b/modules/gdscript/README.md @@ -136,4 +136,4 @@ There are many other classes in the GDScript module. Here is a brief overview of - The [virtual machine](gdscript_vm.cpp) is essentially defined as calling `GDScriptFunction::call()`. - Editor-related functions can be found in parts of `GDScriptLanguage`, originally declared in [`gdscript.h`](gdscript.h) but defined in [`gdscript_editor.cpp`](gdscript_editor.cpp). Code highlighting can be found in [`GDScriptSyntaxHighlighter`](editor/gdscript_highlighter.h). - GDScript decompilation is found in [`gdscript_disassembler.cpp`](gdscript_disassembler.h), defined as `GDScriptFunction::disassemble()`. -- Documentation generation from GDScript comments in [`GDScriptDocGen`](editor/gdscript_docgen.h)
\ No newline at end of file +- Documentation generation from GDScript comments in [`GDScriptDocGen`](editor/gdscript_docgen.h) diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 07d917ea04..1909ca5ab5 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -349,10 +349,11 @@ <param index="1" name="hint_string" type="String" /> <param index="2" name="usage" type="int" enum="PropertyUsageFlags" is_bitfield="true" default="6" /> <description> - Allows you to set a custom hint, hint string, and usage flags for the exported property. Note that there's no validation done in GDScript, it will just pass the hint along to the editor. + Allows you to set a custom hint, hint string, and usage flags for the exported property. Note that there's no validation done in GDScript, it will just pass the parameters to the editor. [codeblock] @export_custom(PROPERTY_HINT_NONE, "suffix:m") var suffix: Vector3 [/codeblock] + [b]Note:[/b] Regardless of the [param usage] value, the [constant PROPERTY_USAGE_SCRIPT_VARIABLE] flag is always added, as with any explicitly declared script variable. </description> </annotation> <annotation name="@export_dir"> diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 316281209a..d74d316704 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -276,8 +276,8 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C id_ctx_plural.resize(3); bool extract_id_ctx_plural = true; - if (function_name == tr_func) { - // Extract from tr(id, ctx). + if (function_name == tr_func || function_name == atr_func) { + // Extract from `tr(id, ctx)` or `atr(id, ctx)`. for (int i = 0; i < p_call->arguments.size(); i++) { if (_is_constant_string(p_call->arguments[i])) { id_ctx_plural.write[i] = p_call->arguments[i]->reduced_value; @@ -289,8 +289,8 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C if (extract_id_ctx_plural) { ids_ctx_plural->push_back(id_ctx_plural); } - } else if (function_name == trn_func) { - // Extract from tr_n(id, plural, n, ctx). + } else if (function_name == trn_func || function_name == atrn_func) { + // Extract from `tr_n(id, plural, n, ctx)` or `atr_n(id, plural, n, ctx)`. Vector<int> indices; indices.push_back(0); indices.push_back(3); diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index fe876134c2..61ff81ed66 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -45,6 +45,8 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug // List of patterns used for extracting translation strings. StringName tr_func = "tr"; StringName trn_func = "tr_n"; + StringName atr_func = "atr"; + StringName atrn_func = "atr_n"; HashSet<StringName> assignment_patterns; HashSet<StringName> first_arg_patterns; HashSet<StringName> second_arg_patterns; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 921ed0b416..de56dd5ece 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -49,11 +49,12 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/core_constants.h" -#include "core/core_string_names.h" #include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/os/os.h" +#include "scene/scene_string_names.h" + #ifdef TOOLS_ENABLED #include "editor/editor_paths.h" #endif @@ -678,6 +679,27 @@ Error GDScript::_static_init() { #ifdef TOOLS_ENABLED +void GDScript::_static_default_init() { + for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) { + const GDScriptDataType &type = E.value.data_type; + // Only initialize builtin types, which are not expected to be `null`. + if (!type.has_type || type.kind != GDScriptDataType::BUILTIN) { + continue; + } + if (type.builtin_type == Variant::ARRAY && type.has_container_element_type(0)) { + Array default_value; + const GDScriptDataType &element_type = type.get_container_element_type(0); + default_value.set_typed(element_type.builtin_type, element_type.native_type, element_type.script_type); + static_variables.write[E.value.index] = default_value; + } else { + Variant default_value; + Callable::CallError err; + Variant::construct(type.builtin_type, default_value, nullptr, 0, err); + static_variables.write[E.value.index] = default_value; + } + } +} + void GDScript::_save_old_static_data() { old_static_variables_indices = static_variables_indices; old_static_variables = static_variables; @@ -841,6 +863,9 @@ Error GDScript::reload(bool p_keep_state) { #ifdef TOOLS_ENABLED if (can_run && p_keep_state) { _restore_old_static_data(); + } else if (!can_run) { + // Initialize static variables with sane default values even if the constructor isn't called. + _static_default_init(); } #endif @@ -1958,19 +1983,22 @@ int GDScriptInstance::get_method_argument_count(const StringName &p_method, bool return 0; } +void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) { + // Call base class first. + if (p_script->_base) { + _call_implicit_ready_recursively(p_script->_base); + } + if (p_script->implicit_ready) { + Callable::CallError err; + p_script->implicit_ready->call(this, nullptr, 0, err); + } +} + Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *sptr = script.ptr(); - if (unlikely(p_method == SNAME("_ready"))) { - // Call implicit ready first, including for the super classes. - while (sptr) { - if (sptr->implicit_ready) { - sptr->implicit_ready->call(this, nullptr, 0, r_error); - } - sptr = sptr->_base; - } - - // Reset this back for the regular call. - sptr = script.ptr(); + if (unlikely(p_method == SceneStringName(_ready))) { + // Call implicit ready first, including for the super classes recursively. + _call_implicit_ready_recursively(sptr); } while (sptr) { HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method); @@ -2011,15 +2039,15 @@ void GDScriptInstance::notification(int p_notification, bool p_reversed) { } String GDScriptInstance::to_string(bool *r_valid) { - if (has_method(CoreStringNames::get_singleton()->_to_string)) { + if (has_method(CoreStringName(_to_string))) { Callable::CallError ce; - Variant ret = callp(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); + Variant ret = callp(CoreStringName(_to_string), nullptr, 0, ce); if (ce.error == Callable::CallError::CALL_OK) { if (ret.get_type() != Variant::STRING) { if (r_valid) { *r_valid = false; } - ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String."); + ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringName(_to_string) + ", must be a String."); } if (r_valid) { *r_valid = true; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 781e284bfc..728459de44 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -169,6 +169,9 @@ private: GDScriptFunction *static_initializer = nullptr; Error _static_init(); +#ifdef TOOLS_ENABLED + void _static_default_init(); // Initialize static variables with default values based on their types. +#endif int subclass_count = 0; RBSet<Object *> instances; @@ -365,6 +368,8 @@ class GDScriptInstance : public ScriptInstance { SelfList<GDScriptFunctionState>::List pending_func_states; + void _call_implicit_ready_recursively(GDScript *p_script); + public: virtual Object *get_owner() { return owner; } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 0636ac5083..a2680c932f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -37,7 +37,6 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/core_constants.h" -#include "core/core_string_names.h" #include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/class_db.h" @@ -231,7 +230,7 @@ bool GDScriptAnalyzer::has_member_name_conflict_in_native_type(const StringName if (ClassDB::has_integer_constant(p_native_type_string, p_member_name)) { return true; } - if (p_member_name == CoreStringNames::get_singleton()->_script) { + if (p_member_name == CoreStringName(script)) { return true; } @@ -722,13 +721,32 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) { const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first); - Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(autoload.path); + String script_path; + if (ResourceLoader::get_resource_type(autoload.path) == "PackedScene") { + // Try to get script from scene if possible. + if (GDScriptLanguage::get_singleton()->has_any_global_constant(autoload.name)) { + Variant constant = GDScriptLanguage::get_singleton()->get_any_global_constant(autoload.name); + Node *node = Object::cast_to<Node>(constant); + if (node != nullptr) { + Ref<GDScript> scr = node->get_script(); + if (scr.is_valid()) { + script_path = scr->get_script_path(); + } + } + } + } else if (ResourceLoader::get_resource_type(autoload.path) == "GDScript") { + script_path = autoload.path; + } + if (script_path.is_empty()) { + return bad_type; + } + Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(script_path); if (ref.is_null()) { - push_error(vformat(R"(The referenced autoload "%s" (from "%s") could not be loaded.)", first, autoload.path), p_type); + push_error(vformat(R"(The referenced autoload "%s" (from "%s") could not be loaded.)", first, script_path), p_type); return bad_type; } if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) { - push_error(vformat(R"(Could not parse singleton "%s" from "%s".)", first, autoload.path), p_type); + push_error(vformat(R"(Could not parse singleton "%s" from "%s".)", first, script_path), p_type); return bad_type; } result = ref->get_parser()->head->get_datatype(); @@ -2143,7 +2161,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { List<GDScriptParser::DataType> par_types; int default_arg_count = 0; BitField<MethodFlags> method_flags; - if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, method_flags)) { + if (get_function_signature(p_for->list, false, list_type, CoreStringName(_iter_get), return_type, par_types, default_arg_count, method_flags)) { variable_type = return_type; variable_type.type_source = list_type.type_source; } else if (!list_type.is_hard_type()) { @@ -3001,6 +3019,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: case Variant::PACKED_COLOR_ARRAY: + case Variant::PACKED_VECTOR4_ARRAY: safe_to_fold = false; break; default: @@ -3099,24 +3118,28 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a bool types_match = true; - for (int i = 0; i < p_call->arguments.size(); i++) { - GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true); - GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype(); - if (!is_type_compatible(par_type, arg_type, true)) { - types_match = false; - break; + { + List<PropertyInfo>::ConstIterator arg_itr = info.arguments.begin(); + for (int i = 0; i < p_call->arguments.size(); ++arg_itr, ++i) { + GDScriptParser::DataType par_type = type_from_property(*arg_itr, true); + GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype(); + if (!is_type_compatible(par_type, arg_type, true)) { + types_match = false; + break; #ifdef DEBUG_ENABLED - } else { - if (par_type.builtin_type == Variant::INT && arg_type.builtin_type == Variant::FLOAT && builtin_type != Variant::INT) { - parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, function_name); - } + } else { + if (par_type.builtin_type == Variant::INT && arg_type.builtin_type == Variant::FLOAT && builtin_type != Variant::INT) { + parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, function_name); + } #endif + } } } if (types_match) { - for (int i = 0; i < p_call->arguments.size(); i++) { - GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true); + List<PropertyInfo>::ConstIterator arg_itr = info.arguments.begin(); + for (int i = 0; i < p_call->arguments.size(); ++arg_itr, ++i) { + GDScriptParser::DataType par_type = type_from_property(*arg_itr, true); if (p_call->arguments[i]->is_constant) { update_const_expression_builtin_type(p_call->arguments[i], par_type, "pass"); } @@ -3336,8 +3359,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a // If the function requires typed arrays we must make literals be typed. for (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) { int index = E.key; - if (index < par_types.size() && par_types[index].is_hard_type() && par_types[index].has_container_element_type(0)) { - update_array_literal_element_type(E.value, par_types[index].get_container_element_type(0)); + if (index < par_types.size() && par_types.get(index).is_hard_type() && par_types.get(index).has_container_element_type(0)) { + update_array_literal_element_type(E.value, par_types.get(index).get_container_element_type(0)); } } validate_call_arg(par_types, default_arg_count, method_flags.has_flag(METHOD_FLAG_VARARG), p_call); @@ -3355,7 +3378,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } if (parent_function) { - push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call); + push_error(vformat(R"*(Cannot call non-static function "%s()" from the static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call); } else { push_error(vformat(R"*(Cannot call non-static function "%s()" from a static variable initializer.)*", p_call->function_name), p_call); } @@ -3371,6 +3394,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } #ifdef DEBUG_ENABLED + // FIXME: No warning for built-in constructors and utilities due to early return. if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL && !(p_call->is_super && p_call->function_name == GDScriptLanguage::get_singleton()->strings._init)) { parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name); @@ -3769,9 +3793,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod } break; case GDScriptParser::ClassNode::Member::FUNCTION: { - if (is_base && (!base.is_meta_type || member.function->is_static)) { + if (is_base && (!base.is_meta_type || member.function->is_static || is_constructor)) { p_identifier->set_datatype(make_callable_type(member.function->info)); p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_FUNCTION; + p_identifier->function_source = member.function; + p_identifier->function_source_is_static = member.function->is_static; return; } } break; @@ -3820,6 +3846,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod if (method_info.name == p_identifier->name) { p_identifier->set_datatype(make_callable_type(method_info)); p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_FUNCTION; + p_identifier->function_source_is_static = method_info.flags & METHOD_FLAG_STATIC; return; } @@ -4000,25 +4027,37 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident } if (found_source) { - bool source_is_variable = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE; - bool source_is_signal = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_SIGNAL; - if ((source_is_variable || source_is_signal) && static_context) { + const bool source_is_instance_variable = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE; + const bool source_is_instance_function = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_FUNCTION && !p_identifier->function_source_is_static; + const bool source_is_signal = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_SIGNAL; + + if (static_context && (source_is_instance_variable || source_is_instance_function || source_is_signal)) { // Get the parent function above any lambda. GDScriptParser::FunctionNode *parent_function = parser->current_function; while (parent_function && parent_function->source_lambda) { parent_function = parent_function->source_lambda->parent_function; } + String source_type; + if (source_is_instance_variable) { + source_type = "non-static variable"; + } else if (source_is_instance_function) { + source_type = "non-static function"; + } else { // source_is_signal + source_type = "signal"; + } + if (parent_function) { - push_error(vformat(R"*(Cannot access %s "%s" from the static function "%s()".)*", source_is_signal ? "signal" : "instance variable", p_identifier->name, parent_function->identifier->name), p_identifier); + push_error(vformat(R"*(Cannot access %s "%s" from the static function "%s()".)*", source_type, p_identifier->name, parent_function->identifier->name), p_identifier); } else { - push_error(vformat(R"*(Cannot access %s "%s" from a static variable initializer.)*", source_is_signal ? "signal" : "instance variable", p_identifier->name), p_identifier); + push_error(vformat(R"*(Cannot access %s "%s" from a static variable initializer.)*", source_type, p_identifier->name), p_identifier); } } if (current_lambda != nullptr) { - // If the identifier is a member variable (including the native class properties) or a signal, we consider the lambda to be using `self`, so we keep a reference to the current instance. - if (source_is_variable || source_is_signal) { + // If the identifier is a member variable (including the native class properties), member function, or a signal, + // we consider the lambda to be using `self`, so we keep a reference to the current instance. + if (source_is_instance_variable || source_is_instance_function || source_is_signal) { mark_lambda_use_self(); return; // No need to capture. } @@ -4378,7 +4417,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri switch (base_type.builtin_type) { // Expect int or real as index. case Variant::PACKED_BYTE_ARRAY: - case Variant::PACKED_COLOR_ARRAY: case Variant::PACKED_FLOAT32_ARRAY: case Variant::PACKED_FLOAT64_ARRAY: case Variant::PACKED_INT32_ARRAY: @@ -4386,6 +4424,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::PACKED_STRING_ARRAY: case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + case Variant::PACKED_VECTOR4_ARRAY: case Variant::ARRAY: case Variant::STRING: error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::FLOAT; @@ -4484,10 +4524,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::QUATERNION: result_type.builtin_type = Variant::FLOAT; break; - // Return Color. - case Variant::PACKED_COLOR_ARRAY: - result_type.builtin_type = Variant::COLOR; - break; // Return String. case Variant::PACKED_STRING_ARRAY: case Variant::STRING: @@ -4509,6 +4545,14 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::BASIS: result_type.builtin_type = Variant::VECTOR3; break; + // Return Color. + case Variant::PACKED_COLOR_ARRAY: + result_type.builtin_type = Variant::COLOR; + break; + // Return Vector4. + case Variant::PACKED_VECTOR4_ARRAY: + result_type.builtin_type = Variant::VECTOR4; + break; // Depends on the index. case Variant::TRANSFORM3D: case Variant::PROJECTION: @@ -5172,12 +5216,13 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", p_call->function_name, p_par_types.size(), p_call->arguments.size()), p_call->arguments[p_par_types.size()]); } - for (int i = 0; i < p_call->arguments.size(); i++) { + List<GDScriptParser::DataType>::ConstIterator par_itr = p_par_types.begin(); + for (int i = 0; i < p_call->arguments.size(); ++par_itr, ++i) { if (i >= p_par_types.size()) { // Already on vararg place. break; } - GDScriptParser::DataType par_type = p_par_types[i]; + GDScriptParser::DataType par_type = *par_itr; if (par_type.is_hard_type() && p_call->arguments[i]->is_constant) { update_const_expression_builtin_type(p_call->arguments[i], par_type, "pass"); diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index bfe090edb0..4cda3d3037 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -109,6 +109,7 @@ uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: case Variant::PACKED_COLOR_ARRAY: + case Variant::PACKED_VECTOR4_ARRAY: case Variant::VARIANT_MAX: // Arrays, dictionaries, and objects are reference counted, so we don't use the pool for them. temp_type = Variant::NIL; @@ -543,6 +544,9 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia case Variant::PACKED_COLOR_ARRAY: append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY); break; + case Variant::PACKED_VECTOR4_ARRAY: + append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY); + break; case Variant::NIL: case Variant::VARIANT_MAX: return; @@ -1196,23 +1200,49 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_ } void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) { - bool is_validated = false; - MethodBind *method = ClassDB::get_method(p_class, p_method); - if (!is_validated) { - // Perform regular call. - append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1); - for (int i = 0; i < p_arguments.size(); i++) { - append(p_arguments[i]); + // Perform regular call. + append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + CallTarget ct = get_call_target(p_target); + append(ct.target); + append(method); + append(p_arguments.size()); + ct.cleanup(); + return; +} + +void GDScriptByteCodeGenerator::write_call_native_static_validated(const GDScriptCodeGenerator::Address &p_target, MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) { + Variant::Type return_type = Variant::NIL; + bool has_return = p_method->has_return(); + + if (has_return) { + PropertyInfo return_info = p_method->get_return_info(); + return_type = return_info.type; + } + + CallTarget ct = get_call_target(p_target, return_type); + + if (has_return) { + Variant::Type temp_type = temporaries[ct.target.address].type; + if (temp_type != return_type) { + write_type_adjust(ct.target, return_type); } - CallTarget ct = get_call_target(p_target); - append(ct.target); - append(method); - append(p_arguments.size()); - ct.cleanup(); - return; } + + GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN; + append_opcode_and_argcount(code, 1 + p_arguments.size()); + + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(ct.target); + append(p_arguments.size()); + append(p_method); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) { @@ -1547,6 +1577,10 @@ void GDScriptByteCodeGenerator::write_for(const Address &p_variable, bool p_use_ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY; iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_COLOR_ARRAY; break; + case Variant::PACKED_VECTOR4_ARRAY: + begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY; + iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR4_ARRAY; + break; default: break; } diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 5a736b2554..34f56a2f5c 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -518,6 +518,7 @@ public: virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override; + virtual void write_call_native_static_validated(const Address &p_target, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index 4c33ed499a..c1c0b61395 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -131,6 +131,7 @@ public: virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0; + virtual void write_call_native_static_validated(const Address &p_target, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 734e37bc09..e62972b949 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -37,7 +37,8 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" -#include "core/core_string_names.h" + +#include "scene/scene_string_names.h" bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) { if (codegen.function_node && codegen.function_node->is_static) { @@ -241,9 +242,9 @@ static bool _can_use_validate_call(const MethodBind *p_method, const Vector<GDSc } MethodInfo info; ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info); - for (int i = 0; i < p_arguments.size(); i++) { - const PropertyInfo &prop = info.arguments[i]; - if (!_is_exact_type(prop, p_arguments[i].type)) { + int i = 0; + for (List<PropertyInfo>::ConstIterator itr = info.arguments.begin(); itr != info.arguments.end(); ++itr, ++i) { + if (!_is_exact_type(*itr, p_arguments[i].type)) { return false; } } @@ -346,7 +347,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code scr = scr->_base; } - if (nc && (identifier == CoreStringNames::get_singleton()->_free || ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) { + if (nc && (identifier == CoreStringName(free_) || ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) { // Get like it was a property. GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here. GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF); @@ -673,7 +674,15 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") && ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) { // It's a static native method call. - gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); + StringName class_name = static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name; + MethodBind *method = ClassDB::get_method(class_name, subscript->attribute->name); + if (_can_use_validate_call(method, arguments)) { + // Exact arguments, use validated call. + gen->write_call_native_static_validated(result, method, arguments); + } else { + // Not exact arguments, use regular static call + gen->write_call_native_static(result, class_name, subscript->attribute->name, arguments); + } } else { GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); if (r_error) { @@ -2227,7 +2236,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); } else { if (p_for_ready) { - func_name = "_ready"; + func_name = SceneStringName(_ready); } else { func_name = "@implicit_new"; } @@ -2658,7 +2667,10 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script, false); + ERR_FAIL_COND_V_MSG(base_type.native_type == StringName(), ERR_BUG, vformat(R"(Failed to get base class for "%s")", p_script->path)); + int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type]; + p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; ERR_FAIL_COND_V(p_script->native.is_null(), ERR_BUG); diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index c7873dcd52..0331045078 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -678,6 +678,50 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4 + argc; } break; + case OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN: { + int instr_var_args = _code_ptr[++ip]; + text += "call native static method validated (return) "; + MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; + int argc = _code_ptr[ip + 1 + instr_var_args]; + text += DADDR(1 + argc) + " = "; + text += method->get_instance_class(); + text += "."; + text += method->get_name(); + text += "("; + for (int i = 0; i < argc; i++) { + if (i > 0) + text += ", "; + text += DADDR(1 + i); + } + text += ")"; + incr = 4 + argc; + } break; + + case OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN: { + int instr_var_args = _code_ptr[++ip]; + + text += "call native static method validated (no return) "; + + MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; + + int argc = _code_ptr[ip + 1 + instr_var_args]; + + text += method->get_instance_class(); + text += "."; + text += method->get_name(); + text += "("; + + for (int i = 0; i < argc; i++) { + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + text += ")"; + + incr = 4 + argc; + } break; + case OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN: { int instr_var_args = _code_ptr[++ip]; text += "call method-bind validated (return) "; @@ -1002,6 +1046,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { m_macro(PACKED_VECTOR2_ARRAY); \ m_macro(PACKED_VECTOR3_ARRAY); \ m_macro(PACKED_COLOR_ARRAY); \ + m_macro(PACKED_VECTOR4_ARRAY); \ m_macro(OBJECT) case OPCODE_ITERATE_BEGIN: { @@ -1106,6 +1151,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY); DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY); DISASSEMBLE_TYPE_ADJUST(PACKED_COLOR_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR4_ARRAY); case OPCODE_ASSERT: { text += "assert ("; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 76d121af37..4ae39d80cd 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -911,6 +911,29 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a option.insert_text = option.display.quote(p_quote_style); r_result.insert(option.display, option); } + } else if (p_annotation->name == SNAME("@export_custom")) { + switch (p_argument) { + case 0: { + static HashMap<StringName, int64_t> items; + if (unlikely(items.is_empty())) { + CoreConstants::get_enum_values(SNAME("PropertyHint"), &items); + } + for (const KeyValue<StringName, int64_t> &item : items) { + ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + r_result.insert(option.display, option); + } + } break; + case 2: { + static HashMap<StringName, int64_t> items; + if (unlikely(items.is_empty())) { + CoreConstants::get_enum_values(SNAME("PropertyUsageFlags"), &items); + } + for (const KeyValue<StringName, int64_t> &item : items) { + ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + r_result.insert(option.display, option); + } + } break; + } } else if (p_annotation->name == SNAME("@warning_ignore")) { for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); @@ -1695,6 +1718,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, if (full) { // If not fully constant, setting this value is detrimental to the inference. r_type.value = a; + r_type.type.is_constant = true; } r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::BUILTIN; @@ -2739,9 +2763,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c // Handle user preference. if (opt.is_quoted()) { opt = opt.unquote().quote(quote_style); - if (use_string_names && info.arguments[p_argidx].type == Variant::STRING_NAME) { + if (use_string_names && info.arguments.get(p_argidx).type == Variant::STRING_NAME) { opt = opt.indent("&"); - } else if (use_node_paths && info.arguments[p_argidx].type == Variant::NODE_PATH) { + } else if (use_node_paths && info.arguments.get(p_argidx).type == Variant::NODE_PATH) { opt = opt.indent("^"); } } @@ -2752,7 +2776,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } if (p_argidx < method_args) { - PropertyInfo arg_info = info.arguments[p_argidx]; + const PropertyInfo &arg_info = info.arguments.get(p_argidx); if (arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { _find_enumeration_candidates(p_context, arg_info.class_name, r_result); } @@ -3340,19 +3364,17 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } method_hint += "("; - if (mi.arguments.size()) { - for (int i = 0; i < mi.arguments.size(); i++) { - if (i > 0) { - method_hint += ", "; - } - String arg = mi.arguments[i].name; - if (arg.contains(":")) { - arg = arg.substr(0, arg.find(":")); - } - method_hint += arg; - if (use_type_hint) { - method_hint += ": " + _get_visual_datatype(mi.arguments[i], true, class_name); - } + for (List<PropertyInfo>::ConstIterator arg_itr = mi.arguments.begin(); arg_itr != mi.arguments.end(); ++arg_itr) { + if (arg_itr != mi.arguments.begin()) { + method_hint += ", "; + } + String arg = arg_itr->name; + if (arg.contains(":")) { + arg = arg.substr(0, arg.find(":")); + } + method_hint += arg; + if (use_type_hint) { + method_hint += ": " + _get_visual_datatype(*arg_itr, true, class_name); } } method_hint += ")"; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 184d256bcd..759e92d68c 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -264,6 +264,8 @@ public: OPCODE_CALL_METHOD_BIND_RET, OPCODE_CALL_BUILTIN_STATIC, OPCODE_CALL_NATIVE_STATIC, + OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN, + OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN, OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, OPCODE_AWAIT, @@ -299,6 +301,7 @@ public: OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, + OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY, OPCODE_ITERATE_BEGIN_OBJECT, OPCODE_ITERATE, OPCODE_ITERATE_INT, @@ -319,6 +322,7 @@ public: OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, OPCODE_ITERATE_PACKED_COLOR_ARRAY, + OPCODE_ITERATE_PACKED_VECTOR4_ARRAY, OPCODE_ITERATE_OBJECT, OPCODE_STORE_GLOBAL, OPCODE_STORE_NAMED_GLOBAL, @@ -359,6 +363,7 @@ public: OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY, OPCODE_ASSERT, OPCODE_BREAKPOINT, OPCODE_LINE, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9799c6e610..9a4c92f601 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -101,7 +101,6 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation); // Export annotations. register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); - register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true); register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>); @@ -121,6 +120,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>); + register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_storage_annotation); register_annotation(MethodInfo("@export_custom", PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "PropertyHint"), PropertyInfo(Variant::STRING, "hint_string"), PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_BITFIELD, "PropertyUsageFlags")), AnnotationInfo::VARIABLE, &GDScriptParser::export_custom_annotation, varray(PROPERTY_USAGE_DEFAULT)); // Export grouping annotations. register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); @@ -1877,6 +1877,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { case Node::CALL: // Fine. break; + case Node::PRELOAD: + // `preload` is a function-like keyword. + push_warning(expression, GDScriptWarning::RETURN_VALUE_DISCARDED, "preload"); + break; case Node::LAMBDA: // Standalone lambdas can't be used, so make this an error. push_error("Standalone lambdas cannot be accessed. Consider assigning it to a variable.", expression); @@ -3199,6 +3203,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre } GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p_previous_operand, bool p_can_assign) { + // We want code completion after a DOLLAR even if the current code is invalid. + make_completion_context(COMPLETION_GET_NODE, nullptr, -1, true); + if (!current.is_node_name() && !check(GDScriptTokenizer::Token::LITERAL) && !check(GDScriptTokenizer::Token::SLASH) && !check(GDScriptTokenizer::Token::PERCENT)) { push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous.get_name())); return nullptr; @@ -3254,7 +3261,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p path_state = PATH_STATE_SLASH; } - make_completion_context(COMPLETION_GET_NODE, get_node, context_argument++); + make_completion_context(COMPLETION_GET_NODE, get_node, context_argument++, true); if (match(GDScriptTokenizer::Token::LITERAL)) { if (previous.literal.get_type() != Variant::STRING) { @@ -4129,6 +4136,9 @@ static String _get_annotation_error_string(const StringName &p_annotation_name, case Variant::COLOR: types.push_back("PackedColorArray"); break; + case Variant::VECTOR4: + types.push_back("PackedVector4Array"); + break; default: break; } @@ -4289,7 +4299,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node case GDScriptParser::DataType::BUILTIN: variable->export_info.type = export_type.builtin_type; variable->export_info.hint = PROPERTY_HINT_NONE; - variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type); + variable->export_info.hint_string = String(); break; case GDScriptParser::DataType::NATIVE: if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { @@ -4390,12 +4400,6 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation); return false; } - } else if (p_annotation->name == SNAME("@export_storage")) { - use_default_variable_type_check = false; // Can be applied to a variable of any type. - - // Save the info because the compiler uses export info for overwriting member info. - variable->export_info = export_type.to_property_info(variable->identifier->name); - variable->export_info.usage |= PROPERTY_USAGE_STORAGE; } if (use_default_variable_type_check) { @@ -4415,19 +4419,50 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node if (variable->export_info.hint) { hint_prefix += "/" + itos(variable->export_info.hint); } + variable->export_info.type = original_export_type_builtin; variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; - variable->export_info.type = original_export_type_builtin; + variable->export_info.usage = PROPERTY_USAGE_DEFAULT; + variable->export_info.class_name = StringName(); } return true; } +// For `@export_storage` and `@export_custom`, there is no need to check the variable type, argument values, +// or handle array exports in a special way, so they are implemented as separate methods. + +bool GDScriptParser::export_storage_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { + ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); + + VariableNode *variable = static_cast<VariableNode *>(p_node); + if (variable->is_static) { + push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); + return false; + } + if (variable->exported) { + push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); + return false; + } + + variable->exported = true; + + // Save the info because the compiler uses export info for overwriting member info. + variable->export_info = variable->get_datatype().to_property_info(variable->identifier->name); + variable->export_info.usage |= PROPERTY_USAGE_STORAGE; + + return true; +} + bool GDScriptParser::export_custom_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); ERR_FAIL_COND_V_MSG(p_annotation->resolved_arguments.size() < 2, false, R"(Annotation "@export_custom" requires 2 arguments.)"); VariableNode *variable = static_cast<VariableNode *>(p_node); + if (variable->is_static) { + push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); + return false; + } if (variable->exported) { push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); return false; @@ -4827,6 +4862,8 @@ static Variant::Type _variant_type_to_typed_array_element_type(Variant::Type p_t return Variant::VECTOR3; case Variant::PACKED_COLOR_ARRAY: return Variant::COLOR; + case Variant::PACKED_VECTOR4_ARRAY: + return Variant::VECTOR4; default: return Variant::NIL; } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 77cb8136f8..96358165c0 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -902,8 +902,11 @@ public: VariableNode *variable_source; ConstantNode *constant_source; SignalNode *signal_source; + FunctionNode *function_source; }; - FunctionNode *source_function = nullptr; + bool function_source_is_static = false; // For non-GDScript scripts. + + FunctionNode *source_function = nullptr; // TODO: Rename to disambiguate `function_source`. int usages = 0; // Useful for binds/iterator variable. @@ -1494,6 +1497,7 @@ private: bool onready_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyHint t_hint, Variant::Type t_type> bool export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); + bool export_storage_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); bool export_custom_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyUsageFlags t_usage> bool export_group_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index e5b0f55df8..3e1de628d2 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -519,6 +519,10 @@ struct GDScriptUtilityFunctionsDefinitions { Vector<Color> d = *p_args[0]; *r_ret = d.size(); } break; + case Variant::PACKED_VECTOR4_ARRAY: { + Vector<Vector4> d = *p_args[0]; + *r_ret = d.size(); + } break; default: { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -756,7 +760,7 @@ Variant::Type GDScriptUtilityFunctions::get_function_argument_type(const StringN GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function); ERR_FAIL_NULL_V(info, Variant::NIL); ERR_FAIL_COND_V(p_arg >= info->info.arguments.size(), Variant::NIL); - return info->info.arguments[p_arg].type; + return info->info.arguments.get(p_arg).type; } int GDScriptUtilityFunctions::get_function_argument_count(const StringName &p_function) { diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 842975698b..5d1805696d 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -32,7 +32,6 @@ #include "gdscript_function.h" #include "gdscript_lambda_callable.h" -#include "core/core_string_names.h" #include "core/os/os.h" #ifdef DEBUG_ENABLED @@ -208,159 +207,165 @@ void (*type_init_function_table[])(Variant *) = { &VariantInitializer<PackedVector2Array>::init, // PACKED_VECTOR2_ARRAY. &VariantInitializer<PackedVector3Array>::init, // PACKED_VECTOR3_ARRAY. &VariantInitializer<PackedColorArray>::init, // PACKED_COLOR_ARRAY. + &VariantInitializer<PackedVector4Array>::init, // PACKED_VECTOR4_ARRAY. }; #if defined(__GNUC__) -#define OPCODES_TABLE \ - static const void *switch_table_ops[] = { \ - &&OPCODE_OPERATOR, \ - &&OPCODE_OPERATOR_VALIDATED, \ - &&OPCODE_TYPE_TEST_BUILTIN, \ - &&OPCODE_TYPE_TEST_ARRAY, \ - &&OPCODE_TYPE_TEST_NATIVE, \ - &&OPCODE_TYPE_TEST_SCRIPT, \ - &&OPCODE_SET_KEYED, \ - &&OPCODE_SET_KEYED_VALIDATED, \ - &&OPCODE_SET_INDEXED_VALIDATED, \ - &&OPCODE_GET_KEYED, \ - &&OPCODE_GET_KEYED_VALIDATED, \ - &&OPCODE_GET_INDEXED_VALIDATED, \ - &&OPCODE_SET_NAMED, \ - &&OPCODE_SET_NAMED_VALIDATED, \ - &&OPCODE_GET_NAMED, \ - &&OPCODE_GET_NAMED_VALIDATED, \ - &&OPCODE_SET_MEMBER, \ - &&OPCODE_GET_MEMBER, \ - &&OPCODE_SET_STATIC_VARIABLE, \ - &&OPCODE_GET_STATIC_VARIABLE, \ - &&OPCODE_ASSIGN, \ - &&OPCODE_ASSIGN_NULL, \ - &&OPCODE_ASSIGN_TRUE, \ - &&OPCODE_ASSIGN_FALSE, \ - &&OPCODE_ASSIGN_TYPED_BUILTIN, \ - &&OPCODE_ASSIGN_TYPED_ARRAY, \ - &&OPCODE_ASSIGN_TYPED_NATIVE, \ - &&OPCODE_ASSIGN_TYPED_SCRIPT, \ - &&OPCODE_CAST_TO_BUILTIN, \ - &&OPCODE_CAST_TO_NATIVE, \ - &&OPCODE_CAST_TO_SCRIPT, \ - &&OPCODE_CONSTRUCT, \ - &&OPCODE_CONSTRUCT_VALIDATED, \ - &&OPCODE_CONSTRUCT_ARRAY, \ - &&OPCODE_CONSTRUCT_TYPED_ARRAY, \ - &&OPCODE_CONSTRUCT_DICTIONARY, \ - &&OPCODE_CALL, \ - &&OPCODE_CALL_RETURN, \ - &&OPCODE_CALL_ASYNC, \ - &&OPCODE_CALL_UTILITY, \ - &&OPCODE_CALL_UTILITY_VALIDATED, \ - &&OPCODE_CALL_GDSCRIPT_UTILITY, \ - &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \ - &&OPCODE_CALL_SELF_BASE, \ - &&OPCODE_CALL_METHOD_BIND, \ - &&OPCODE_CALL_METHOD_BIND_RET, \ - &&OPCODE_CALL_BUILTIN_STATIC, \ - &&OPCODE_CALL_NATIVE_STATIC, \ - &&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \ - &&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \ - &&OPCODE_AWAIT, \ - &&OPCODE_AWAIT_RESUME, \ - &&OPCODE_CREATE_LAMBDA, \ - &&OPCODE_CREATE_SELF_LAMBDA, \ - &&OPCODE_JUMP, \ - &&OPCODE_JUMP_IF, \ - &&OPCODE_JUMP_IF_NOT, \ - &&OPCODE_JUMP_TO_DEF_ARGUMENT, \ - &&OPCODE_JUMP_IF_SHARED, \ - &&OPCODE_RETURN, \ - &&OPCODE_RETURN_TYPED_BUILTIN, \ - &&OPCODE_RETURN_TYPED_ARRAY, \ - &&OPCODE_RETURN_TYPED_NATIVE, \ - &&OPCODE_RETURN_TYPED_SCRIPT, \ - &&OPCODE_ITERATE_BEGIN, \ - &&OPCODE_ITERATE_BEGIN_INT, \ - &&OPCODE_ITERATE_BEGIN_FLOAT, \ - &&OPCODE_ITERATE_BEGIN_VECTOR2, \ - &&OPCODE_ITERATE_BEGIN_VECTOR2I, \ - &&OPCODE_ITERATE_BEGIN_VECTOR3, \ - &&OPCODE_ITERATE_BEGIN_VECTOR3I, \ - &&OPCODE_ITERATE_BEGIN_STRING, \ - &&OPCODE_ITERATE_BEGIN_DICTIONARY, \ - &&OPCODE_ITERATE_BEGIN_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \ - &&OPCODE_ITERATE_BEGIN_OBJECT, \ - &&OPCODE_ITERATE, \ - &&OPCODE_ITERATE_INT, \ - &&OPCODE_ITERATE_FLOAT, \ - &&OPCODE_ITERATE_VECTOR2, \ - &&OPCODE_ITERATE_VECTOR2I, \ - &&OPCODE_ITERATE_VECTOR3, \ - &&OPCODE_ITERATE_VECTOR3I, \ - &&OPCODE_ITERATE_STRING, \ - &&OPCODE_ITERATE_DICTIONARY, \ - &&OPCODE_ITERATE_ARRAY, \ - &&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \ - &&OPCODE_ITERATE_PACKED_INT32_ARRAY, \ - &&OPCODE_ITERATE_PACKED_INT64_ARRAY, \ - &&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \ - &&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \ - &&OPCODE_ITERATE_PACKED_STRING_ARRAY, \ - &&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \ - &&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \ - &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \ - &&OPCODE_ITERATE_OBJECT, \ - &&OPCODE_STORE_GLOBAL, \ - &&OPCODE_STORE_NAMED_GLOBAL, \ - &&OPCODE_TYPE_ADJUST_BOOL, \ - &&OPCODE_TYPE_ADJUST_INT, \ - &&OPCODE_TYPE_ADJUST_FLOAT, \ - &&OPCODE_TYPE_ADJUST_STRING, \ - &&OPCODE_TYPE_ADJUST_VECTOR2, \ - &&OPCODE_TYPE_ADJUST_VECTOR2I, \ - &&OPCODE_TYPE_ADJUST_RECT2, \ - &&OPCODE_TYPE_ADJUST_RECT2I, \ - &&OPCODE_TYPE_ADJUST_VECTOR3, \ - &&OPCODE_TYPE_ADJUST_VECTOR3I, \ - &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \ - &&OPCODE_TYPE_ADJUST_VECTOR4, \ - &&OPCODE_TYPE_ADJUST_VECTOR4I, \ - &&OPCODE_TYPE_ADJUST_PLANE, \ - &&OPCODE_TYPE_ADJUST_QUATERNION, \ - &&OPCODE_TYPE_ADJUST_AABB, \ - &&OPCODE_TYPE_ADJUST_BASIS, \ - &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \ - &&OPCODE_TYPE_ADJUST_PROJECTION, \ - &&OPCODE_TYPE_ADJUST_COLOR, \ - &&OPCODE_TYPE_ADJUST_STRING_NAME, \ - &&OPCODE_TYPE_ADJUST_NODE_PATH, \ - &&OPCODE_TYPE_ADJUST_RID, \ - &&OPCODE_TYPE_ADJUST_OBJECT, \ - &&OPCODE_TYPE_ADJUST_CALLABLE, \ - &&OPCODE_TYPE_ADJUST_SIGNAL, \ - &&OPCODE_TYPE_ADJUST_DICTIONARY, \ - &&OPCODE_TYPE_ADJUST_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \ - &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \ - &&OPCODE_ASSERT, \ - &&OPCODE_BREAKPOINT, \ - &&OPCODE_LINE, \ - &&OPCODE_END \ - }; \ +#define OPCODES_TABLE \ + static const void *switch_table_ops[] = { \ + &&OPCODE_OPERATOR, \ + &&OPCODE_OPERATOR_VALIDATED, \ + &&OPCODE_TYPE_TEST_BUILTIN, \ + &&OPCODE_TYPE_TEST_ARRAY, \ + &&OPCODE_TYPE_TEST_NATIVE, \ + &&OPCODE_TYPE_TEST_SCRIPT, \ + &&OPCODE_SET_KEYED, \ + &&OPCODE_SET_KEYED_VALIDATED, \ + &&OPCODE_SET_INDEXED_VALIDATED, \ + &&OPCODE_GET_KEYED, \ + &&OPCODE_GET_KEYED_VALIDATED, \ + &&OPCODE_GET_INDEXED_VALIDATED, \ + &&OPCODE_SET_NAMED, \ + &&OPCODE_SET_NAMED_VALIDATED, \ + &&OPCODE_GET_NAMED, \ + &&OPCODE_GET_NAMED_VALIDATED, \ + &&OPCODE_SET_MEMBER, \ + &&OPCODE_GET_MEMBER, \ + &&OPCODE_SET_STATIC_VARIABLE, \ + &&OPCODE_GET_STATIC_VARIABLE, \ + &&OPCODE_ASSIGN, \ + &&OPCODE_ASSIGN_NULL, \ + &&OPCODE_ASSIGN_TRUE, \ + &&OPCODE_ASSIGN_FALSE, \ + &&OPCODE_ASSIGN_TYPED_BUILTIN, \ + &&OPCODE_ASSIGN_TYPED_ARRAY, \ + &&OPCODE_ASSIGN_TYPED_NATIVE, \ + &&OPCODE_ASSIGN_TYPED_SCRIPT, \ + &&OPCODE_CAST_TO_BUILTIN, \ + &&OPCODE_CAST_TO_NATIVE, \ + &&OPCODE_CAST_TO_SCRIPT, \ + &&OPCODE_CONSTRUCT, \ + &&OPCODE_CONSTRUCT_VALIDATED, \ + &&OPCODE_CONSTRUCT_ARRAY, \ + &&OPCODE_CONSTRUCT_TYPED_ARRAY, \ + &&OPCODE_CONSTRUCT_DICTIONARY, \ + &&OPCODE_CALL, \ + &&OPCODE_CALL_RETURN, \ + &&OPCODE_CALL_ASYNC, \ + &&OPCODE_CALL_UTILITY, \ + &&OPCODE_CALL_UTILITY_VALIDATED, \ + &&OPCODE_CALL_GDSCRIPT_UTILITY, \ + &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \ + &&OPCODE_CALL_SELF_BASE, \ + &&OPCODE_CALL_METHOD_BIND, \ + &&OPCODE_CALL_METHOD_BIND_RET, \ + &&OPCODE_CALL_BUILTIN_STATIC, \ + &&OPCODE_CALL_NATIVE_STATIC, \ + &&OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN, \ + &&OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN, \ + &&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \ + &&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \ + &&OPCODE_AWAIT, \ + &&OPCODE_AWAIT_RESUME, \ + &&OPCODE_CREATE_LAMBDA, \ + &&OPCODE_CREATE_SELF_LAMBDA, \ + &&OPCODE_JUMP, \ + &&OPCODE_JUMP_IF, \ + &&OPCODE_JUMP_IF_NOT, \ + &&OPCODE_JUMP_TO_DEF_ARGUMENT, \ + &&OPCODE_JUMP_IF_SHARED, \ + &&OPCODE_RETURN, \ + &&OPCODE_RETURN_TYPED_BUILTIN, \ + &&OPCODE_RETURN_TYPED_ARRAY, \ + &&OPCODE_RETURN_TYPED_NATIVE, \ + &&OPCODE_RETURN_TYPED_SCRIPT, \ + &&OPCODE_ITERATE_BEGIN, \ + &&OPCODE_ITERATE_BEGIN_INT, \ + &&OPCODE_ITERATE_BEGIN_FLOAT, \ + &&OPCODE_ITERATE_BEGIN_VECTOR2, \ + &&OPCODE_ITERATE_BEGIN_VECTOR2I, \ + &&OPCODE_ITERATE_BEGIN_VECTOR3, \ + &&OPCODE_ITERATE_BEGIN_VECTOR3I, \ + &&OPCODE_ITERATE_BEGIN_STRING, \ + &&OPCODE_ITERATE_BEGIN_DICTIONARY, \ + &&OPCODE_ITERATE_BEGIN_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY, \ + &&OPCODE_ITERATE_BEGIN_OBJECT, \ + &&OPCODE_ITERATE, \ + &&OPCODE_ITERATE_INT, \ + &&OPCODE_ITERATE_FLOAT, \ + &&OPCODE_ITERATE_VECTOR2, \ + &&OPCODE_ITERATE_VECTOR2I, \ + &&OPCODE_ITERATE_VECTOR3, \ + &&OPCODE_ITERATE_VECTOR3I, \ + &&OPCODE_ITERATE_STRING, \ + &&OPCODE_ITERATE_DICTIONARY, \ + &&OPCODE_ITERATE_ARRAY, \ + &&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \ + &&OPCODE_ITERATE_PACKED_INT32_ARRAY, \ + &&OPCODE_ITERATE_PACKED_INT64_ARRAY, \ + &&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \ + &&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \ + &&OPCODE_ITERATE_PACKED_STRING_ARRAY, \ + &&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \ + &&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \ + &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \ + &&OPCODE_ITERATE_PACKED_VECTOR4_ARRAY, \ + &&OPCODE_ITERATE_OBJECT, \ + &&OPCODE_STORE_GLOBAL, \ + &&OPCODE_STORE_NAMED_GLOBAL, \ + &&OPCODE_TYPE_ADJUST_BOOL, \ + &&OPCODE_TYPE_ADJUST_INT, \ + &&OPCODE_TYPE_ADJUST_FLOAT, \ + &&OPCODE_TYPE_ADJUST_STRING, \ + &&OPCODE_TYPE_ADJUST_VECTOR2, \ + &&OPCODE_TYPE_ADJUST_VECTOR2I, \ + &&OPCODE_TYPE_ADJUST_RECT2, \ + &&OPCODE_TYPE_ADJUST_RECT2I, \ + &&OPCODE_TYPE_ADJUST_VECTOR3, \ + &&OPCODE_TYPE_ADJUST_VECTOR3I, \ + &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \ + &&OPCODE_TYPE_ADJUST_VECTOR4, \ + &&OPCODE_TYPE_ADJUST_VECTOR4I, \ + &&OPCODE_TYPE_ADJUST_PLANE, \ + &&OPCODE_TYPE_ADJUST_QUATERNION, \ + &&OPCODE_TYPE_ADJUST_AABB, \ + &&OPCODE_TYPE_ADJUST_BASIS, \ + &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \ + &&OPCODE_TYPE_ADJUST_PROJECTION, \ + &&OPCODE_TYPE_ADJUST_COLOR, \ + &&OPCODE_TYPE_ADJUST_STRING_NAME, \ + &&OPCODE_TYPE_ADJUST_NODE_PATH, \ + &&OPCODE_TYPE_ADJUST_RID, \ + &&OPCODE_TYPE_ADJUST_OBJECT, \ + &&OPCODE_TYPE_ADJUST_CALLABLE, \ + &&OPCODE_TYPE_ADJUST_SIGNAL, \ + &&OPCODE_TYPE_ADJUST_DICTIONARY, \ + &&OPCODE_TYPE_ADJUST_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY, \ + &&OPCODE_ASSERT, \ + &&OPCODE_BREAKPOINT, \ + &&OPCODE_LINE, \ + &&OPCODE_END \ + }; \ static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum."); #define OPCODE(m_op) \ @@ -428,6 +433,7 @@ void (*type_init_function_table[])(Variant *) = { #define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array #define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array #define OP_GET_PACKED_COLOR_ARRAY get_color_array +#define OP_GET_PACKED_VECTOR4_ARRAY get_vector4_array #define OP_GET_TRANSFORM3D get_transform #define OP_GET_TRANSFORM2D get_transform2d #define OP_GET_PROJECTION get_projection @@ -882,23 +888,27 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif #ifdef DEBUG_ENABLED if (!valid) { - Object *obj = dst->get_validated_object(); - String v = index->operator String(); - bool read_only_property = false; - if (obj) { - read_only_property = ClassDB::has_property(obj->get_class_name(), v) && (ClassDB::get_property_setter(obj->get_class_name(), v) == StringName()); - } - if (read_only_property) { - err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", v, _get_var_type(dst)); + if (dst->is_read_only()) { + err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "')."; } else { - if (!v.is_empty()) { - v = "'" + v + "'"; - } else { - v = "of type '" + _get_var_type(index) + "'"; + Object *obj = dst->get_validated_object(); + String v = index->operator String(); + bool read_only_property = false; + if (obj) { + read_only_property = ClassDB::has_property(obj->get_class_name(), v) && (ClassDB::get_property_setter(obj->get_class_name(), v) == StringName()); } - err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; - if (err_code == Variant::VariantSetError::SET_INDEXED_ERR) { - err_text = "Invalid assignment of index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; + if (read_only_property) { + err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", v, _get_var_type(dst)); + } else { + if (!v.is_empty()) { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; + if (err_code == Variant::VariantSetError::SET_INDEXED_ERR) { + err_text = "Invalid assignment of index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; + } } } OPCODE_BREAK; @@ -924,13 +934,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (!valid) { - String v = index->operator String(); - if (!v.is_empty()) { - v = "'" + v + "'"; + if (dst->is_read_only()) { + err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "')."; } else { - v = "of type '" + _get_var_type(index) + "'"; + String v = index->operator String(); + if (!v.is_empty()) { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; } - err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; OPCODE_BREAK; } #endif @@ -956,13 +970,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (oob) { - String v = index->operator String(); - if (!v.is_empty()) { - v = "'" + v + "'"; + if (dst->is_read_only()) { + err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "')."; } else { - v = "of type '" + _get_var_type(index) + "'"; + String v = index->operator String(); + if (!v.is_empty()) { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Out of bounds set index " + v + " (on base: '" + _get_var_type(dst) + "')"; } - err_text = "Out of bounds set index " + v + " (on base: '" + _get_var_type(dst) + "')"; OPCODE_BREAK; } #endif @@ -1090,15 +1108,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (!valid) { - Object *obj = dst->get_validated_object(); - bool read_only_property = false; - if (obj) { - read_only_property = ClassDB::has_property(obj->get_class_name(), *index) && (ClassDB::get_property_setter(obj->get_class_name(), *index) == StringName()); - } - if (read_only_property) { - err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", String(*index), _get_var_type(dst)); + if (dst->is_read_only()) { + err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "')."; } else { - err_text = "Invalid assignment of property or key '" + String(*index) + "' with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; + Object *obj = dst->get_validated_object(); + bool read_only_property = false; + if (obj) { + read_only_property = ClassDB::has_property(obj->get_class_name(), *index) && (ClassDB::get_property_setter(obj->get_class_name(), *index) == StringName()); + } + if (read_only_property) { + err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", String(*index), _get_var_type(dst)); + } else { + err_text = "Invalid assignment of property or key '" + String(*index) + "' with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; + } } OPCODE_BREAK; } @@ -1718,7 +1740,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (base_type == Variant::OBJECT) { if (base_obj) { MethodBind *method = ClassDB::get_method(base_class, *methodname); - if (*methodname == CoreStringNames::get_singleton()->_free || (method && !method->has_return())) { + if (*methodname == CoreStringName(free_) || (method && !method->has_return())) { err_text = R"(Trying to get a return value of a method that returns "void")"; OPCODE_BREAK; } @@ -1956,6 +1978,78 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN) { + LOAD_INSTRUCTION_ARGS + CHECK_SPACE(3 + instr_arg_count); + + ip += instr_arg_count; + + int argc = _code_ptr[ip + 1]; + GD_ERR_BREAK(argc < 0); + + GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); + MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + + Variant **argptrs = instruction_args; + +#ifdef DEBUG_ENABLED + uint64_t call_time = 0; + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { + call_time = OS::get_singleton()->get_ticks_usec(); + } +#endif + + GET_INSTRUCTION_ARG(ret, argc); + method->validated_call(nullptr, (const Variant **)argptrs, ret); + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { + uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time; + _profile_native_call(t_taken, method->get_name(), method->get_instance_class()); + function_call_time += t_taken; + } +#endif + + ip += 3; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN) { + LOAD_INSTRUCTION_ARGS + CHECK_SPACE(3 + instr_arg_count); + + ip += instr_arg_count; + + int argc = _code_ptr[ip + 1]; + GD_ERR_BREAK(argc < 0); + + GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); + MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + + Variant **argptrs = instruction_args; +#ifdef DEBUG_ENABLED + uint64_t call_time = 0; + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { + call_time = OS::get_singleton()->get_ticks_usec(); + } +#endif + + GET_INSTRUCTION_ARG(ret, argc); + VariantInternal::initialize(ret, Variant::NIL); + method->validated_call(nullptr, (const Variant **)argptrs, nullptr); + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { + uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time; + _profile_native_call(t_taken, method->get_name(), method->get_instance_class()); + function_call_time += t_taken; + } +#endif + + ip += 3; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN) { LOAD_INSTRUCTION_ARGS CHECK_SPACE(3 + instr_arg_count); @@ -2969,6 +3063,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR2, Vector2, get_vector2_array, VECTOR2, Vector2, get_vector2); OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR3, Vector3, get_vector3_array, VECTOR3, Vector3, get_vector3); OPCODE_ITERATE_BEGIN_PACKED_ARRAY(COLOR, Color, get_color_array, COLOR, Color, get_color); + OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR4, Vector4, get_vector4_array, VECTOR4, Vector4, get_vector4); OPCODE(OPCODE_ITERATE_BEGIN_OBJECT) { CHECK_SPACE(4); @@ -3001,7 +3096,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a const Variant *args[] = { &vref }; Callable::CallError ce; - Variant has_next = obj->callp(CoreStringNames::get_singleton()->_iter_init, args, 1, ce); + Variant has_next = obj->callp(CoreStringName(_iter_init), args, 1, ce); #ifdef DEBUG_ENABLED if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) { @@ -3017,7 +3112,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a *counter = ref[0]; GET_VARIANT_PTR(iterator, 2); - *iterator = obj->callp(CoreStringNames::get_singleton()->_iter_get, (const Variant **)&counter, 1, ce); + *iterator = obj->callp(CoreStringName(_iter_get), (const Variant **)&counter, 1, ce); #ifdef DEBUG_ENABLED if (ce.error != Callable::CallError::CALL_OK) { err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container); @@ -3304,6 +3399,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_ITERATE_PACKED_ARRAY(VECTOR2, Vector2, get_vector2_array, get_vector2); OPCODE_ITERATE_PACKED_ARRAY(VECTOR3, Vector3, get_vector3_array, get_vector3); OPCODE_ITERATE_PACKED_ARRAY(COLOR, Color, get_color_array, get_color); + OPCODE_ITERATE_PACKED_ARRAY(VECTOR4, Vector4, get_vector4_array, get_vector4); OPCODE(OPCODE_ITERATE_OBJECT) { CHECK_SPACE(4); @@ -3334,7 +3430,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a const Variant *args[] = { &vref }; Callable::CallError ce; - Variant has_next = obj->callp(CoreStringNames::get_singleton()->_iter_next, args, 1, ce); + Variant has_next = obj->callp(CoreStringName(_iter_next), args, 1, ce); #ifdef DEBUG_ENABLED if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) { @@ -3350,7 +3446,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a *counter = ref[0]; GET_VARIANT_PTR(iterator, 2); - *iterator = obj->callp(CoreStringNames::get_singleton()->_iter_get, (const Variant **)&counter, 1, ce); + *iterator = obj->callp(CoreStringName(_iter_get), (const Variant **)&counter, 1, ce); #ifdef DEBUG_ENABLED if (ce.error != Callable::CallError::CALL_OK) { err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container); @@ -3435,6 +3531,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY, PackedVector2Array); OPCODE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY, PackedVector3Array); OPCODE_TYPE_ADJUST(PACKED_COLOR_ARRAY, PackedColorArray); + OPCODE_TYPE_ADJUST(PACKED_VECTOR4_ARRAY, PackedVector4Array); OPCODE(OPCODE_ASSERT) { CHECK_SPACE(3); diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 48a0abe617..611a9ad2d9 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -74,7 +74,7 @@ String GDScriptWarning::get_message() const { case UNREACHABLE_PATTERN: return "Unreachable pattern (pattern after wildcard or bind)."; case STANDALONE_EXPRESSION: - return "Standalone expression (the line has no effect)."; + return "Standalone expression (the line may have no effect)."; case STANDALONE_TERNARY: return "Standalone ternary operator: the return value is being discarded."; case INCOMPATIBLE_TERNARY: diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index ad7af34bf1..2a3db4f508 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -510,7 +510,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN node_stack.push_back(p_func->body); while (!node_stack.is_empty()) { - GDScriptParser::Node *node = node_stack[0]; + GDScriptParser::Node *node = node_stack.front()->get(); node_stack.pop_front(); switch (node->type) { diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h index 2ace5ca446..4ae5ab6cbf 100644 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ b/modules/gdscript/language_server/gdscript_language_server.h @@ -34,7 +34,7 @@ #include "../gdscript_parser.h" #include "gdscript_language_protocol.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" class GDScriptLanguageServer : public EditorPlugin { GDCLASS(GDScriptLanguageServer, EditorPlugin); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 853a8e0f19..09defdf8cd 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -223,7 +223,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(path); String err_msg = "Failed parse script " + path; if (S) { - err_msg += "\n" + S->value->get_errors()[0].message; + err_msg += "\n" + S->value->get_errors().front()->get().message; } ERR_CONTINUE_MSG(err != OK, err_msg); } @@ -233,18 +233,25 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) { Error err; Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err); - if (OK == err) { - dir->list_dir_begin(); - String file_name = dir->get_next(); - while (file_name.length()) { - if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") { - list_script_files(p_root_dir.path_join(file_name), r_files); - } else if (file_name.ends_with(".gd")) { - String script_file = p_root_dir.path_join(file_name); - r_files.push_back(script_file); - } - file_name = dir->get_next(); + if (OK != err) { + return; + } + + // Ignore scripts in directories with a .gdignore file. + if (dir->file_exists(".gdignore")) { + return; + } + + dir->list_dir_begin(); + String file_name = dir->get_next(); + while (file_name.length()) { + if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") { + list_script_files(p_root_dir.path_join(file_name), r_files); + } else if (file_name.ends_with(".gd")) { + String script_file = p_root_dir.path_join(file_name); + r_files.push_back(script_file); } + file_name = dir->get_next(); } } @@ -612,8 +619,8 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { _get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners); - for (int i = 0; i < owners.size(); i++) { - NodePath owner_path = owners[i]; + for (const String &owner : owners) { + NodePath owner_path = owner; Ref<Resource> owner_res = ResourceLoader::load(owner_path); if (Object::cast_to<PackedScene>(owner_res.ptr())) { Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); @@ -688,7 +695,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } else { ScriptLanguage::LookupResult ret; - if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").find("new(") > -1) { + if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").contains("new(")) { symbol_identifier = "_init"; } if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) { diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index e3d16eaf42..fbfa4a0a79 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -38,7 +38,6 @@ #include "core/config/project_settings.h" #include "core/core_globals.h" -#include "core/core_string_names.h" #include "core/io/dir_access.h" #include "core/io/file_access_pack.h" #include "core/os/os.h" @@ -573,7 +572,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { const List<GDScriptParser::ParserError> &errors = parser.get_errors(); if (!errors.is_empty()) { // Only the first error since the following might be cascading. - result.output += errors[0].message + "\n"; // TODO: line, column? + result.output += errors.front()->get().message + "\n"; // TODO: line, column? } if (!p_is_generating) { result.passed = check_output(result.output); @@ -592,7 +591,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { const List<GDScriptParser::ParserError> &errors = parser.get_errors(); if (!errors.is_empty()) { // Only the first error since the following might be cascading. - result.output += errors[0].message + "\n"; // TODO: line, column? + result.output += errors.front()->get().message + "\n"; // TODO: line, column? } if (!p_is_generating) { result.passed = check_output(result.output); diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h index b2289ef9cc..d6befd2db3 100644 --- a/modules/gdscript/tests/gdscript_test_runner_suite.h +++ b/modules/gdscript/tests/gdscript_test_runner_suite.h @@ -81,11 +81,10 @@ TEST_CASE("[Modules][GDScript] Validate built-in API") { SUBCASE("[Modules][GDScript] Validate built-in methods") { for (const MethodInfo &mi : builtin_methods) { - for (int j = 0; j < mi.arguments.size(); j++) { - PropertyInfo arg = mi.arguments[j]; - - TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")), - vformat("Unnamed argument in position %d of built-in method '%s'.", j, mi.name)); + int i = 0; + for (List<PropertyInfo>::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++i) { + TEST_COND((itr->name.is_empty() || itr->name.begins_with("_unnamed_arg")), + vformat("Unnamed argument in position %d of built-in method '%s'.", i, mi.name)); } } } @@ -96,11 +95,10 @@ TEST_CASE("[Modules][GDScript] Validate built-in API") { SUBCASE("[Modules][GDScript] Validate built-in annotations") { for (const MethodInfo &ai : builtin_annotations) { - for (int j = 0; j < ai.arguments.size(); j++) { - PropertyInfo arg = ai.arguments[j]; - - TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")), - vformat("Unnamed argument in position %d of built-in annotation '%s'.", j, ai.name)); + int i = 0; + for (List<PropertyInfo>::ConstIterator itr = ai.arguments.begin(); itr != ai.arguments.end(); ++itr, ++i) { + TEST_COND((itr->name.is_empty() || itr->name.begins_with("_unnamed_arg")), + vformat("Unnamed argument in position %d of built-in annotation '%s'.", i, ai.name)); } } } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static.gd b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static.gd new file mode 100644 index 0000000000..e041aeb914 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static.gd @@ -0,0 +1,10 @@ +# GH-91403 + +static func static_func(): + print(non_static_func) + +func non_static_func(): + pass + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static.out b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static.out new file mode 100644 index 0000000000..d8d6c8bc1b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot access non-static function "non_static_func" from the static function "static_func()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static_in_lambda_param.gd b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static_in_lambda_param.gd new file mode 100644 index 0000000000..36bc9dbf15 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static_in_lambda_param.gd @@ -0,0 +1,15 @@ +# GH-91403 + +func non_static_func(): + pass + +static func static_func( + f := func (): + var g := func (): + print(non_static_func) + g.call() +): + f.call() + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static_in_lambda_param.out b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static_in_lambda_param.out new file mode 100644 index 0000000000..d8d6c8bc1b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_access_non_static_in_lambda_param.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot access non-static function "non_static_func" from the static function "static_func()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static.out b/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static.out index b78f131345..c094c08cd8 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Cannot call non-static function "non_static_func()" from static function "static_func()". +Cannot call non-static function "non_static_func()" from the static function "static_func()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda.out b/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda.out index b78f131345..c094c08cd8 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Cannot call non-static function "non_static_func()" from static function "static_func()". +Cannot call non-static function "non_static_func()" from the static function "static_func()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda_param.out b/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda_param.out index b78f131345..c094c08cd8 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda_param.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda_param.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Cannot call non-static function "non_static_func()" from static function "static_func()". +Cannot call non-static function "non_static_func()" from the static function "static_func()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda.gd b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda.gd new file mode 100644 index 0000000000..7ae5bea7d7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda.gd @@ -0,0 +1,14 @@ +# GH-91403 + +func non_static_func(): + pass + +static var static_var = func (): + var f := func (): + var g := func (): + print(non_static_func) + g.call() + f.call() + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda.out b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda.out new file mode 100644 index 0000000000..153e81b405 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot access non-static function "non_static_func" from a static variable initializer. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda_setter.gd b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda_setter.gd new file mode 100644 index 0000000000..7479afc532 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda_setter.gd @@ -0,0 +1,15 @@ +# GH-91403 + +func non_static_func(): + pass + +static var static_var: + set(_value): + var f := func (): + var g := func (): + print(non_static_func) + g.call() + f.call() + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda_setter.out b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda_setter.out new file mode 100644 index 0000000000..de43f2d3c4 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_access_non_static_in_lambda_setter.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot access non-static function "non_static_func" from the static function "@static_var_setter()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda_setter.out b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda_setter.out index cdf3ab2aeb..a285b80025 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda_setter.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda_setter.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Cannot call non-static function "non_static_func()" from static function "@static_var_setter()". +Cannot call non-static function "non_static_func()" from the static function "@static_var_setter()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_access.gd new file mode 100644 index 0000000000..a21b2c4470 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_access.gd @@ -0,0 +1,11 @@ +# GH-91403 + +@static_unload + +func non_static(): + return "non static" + +static var static_var = Callable(non_static) + +func test(): + print("does not run") diff --git a/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_access.out b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_access.out new file mode 100644 index 0000000000..a95069dc4f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_access.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot access non-static function "non_static" from a static variable initializer. diff --git a/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd index 73d0f9096c..18675e5725 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.gd @@ -345,3 +345,12 @@ func test(): prints(x and true) prints(x or false) prints(x or true) + + # TYPE_PACKED_VECTOR4_ARRAY + x = PackedVector4Array([Vector4.ONE]) + prints("TYPE_PACKED_VECTOR4_ARRAY") + prints(not x) + prints(x and false) + prints(x and true) + prints(x or false) + prints(x or true) diff --git a/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out index e2945c910a..47f9d7548b 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out +++ b/modules/gdscript/tests/scripts/analyzer/features/boolean_operators_for_all_types.out @@ -227,3 +227,9 @@ false true true true +TYPE_PACKED_VECTOR4_ARRAY +false +false +true +true +true diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd b/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd index 77ef9e2073..f861cadb5d 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd @@ -6,4 +6,3 @@ func test(): var a := Foo.A var b := a as int + 1 print(b) - diff --git a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out index 505af5f1f3..0d96f8c021 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out +++ b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out @@ -1,11 +1,11 @@ GDTEST_OK var test_1: Dictionary - hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_2: TestExportEnumAsDictionary.MyEnum - hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM + hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum" var test_3: Dictionary - hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_4: TestExportEnumAsDictionary.MyEnum - hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM + hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum" var test_5: TestExportEnumAsDictionary.MyEnum - hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM + hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum" diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd index 9d0324ead8..738b5f7b3a 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd @@ -3,4 +3,3 @@ const Constants = preload("gdscript_to_preload.notest.gd") func test(): var a := Constants.A print(a) - diff --git a/modules/gdscript/tests/scripts/analyzer/features/static_non_static_access.gd b/modules/gdscript/tests/scripts/analyzer/features/static_non_static_access.gd new file mode 100644 index 0000000000..80ceb6d1a9 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/static_non_static_access.gd @@ -0,0 +1,75 @@ +@static_unload + +static var static_var +var non_static_var + +signal my_signal() + +static func static_func(): + pass + +func non_static_func(): + pass + +static var test_static_var_lambda = func (): + static_func() + print(static_func) + static_var = 1 + print(static_var) + +var test_non_static_var_lambda = func (): + static_func() + print(static_func) + static_var = 1 + print(static_var) + + non_static_func() + print(non_static_func) + non_static_var = 1 + print(non_static_var) + my_signal.emit() + print(my_signal) + +static var test_static_var_setter: + set(_value): + static_func() + print(static_func) + static_var = 1 + print(static_var) + +var test_non_static_var_setter: + set(_value): + static_func() + print(static_func) + static_var = 1 + print(static_var) + + non_static_func() + print(non_static_func) + non_static_var = 1 + print(non_static_var) + my_signal.emit() + print(my_signal) + +static func test_static_func(): + static_func() + print(static_func) + static_var = 1 + print(static_var) + +func test_non_static_func(): + static_func() + print(static_func) + static_var = 1 + print(static_var) + + non_static_func() + print(non_static_func) + non_static_var = 1 + print(non_static_var) + my_signal.emit() + print(my_signal) + +func test(): + test_static_var_lambda = null + test_non_static_var_lambda = null diff --git a/modules/gdscript/tests/scripts/analyzer/features/static_non_static_access.out b/modules/gdscript/tests/scripts/analyzer/features/static_non_static_access.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/static_non_static_access.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg index 009ab9f9ce..9c580b711d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg index 0fb46a4704..446198dd35 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg index 009ab9f9ce..9c580b711d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg index 0fb46a4704..446198dd35 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg index 009ab9f9ce..9c580b711d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg index 0fb46a4704..446198dd35 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg index 009ab9f9ce..9c580b711d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg index 0fb46a4704..446198dd35 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg index a72b489be6..8b68d51a89 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg @@ -4,7 +4,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg index adf06c8707..72c0549d3b 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg @@ -4,7 +4,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg index 009ab9f9ce..9c580b711d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg index 0fb46a4704..446198dd35 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg index 009ab9f9ce..9c580b711d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg index 0fb46a4704..446198dd35 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg @@ -6,7 +6,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg index a72b489be6..8b68d51a89 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg @@ -4,7 +4,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; GDScript: class_a.notest.gd {"display": "property_of_a"}, {"display": "func_of_a"}, diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg index adf06c8707..72c0549d3b 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg @@ -4,7 +4,7 @@ include=[ {"display": "add_child"}, {"display": "owner"}, {"display": "child_entered_tree"}, - + ; AnimationPlayer {"display": "autoplay"}, {"display": "play"}, diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.gd b/modules/gdscript/tests/scripts/lsp/lambdas.gd index 6f5d468eea..fbee264f3b 100644 --- a/modules/gdscript/tests/scripts/lsp/lambdas.gd +++ b/modules/gdscript/tests/scripts/lsp/lambdas.gd @@ -7,7 +7,7 @@ var lambda_member1 := func(alpha: int, beta): return alpha + beta # | | ^^^^^ \1:alpha -> \1:alpha # ^^^^^^^^^^^^^^ \1 -> \1 -var lambda_member2 := func(alpha, beta: int) -> int: +var lambda_member2 := func(alpha, beta: int) -> int: # | | | | | | # | | | | | | # | | | | ^^^^ \2:beta -> \2:beta @@ -76,7 +76,7 @@ func _ready() -> void: # | | | | ^^^^ \local:beta -> \local:beta # | | ^^^^^ \local:alpha -> \local:alpha # ^^^^^^^^^^^^ \local -> \local - + var value := 42 # ^^^^^ local:value -> local:value var lambda_capture = func(): return value + some_name.length() diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.gd b/modules/gdscript/tests/scripts/lsp/local_variables.gd index b6cc46f7da..43e8937800 100644 --- a/modules/gdscript/tests/scripts/lsp/local_variables.gd +++ b/modules/gdscript/tests/scripts/lsp/local_variables.gd @@ -9,7 +9,7 @@ func test_member() -> void: # ^^^^ test -> test test += 3 #<^^ -> test - member += 5 + member += 5 #<^^^^ -> member test = return_arg(test) # | ^^^^ -> test @@ -22,4 +22,4 @@ func return_arg(arg: int) -> int: arg += 2 #<^ -> arg return arg - # ^^^ -> arg
\ No newline at end of file + # ^^^ -> arg diff --git a/modules/gdscript/tests/scripts/lsp/properties.gd b/modules/gdscript/tests/scripts/lsp/properties.gd index 8dfaee2e5b..1acaddbe2c 100644 --- a/modules/gdscript/tests/scripts/lsp/properties.gd +++ b/modules/gdscript/tests/scripts/lsp/properties.gd @@ -16,7 +16,7 @@ var prop3 := 42: #<^^^ -> prop3 var prop4: int: # ^^^^^ prop4 -> prop4 - get: + get: return 42 var prop5 := 42: # ^^^^^ prop5 -> prop5 diff --git a/modules/gdscript/tests/scripts/lsp/scopes.gd b/modules/gdscript/tests/scripts/lsp/scopes.gd index 20b8fb9bd7..9314ab427c 100644 --- a/modules/gdscript/tests/scripts/lsp/scopes.gd +++ b/modules/gdscript/tests/scripts/lsp/scopes.gd @@ -68,16 +68,16 @@ func m(): match value: # ^^^^^ -> m:value - 13: + 13: print(value) # ^^^^^ -> m:value - [var start, _, var end]: + [var start, _, var end]: # | | ^^^ m:match:array:end -> m:match:array:end # ^^^^^ m:match:array:start -> m:match:array:start print(start + end) # | | ^^^ -> m:match:array:end # ^^^^^ -> m:match:array:start - { "name": var name }: + { "name": var name }: # ^^^^ m:match:dict:var -> m:match:dict:var print(name) # ^^^^ -> m:match:dict:var @@ -87,10 +87,10 @@ func m(): # ^^^^^^^^ -> m:match:var func m2(): - var value = 42 + var value = 42 # ^^^^^ m2:value -> m2:value - match value: + match value: # ^^^^^ -> m2:value { "name": var name }: # ^^^^ m2:match:dict:var -> m2:match:dict:var diff --git a/modules/gdscript/tests/scripts/parser/features/annotations.out b/modules/gdscript/tests/scripts/parser/features/annotations.out index 2ba9dd7496..6516672820 100644 --- a/modules/gdscript/tests/scripts/parser/features/annotations.out +++ b/modules/gdscript/tests/scripts/parser/features/annotations.out @@ -1,25 +1,25 @@ GDTEST_OK var test_1: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_2: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_3: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_4: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_5: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_6: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_7: int = 42 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_8: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_9: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_10: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_11: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_12: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.gd b/modules/gdscript/tests/scripts/parser/features/export_arrays.gd index ddfb186aa4..0d97135a7b 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_arrays.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.gd @@ -63,6 +63,7 @@ var temp_packed_float64_array: PackedFloat64Array var temp_packed_color_array: PackedColorArray var temp_packed_vector2_array: PackedVector2Array var temp_packed_vector3_array: PackedVector3Array +var temp_packed_vector4_array: PackedVector4Array @export var test_weak_packed_byte_array = temp_packed_byte_array @export var test_weak_packed_int32_array = temp_packed_int32_array @@ -72,6 +73,7 @@ var temp_packed_vector3_array: PackedVector3Array @export var test_weak_packed_color_array = temp_packed_color_array @export var test_weak_packed_vector2_array = temp_packed_vector2_array @export var test_weak_packed_vector3_array = temp_packed_vector3_array +@export var test_weak_packed_vector4_array = temp_packed_vector4_array @export_range(1, 10) var test_range_weak_packed_byte_array = temp_packed_byte_array @export_range(1, 10) var test_range_weak_packed_int32_array = temp_packed_int32_array diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.out b/modules/gdscript/tests/scripts/parser/features/export_arrays.out index 00e75fcc43..f1522d096f 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_arrays.out +++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.out @@ -1,137 +1,139 @@ GDTEST_OK var test_dir: Array - hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_dir_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_file: Array - hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_file_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_dir: Array - hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_dir_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_file: Array - hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_file_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag: Array - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav: Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys: Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render: Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav: Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys: Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render: Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_multiline: Array - hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<MULTILINE_TEXT>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_multiline_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<MULTILINE_TEXT>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_placeholder: Array - hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<PLACEHOLDER_TEXT>:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_placeholder_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<PLACEHOLDER_TEXT>:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int: Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_float_step: Array - hint=TYPE_STRING hint_string="int/RANGE:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float: Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float_packed32: PackedFloat32Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float_packed64: PackedFloat64Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing: Array - hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing_packed32: PackedFloat32Array - hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing_packed64: PackedFloat64Array - hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_node_path: Array - hint=TYPE_STRING hint_string="NodePath/NODE_PATH_VALID_TYPES:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<NodePath>/<NODE_PATH_VALID_TYPES>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color: Array - hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color_packed: PackedColorArray - hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_byte_array: PackedByteArray - hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int32_array: PackedInt32Array - hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int64_array: PackedInt64Array - hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_float32_array: PackedFloat32Array - hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_float64_array: PackedFloat64Array - hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_color_array: PackedColorArray - hint=TYPE_STRING hint_string="Color:Color" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_vector2_array: PackedVector2Array - hint=TYPE_STRING hint_string="Vector2:Vector2" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Vector2>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_vector3_array: PackedVector3Array - hint=TYPE_STRING hint_string="Vector3:Vector3" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Vector3>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_weak_packed_vector4_array: PackedVector4Array + hint=TYPE_STRING hint_string="<Vector4>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_byte_array: PackedByteArray - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_int32_array: PackedInt32Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_int64_array: PackedInt64Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_float32_array: PackedFloat32Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_float64_array: PackedFloat64Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_noalpha_weak_packed_color_array: PackedColorArray - hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.out b/modules/gdscript/tests/scripts/parser/features/export_enum.out index c87f9b17f0..31d3fa8902 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_enum.out +++ b/modules/gdscript/tests/scripts/parser/features/export_enum.out @@ -1,41 +1,41 @@ GDTEST_OK var test_untyped: int = null - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_with_values: int = null - hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_variant: int = null - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_int: int = 0 - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_string: String = "" - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_array_int: Array = Array[int]([]) - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_array_string: Array = Array[String]([]) - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_byte_array: PackedByteArray = PackedByteArray() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int32_array: PackedInt32Array = PackedInt32Array() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int64_array: PackedInt64Array = PackedInt64Array() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_string_array: PackedStringArray = PackedStringArray() - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_variant: int = null - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_int: int = 0 - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_string: String = "" - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_array_int: Array = Array[int]([]) - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_array_string: Array = Array[String]([]) - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_array_int: Array = Array[int]([]) - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_packed_int32_array: PackedInt32Array = PackedInt32Array() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_array_string: Array = Array[String]([]) - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_packed_string_array: PackedStringArray = PackedStringArray() - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd index 2a218774de..8b343de5ef 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd @@ -2,19 +2,43 @@ extends Node const Utils = preload("../../utils.notest.gd") +# Built-in types. @export var test_weak_int = 1 @export var test_hard_int: int = 2 -@export_storage var test_storage_untyped -@export_storage var test_storage_weak_int = 3 # Property info still `Variant`, unlike `@export`. -@export_storage var test_storage_hard_int: int = 4 @export_range(0, 100) var test_range = 100 @export_range(0, 100, 1) var test_range_step = 101 @export_range(0, 100, 1, "or_greater") var test_range_step_or_greater = 102 @export var test_color: Color @export_color_no_alpha var test_color_no_alpha: Color @export_node_path("Sprite2D", "Sprite3D", "Control", "Node") var test_node_path := ^"hello" -@export var test_node: Node -@export var test_node_array: Array[Node] + +# Enums. +@export var test_side: Side +@export var test_atm: AutoTranslateMode + +# Resources and nodes. +@export var test_image: Image +@export var test_timer: Timer + +# Arrays. +@export var test_array: Array +@export var test_array_bool: Array[bool] +@export var test_array_array: Array[Array] +@export var test_array_side: Array[Side] +@export var test_array_atm: Array[AutoTranslateMode] +@export var test_array_image: Array[Image] +@export var test_array_timer: Array[Timer] + +# `@export_storage`. +@export_storage var test_storage_untyped +@export_storage var test_storage_weak_int = 3 # Property info still `Variant`, unlike `@export`. +@export_storage var test_storage_hard_int: int = 4 + +# `@export_custom`. +# NOTE: `PROPERTY_USAGE_NIL_IS_VARIANT` flag will be removed. +@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_untyped +@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_weak_int = 5 +@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_hard_int: int = 6 func test(): for property in get_property_list(): diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out index b3f9d0ca9c..99d7b27130 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.out +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -1,27 +1,51 @@ GDTEST_OK var test_weak_int: int = 1 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_int: int = 2 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE -var test_storage_untyped: Variant = null - hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT -var test_storage_weak_int: Variant = 3 - hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT -var test_storage_hard_int: int = 4 - hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range: int = 100 - hint=RANGE hint_string="0,100" usage=DEFAULT|SCRIPT_VARIABLE + hint=RANGE hint_string="0,100" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_step: int = 101 - hint=RANGE hint_string="0,100,1" usage=DEFAULT|SCRIPT_VARIABLE + hint=RANGE hint_string="0,100,1" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_step_or_greater: int = 102 - hint=RANGE hint_string="0,100,1,or_greater" usage=DEFAULT|SCRIPT_VARIABLE + hint=RANGE hint_string="0,100,1,or_greater" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color: Color = Color(0, 0, 0, 1) - hint=NONE hint_string="Color" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color_no_alpha: Color = Color(0, 0, 0, 1) - hint=COLOR_NO_ALPHA hint_string="" usage=DEFAULT|SCRIPT_VARIABLE + hint=COLOR_NO_ALPHA hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_node_path: NodePath = NodePath("hello") - hint=NODE_PATH_VALID_TYPES hint_string="Sprite2D,Sprite3D,Control,Node" usage=DEFAULT|SCRIPT_VARIABLE -var test_node: Node = null - hint=NODE_TYPE hint_string="Node" usage=DEFAULT|SCRIPT_VARIABLE -var test_node_array: Array = Array[Node]([]) - hint=TYPE_STRING hint_string="Object/NODE_TYPE:Node" usage=DEFAULT|SCRIPT_VARIABLE + hint=NODE_PATH_VALID_TYPES hint_string="Sprite2D,Sprite3D,Control,Node" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_side: Side = 0 + hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side" +var test_atm: Node.AutoTranslateMode = 0 + hint=ENUM hint_string="Auto Translate Mode Inherit:0,Auto Translate Mode Always:1,Auto Translate Mode Disabled:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.AutoTranslateMode" +var test_image: Image = null + hint=RESOURCE_TYPE hint_string="Image" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"Image" +var test_timer: Timer = null + hint=NODE_TYPE hint_string="Timer" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"Timer" +var test_array: Array = [] + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_bool: Array = Array[bool]([]) + hint=TYPE_STRING hint_string="<bool>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_array: Array = Array[Array]([]) + hint=TYPE_STRING hint_string="<Array>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_side: Array = Array[int]([]) + hint=TYPE_STRING hint_string="<int>/<ENUM>:Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_atm: Array = Array[int]([]) + hint=TYPE_STRING hint_string="<int>/<ENUM>:Auto Translate Mode Inherit:0,Auto Translate Mode Always:1,Auto Translate Mode Disabled:2" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_image: Array = Array[Image]([]) + hint=TYPE_STRING hint_string="<Object>/<RESOURCE_TYPE>:Image" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_timer: Array = Array[Timer]([]) + hint=TYPE_STRING hint_string="<Object>/<NODE_TYPE>:Timer" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_storage_untyped: Variant = null + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT class_name=&"" +var test_storage_weak_int: Variant = 3 + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT class_name=&"" +var test_storage_hard_int: int = 4 + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE class_name=&"" +var test_export_custom_untyped: null = null + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_export_custom_weak_int: int = 5 + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_export_custom_hard_int: int = 6 + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd index a278ea1154..24f4c14f50 100644 --- a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd @@ -23,4 +23,3 @@ func test(): bar([3]) bar([4]) bar([5]) - diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd index 00598e4d50..f8f70b8cc3 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd @@ -4,3 +4,4 @@ func i_return_int() -> int: func test(): i_return_int() + preload("../../utils.notest.gd") # `preload` is a function-like keyword. diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out index f2db4e9307..107051df6c 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out @@ -3,3 +3,7 @@ GDTEST_OK >> Line: 6 >> RETURN_VALUE_DISCARDED >> The function "i_return_int()" returns a value that will be discarded if not used. +>> WARNING +>> Line: 7 +>> RETURN_VALUE_DISCARDED +>> The function "preload()" returns a value that will be discarded if not used. diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd index dc4223ec2d..74f42b012b 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd +++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd @@ -6,3 +6,16 @@ func test(): Vector3.ZERO [true, false] float(125) + # The following statements should not produce `STANDALONE_EXPRESSION`: + var _a = 1 + _a = 2 # Assignment is a local (or global) side effect. + @warning_ignore("redundant_await") + await 3 # The `await` operand is usually a coroutine or a signal. + absi(4) # A call (in general) can have side effects. + @warning_ignore("return_value_discarded") + preload("../../utils.notest.gd") # A static initializer may have side effects. + """ + Python-like "comment". + """ + @warning_ignore("standalone_ternary") + 1 if 2 else 3 # Produces `STANDALONE_TERNARY` instead. diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out index a2c67a6e51..72c659c952 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out +++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out @@ -2,16 +2,16 @@ GDTEST_OK >> WARNING >> Line: 3 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). >> WARNING >> Line: 4 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). >> WARNING >> Line: 6 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). >> WARNING >> Line: 7 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out b/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out index c524a1ae6b..350d5d1d45 100644 --- a/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out +++ b/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> runtime/errors/constant_array_is_deep.gd >> 6 ->> Invalid assignment of property or key '0' with value of type 'int' on a base object of type 'Dictionary'. +>> Invalid assignment on read-only value (on base: 'Dictionary'). diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out index cf51b0262d..5f1f372b0a 100644 --- a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out +++ b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> runtime/errors/constant_dictionary_is_deep.gd >> 6 ->> Invalid assignment of index '0' (on base: 'Array') with value of type 'int'. +>> Invalid assignment on read-only value (on base: 'Array'). diff --git a/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.gd b/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.gd new file mode 100644 index 0000000000..2f31ecc52f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.gd @@ -0,0 +1,4 @@ +func test(): + var dictionary := { "a": 0 } + dictionary.make_read_only() + dictionary.a = 1 diff --git a/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out b/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out new file mode 100644 index 0000000000..f7d531e119 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/read_only_dictionary.gd +>> 4 +>> Invalid assignment on read-only value (on base: 'Dictionary'). diff --git a/modules/gdscript/tests/scripts/runtime/features/argument_count.gd b/modules/gdscript/tests/scripts/runtime/features/argument_count.gd index c67ce25cbe..104489cfe6 100644 --- a/modules/gdscript/tests/scripts/runtime/features/argument_count.gd +++ b/modules/gdscript/tests/scripts/runtime/features/argument_count.gd @@ -57,7 +57,7 @@ func test(): var lambda_callable_2 : Callable = func(_foo, _bar, _baz): pass print(lambda_callable_2.get_argument_count()) # Should print 3. - # Test lambas with self. + # Test lambdas with self. var lambda_self_callable_1 : Callable = func(_foo, _bar): return self print(lambda_self_callable_1.get_argument_count()) # Should print 2. var lambda_self_callable_2 : Callable = func(_foo, _bar, _baz): return self diff --git a/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd b/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd new file mode 100644 index 0000000000..a1a9e350b0 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd @@ -0,0 +1,6 @@ +func test(): + # Validated native static call with return value. + print(FileAccess.file_exists("some_file")) + + # Validated native static call without return value. + Node.print_orphan_nodes() diff --git a/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.out b/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.out new file mode 100644 index 0000000000..44302c8137 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.out @@ -0,0 +1,2 @@ +GDTEST_OK +false diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd index 809d0d28a9..5d8dafc4a1 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd @@ -140,3 +140,7 @@ func test(): # PackedColorArray value = PackedColorArray() print(value == null) + + # PackedVector4Array + value = PackedVector4Array() + print(value == null) diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out index 27423ab8e7..e0e222eccc 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out @@ -34,3 +34,4 @@ false false false false +false diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd index f46afb0f18..88286ede03 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd @@ -140,3 +140,7 @@ func test(): # PackedColorArray value = PackedColorArray() print(value != null) + + # PackedVector4Array + value = PackedVector4Array() + print(value != null) diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out index a11c47854a..f6e72aedd5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out @@ -34,3 +34,4 @@ true true true true +true diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd index 7649062fda..6ca1b3e490 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd @@ -136,3 +136,7 @@ func test(): # PackedColorArray value = PackedColorArray() print(null == value) + + # PackedVector4Array + value = PackedVector4Array() + print(null == value) diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out index 639f6027b9..27423ab8e7 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out @@ -33,3 +33,4 @@ false false false false +false diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd index 8d5f9df1b8..d7addfa390 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd @@ -136,3 +136,7 @@ func test(): # PackedColorArray value = PackedColorArray() print(null != value) + + # PackedVector4Array + value = PackedVector4Array() + print(null != value) diff --git a/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out index d1e332afba..a11c47854a 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out @@ -33,3 +33,4 @@ true true true true +true diff --git a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out index 9387ec50d7..a1e7233078 100644 --- a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out +++ b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out @@ -1,8 +1,8 @@ GDTEST_OK Not shadowed: Resource var test_1: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" @export_category("test_1") - hint=NONE hint_string="" usage=CATEGORY + hint=NONE hint_string="" usage=CATEGORY class_name=&"" var test_2: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd new file mode 100644 index 0000000000..99156adb28 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd @@ -0,0 +1,18 @@ +#GH-63329 +class A extends Node: + @onready var a := get_value("a") + + func get_value(var_name: String) -> String: + print(var_name) + return var_name + +class B extends A: + @onready var b := get_value("b") + + func _ready(): + pass + +func test(): + var node := B.new() + node._ready() + node.free() diff --git a/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out new file mode 100644 index 0000000000..b417ce67ca --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out @@ -0,0 +1,3 @@ +GDTEST_OK +a +b diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd index 0dbb252b0e..8579baf876 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.gd +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd @@ -40,3 +40,4 @@ func test(): print(PackedVector2Array([Vector2.ONE, Vector2.ZERO])) print(PackedVector3Array([Vector3.ONE, Vector3.ZERO])) print(PackedColorArray([Color.RED, Color.BLUE, Color.GREEN])) + print(PackedVector4Array([Vector4.ONE, Vector4.ZERO])) diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out index 1f33de00cc..7833b6e213 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.out +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out @@ -32,3 +32,4 @@ Node::[signal]property_list_changed [(1, 1), (0, 0)] [(1, 1, 1), (0, 0, 0)] [(1, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1)] +[(1, 1, 1, 1), (0, 0, 0, 0)] diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index 1cf46c179e..7fdd6556ec 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -55,18 +55,18 @@ static func get_human_readable_hint_string(property: Dictionary) -> String: if elem_type_hint.is_valid_int(): elem_type = elem_type_hint.to_int() - type_hint_prefixes += type_string(elem_type) + ":" + type_hint_prefixes += "<%s>:" % type_string(elem_type) else: if elem_type_hint.count("/") != 1: push_error("Invalid PROPERTY_HINT_TYPE_STRING format.") elem_type = elem_type_hint.get_slice("/", 0).to_int() elem_hint = elem_type_hint.get_slice("/", 1).to_int() - type_hint_prefixes += "%s/%s:" % [ - type_string(elem_type), - get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"), + type_hint_prefixes += "<%s>/<%s>:" % [ + type_string(elem_type), + get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"), ] - if elem_type < TYPE_ARRAY: + if elem_type < TYPE_ARRAY or hint_string.is_empty(): break return type_hint_prefixes + hint_string @@ -76,10 +76,11 @@ static func get_human_readable_hint_string(property: Dictionary) -> String: static func print_property_extended_info(property: Dictionary, base: Object = null, is_static: bool = false) -> void: print(get_property_signature(property, base, is_static)) - print(' hint=%s hint_string="%s" usage=%s' % [ + print(' hint=%s hint_string="%s" usage=%s class_name=&"%s"' % [ get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"), - get_human_readable_hint_string(property), + get_human_readable_hint_string(property).c_escape(), get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""), + property.class_name.c_escape(), ]) diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index f6965cf7cf..fbc72a0508 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -188,11 +188,11 @@ static void recursively_disassemble_functions(const Ref<GDScript> script, const const MethodInfo &mi = func->get_method_info(); String signature = "Disassembling " + mi.name + "("; - for (int i = 0; i < mi.arguments.size(); i++) { - if (i > 0) { + for (List<PropertyInfo>::ConstIterator arg_itr = mi.arguments.begin(); arg_itr != mi.arguments.end(); ++arg_itr) { + if (arg_itr != mi.arguments.begin()) { signature += ", "; } - signature += mi.arguments[i].name; + signature += arg_itr->name; } print_line(signature + ")"); #ifdef TOOLS_ENABLED diff --git a/modules/gdscript/tests/test_lsp.h b/modules/gdscript/tests/test_lsp.h index 6192272f80..b85c727bc5 100644 --- a/modules/gdscript/tests/test_lsp.h +++ b/modules/gdscript/tests/test_lsp.h @@ -227,7 +227,7 @@ Vector<InlineTestData> read_tests(const String &p_path) { if (InlineTestData::try_parse(lines, i, d)) { if (!d.name.is_empty()) { // Safety check: names must be unique. - if (names.find(d.name) != -1) { + if (names.has(d.name)) { FAIL(vformat("Duplicated name '%s' in '%s'. Names must be unique!", d.name, p_path)); } names.append(d.name); diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h index 683ff6d4f6..6bc6160571 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h @@ -36,7 +36,7 @@ #include "../gltf_document.h" #include "editor_scene_exporter_gltf_settings.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" class EditorFileDialog; class EditorInspector; diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp index d11300343a..16f32af903 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp @@ -39,7 +39,7 @@ bool EditorSceneExporterGLTFSettings::_set(const StringName &p_name, const Varia } if (p_name == StringName("image_format")) { _document->set_image_format(p_value); - emit_signal("property_list_changed"); + emit_signal(CoreStringName(property_list_changed)); return true; } if (p_name == StringName("lossy_quality")) { @@ -77,7 +77,7 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_l for (PropertyInfo prop : _property_list) { if (prop.name == "lossy_quality") { String image_format = get("image_format"); - bool is_image_format_lossy = image_format == "JPEG" || image_format.findn("Lossy") != -1; + bool is_image_format_lossy = image_format == "JPEG" || image_format.containsn("Lossy"); prop.usage = is_image_format_lossy ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE; } p_list->push_back(prop); @@ -86,7 +86,7 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_l void EditorSceneExporterGLTFSettings::_on_extension_property_list_changed() { generate_property_list(_document); - emit_signal("property_list_changed"); + emit_signal(CoreStringName(property_list_changed)); } bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) { @@ -136,8 +136,8 @@ void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p // Add properties from all document extensions. for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) { const Callable on_prop_changed = callable_mp(this, &EditorSceneExporterGLTFSettings::_on_extension_property_list_changed); - if (!extension->is_connected("property_list_changed", on_prop_changed)) { - extension->connect("property_list_changed", on_prop_changed); + if (!extension->is_connected(CoreStringName(property_list_changed), on_prop_changed)) { + extension->connect(CoreStringName(property_list_changed), on_prop_changed); } const String config_prefix = get_friendly_config_prefix(extension); _config_name_to_extension_map[config_prefix] = extension; diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 42c3ecc7cb..ccf347e03e 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -493,7 +493,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() { blender_path_browse = memnew(Button); blender_path_browse->set_text(TTR("Browse")); - blender_path_browse->connect("pressed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_browse_install)); + blender_path_browse->connect(SceneStringName(pressed), callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_browse_install)); hb->add_child(blender_path_browse); hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 4c32a29ce0..b92176a63a 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -105,10 +105,6 @@ static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) { } Error GLTFDocument::_serialize(Ref<GLTFState> p_state) { - if (!p_state->buffers.size()) { - p_state->buffers.push_back(Vector<uint8_t>()); - } - for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); Error err = ext->export_preserialize(p_state); @@ -243,7 +239,6 @@ Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> p_state) const { } Error GLTFDocument::_serialize_scenes(Ref<GLTFState> p_state) { - ERR_FAIL_COND_V_MSG(p_state->root_nodes.is_empty(), ERR_INVALID_DATA, "GLTF export: The scene must have at least one root node."); // Godot only supports one scene per glTF file. Array scenes; Dictionary scene_dict; @@ -251,7 +246,9 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> p_state) { p_state->json["scenes"] = scenes; p_state->json["scene"] = 0; // Add nodes to the scene dict. - scene_dict["nodes"] = p_state->root_nodes; + if (!p_state->root_nodes.is_empty()) { + scene_dict["nodes"] = p_state->root_nodes; + } if (!p_state->scene_name.is_empty()) { scene_dict["name"] = p_state->scene_name; } @@ -458,9 +455,15 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) { ERR_CONTINUE(err != OK); } + if (extensions.is_empty()) { + node.erase("extensions"); + } + nodes.push_back(node); } - p_state->json["nodes"] = nodes; + if (!nodes.is_empty()) { + p_state->json["nodes"] = nodes; + } return OK; } @@ -691,11 +694,11 @@ static Vector<uint8_t> _parse_base64_uri(const String &p_uri) { Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path) { print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); - if (!p_state->buffers.size()) { + if (p_state->buffers.is_empty()) { return OK; } Array buffers; - if (p_state->buffers.size()) { + if (!p_state->buffers.is_empty()) { Vector<uint8_t> buffer_data = p_state->buffers[0]; Dictionary gltf_buffer; @@ -730,7 +733,7 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> p_state, const String &p_p Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path) { print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); - if (!p_state->buffers.size()) { + if (p_state->buffers.is_empty()) { return OK; } Array buffers; @@ -1543,6 +1546,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_SCALAR; int component_type; @@ -1654,6 +1660,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> p_state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC2; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1704,6 +1713,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> p_state Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1768,6 +1780,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> p_sta Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1816,6 +1831,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> p_stat Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; @@ -1866,6 +1884,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1938,6 +1959,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> p_stat Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1985,6 +2009,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -2058,6 +2085,9 @@ GLTFAccessorIndex GLTFDocument::_encode_sparse_accessor_as_vec3(Ref<GLTFState> p Ref<GLTFAccessor> sparse_accessor; sparse_accessor.instantiate(); + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -2160,6 +2190,9 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; + if (p_state->buffers.is_empty()) { + p_state->buffers.push_back(Vector<uint8_t>()); + } int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_MAT4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -6944,7 +6977,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> p_state, const String p_path) const uint32_t text_chunk_type = 0x4E4F534A; //JSON uint32_t binary_data_length = 0; - if (p_state->buffers.size()) { + if (p_state->buffers.size() > 0) { binary_data_length = p_state->buffers[0].size(); } const uint32_t binary_chunk_length = ((binary_data_length + 3) & (~3)); @@ -6953,20 +6986,28 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> p_state, const String p_path) file->create(FileAccess::ACCESS_RESOURCES); file->store_32(magic); file->store_32(p_state->major_version); // version - file->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length + uint32_t total_length = header_size + chunk_header_size + text_chunk_length; + if (binary_chunk_length) { + total_length += chunk_header_size + binary_chunk_length; + } + file->store_32(total_length); + + // Write the JSON text chunk. file->store_32(text_chunk_length); file->store_32(text_chunk_type); file->store_buffer((uint8_t *)&cs[0], cs.length()); for (uint32_t pad_i = text_data_length; pad_i < text_chunk_length; pad_i++) { file->store_8(' '); } + + // Write a single binary chunk. if (binary_chunk_length) { file->store_32(binary_chunk_length); file->store_32(binary_chunk_type); file->store_buffer(p_state->buffers[0].ptr(), binary_data_length); - } - for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { - file->store_8(0); + for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { + file->store_8(0); + } } } else { err = _encode_buffer_bins(p_state, p_path); @@ -7032,7 +7073,7 @@ void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> p_state) { Vector<Ref<GLTFDocumentExtension>> GLTFDocument::all_document_extensions; void GLTFDocument::register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority) { - if (all_document_extensions.find(p_extension) == -1) { + if (!all_document_extensions.has(p_extension)) { if (p_first_priority) { all_document_extensions.insert(0, p_extension); } else { @@ -7073,7 +7114,7 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Erro const uint32_t text_chunk_type = 0x4E4F534A; //JSON int32_t binary_data_length = 0; - if (p_state->buffers.size()) { + if (p_state->buffers.size() > 0) { binary_data_length = p_state->buffers[0].size(); } const int32_t binary_chunk_length = binary_data_length; diff --git a/modules/gltf/skin_tool.cpp b/modules/gltf/skin_tool.cpp index 2fb55a5f9e..a344334d93 100644 --- a/modules/gltf/skin_tool.cpp +++ b/modules/gltf/skin_tool.cpp @@ -57,9 +57,9 @@ bool SkinTool::_capture_nodes_in_skin(const Vector<Ref<GLTFNode>> &nodes, Ref<GL if (found_joint) { // Mark it if we happen to find another skins joint... - if (current_node->joint && p_skin->joints.find(p_node_index) < 0) { + if (current_node->joint && !p_skin->joints.has(p_node_index)) { p_skin->joints.push_back(p_node_index); - } else if (p_skin->non_joints.find(p_node_index) < 0) { + } else if (!p_skin->non_joints.has(p_node_index)) { p_skin->non_joints.push_back(p_node_index); } } @@ -79,7 +79,7 @@ void SkinTool::_capture_nodes_for_multirooted_skin(Vector<Ref<GLTFNode>> &r_node const SkinNodeIndex parent = r_nodes[node_index]->parent; disjoint_set.insert(node_index); - if (p_skin->joints.find(parent) >= 0) { + if (p_skin->joints.has(parent)) { disjoint_set.create_union(parent, node_index); } } @@ -109,9 +109,9 @@ void SkinTool::_capture_nodes_for_multirooted_skin(Vector<Ref<GLTFNode>> &r_node while (r_nodes[current_node]->height > maxHeight) { SkinNodeIndex parent = r_nodes[current_node]->parent; - if (r_nodes[parent]->joint && p_skin->joints.find(parent) < 0) { + if (r_nodes[parent]->joint && !p_skin->joints.has(parent)) { p_skin->joints.push_back(parent); - } else if (p_skin->non_joints.find(parent) < 0) { + } else if (!p_skin->non_joints.has(parent)) { p_skin->non_joints.push_back(parent); } @@ -138,9 +138,9 @@ void SkinTool::_capture_nodes_for_multirooted_skin(Vector<Ref<GLTFNode>> &r_node const SkinNodeIndex current_node = roots[i]; const SkinNodeIndex parent = r_nodes[current_node]->parent; - if (r_nodes[parent]->joint && p_skin->joints.find(parent) < 0) { + if (r_nodes[parent]->joint && !p_skin->joints.has(parent)) { p_skin->joints.push_back(parent); - } else if (p_skin->non_joints.find(parent) < 0) { + } else if (!p_skin->non_joints.has(parent)) { p_skin->non_joints.push_back(parent); } @@ -166,7 +166,7 @@ Error SkinTool::_expand_skin(Vector<Ref<GLTFNode>> &r_nodes, Ref<GLTFSkin> p_ski const SkinNodeIndex parent = r_nodes[node_index]->parent; disjoint_set.insert(node_index); - if (all_skin_nodes.find(parent) >= 0) { + if (all_skin_nodes.has(parent)) { disjoint_set.create_union(parent, node_index); } } @@ -216,7 +216,7 @@ Error SkinTool::_verify_skin(Vector<Ref<GLTFNode>> &r_nodes, Ref<GLTFSkin> p_ski const SkinNodeIndex parent = r_nodes[node_index]->parent; disjoint_set.insert(node_index); - if (all_skin_nodes.find(parent) >= 0) { + if (all_skin_nodes.has(parent)) { disjoint_set.create_union(parent, node_index); } } @@ -365,7 +365,7 @@ Error SkinTool::_determine_skeletons( for (int j = 0; j < groups.size() && i != j; ++j) { const Vector<SkinNodeIndex> &group = groups[j]; - if (group.find(node_i_parent) >= 0) { + if (group.has(node_i_parent)) { const SkinNodeIndex node_j = highest_group_members[j]; skeleton_sets.create_union(node_i, node_j); } @@ -393,7 +393,7 @@ Error SkinTool::_determine_skeletons( // If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton for (int i = 0; i < skeleton_nodes.size(); ++i) { SkinNodeIndex skel_node_i = skeleton_nodes[i]; - if (skin->joints.find(skel_node_i) >= 0 || skin->non_joints.find(skel_node_i) >= 0) { + if (skin->joints.has(skel_node_i) || skin->non_joints.has(skel_node_i)) { skin->skeleton = skel_i; continue; } @@ -454,7 +454,7 @@ Error SkinTool::_reparent_non_joint_skeleton_subtrees( subtree_set.insert(node_i); const SkinNodeIndex parent_i = nodes[node_i]->parent; - if (parent_i >= 0 && p_non_joints.find(parent_i) >= 0 && !nodes[parent_i]->joint) { + if (parent_i >= 0 && p_non_joints.has(parent_i) && !nodes[parent_i]->joint) { subtree_set.create_union(parent_i, node_i); } } diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index ef7276f493..cf13068efa 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -135,7 +135,7 @@ <return type="Vector3" /> <param index="0" name="map_position" type="Vector3i" /> <description> - Returns the position of a grid cell in the GridMap's local coordinate space. To convert the returned value into global coordinates, use [method Node3D.to_global]. See also [method map_to_local]. + Returns the position of a grid cell in the GridMap's local coordinate space. To convert the returned value into global coordinates, use [method Node3D.to_global]. See also [method local_to_map]. </description> </method> <method name="resource_changed" deprecated="Use [signal Resource.changed] instead."> diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index d53bf7f7ec..27c74421db 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -32,7 +32,6 @@ #ifdef TOOLS_ENABLED -#include "core/core_string_names.h" #include "core/input/input.h" #include "core/os/keyboard.h" #include "editor/editor_node.h" @@ -949,7 +948,7 @@ void GridMapEditor::_update_mesh_library() { void GridMapEditor::edit(GridMap *p_gridmap) { if (node) { node->disconnect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids)); - node->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GridMapEditor::_update_mesh_library)); + node->disconnect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library)); if (mesh_library.is_valid()) { mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette)); mesh_library = Ref<MeshLibrary>(); @@ -987,7 +986,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { update_grid(); node->connect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids)); - node->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GridMapEditor::_update_mesh_library)); + node->connect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library)); _update_mesh_library(); } @@ -1225,8 +1224,8 @@ GridMapEditor::GridMapEditor() { spatial_editor_hb->add_child(floor); floor->connect("value_changed", callable_mp(this, &GridMapEditor::_floor_changed)); - floor->connect("mouse_exited", callable_mp(this, &GridMapEditor::_floor_mouse_exited)); - floor->get_line_edit()->connect("mouse_exited", callable_mp(this, &GridMapEditor::_floor_mouse_exited)); + floor->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited)); + floor->get_line_edit()->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited)); spatial_editor_hb->add_child(memnew(VSeparator)); @@ -1288,21 +1287,21 @@ GridMapEditor::GridMapEditor() { search_box->set_clear_button_enabled(true); hb->add_child(search_box); search_box->connect("text_changed", callable_mp(this, &GridMapEditor::_text_changed)); - search_box->connect("gui_input", callable_mp(this, &GridMapEditor::_sbox_input)); + search_box->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_sbox_input)); mode_thumbnail = memnew(Button); mode_thumbnail->set_theme_type_variation("FlatButton"); mode_thumbnail->set_toggle_mode(true); mode_thumbnail->set_pressed(true); hb->add_child(mode_thumbnail); - mode_thumbnail->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_THUMBNAIL)); + mode_thumbnail->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_THUMBNAIL)); mode_list = memnew(Button); mode_list->set_theme_type_variation("FlatButton"); mode_list->set_toggle_mode(true); mode_list->set_pressed(false); hb->add_child(mode_list); - mode_list->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_LIST)); + mode_list->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_LIST)); size_slider = memnew(HSlider); size_slider->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1319,7 +1318,7 @@ GridMapEditor::GridMapEditor() { mesh_library_palette->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); add_child(mesh_library_palette); mesh_library_palette->set_v_size_flags(SIZE_EXPAND_FILL); - mesh_library_palette->connect("gui_input", callable_mp(this, &GridMapEditor::_mesh_library_palette_input)); + mesh_library_palette->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_mesh_library_palette_input)); info_message = memnew(Label); info_message->set_text(TTR("Give a MeshLibrary resource to this GridMap to use its meshes.")); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index 924e21aef5..cfa0f0c35c 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -35,7 +35,7 @@ #include "../grid_map.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" #include "scene/gui/box_container.h" #include "scene/gui/item_list.h" #include "scene/gui/slider.h" diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 25519c6e3c..71171be3f1 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -30,14 +30,12 @@ #include "grid_map.h" -#include "core/core_string_names.h" #include "core/io/marshalls.h" #include "scene/3d/light_3d.h" #include "scene/resources/3d/mesh_library.h" #include "scene/resources/3d/primitive_meshes.h" #include "scene/resources/physics_material.h" #include "scene/resources/surface_tool.h" -#include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" #include "servers/rendering_server.h" @@ -266,7 +264,7 @@ void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) { } _recreate_octant_data(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } Ref<MeshLibrary> GridMap::get_mesh_library() const { @@ -1136,7 +1134,7 @@ void GridMap::_bind_methods() { BIND_CONSTANT(INVALID_CELL_ITEM); ADD_SIGNAL(MethodInfo("cell_size_changed", PropertyInfo(Variant::VECTOR3, "cell_size"))); - ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed)); + ADD_SIGNAL(MethodInfo(CoreStringName(changed))); } void GridMap::set_cell_scale(float p_scale) { diff --git a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp index 9960c4e07c..cd3814879a 100644 --- a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp +++ b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp @@ -31,13 +31,9 @@ #include "audio_stream_interactive_editor_plugin.h" #include "../audio_stream_interactive.h" -#include "core/input/input.h" -#include "core/os/keyboard.h" #include "editor/editor_node.h" -#include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" -#include "editor/themes/editor_scale.h" #include "scene/gui/check_box.h" #include "scene/gui/option_button.h" #include "scene/gui/spin_box.h" @@ -73,7 +69,7 @@ void AudioStreamInteractiveTransitionEditor::_edited() { int filler = use_filler ? filler_clip->get_selected() - 1 : 0; bool hold = hold_previous->is_pressed(); - EditorUndoRedoManager::get_singleton()->create_action("Edit Transitions"); + EditorUndoRedoManager::get_singleton()->create_action(TTR("Edit Transitions")); for (int i = 0; i < selected.size(); i++) { if (!enabled) { if (audio_stream_interactive->has_transition(selected[i].x, selected[i].y)) { @@ -177,7 +173,6 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() { }; for (int i = 0; i <= clip_count; i++) { for (int j = 0; j <= clip_count; j++) { - String txt; int from = i == clip_count ? AudioStreamInteractive::CLIP_ANY : i; int to = j == clip_count ? AudioStreamInteractive::CLIP_ANY : j; @@ -187,32 +182,34 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() { if (!exists) { if (audio_stream_interactive->has_transition(AudioStreamInteractive::CLIP_ANY, to)) { from = AudioStreamInteractive::CLIP_ANY; - tooltip = "Using Any Clip -> " + audio_stream_interactive->get_clip_name(to) + "."; + tooltip = vformat(TTR("Using Any Clip -> %s."), audio_stream_interactive->get_clip_name(to)); } else if (audio_stream_interactive->has_transition(from, AudioStreamInteractive::CLIP_ANY)) { to = AudioStreamInteractive::CLIP_ANY; - tooltip = "Using " + audio_stream_interactive->get_clip_name(from) + " -> Any Clip."; + tooltip = vformat(TTR("Using %s -> Any Clip."), audio_stream_interactive->get_clip_name(from)); } else if (audio_stream_interactive->has_transition(AudioStreamInteractive::CLIP_ANY, AudioStreamInteractive::CLIP_ANY)) { from = to = AudioStreamInteractive::CLIP_ANY; - tooltip = "Using All CLips -> Any Clip."; + tooltip = TTR("Using All Clips -> Any Clip."); } else { - tooltip = "No transition available."; + tooltip = TTR("No transition available."); } } + String from_time; + String to_time; if (audio_stream_interactive->has_transition(from, to)) { icon = fade_icons[audio_stream_interactive->get_transition_fade_mode(from, to)]; switch (audio_stream_interactive->get_transition_from_time(from, to)) { case AudioStreamInteractive::TRANSITION_FROM_TIME_IMMEDIATE: { - txt += TTR("Immediate"); + from_time = TTR("Immediate"); } break; case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BEAT: { - txt += TTR("Next Beat"); + from_time = TTR("Next Beat"); } break; case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BAR: { - txt += TTR("Next Bar"); + from_time = TTR("Next Bar"); } break; case AudioStreamInteractive::TRANSITION_FROM_TIME_END: { - txt += TTR("Clip End"); + from_time = TTR("Clip End"); } break; default: { } @@ -220,13 +217,13 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() { switch (audio_stream_interactive->get_transition_to_time(from, to)) { case AudioStreamInteractive::TRANSITION_TO_TIME_SAME_POSITION: { - txt += TTR(L"⮕ Same"); + to_time = TTR("Same", "Transition Time Position"); } break; case AudioStreamInteractive::TRANSITION_TO_TIME_START: { - txt += TTR(L"⮕ Start"); + to_time = TTR("Start", "Transition Time Position"); } break; case AudioStreamInteractive::TRANSITION_TO_TIME_PREVIOUS_POSITION: { - txt += TTR(L"⮕ Prev"); + to_time = TTR("Prev", "Transition Time Position"); } break; default: { } @@ -234,7 +231,7 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() { } rows[j]->set_icon(i, icon); - rows[j]->set_text(i, txt); + rows[j]->set_text(i, to_time.is_empty() ? from_time : vformat(U"%s ⮕ %s", from_time, to_time)); rows[j]->set_tooltip_text(i, tooltip); if (exists) { rows[j]->set_custom_color(i, font_color); @@ -253,8 +250,8 @@ void AudioStreamInteractiveTransitionEditor::edit(Object *p_obj) { return; } - Ref<Font> header_font = get_theme_font("bold", "EditorFonts"); - int header_font_size = get_theme_font_size("bold_size", "EditorFonts"); + Ref<Font> header_font = get_theme_font("bold", EditorStringName(EditorFonts)); + int header_font_size = get_theme_font_size("bold_size", EditorStringName(EditorFonts)); tree->clear(); rows.clear(); @@ -267,10 +264,10 @@ void AudioStreamInteractiveTransitionEditor::edit(Object *p_obj) { TreeItem *header = tree->create_item(root); // Header int header_index = clip_count + 1; header->set_text(header_index, TTR("From / To")); - header->set_editable(0, false); + header->set_selectable(header_index, false); filler_clip->clear(); - filler_clip->add_item("Disabled", -1); + filler_clip->add_item(TTR("Disabled"), -1); Color header_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)); @@ -280,7 +277,6 @@ void AudioStreamInteractiveTransitionEditor::edit(Object *p_obj) { for (int i = 0; i <= clip_count; i++) { int cell_index = i; int clip_i = i == clip_count ? AudioStreamInteractive::CLIP_ANY : i; - header->set_editable(cell_index, false); header->set_selectable(cell_index, false); header->set_custom_font(cell_index, header_font); header->set_custom_font_size(cell_index, header_font_size); @@ -332,6 +328,7 @@ AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor() split = memnew(HSplitContainer); add_child(split); tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_hide_root(true); tree->add_theme_constant_override("draw_guides", 1); tree->set_select_mode(Tree::SELECT_MULTI); @@ -343,9 +340,9 @@ AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor() split->add_child(edit_vb); transition_enabled = memnew(CheckBox); - transition_enabled->set_text(TTR("Use Transition")); - edit_vb->add_margin_child(TTR("Transition Enabled:"), transition_enabled); - transition_enabled->connect("pressed", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited)); + transition_enabled->set_text(TTR("Enabled")); + edit_vb->add_margin_child(TTR("Use Transition:"), transition_enabled); + transition_enabled->connect(SceneStringName(pressed), callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited)); transition_from = memnew(OptionButton); edit_vb->add_margin_child(TTR("Transition From:"), transition_from); @@ -375,11 +372,12 @@ AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor() filler_clip = memnew(OptionButton); edit_vb->add_margin_child(TTR("Filler Clip:"), filler_clip); + filler_clip->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); filler_clip->connect("item_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1)); hold_previous = memnew(CheckBox); hold_previous->set_text(TTR("Enabled")); - hold_previous->connect("pressed", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited)); + hold_previous->connect(SceneStringName(pressed), callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited)); edit_vb->add_margin_child(TTR("Hold Previous:"), hold_previous); set_exclusive(true); @@ -399,7 +397,7 @@ void EditorInspectorPluginAudioStreamInteractive::parse_end(Object *p_object) { if (Object::cast_to<AudioStreamInteractive>(p_object)) { Button *button = EditorInspector::create_inspector_action_button(TTR("Edit Transitions")); button->set_icon(audio_stream_interactive_transition_editor->get_editor_theme_icon(SNAME("Blend"))); - button->connect("pressed", callable_mp(this, &EditorInspectorPluginAudioStreamInteractive::_edit).bind(p_object)); + button->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorPluginAudioStreamInteractive::_edit).bind(p_object)); add_custom_control(button); } } diff --git a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h index 730d1ca83b..3c50b0d5cc 100644 --- a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h +++ b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h @@ -32,7 +32,7 @@ #define AUDIO_STREAM_INTERACTIVE_EDITOR_PLUGIN_H #include "editor/editor_inspector.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" #include "scene/gui/dialogs.h" class CheckBox; diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 835fb3e59d..7ac7bd8088 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -226,7 +226,7 @@ void LightmapperRD::_sort_triangle_clusters(uint32_t p_cluster_size, uint32_t p_ } } -Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata) { +Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_size, int p_denoiser_range, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata) { Vector<Size2i> sizes; for (int m_i = 0; m_i < mesh_instances.size(); m_i++) { @@ -261,7 +261,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ 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); // 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; @@ -428,6 +428,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i SWAP(edge.a, edge.b); SWAP(edge.na, edge.nb); SWAP(uv2.a, uv2.b); + SWAP(uv2.indices.x, uv2.indices.y); SWAP(edge_indices.x, edge_indices.y); } @@ -906,7 +907,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID return BAKE_OK; } -LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function) { +LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function) { RID denoise_params_buffer = p_rd->uniform_buffer_create(sizeof(DenoiseParams)); DenoiseParams denoise_params; denoise_params.spatial_bandwidth = 5.0f; @@ -914,6 +915,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh denoise_params.albedo_bandwidth = 1.0f; denoise_params.normal_bandwidth = 0.1f; denoise_params.filter_strength = 10.0f; + denoise_params.half_search_window = p_denoiser_range; p_rd->buffer_update(denoise_params_buffer, 0, sizeof(DenoiseParams), &denoise_params); Vector<RD::Uniform> uniforms = dilate_or_denoise_common_uniforms(p_source_light_tex, p_dest_light_tex); @@ -976,7 +978,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh return BAKE_OK; } -LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) { +LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) { int denoiser = GLOBAL_GET("rendering/lightmapping/denoising/denoiser"); String oidn_path = EDITOR_GET("filesystem/tools/oidn/oidn_denoise_path"); @@ -1008,7 +1010,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d Vector<Ref<Image>> albedo_images; Vector<Ref<Image>> emission_images; - BakeError bake_error = _blit_meshes_into_atlas(p_max_texture_size, albedo_images, emission_images, bounds, atlas_size, atlas_slices, p_step_function, p_bake_userdata); + BakeError bake_error = _blit_meshes_into_atlas(p_max_texture_size, p_denoiser_range, albedo_images, emission_images, bounds, atlas_size, atlas_slices, p_step_function, p_bake_userdata); if (bake_error != BAKE_OK) { return bake_error; } @@ -1793,7 +1795,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } else { // JNLM (built-in). SWAP(light_accum_tex, light_accum_tex2); - error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, atlas_size, atlas_slices, p_bake_sh, p_step_function); + error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, p_bake_sh, p_step_function); } if (unlikely(error != BAKE_OK)) { return error; diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h index 5414048ddc..487c44a480 100644 --- a/modules/lightmapper_rd/lightmapper_rd.h +++ b/modules/lightmapper_rd/lightmapper_rd.h @@ -262,16 +262,17 @@ class LightmapperRD : public Lightmapper { float albedo_bandwidth; float normal_bandwidth; + int half_search_window; float filter_strength; - float pad[3]; + float pad[2]; }; - BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata); + BakeError _blit_meshes_into_atlas(int p_max_texture_size, int p_denoiser_range, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata); void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, uint32_t p_cluster_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &r_triangle_indices_buffer, RID &r_cluster_indices_buffer, RID &r_cluster_aabbs_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata); void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform); BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices); - BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function); + BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function); Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name); Ref<Image> _read_pfm(const String &p_name); @@ -283,7 +284,7 @@ public: virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override; virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override; virtual void add_probe(const Vector3 &p_position) override; - virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override; + virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override; int get_bake_texture_count() const override; Ref<Image> get_bake_texture(int p_index) const override; diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 1d088450e9..9424d5a4c1 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -76,6 +76,7 @@ layout(set = 1, binding = 3) uniform DenoiseParams { float albedo_bandwidth; float normal_bandwidth; + int half_search_window; float filter_strength; } denoise_params; @@ -849,10 +850,10 @@ void main() { // Half the size of the patch window around each pixel that is weighted to compute the denoised pixel. // A value of 1 represents a 3x3 window, a value of 2 a 5x5 window, etc. - const int HALF_PATCH_WINDOW = 4; + const int HALF_PATCH_WINDOW = 3; // Half the size of the search window around each pixel that is denoised and weighted to compute the denoised pixel. - const int HALF_SEARCH_WINDOW = 10; + const int HALF_SEARCH_WINDOW = denoise_params.half_search_window; // For all of the following sigma values, smaller values will give less weight to pixels that have a bigger distance // in the feature being evaluated. Therefore, smaller values are likely to cause more noise to appear, but will also diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml index 1be8cc828d..0dbe06d220 100644 --- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml +++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml @@ -34,9 +34,20 @@ <member name="k2" type="float" setter="set_k2" getter="get_k2" default="0.215"> The k2 lens factor, see k1. </member> + <member name="offset_rect" type="Rect2" setter="set_offset_rect" getter="get_offset_rect" default="Rect2(0, 0, 1, 1)"> + Set the offset rect relative to the area being rendered. A length of 1 represents the whole rendering area on that axis. + </member> <member name="oversample" type="float" setter="set_oversample" getter="get_oversample" default="1.5"> The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance. </member> + <member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0"> + The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> + <member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0"> + The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. This improves performance at the cost of quality. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> <member name="xr_play_area_mode" type="int" setter="set_play_area_mode" getter="get_play_area_mode" overrides="XRInterface" enum="XRInterface.PlayAreaMode" default="1" /> </members> </class> diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 94a3f0777e..f27281866a 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -126,7 +126,7 @@ void MobileVRInterface::set_position_from_sensors() { // 9dof is a misleading marketing term coming from 3 accelerometer axis + 3 gyro axis + 3 magnetometer axis = 9 axis // but in reality this only offers 3 dof (yaw, pitch, roll) orientation - Basis orientation; + Basis orientation = head_transform.basis; uint64_t ticks = OS::get_singleton()->get_ticks_usec(); uint64_t ticks_elapsed = ticks - last_ticks; @@ -230,6 +230,9 @@ void MobileVRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("set_display_to_lens", "display_to_lens"), &MobileVRInterface::set_display_to_lens); ClassDB::bind_method(D_METHOD("get_display_to_lens"), &MobileVRInterface::get_display_to_lens); + ClassDB::bind_method(D_METHOD("set_offset_rect", "offset_rect"), &MobileVRInterface::set_offset_rect); + ClassDB::bind_method(D_METHOD("get_offset_rect"), &MobileVRInterface::get_offset_rect); + ClassDB::bind_method(D_METHOD("set_oversample", "oversample"), &MobileVRInterface::set_oversample); ClassDB::bind_method(D_METHOD("get_oversample"), &MobileVRInterface::get_oversample); @@ -243,9 +246,20 @@ void MobileVRInterface::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "iod", PROPERTY_HINT_RANGE, "4.0,10.0,0.1"), "set_iod", "get_iod"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "display_width", PROPERTY_HINT_RANGE, "5.0,25.0,0.1"), "set_display_width", "get_display_width"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "display_to_lens", PROPERTY_HINT_RANGE, "5.0,25.0,0.1"), "set_display_to_lens", "get_display_to_lens"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "offset_rect"), "set_offset_rect", "get_offset_rect"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversample", PROPERTY_HINT_RANGE, "1.0,2.0,0.1"), "set_oversample", "get_oversample"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "k1", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k1", "get_k1"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "k2", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k2", "get_k2"); + + ClassDB::bind_method(D_METHOD("get_vrs_min_radius"), &MobileVRInterface::get_vrs_min_radius); + ClassDB::bind_method(D_METHOD("set_vrs_min_radius", "radius"), &MobileVRInterface::set_vrs_min_radius); + + ClassDB::bind_method(D_METHOD("get_vrs_strength"), &MobileVRInterface::get_vrs_strength); + ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &MobileVRInterface::set_vrs_strength); + + ADD_GROUP("Vulkan VRS", "vrs_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_min_radius", PROPERTY_HINT_RANGE, "1.0,100.0,1.0"), "set_vrs_min_radius", "get_vrs_min_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); } void MobileVRInterface::set_eye_height(const double p_eye_height) { @@ -256,6 +270,14 @@ double MobileVRInterface::get_eye_height() const { return eye_height; } +void MobileVRInterface::set_offset_rect(const Rect2 &p_offset_rect) { + offset_rect = p_offset_rect; +} + +Rect2 MobileVRInterface::get_offset_rect() const { + return offset_rect; +} + void MobileVRInterface::set_iod(const double p_iod) { intraocular_dist = p_iod; }; @@ -304,6 +326,22 @@ double MobileVRInterface::get_k2() const { return k2; }; +float MobileVRInterface::get_vrs_min_radius() const { + return xr_vrs.get_vrs_min_radius(); +} + +void MobileVRInterface::set_vrs_min_radius(float p_vrs_min_radius) { + xr_vrs.set_vrs_min_radius(p_vrs_min_radius); +} + +float MobileVRInterface::get_vrs_strength() const { + return xr_vrs.get_vrs_strength(); +} + +void MobileVRInterface::set_vrs_strength(float p_vrs_strength) { + xr_vrs.set_vrs_strength(p_vrs_strength); +} + uint32_t MobileVRInterface::get_view_count() { // needs stereo... return 2; @@ -477,11 +515,18 @@ Vector<BlitToScreen> MobileVRInterface::post_draw_viewport(RID p_render_target, Vector<BlitToScreen> blit_to_screen; - // We must have a valid render target + // We must have a valid render target. ERR_FAIL_COND_V(!p_render_target.is_valid(), blit_to_screen); - // Because we are rendering to our device we must use our main viewport! - ERR_FAIL_COND_V(p_screen_rect == Rect2(), blit_to_screen); + // We will only output to screen if this is our main viewport. + if (p_screen_rect == Rect2()) { + // Warn the developer once, it's up to the developer to output to screen. + WARN_PRINT_ONCE("SubViewport used with MobileVRInterface, no output to screen"); + + return blit_to_screen; + } + + Rect2 modified_screen_rect = Rect2(p_screen_rect.position + offset_rect.position * p_screen_rect.size, p_screen_rect.size * offset_rect.size); // and add our blits BlitToScreen blit; @@ -494,16 +539,16 @@ Vector<BlitToScreen> MobileVRInterface::post_draw_viewport(RID p_render_target, blit.lens_distortion.aspect_ratio = aspect; // left eye - blit.dst_rect = p_screen_rect; + blit.dst_rect = modified_screen_rect; blit.dst_rect.size.width *= 0.5; blit.multi_view.layer = 0; blit.lens_distortion.eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0); blit_to_screen.push_back(blit); // right eye - blit.dst_rect = p_screen_rect; + blit.dst_rect = modified_screen_rect; blit.dst_rect.size.width *= 0.5; - blit.dst_rect.position.x = blit.dst_rect.size.width; + blit.dst_rect.position.x += blit.dst_rect.size.width; blit.multi_view.layer = 1; blit.lens_distortion.eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0); blit_to_screen.push_back(blit); @@ -528,6 +573,23 @@ void MobileVRInterface::process() { }; }; +RID MobileVRInterface::get_vrs_texture() { + PackedVector2Array eye_foci; + + Size2 target_size = get_render_target_size(); + real_t aspect_ratio = target_size.x / target_size.y; + uint32_t view_count = get_view_count(); + + for (uint32_t v = 0; v < view_count; v++) { + Projection cm = get_projection_for_view(v, aspect_ratio, 0.1, 1000.0); + Vector3 center = cm.xform(Vector3(0.0, 0.0, 999.0)); + + eye_foci.push_back(Vector2(center.x, center.y)); + } + + return xr_vrs.make_vrs_texture(target_size, eye_foci); +} + MobileVRInterface::MobileVRInterface() {} MobileVRInterface::~MobileVRInterface() { diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index f680d8aa11..490b1c393c 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -33,6 +33,7 @@ #include "servers/xr/xr_interface.h" #include "servers/xr/xr_positional_tracker.h" +#include "servers/xr/xr_vrs.h" /** The mobile interface is a native VR interface that can be used on Android and iOS phones. @@ -62,6 +63,8 @@ private: double display_to_lens = 4.0; double oversample = 1.5; + Rect2 offset_rect = Rect2(0, 0, 1, 1); // Full screen rect. + double k1 = 0.215; double k2 = 0.215; double aspect = 1.0; @@ -70,6 +73,8 @@ private: Ref<XRPositionalTracker> head; Transform3D head_transform; + XRVRS xr_vrs; + /* logic for processing our sensor data, this was originally in our positional tracker logic but I think that doesn't make sense in hindsight. It only makes marginally more sense to park it here for now, @@ -121,6 +126,9 @@ public: void set_display_width(const double p_display_width); double get_display_width() const; + void set_offset_rect(const Rect2 &p_offset_rect); + Rect2 get_offset_rect() const; + void set_display_to_lens(const double p_display_to_lens); double get_display_to_lens() const; @@ -133,6 +141,12 @@ public: void set_k2(const double p_k2); double get_k2() const; + float get_vrs_min_radius() const; + void set_vrs_min_radius(float p_vrs_min_radius); + + float get_vrs_strength() const; + void set_vrs_strength(float p_vrs_strength); + virtual StringName get_name() const override; virtual uint32_t get_capabilities() const override; @@ -156,6 +170,8 @@ public: virtual void process() override; + virtual RID get_vrs_texture() override; + MobileVRInterface(); ~MobileVRInterface(); }; diff --git a/modules/modules_builders.py b/modules/modules_builders.py deleted file mode 100644 index 5db7c88a90..0000000000 --- a/modules/modules_builders.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Functions used to generate source files during build time""" - - -def generate_modules_enabled(target, source, env): - with open(target[0].path, "w", encoding="utf-8", newline="\n") as f: - for module in env.module_list: - f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED")) - - -def generate_modules_tests(target, source, env): - import os - - with open(target[0].path, "w", encoding="utf-8", newline="\n") as f: - for header in source: - f.write('#include "%s"\n' % (os.path.normpath(header.path))) diff --git a/modules/mono/.editorconfig b/modules/mono/.editorconfig index 1e5ae28396..fcd10461ad 100644 --- a/modules/mono/.editorconfig +++ b/modules/mono/.editorconfig @@ -1,3 +1,7 @@ +[*.{sln,csproj}] +end_of_line = crlf +charset = utf-8-bom + [*.sln] indent_style = tab diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index c4aba577db..04af60e22f 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -166,10 +166,10 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Array arguments; signal_dict["arguments"] = arguments; - for (int i = 0; i < mi.arguments.size(); i++) { + for (const PropertyInfo &pi : mi.arguments) { Dictionary argument_dict; arguments.push_back(argument_dict); - argument_dict["type"] = mi.arguments[i].type; + argument_dict["type"] = pi.type; } } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index ff2ca9f0ce..36c8a40ed9 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1596,14 +1596,7 @@ void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const { return; } - const CSharpScript *top = script.ptr(); - while (top != nullptr) { - for (const CSharpScript::CSharpMethodInfo &E : top->methods) { - p_list->push_back(E.method_info); - } - - top = top->base_script.ptr(); - } + script->get_script_method_list(p_list); } bool CSharpInstance::has_method(const StringName &p_method) const { @@ -1771,16 +1764,19 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f } void CSharpInstance::connect_event_signals() { - // The script signals list includes the signals declared in base scripts. - for (CSharpScript::EventSignalInfo &signal : script->get_script_event_signals()) { - String signal_name = signal.name; + const CSharpScript *top = script.ptr(); + while (top != nullptr && top->valid) { + for (const CSharpScript::EventSignalInfo &signal : top->event_signals) { + String signal_name = signal.name; - // TODO: Use pooling for ManagedCallable instances. - EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name)); + // TODO: Use pooling for ManagedCallable instances. + EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name)); - Callable callable(event_signal_callable); - connected_event_signals.push_back(callable); - owner->connect(signal_name, callable); + Callable callable(event_signal_callable); + connected_event_signals.push_back(callable); + owner->connect(signal_name, callable); + } + top = top->base_script.ptr(); } } @@ -2624,25 +2620,33 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const { } } + if (base_script.is_valid()) { + return base_script->has_script_signal(p_signal); + } + return false; } -void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { +void CSharpScript::_get_script_signal_list(List<MethodInfo> *r_signals, bool p_include_base) const { if (!valid) { return; } - for (const EventSignalInfo &signal : get_script_event_signals()) { + for (const EventSignalInfo &signal : event_signals) { r_signals->push_back(signal.method_info); } -} -Vector<CSharpScript::EventSignalInfo> CSharpScript::get_script_event_signals() const { - if (!valid) { - return Vector<EventSignalInfo>(); + if (!p_include_base) { + return; + } + + if (base_script.is_valid()) { + base_script->get_script_signal_list(r_signals); } +} - return event_signals; +void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + _get_script_signal_list(r_signals, true); } bool CSharpScript::inherits_script(const Ref<Script> &p_script) const { diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index e3f39c50f4..c48e1a95c9 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -41,7 +41,7 @@ #include "core/templates/self_list.h" #ifdef TOOLS_ENABLED -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" #endif class CSharpScript; @@ -215,6 +215,8 @@ private: // Do not use unless you know what you are doing static void update_script_class_info(Ref<CSharpScript> p_script); + void _get_script_signal_list(List<MethodInfo> *r_signals, bool p_include_base) const; + protected: static void _bind_methods(); @@ -251,8 +253,6 @@ public: bool has_script_signal(const StringName &p_signal) const override; void get_script_signal_list(List<MethodInfo> *r_signals) const override; - Vector<EventSignalInfo> get_script_event_signals() const; - bool get_property_default_value(const StringName &p_property, Variant &r_value) const override; void get_script_property_list(List<PropertyInfo> *r_list) const override; void update_exports() override; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln index 9674626183..2c78645493 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln @@ -1,5 +1,8 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.NET.Sdk", "Godot.NET.Sdk\Godot.NET.Sdk.csproj", "{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators", "Godot.SourceGenerators\Godot.SourceGenerators.csproj", "{32D31B23-2A45-4099-B4F5-95B4C8FF7D9F}" @@ -37,4 +40,10 @@ Global {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {49831022-16BD-41E0-A5F3-EDE1279F4176} + EndGlobalSection EndGlobal diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj index ccef90c911..74623a60ba 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.Build.NoTargets/2.0.1"> +<Project Sdk="Microsoft.Build.NoTargets/2.0.1"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> @@ -14,6 +14,7 @@ <PackageType>MSBuildSdk</PackageType> <PackageTags>MSBuildSdk</PackageTags> <PackageLicenseExpression>MIT</PackageLicenseExpression> + <Copyright>Copyright (c) Godot Engine contributors</Copyright> <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Exclude target framework from the package dependencies as we don't include the build output --> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props index 5c3af17e77..c4034f1f9f 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props @@ -71,7 +71,7 @@ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('osx')) ">macos</GodotTargetPlatform> <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('win')) ">windows</GodotTargetPlatform> </PropertyGroup> - + <!-- Auto-detect the target Godot platform if it was not specified and there's no runtime identifier information. --> <PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' "> <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets index b51ce5cb8c..0391e9f829 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets @@ -11,10 +11,10 @@ <XCodePath Condition=" '$(XCodePath)' == '' ">/Applications/Xcode.app/Contents/Developer</XCodePath> <XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath> </PropertyGroup> - + <Target Name="PrepareBeforeIlcCompile" BeforeTargets="IlcCompile"> - + <Copy SourceFiles="%(ResolvedRuntimePack.PackageDirectory)/runtimes/$(RuntimeIdentifier)/native/icudt.dat" DestinationFolder="$(PublishDir)"/> <!-- We need to find the path to Xcode so we can set manual linker args to the correct SDKs @@ -29,9 +29,9 @@ <XCodePath>$(XcodeSelect)</XCodePath> <XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath> </PropertyGroup> - + <Message Importance="normal" Text="Found XCode at $(XcodeSelect)" Condition=" '$(FindXCode)' == 'true' "/> - + <ItemGroup> <LinkerArg Include="-mios-simulator-version-min=12.0 -isysroot %22$(XCodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22" Condition=" $(RuntimeIdentifier.Contains('simulator')) "/> @@ -54,5 +54,5 @@ </ItemGroup> <Copy SourceFiles="@(SymbolFiles)" DestinationFolder="$(PublishDir)$(TargetName).framework.dSYM"/> </Target> - + </Project> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj index d0907c1cd4..fc887313d5 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj index e5a81c0e1c..31a255dcdf 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs index 3cc5841097..724fb164e0 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs @@ -57,4 +57,13 @@ public class ScriptPropertiesGeneratorTests "ScriptBoilerplate_ScriptProperties.generated.cs", "OuterClass.NestedClass_ScriptProperties.generated.cs" ); } + + [Fact] + public async void AbstractGenericNode() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + "AbstractGenericNode.cs", + "AbstractGenericNode(Of T)_ScriptProperties.generated.cs" + ); + } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AbstractGenericNode(Of T)_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AbstractGenericNode(Of T)_ScriptProperties.generated.cs new file mode 100644 index 0000000000..a561c5fc0d --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AbstractGenericNode(Of T)_ScriptProperties.generated.cs @@ -0,0 +1,49 @@ +using Godot; +using Godot.NativeInterop; + +partial class AbstractGenericNode<T> +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword + /// <summary> + /// Cached StringNames for the properties and fields contained in this class, for fast lookup. + /// </summary> + public new class PropertyName : global::Godot.Node.PropertyName { + /// <summary> + /// Cached name for the 'MyArray' property. + /// </summary> + public new static readonly global::Godot.StringName MyArray = "MyArray"; + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value) + { + if (name == PropertyName.MyArray) { + this.MyArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<T>(value); + return true; + } + return base.SetGodotClassPropertyValue(name, value); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value) + { + if (name == PropertyName.MyArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.MyArray); + return true; + } + return base.GetGodotClassPropertyValue(name, out value); + } + /// <summary> + /// Get the property information for all the properties declared in this class. + /// This method is used by Godot to register the available properties in the editor. + /// Do not call this method. + /// </summary> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList() + { + var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>(); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.MyArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + return properties; + } +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs index 96ff0f75e9..825daffe80 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs @@ -33,15 +33,15 @@ partial class AllReadOnly value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyAutoProperty); return true; } - else if (name == PropertyName.ReadOnlyProperty) { + if (name == PropertyName.ReadOnlyProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyProperty); return true; } - else if (name == PropertyName.InitOnlyAutoProperty) { + if (name == PropertyName.InitOnlyAutoProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.InitOnlyAutoProperty); return true; } - else if (name == PropertyName.ReadOnlyField) { + if (name == PropertyName.ReadOnlyField) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyField); return true; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs index 91dd282b99..615450efe8 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs @@ -25,7 +25,7 @@ partial class AllWriteOnly this.WriteOnlyProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName._writeOnlyBackingField) { + if (name == PropertyName._writeOnlyBackingField) { this._writeOnlyBackingField = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs index 6ba6439d70..f5046bf34c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs @@ -2,5 +2,5 @@ using Godot; public partial class ClassPartialModifier : Node { - + } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs index 334adc1243..67ec4fa883 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs @@ -257,239 +257,239 @@ partial class ExportedFields this._fieldBoolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName._fieldChar) { + if (name == PropertyName._fieldChar) { this._fieldChar = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); return true; } - else if (name == PropertyName._fieldSByte) { + if (name == PropertyName._fieldSByte) { this._fieldSByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); return true; } - else if (name == PropertyName._fieldInt16) { + if (name == PropertyName._fieldInt16) { this._fieldInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); return true; } - else if (name == PropertyName._fieldInt32) { + if (name == PropertyName._fieldInt32) { this._fieldInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } - else if (name == PropertyName._fieldInt64) { + if (name == PropertyName._fieldInt64) { this._fieldInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); return true; } - else if (name == PropertyName._fieldByte) { + if (name == PropertyName._fieldByte) { this._fieldByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); return true; } - else if (name == PropertyName._fieldUInt16) { + if (name == PropertyName._fieldUInt16) { this._fieldUInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); return true; } - else if (name == PropertyName._fieldUInt32) { + if (name == PropertyName._fieldUInt32) { this._fieldUInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); return true; } - else if (name == PropertyName._fieldUInt64) { + if (name == PropertyName._fieldUInt64) { this._fieldUInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); return true; } - else if (name == PropertyName._fieldSingle) { + if (name == PropertyName._fieldSingle) { this._fieldSingle = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); return true; } - else if (name == PropertyName._fieldDouble) { + if (name == PropertyName._fieldDouble) { this._fieldDouble = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); return true; } - else if (name == PropertyName._fieldString) { + if (name == PropertyName._fieldString) { this._fieldString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._fieldVector2) { + if (name == PropertyName._fieldVector2) { this._fieldVector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); return true; } - else if (name == PropertyName._fieldVector2I) { + if (name == PropertyName._fieldVector2I) { this._fieldVector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); return true; } - else if (name == PropertyName._fieldRect2) { + if (name == PropertyName._fieldRect2) { this._fieldRect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); return true; } - else if (name == PropertyName._fieldRect2I) { + if (name == PropertyName._fieldRect2I) { this._fieldRect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); return true; } - else if (name == PropertyName._fieldTransform2D) { + if (name == PropertyName._fieldTransform2D) { this._fieldTransform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); return true; } - else if (name == PropertyName._fieldVector3) { + if (name == PropertyName._fieldVector3) { this._fieldVector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); return true; } - else if (name == PropertyName._fieldVector3I) { + if (name == PropertyName._fieldVector3I) { this._fieldVector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); return true; } - else if (name == PropertyName._fieldBasis) { + if (name == PropertyName._fieldBasis) { this._fieldBasis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); return true; } - else if (name == PropertyName._fieldQuaternion) { + if (name == PropertyName._fieldQuaternion) { this._fieldQuaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); return true; } - else if (name == PropertyName._fieldTransform3D) { + if (name == PropertyName._fieldTransform3D) { this._fieldTransform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); return true; } - else if (name == PropertyName._fieldVector4) { + if (name == PropertyName._fieldVector4) { this._fieldVector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); return true; } - else if (name == PropertyName._fieldVector4I) { + if (name == PropertyName._fieldVector4I) { this._fieldVector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); return true; } - else if (name == PropertyName._fieldProjection) { + if (name == PropertyName._fieldProjection) { this._fieldProjection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); return true; } - else if (name == PropertyName._fieldAabb) { + if (name == PropertyName._fieldAabb) { this._fieldAabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); return true; } - else if (name == PropertyName._fieldColor) { + if (name == PropertyName._fieldColor) { this._fieldColor = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); return true; } - else if (name == PropertyName._fieldPlane) { + if (name == PropertyName._fieldPlane) { this._fieldPlane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); return true; } - else if (name == PropertyName._fieldCallable) { + if (name == PropertyName._fieldCallable) { this._fieldCallable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); return true; } - else if (name == PropertyName._fieldSignal) { + if (name == PropertyName._fieldSignal) { this._fieldSignal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); return true; } - else if (name == PropertyName._fieldEnum) { + if (name == PropertyName._fieldEnum) { this._fieldEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyEnum>(value); return true; } - else if (name == PropertyName._fieldFlagsEnum) { + if (name == PropertyName._fieldFlagsEnum) { this._fieldFlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyFlagsEnum>(value); return true; } - else if (name == PropertyName._fieldByteArray) { + if (name == PropertyName._fieldByteArray) { this._fieldByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); return true; } - else if (name == PropertyName._fieldInt32Array) { + if (name == PropertyName._fieldInt32Array) { this._fieldInt32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName._fieldInt64Array) { + if (name == PropertyName._fieldInt64Array) { this._fieldInt64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); return true; } - else if (name == PropertyName._fieldSingleArray) { + if (name == PropertyName._fieldSingleArray) { this._fieldSingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); return true; } - else if (name == PropertyName._fieldDoubleArray) { + if (name == PropertyName._fieldDoubleArray) { this._fieldDoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); return true; } - else if (name == PropertyName._fieldStringArray) { + if (name == PropertyName._fieldStringArray) { this._fieldStringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName._fieldStringArrayEnum) { + if (name == PropertyName._fieldStringArrayEnum) { this._fieldStringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName._fieldVector2Array) { + if (name == PropertyName._fieldVector2Array) { this._fieldVector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); return true; } - else if (name == PropertyName._fieldVector3Array) { + if (name == PropertyName._fieldVector3Array) { this._fieldVector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); return true; } - else if (name == PropertyName._fieldColorArray) { + if (name == PropertyName._fieldColorArray) { this._fieldColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); return true; } - else if (name == PropertyName._fieldGodotObjectOrDerivedArray) { + if (name == PropertyName._fieldGodotObjectOrDerivedArray) { this._fieldGodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName._fieldStringNameArray) { + if (name == PropertyName._fieldStringNameArray) { this._fieldStringNameArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName[]>(value); return true; } - else if (name == PropertyName._fieldNodePathArray) { + if (name == PropertyName._fieldNodePathArray) { this._fieldNodePathArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath[]>(value); return true; } - else if (name == PropertyName._fieldRidArray) { + if (name == PropertyName._fieldRidArray) { this._fieldRidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); return true; } - else if (name == PropertyName._fieldEmptyInt32Array) { + if (name == PropertyName._fieldEmptyInt32Array) { this._fieldEmptyInt32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName._fieldArrayFromList) { + if (name == PropertyName._fieldArrayFromList) { this._fieldArrayFromList = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName._fieldVariant) { + if (name == PropertyName._fieldVariant) { this._fieldVariant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); return true; } - else if (name == PropertyName._fieldGodotObjectOrDerived) { + if (name == PropertyName._fieldGodotObjectOrDerived) { this._fieldGodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName._fieldGodotResourceTexture) { + if (name == PropertyName._fieldGodotResourceTexture) { this._fieldGodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); return true; } - else if (name == PropertyName._fieldStringName) { + if (name == PropertyName._fieldStringName) { this._fieldStringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); return true; } - else if (name == PropertyName._fieldNodePath) { + if (name == PropertyName._fieldNodePath) { this._fieldNodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); return true; } - else if (name == PropertyName._fieldRid) { + if (name == PropertyName._fieldRid) { this._fieldRid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); return true; } - else if (name == PropertyName._fieldGodotDictionary) { + if (name == PropertyName._fieldGodotDictionary) { this._fieldGodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); return true; } - else if (name == PropertyName._fieldGodotArray) { + if (name == PropertyName._fieldGodotArray) { this._fieldGodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); return true; } - else if (name == PropertyName._fieldGodotGenericDictionary) { + if (name == PropertyName._fieldGodotGenericDictionary) { this._fieldGodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); return true; } - else if (name == PropertyName._fieldGodotGenericArray) { + if (name == PropertyName._fieldGodotGenericArray) { this._fieldGodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); return true; } - else if (name == PropertyName._fieldEmptyInt64Array) { + if (name == PropertyName._fieldEmptyInt64Array) { this._fieldEmptyInt64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); return true; } @@ -503,239 +503,239 @@ partial class ExportedFields value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this._fieldBoolean); return true; } - else if (name == PropertyName._fieldChar) { + if (name == PropertyName._fieldChar) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this._fieldChar); return true; } - else if (name == PropertyName._fieldSByte) { + if (name == PropertyName._fieldSByte) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this._fieldSByte); return true; } - else if (name == PropertyName._fieldInt16) { + if (name == PropertyName._fieldInt16) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this._fieldInt16); return true; } - else if (name == PropertyName._fieldInt32) { + if (name == PropertyName._fieldInt32) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._fieldInt32); return true; } - else if (name == PropertyName._fieldInt64) { + if (name == PropertyName._fieldInt64) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this._fieldInt64); return true; } - else if (name == PropertyName._fieldByte) { + if (name == PropertyName._fieldByte) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this._fieldByte); return true; } - else if (name == PropertyName._fieldUInt16) { + if (name == PropertyName._fieldUInt16) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this._fieldUInt16); return true; } - else if (name == PropertyName._fieldUInt32) { + if (name == PropertyName._fieldUInt32) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this._fieldUInt32); return true; } - else if (name == PropertyName._fieldUInt64) { + if (name == PropertyName._fieldUInt64) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this._fieldUInt64); return true; } - else if (name == PropertyName._fieldSingle) { + if (name == PropertyName._fieldSingle) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this._fieldSingle); return true; } - else if (name == PropertyName._fieldDouble) { + if (name == PropertyName._fieldDouble) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this._fieldDouble); return true; } - else if (name == PropertyName._fieldString) { + if (name == PropertyName._fieldString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fieldString); return true; } - else if (name == PropertyName._fieldVector2) { + if (name == PropertyName._fieldVector2) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this._fieldVector2); return true; } - else if (name == PropertyName._fieldVector2I) { + if (name == PropertyName._fieldVector2I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this._fieldVector2I); return true; } - else if (name == PropertyName._fieldRect2) { + if (name == PropertyName._fieldRect2) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this._fieldRect2); return true; } - else if (name == PropertyName._fieldRect2I) { + if (name == PropertyName._fieldRect2I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this._fieldRect2I); return true; } - else if (name == PropertyName._fieldTransform2D) { + if (name == PropertyName._fieldTransform2D) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this._fieldTransform2D); return true; } - else if (name == PropertyName._fieldVector3) { + if (name == PropertyName._fieldVector3) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this._fieldVector3); return true; } - else if (name == PropertyName._fieldVector3I) { + if (name == PropertyName._fieldVector3I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this._fieldVector3I); return true; } - else if (name == PropertyName._fieldBasis) { + if (name == PropertyName._fieldBasis) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this._fieldBasis); return true; } - else if (name == PropertyName._fieldQuaternion) { + if (name == PropertyName._fieldQuaternion) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this._fieldQuaternion); return true; } - else if (name == PropertyName._fieldTransform3D) { + if (name == PropertyName._fieldTransform3D) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this._fieldTransform3D); return true; } - else if (name == PropertyName._fieldVector4) { + if (name == PropertyName._fieldVector4) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this._fieldVector4); return true; } - else if (name == PropertyName._fieldVector4I) { + if (name == PropertyName._fieldVector4I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this._fieldVector4I); return true; } - else if (name == PropertyName._fieldProjection) { + if (name == PropertyName._fieldProjection) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this._fieldProjection); return true; } - else if (name == PropertyName._fieldAabb) { + if (name == PropertyName._fieldAabb) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this._fieldAabb); return true; } - else if (name == PropertyName._fieldColor) { + if (name == PropertyName._fieldColor) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this._fieldColor); return true; } - else if (name == PropertyName._fieldPlane) { + if (name == PropertyName._fieldPlane) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this._fieldPlane); return true; } - else if (name == PropertyName._fieldCallable) { + if (name == PropertyName._fieldCallable) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this._fieldCallable); return true; } - else if (name == PropertyName._fieldSignal) { + if (name == PropertyName._fieldSignal) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this._fieldSignal); return true; } - else if (name == PropertyName._fieldEnum) { + if (name == PropertyName._fieldEnum) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyEnum>(this._fieldEnum); return true; } - else if (name == PropertyName._fieldFlagsEnum) { + if (name == PropertyName._fieldFlagsEnum) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyFlagsEnum>(this._fieldFlagsEnum); return true; } - else if (name == PropertyName._fieldByteArray) { + if (name == PropertyName._fieldByteArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this._fieldByteArray); return true; } - else if (name == PropertyName._fieldInt32Array) { + if (name == PropertyName._fieldInt32Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this._fieldInt32Array); return true; } - else if (name == PropertyName._fieldInt64Array) { + if (name == PropertyName._fieldInt64Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this._fieldInt64Array); return true; } - else if (name == PropertyName._fieldSingleArray) { + if (name == PropertyName._fieldSingleArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this._fieldSingleArray); return true; } - else if (name == PropertyName._fieldDoubleArray) { + if (name == PropertyName._fieldDoubleArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this._fieldDoubleArray); return true; } - else if (name == PropertyName._fieldStringArray) { + if (name == PropertyName._fieldStringArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this._fieldStringArray); return true; } - else if (name == PropertyName._fieldStringArrayEnum) { + if (name == PropertyName._fieldStringArrayEnum) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this._fieldStringArrayEnum); return true; } - else if (name == PropertyName._fieldVector2Array) { + if (name == PropertyName._fieldVector2Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this._fieldVector2Array); return true; } - else if (name == PropertyName._fieldVector3Array) { + if (name == PropertyName._fieldVector3Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this._fieldVector3Array); return true; } - else if (name == PropertyName._fieldColorArray) { + if (name == PropertyName._fieldColorArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this._fieldColorArray); return true; } - else if (name == PropertyName._fieldGodotObjectOrDerivedArray) { + if (name == PropertyName._fieldGodotObjectOrDerivedArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this._fieldGodotObjectOrDerivedArray); return true; } - else if (name == PropertyName._fieldStringNameArray) { + if (name == PropertyName._fieldStringNameArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName[]>(this._fieldStringNameArray); return true; } - else if (name == PropertyName._fieldNodePathArray) { + if (name == PropertyName._fieldNodePathArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath[]>(this._fieldNodePathArray); return true; } - else if (name == PropertyName._fieldRidArray) { + if (name == PropertyName._fieldRidArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this._fieldRidArray); return true; } - else if (name == PropertyName._fieldEmptyInt32Array) { + if (name == PropertyName._fieldEmptyInt32Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this._fieldEmptyInt32Array); return true; } - else if (name == PropertyName._fieldArrayFromList) { + if (name == PropertyName._fieldArrayFromList) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this._fieldArrayFromList); return true; } - else if (name == PropertyName._fieldVariant) { + if (name == PropertyName._fieldVariant) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this._fieldVariant); return true; } - else if (name == PropertyName._fieldGodotObjectOrDerived) { + if (name == PropertyName._fieldGodotObjectOrDerived) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this._fieldGodotObjectOrDerived); return true; } - else if (name == PropertyName._fieldGodotResourceTexture) { + if (name == PropertyName._fieldGodotResourceTexture) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this._fieldGodotResourceTexture); return true; } - else if (name == PropertyName._fieldStringName) { + if (name == PropertyName._fieldStringName) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this._fieldStringName); return true; } - else if (name == PropertyName._fieldNodePath) { + if (name == PropertyName._fieldNodePath) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this._fieldNodePath); return true; } - else if (name == PropertyName._fieldRid) { + if (name == PropertyName._fieldRid) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this._fieldRid); return true; } - else if (name == PropertyName._fieldGodotDictionary) { + if (name == PropertyName._fieldGodotDictionary) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this._fieldGodotDictionary); return true; } - else if (name == PropertyName._fieldGodotArray) { + if (name == PropertyName._fieldGodotArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this._fieldGodotArray); return true; } - else if (name == PropertyName._fieldGodotGenericDictionary) { + if (name == PropertyName._fieldGodotGenericDictionary) { value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this._fieldGodotGenericDictionary); return true; } - else if (name == PropertyName._fieldGodotGenericArray) { + if (name == PropertyName._fieldGodotGenericArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this._fieldGodotGenericArray); return true; } - else if (name == PropertyName._fieldEmptyInt64Array) { + if (name == PropertyName._fieldEmptyInt64Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this._fieldEmptyInt64Array); return true; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs index 6e0e9fffbe..aa876d8d7d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs @@ -293,275 +293,275 @@ partial class ExportedProperties this.NotGenerateComplexLamdaProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.NotGenerateLamdaNoFieldProperty) { + if (name == PropertyName.NotGenerateLamdaNoFieldProperty) { this.NotGenerateLamdaNoFieldProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.NotGenerateComplexReturnProperty) { + if (name == PropertyName.NotGenerateComplexReturnProperty) { this.NotGenerateComplexReturnProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.NotGenerateReturnsProperty) { + if (name == PropertyName.NotGenerateReturnsProperty) { this.NotGenerateReturnsProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.FullPropertyString) { + if (name == PropertyName.FullPropertyString) { this.FullPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.FullPropertyString_Complex) { + if (name == PropertyName.FullPropertyString_Complex) { this.FullPropertyString_Complex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.LamdaPropertyString) { + if (name == PropertyName.LamdaPropertyString) { this.LamdaPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.PropertyBoolean) { + if (name == PropertyName.PropertyBoolean) { this.PropertyBoolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName.PropertyChar) { + if (name == PropertyName.PropertyChar) { this.PropertyChar = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); return true; } - else if (name == PropertyName.PropertySByte) { + if (name == PropertyName.PropertySByte) { this.PropertySByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); return true; } - else if (name == PropertyName.PropertyInt16) { + if (name == PropertyName.PropertyInt16) { this.PropertyInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); return true; } - else if (name == PropertyName.PropertyInt32) { + if (name == PropertyName.PropertyInt32) { this.PropertyInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } - else if (name == PropertyName.PropertyInt64) { + if (name == PropertyName.PropertyInt64) { this.PropertyInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); return true; } - else if (name == PropertyName.PropertyByte) { + if (name == PropertyName.PropertyByte) { this.PropertyByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); return true; } - else if (name == PropertyName.PropertyUInt16) { + if (name == PropertyName.PropertyUInt16) { this.PropertyUInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); return true; } - else if (name == PropertyName.PropertyUInt32) { + if (name == PropertyName.PropertyUInt32) { this.PropertyUInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); return true; } - else if (name == PropertyName.PropertyUInt64) { + if (name == PropertyName.PropertyUInt64) { this.PropertyUInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); return true; } - else if (name == PropertyName.PropertySingle) { + if (name == PropertyName.PropertySingle) { this.PropertySingle = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); return true; } - else if (name == PropertyName.PropertyDouble) { + if (name == PropertyName.PropertyDouble) { this.PropertyDouble = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); return true; } - else if (name == PropertyName.PropertyString) { + if (name == PropertyName.PropertyString) { this.PropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.PropertyVector2) { + if (name == PropertyName.PropertyVector2) { this.PropertyVector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); return true; } - else if (name == PropertyName.PropertyVector2I) { + if (name == PropertyName.PropertyVector2I) { this.PropertyVector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); return true; } - else if (name == PropertyName.PropertyRect2) { + if (name == PropertyName.PropertyRect2) { this.PropertyRect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); return true; } - else if (name == PropertyName.PropertyRect2I) { + if (name == PropertyName.PropertyRect2I) { this.PropertyRect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); return true; } - else if (name == PropertyName.PropertyTransform2D) { + if (name == PropertyName.PropertyTransform2D) { this.PropertyTransform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); return true; } - else if (name == PropertyName.PropertyVector3) { + if (name == PropertyName.PropertyVector3) { this.PropertyVector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); return true; } - else if (name == PropertyName.PropertyVector3I) { + if (name == PropertyName.PropertyVector3I) { this.PropertyVector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); return true; } - else if (name == PropertyName.PropertyBasis) { + if (name == PropertyName.PropertyBasis) { this.PropertyBasis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); return true; } - else if (name == PropertyName.PropertyQuaternion) { + if (name == PropertyName.PropertyQuaternion) { this.PropertyQuaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); return true; } - else if (name == PropertyName.PropertyTransform3D) { + if (name == PropertyName.PropertyTransform3D) { this.PropertyTransform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); return true; } - else if (name == PropertyName.PropertyVector4) { + if (name == PropertyName.PropertyVector4) { this.PropertyVector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); return true; } - else if (name == PropertyName.PropertyVector4I) { + if (name == PropertyName.PropertyVector4I) { this.PropertyVector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); return true; } - else if (name == PropertyName.PropertyProjection) { + if (name == PropertyName.PropertyProjection) { this.PropertyProjection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); return true; } - else if (name == PropertyName.PropertyAabb) { + if (name == PropertyName.PropertyAabb) { this.PropertyAabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); return true; } - else if (name == PropertyName.PropertyColor) { + if (name == PropertyName.PropertyColor) { this.PropertyColor = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); return true; } - else if (name == PropertyName.PropertyPlane) { + if (name == PropertyName.PropertyPlane) { this.PropertyPlane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); return true; } - else if (name == PropertyName.PropertyCallable) { + if (name == PropertyName.PropertyCallable) { this.PropertyCallable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); return true; } - else if (name == PropertyName.PropertySignal) { + if (name == PropertyName.PropertySignal) { this.PropertySignal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); return true; } - else if (name == PropertyName.PropertyEnum) { + if (name == PropertyName.PropertyEnum) { this.PropertyEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyEnum>(value); return true; } - else if (name == PropertyName.PropertyFlagsEnum) { + if (name == PropertyName.PropertyFlagsEnum) { this.PropertyFlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyFlagsEnum>(value); return true; } - else if (name == PropertyName.PropertyByteArray) { + if (name == PropertyName.PropertyByteArray) { this.PropertyByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); return true; } - else if (name == PropertyName.PropertyInt32Array) { + if (name == PropertyName.PropertyInt32Array) { this.PropertyInt32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName.PropertyInt64Array) { + if (name == PropertyName.PropertyInt64Array) { this.PropertyInt64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); return true; } - else if (name == PropertyName.PropertySingleArray) { + if (name == PropertyName.PropertySingleArray) { this.PropertySingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); return true; } - else if (name == PropertyName.PropertyDoubleArray) { + if (name == PropertyName.PropertyDoubleArray) { this.PropertyDoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); return true; } - else if (name == PropertyName.PropertyStringArray) { + if (name == PropertyName.PropertyStringArray) { this.PropertyStringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName.PropertyStringArrayEnum) { + if (name == PropertyName.PropertyStringArrayEnum) { this.PropertyStringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName.PropertyVector2Array) { + if (name == PropertyName.PropertyVector2Array) { this.PropertyVector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); return true; } - else if (name == PropertyName.PropertyVector3Array) { + if (name == PropertyName.PropertyVector3Array) { this.PropertyVector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); return true; } - else if (name == PropertyName.PropertyColorArray) { + if (name == PropertyName.PropertyColorArray) { this.PropertyColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); return true; } - else if (name == PropertyName.PropertyGodotObjectOrDerivedArray) { + if (name == PropertyName.PropertyGodotObjectOrDerivedArray) { this.PropertyGodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName.field_StringNameArray) { + if (name == PropertyName.field_StringNameArray) { this.field_StringNameArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName[]>(value); return true; } - else if (name == PropertyName.field_NodePathArray) { + if (name == PropertyName.field_NodePathArray) { this.field_NodePathArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath[]>(value); return true; } - else if (name == PropertyName.field_RidArray) { + if (name == PropertyName.field_RidArray) { this.field_RidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); return true; } - else if (name == PropertyName.PropertyVariant) { + if (name == PropertyName.PropertyVariant) { this.PropertyVariant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); return true; } - else if (name == PropertyName.PropertyGodotObjectOrDerived) { + if (name == PropertyName.PropertyGodotObjectOrDerived) { this.PropertyGodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName.PropertyGodotResourceTexture) { + if (name == PropertyName.PropertyGodotResourceTexture) { this.PropertyGodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); return true; } - else if (name == PropertyName.PropertyStringName) { + if (name == PropertyName.PropertyStringName) { this.PropertyStringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); return true; } - else if (name == PropertyName.PropertyNodePath) { + if (name == PropertyName.PropertyNodePath) { this.PropertyNodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); return true; } - else if (name == PropertyName.PropertyRid) { + if (name == PropertyName.PropertyRid) { this.PropertyRid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); return true; } - else if (name == PropertyName.PropertyGodotDictionary) { + if (name == PropertyName.PropertyGodotDictionary) { this.PropertyGodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); return true; } - else if (name == PropertyName.PropertyGodotArray) { + if (name == PropertyName.PropertyGodotArray) { this.PropertyGodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); return true; } - else if (name == PropertyName.PropertyGodotGenericDictionary) { + if (name == PropertyName.PropertyGodotGenericDictionary) { this.PropertyGodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); return true; } - else if (name == PropertyName.PropertyGodotGenericArray) { + if (name == PropertyName.PropertyGodotGenericArray) { this.PropertyGodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); return true; } - else if (name == PropertyName._notGeneratePropertyString) { + if (name == PropertyName._notGeneratePropertyString) { this._notGeneratePropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._notGeneratePropertyInt) { + if (name == PropertyName._notGeneratePropertyInt) { this._notGeneratePropertyInt = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } - else if (name == PropertyName._fullPropertyString) { + if (name == PropertyName._fullPropertyString) { this._fullPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._fullPropertyStringComplex) { + if (name == PropertyName._fullPropertyStringComplex) { this._fullPropertyStringComplex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._lamdaPropertyString) { + if (name == PropertyName._lamdaPropertyString) { this._lamdaPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } @@ -575,275 +575,275 @@ partial class ExportedProperties value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateComplexLamdaProperty); return true; } - else if (name == PropertyName.NotGenerateLamdaNoFieldProperty) { + if (name == PropertyName.NotGenerateLamdaNoFieldProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateLamdaNoFieldProperty); return true; } - else if (name == PropertyName.NotGenerateComplexReturnProperty) { + if (name == PropertyName.NotGenerateComplexReturnProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateComplexReturnProperty); return true; } - else if (name == PropertyName.NotGenerateReturnsProperty) { + if (name == PropertyName.NotGenerateReturnsProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateReturnsProperty); return true; } - else if (name == PropertyName.FullPropertyString) { + if (name == PropertyName.FullPropertyString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullPropertyString); return true; } - else if (name == PropertyName.FullPropertyString_Complex) { + if (name == PropertyName.FullPropertyString_Complex) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullPropertyString_Complex); return true; } - else if (name == PropertyName.LamdaPropertyString) { + if (name == PropertyName.LamdaPropertyString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.LamdaPropertyString); return true; } - else if (name == PropertyName.PropertyBoolean) { + if (name == PropertyName.PropertyBoolean) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.PropertyBoolean); return true; } - else if (name == PropertyName.PropertyChar) { + if (name == PropertyName.PropertyChar) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this.PropertyChar); return true; } - else if (name == PropertyName.PropertySByte) { + if (name == PropertyName.PropertySByte) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this.PropertySByte); return true; } - else if (name == PropertyName.PropertyInt16) { + if (name == PropertyName.PropertyInt16) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this.PropertyInt16); return true; } - else if (name == PropertyName.PropertyInt32) { + if (name == PropertyName.PropertyInt32) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this.PropertyInt32); return true; } - else if (name == PropertyName.PropertyInt64) { + if (name == PropertyName.PropertyInt64) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this.PropertyInt64); return true; } - else if (name == PropertyName.PropertyByte) { + if (name == PropertyName.PropertyByte) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this.PropertyByte); return true; } - else if (name == PropertyName.PropertyUInt16) { + if (name == PropertyName.PropertyUInt16) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this.PropertyUInt16); return true; } - else if (name == PropertyName.PropertyUInt32) { + if (name == PropertyName.PropertyUInt32) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this.PropertyUInt32); return true; } - else if (name == PropertyName.PropertyUInt64) { + if (name == PropertyName.PropertyUInt64) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this.PropertyUInt64); return true; } - else if (name == PropertyName.PropertySingle) { + if (name == PropertyName.PropertySingle) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this.PropertySingle); return true; } - else if (name == PropertyName.PropertyDouble) { + if (name == PropertyName.PropertyDouble) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this.PropertyDouble); return true; } - else if (name == PropertyName.PropertyString) { + if (name == PropertyName.PropertyString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.PropertyString); return true; } - else if (name == PropertyName.PropertyVector2) { + if (name == PropertyName.PropertyVector2) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this.PropertyVector2); return true; } - else if (name == PropertyName.PropertyVector2I) { + if (name == PropertyName.PropertyVector2I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this.PropertyVector2I); return true; } - else if (name == PropertyName.PropertyRect2) { + if (name == PropertyName.PropertyRect2) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this.PropertyRect2); return true; } - else if (name == PropertyName.PropertyRect2I) { + if (name == PropertyName.PropertyRect2I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this.PropertyRect2I); return true; } - else if (name == PropertyName.PropertyTransform2D) { + if (name == PropertyName.PropertyTransform2D) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this.PropertyTransform2D); return true; } - else if (name == PropertyName.PropertyVector3) { + if (name == PropertyName.PropertyVector3) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this.PropertyVector3); return true; } - else if (name == PropertyName.PropertyVector3I) { + if (name == PropertyName.PropertyVector3I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this.PropertyVector3I); return true; } - else if (name == PropertyName.PropertyBasis) { + if (name == PropertyName.PropertyBasis) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this.PropertyBasis); return true; } - else if (name == PropertyName.PropertyQuaternion) { + if (name == PropertyName.PropertyQuaternion) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this.PropertyQuaternion); return true; } - else if (name == PropertyName.PropertyTransform3D) { + if (name == PropertyName.PropertyTransform3D) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this.PropertyTransform3D); return true; } - else if (name == PropertyName.PropertyVector4) { + if (name == PropertyName.PropertyVector4) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this.PropertyVector4); return true; } - else if (name == PropertyName.PropertyVector4I) { + if (name == PropertyName.PropertyVector4I) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this.PropertyVector4I); return true; } - else if (name == PropertyName.PropertyProjection) { + if (name == PropertyName.PropertyProjection) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this.PropertyProjection); return true; } - else if (name == PropertyName.PropertyAabb) { + if (name == PropertyName.PropertyAabb) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this.PropertyAabb); return true; } - else if (name == PropertyName.PropertyColor) { + if (name == PropertyName.PropertyColor) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this.PropertyColor); return true; } - else if (name == PropertyName.PropertyPlane) { + if (name == PropertyName.PropertyPlane) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this.PropertyPlane); return true; } - else if (name == PropertyName.PropertyCallable) { + if (name == PropertyName.PropertyCallable) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.PropertyCallable); return true; } - else if (name == PropertyName.PropertySignal) { + if (name == PropertyName.PropertySignal) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this.PropertySignal); return true; } - else if (name == PropertyName.PropertyEnum) { + if (name == PropertyName.PropertyEnum) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyEnum>(this.PropertyEnum); return true; } - else if (name == PropertyName.PropertyFlagsEnum) { + if (name == PropertyName.PropertyFlagsEnum) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyFlagsEnum>(this.PropertyFlagsEnum); return true; } - else if (name == PropertyName.PropertyByteArray) { + if (name == PropertyName.PropertyByteArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this.PropertyByteArray); return true; } - else if (name == PropertyName.PropertyInt32Array) { + if (name == PropertyName.PropertyInt32Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.PropertyInt32Array); return true; } - else if (name == PropertyName.PropertyInt64Array) { + if (name == PropertyName.PropertyInt64Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.PropertyInt64Array); return true; } - else if (name == PropertyName.PropertySingleArray) { + if (name == PropertyName.PropertySingleArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this.PropertySingleArray); return true; } - else if (name == PropertyName.PropertyDoubleArray) { + if (name == PropertyName.PropertyDoubleArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this.PropertyDoubleArray); return true; } - else if (name == PropertyName.PropertyStringArray) { + if (name == PropertyName.PropertyStringArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.PropertyStringArray); return true; } - else if (name == PropertyName.PropertyStringArrayEnum) { + if (name == PropertyName.PropertyStringArrayEnum) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.PropertyStringArrayEnum); return true; } - else if (name == PropertyName.PropertyVector2Array) { + if (name == PropertyName.PropertyVector2Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this.PropertyVector2Array); return true; } - else if (name == PropertyName.PropertyVector3Array) { + if (name == PropertyName.PropertyVector3Array) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this.PropertyVector3Array); return true; } - else if (name == PropertyName.PropertyColorArray) { + if (name == PropertyName.PropertyColorArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this.PropertyColorArray); return true; } - else if (name == PropertyName.PropertyGodotObjectOrDerivedArray) { + if (name == PropertyName.PropertyGodotObjectOrDerivedArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this.PropertyGodotObjectOrDerivedArray); return true; } - else if (name == PropertyName.field_StringNameArray) { + if (name == PropertyName.field_StringNameArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName[]>(this.field_StringNameArray); return true; } - else if (name == PropertyName.field_NodePathArray) { + if (name == PropertyName.field_NodePathArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath[]>(this.field_NodePathArray); return true; } - else if (name == PropertyName.field_RidArray) { + if (name == PropertyName.field_RidArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this.field_RidArray); return true; } - else if (name == PropertyName.PropertyVariant) { + if (name == PropertyName.PropertyVariant) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this.PropertyVariant); return true; } - else if (name == PropertyName.PropertyGodotObjectOrDerived) { + if (name == PropertyName.PropertyGodotObjectOrDerived) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this.PropertyGodotObjectOrDerived); return true; } - else if (name == PropertyName.PropertyGodotResourceTexture) { + if (name == PropertyName.PropertyGodotResourceTexture) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this.PropertyGodotResourceTexture); return true; } - else if (name == PropertyName.PropertyStringName) { + if (name == PropertyName.PropertyStringName) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this.PropertyStringName); return true; } - else if (name == PropertyName.PropertyNodePath) { + if (name == PropertyName.PropertyNodePath) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this.PropertyNodePath); return true; } - else if (name == PropertyName.PropertyRid) { + if (name == PropertyName.PropertyRid) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this.PropertyRid); return true; } - else if (name == PropertyName.PropertyGodotDictionary) { + if (name == PropertyName.PropertyGodotDictionary) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this.PropertyGodotDictionary); return true; } - else if (name == PropertyName.PropertyGodotArray) { + if (name == PropertyName.PropertyGodotArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this.PropertyGodotArray); return true; } - else if (name == PropertyName.PropertyGodotGenericDictionary) { + if (name == PropertyName.PropertyGodotGenericDictionary) { value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this.PropertyGodotGenericDictionary); return true; } - else if (name == PropertyName.PropertyGodotGenericArray) { + if (name == PropertyName.PropertyGodotGenericArray) { value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.PropertyGodotGenericArray); return true; } - else if (name == PropertyName._notGeneratePropertyString) { + if (name == PropertyName._notGeneratePropertyString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._notGeneratePropertyString); return true; } - else if (name == PropertyName._notGeneratePropertyInt) { + if (name == PropertyName._notGeneratePropertyInt) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._notGeneratePropertyInt); return true; } - else if (name == PropertyName._fullPropertyString) { + if (name == PropertyName._fullPropertyString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullPropertyString); return true; } - else if (name == PropertyName._fullPropertyStringComplex) { + if (name == PropertyName._fullPropertyStringComplex) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullPropertyStringComplex); return true; } - else if (name == PropertyName._lamdaPropertyString) { + if (name == PropertyName._lamdaPropertyString) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._lamdaPropertyString); return true; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs index 91f808f55e..cabdbe8d99 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs @@ -41,7 +41,7 @@ partial class MixedReadOnlyWriteOnly this.WriteOnlyProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName._writeOnlyBackingField) { + if (name == PropertyName._writeOnlyBackingField) { this._writeOnlyBackingField = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } @@ -55,19 +55,19 @@ partial class MixedReadOnlyWriteOnly value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyAutoProperty); return true; } - else if (name == PropertyName.ReadOnlyProperty) { + if (name == PropertyName.ReadOnlyProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyProperty); return true; } - else if (name == PropertyName.InitOnlyAutoProperty) { + if (name == PropertyName.InitOnlyAutoProperty) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.InitOnlyAutoProperty); return true; } - else if (name == PropertyName.ReadOnlyField) { + if (name == PropertyName.ReadOnlyField) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyField); return true; } - else if (name == PropertyName._writeOnlyBackingField) { + if (name == PropertyName._writeOnlyBackingField) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this._writeOnlyBackingField); return true; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptMethods.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptMethods.generated.cs index 8656f4617e..a6e58bf27d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptMethods.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptMethods.generated.cs @@ -54,7 +54,7 @@ partial class ScriptBoilerplate if (method == MethodName._Process) { return true; } - else if (method == MethodName.Bazz) { + if (method == MethodName.Bazz) { return true; } return base.HasGodotClassMethod(method); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptProperties.generated.cs index 09368b7ab6..81cc27502f 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptProperties.generated.cs @@ -25,7 +25,7 @@ partial class ScriptBoilerplate this._nodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); return true; } - else if (name == PropertyName._velocity) { + if (name == PropertyName._velocity) { this._velocity = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } @@ -39,7 +39,7 @@ partial class ScriptBoilerplate value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this._nodePath); return true; } - else if (name == PropertyName._velocity) { + if (name == PropertyName._velocity) { value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._velocity); return true; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AbstractGenericNode.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AbstractGenericNode.cs new file mode 100644 index 0000000000..cee4f67921 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AbstractGenericNode.cs @@ -0,0 +1,7 @@ +using Godot; + +public abstract partial class AbstractGenericNode<[MustBeVariant] T> : Node +{ + [Export] // This should be included, but without type hints. + public Godot.Collections.Array<T> MyArray { get; set; } = new(); +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs index c8ff673b76..fb70f104aa 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs @@ -2,5 +2,5 @@ using Godot; public class {|GD0001:ClassPartialModifier|} : Node { - + } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs index 1908703a71..91a376462b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs @@ -2,7 +2,7 @@ using Godot; // This works because it inherits from GodotObject. [GlobalClass] -public partial class CustomGlobalClass1 : GodotObject +public partial class CustomGlobalClass1 : GodotObject { } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs index 4f7885cf37..0685d0b34a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs @@ -2,7 +2,7 @@ using Godot; // This works because it inherits from GodotObject and it doesn't have any generic type parameter. [GlobalClass] -public partial class CustomGlobalClass : GodotObject +public partial class CustomGlobalClass : GodotObject { } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs index 462da31d66..053ae36ae7 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs @@ -10,7 +10,7 @@ public class MustBeVariantGD0301 // This raises a GD0301 diagnostic error: object is not Variant (and Method<T> requires a variant generic type). Method<{|GD0301:object|}>(); } - + public void MethodCallsOk() { // All these calls are valid because they are Variant types. @@ -66,10 +66,16 @@ public class MustBeVariantGD0301 Method<Rid[]>(); } + public void MethodCallDynamic() + { + dynamic self = this; + self.Method<object>(); + } + public void Method<[MustBeVariant] T>() { } - + public void MustBeVariantClasses() { new ClassWithGenericVariant<bool>(); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj index 8a3b17ac49..1aa2979e76 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <LangVersion>10</LangVersion> @@ -14,6 +14,7 @@ <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> <PackageLicenseExpression>MIT</PackageLicenseExpression> + <Copyright>Copyright (c) Godot Engine contributors</Copyright> <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Do not include the generator as a lib dependency --> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs index 834beaa131..4cf6a9f431 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs @@ -44,7 +44,8 @@ namespace Godot.SourceGenerators PackedVector2Array = 35, PackedVector3Array = 36, PackedColorArray = 37, - Max = 38 + PackedVector4Array = 38, + Max = 39 } internal enum PropertyHint diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs index be6af117eb..bfb735e72f 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs @@ -51,6 +51,7 @@ namespace Godot.SourceGenerators StringArray, Vector2Array, Vector3Array, + Vector4Array, ColorArray, GodotObjectOrDerivedArray, SystemArrayOfStringName, 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 0258f53062..d272832950 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -66,6 +66,7 @@ namespace Godot.SourceGenerators MarshalType.StringArray => VariantType.PackedStringArray, MarshalType.Vector2Array => VariantType.PackedVector2Array, MarshalType.Vector3Array => VariantType.PackedVector3Array, + MarshalType.Vector4Array => VariantType.PackedVector4Array, MarshalType.ColorArray => VariantType.PackedColorArray, MarshalType.GodotObjectOrDerivedArray => VariantType.Array, MarshalType.SystemArrayOfStringName => VariantType.Array, @@ -190,6 +191,8 @@ namespace Godot.SourceGenerators return MarshalType.Vector2Array; case { Name: "Vector3" }: return MarshalType.Vector3Array; + case { Name: "Vector4" }: + return MarshalType.Vector4Array; case { Name: "Color" }: return MarshalType.ColorArray; case { Name: "StringName" }: diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs index 95eaca4d3d..e894e7a86c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs @@ -50,8 +50,18 @@ namespace Godot.SourceGenerators var typeSymbol = sm.GetSymbolInfo(typeSyntax).Symbol as ITypeSymbol; Helper.ThrowIfNull(typeSymbol); - var parentSymbol = sm.GetSymbolInfo(parentSyntax).Symbol; - Helper.ThrowIfNull(parentSymbol); + var parentSymbolInfo = sm.GetSymbolInfo(parentSyntax); + var parentSymbol = parentSymbolInfo.Symbol; + if (parentSymbol == null) + { + if (parentSymbolInfo.CandidateReason == CandidateReason.LateBound) + { + // Invocations on dynamic are late bound so we can't retrieve the symbol. + continue; + } + + Helper.ThrowIfNull(parentSymbol); + } if (!ShouldCheckTypeArgument(context, parentSyntax, parentSymbol, typeSyntax, typeSymbol, i)) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs index f314f7dada..39d3a6f94e 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs @@ -253,11 +253,9 @@ namespace Godot.SourceGenerators source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n"); - bool isFirstEntry = true; foreach (string methodName in distinctMethodNames) { - GenerateHasMethodEntry(methodName, source, isFirstEntry); - isFirstEntry = false; + GenerateHasMethodEntry(methodName, source); } source.Append(" return base.HasGodotClassMethod(method);\n"); @@ -412,13 +410,10 @@ namespace Godot.SourceGenerators private static void GenerateHasMethodEntry( string methodName, - StringBuilder source, - bool isFirstEntry + StringBuilder source ) { source.Append(" "); - if (!isFirstEntry) - source.Append("else "); source.Append("if (method == MethodName."); source.Append(methodName); source.Append(") {\n return true;\n }\n"); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index a0e410e31a..02c2cd4034 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -172,7 +172,6 @@ namespace Godot.SourceGenerators if (godotClassProperties.Length > 0 || godotClassFields.Length > 0) { - bool isFirstEntry; // Generate SetGodotClassPropertyValue @@ -186,15 +185,13 @@ namespace Godot.SourceGenerators source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, "); source.Append("in godot_variant value)\n {\n"); - isFirstEntry = true; foreach (var property in godotClassProperties) { if (property.PropertySymbol.IsReadOnly || property.PropertySymbol.SetMethod!.IsInitOnly) continue; GeneratePropertySetter(property.PropertySymbol.Name, - property.PropertySymbol.Type, property.Type, source, isFirstEntry); - isFirstEntry = false; + property.PropertySymbol.Type, property.Type, source); } foreach (var field in godotClassFields) @@ -203,8 +200,7 @@ namespace Godot.SourceGenerators continue; GeneratePropertySetter(field.FieldSymbol.Name, - field.FieldSymbol.Type, field.Type, source, isFirstEntry); - isFirstEntry = false; + field.FieldSymbol.Type, field.Type, source); } source.Append(" return base.SetGodotClassPropertyValue(name, value);\n"); @@ -222,22 +218,19 @@ namespace Godot.SourceGenerators source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, "); source.Append("out godot_variant value)\n {\n"); - isFirstEntry = true; foreach (var property in godotClassProperties) { if (property.PropertySymbol.IsWriteOnly) continue; GeneratePropertyGetter(property.PropertySymbol.Name, - property.PropertySymbol.Type, property.Type, source, isFirstEntry); - isFirstEntry = false; + property.PropertySymbol.Type, property.Type, source); } foreach (var field in godotClassFields) { GeneratePropertyGetter(field.FieldSymbol.Name, - field.FieldSymbol.Type, field.Type, source, isFirstEntry); - isFirstEntry = false; + field.FieldSymbol.Type, field.Type, source); } source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n"); @@ -318,15 +311,11 @@ namespace Godot.SourceGenerators string propertyMemberName, ITypeSymbol propertyTypeSymbol, MarshalType propertyMarshalType, - StringBuilder source, - bool isFirstEntry + StringBuilder source ) { source.Append(" "); - if (!isFirstEntry) - source.Append("else "); - source.Append("if (name == PropertyName.") .Append(propertyMemberName) .Append(") {\n") @@ -343,15 +332,11 @@ namespace Godot.SourceGenerators string propertyMemberName, ITypeSymbol propertyTypeSymbol, MarshalType propertyMarshalType, - StringBuilder source, - bool isFirstEntry + StringBuilder source ) { source.Append(" "); - if (!isFirstEntry) - source.Append("else "); - source.Append("if (name == PropertyName.") .Append(propertyMemberName) .Append(") {\n") @@ -590,6 +575,11 @@ namespace Godot.SourceGenerators if (variantType == VariantType.Object && type is INamedTypeSymbol memberNamedType) { + if (TryGetNodeOrResourceType(exportAttr, out hint, out hintString)) + { + return true; + } + if (memberNamedType.InheritsFrom("GodotSharp", "Godot.Resource")) { hint = PropertyHint.ResourceType; @@ -607,6 +597,37 @@ namespace Godot.SourceGenerators } } + static bool TryGetNodeOrResourceType(AttributeData exportAttr, out PropertyHint hint, out string? hintString) + { + hint = PropertyHint.None; + hintString = null; + + if (exportAttr.ConstructorArguments.Length <= 1) return false; + + var hintValue = exportAttr.ConstructorArguments[0].Value; + + var hintEnum = hintValue switch + { + null => PropertyHint.None, + int intValue => (PropertyHint)intValue, + _ => (PropertyHint)(long)hintValue + }; + + if (!hintEnum.HasFlag(PropertyHint.NodeType) && !hintEnum.HasFlag(PropertyHint.ResourceType)) + return false; + + var hintStringValue = exportAttr.ConstructorArguments[1].Value?.ToString(); + if (string.IsNullOrWhiteSpace(hintStringValue)) + { + return false; + } + + hint = hintEnum; + hintString = hintStringValue; + + return true; + } + static string GetTypeName(INamedTypeSymbol memberSymbol) { if (memberSymbol.GetAttributes() @@ -658,7 +679,10 @@ namespace Godot.SourceGenerators var elementType = MarshalUtils.GetArrayElementType(type); if (elementType == null) - return false; // Non-generic Array, so there's no hint to add + return false; // Non-generic Array, so there's no hint to add. + + if (elementType.TypeKind == TypeKind.TypeParameter) + return false; // The generic is not constructed, we can't really hint anything. var elementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementType, typeCache)!.Value; var elementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(elementMarshalType)!.Value; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index 107bd93faa..deac5f2bcf 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -319,11 +319,9 @@ namespace Godot.SourceGenerators source.Append( " protected override bool HasGodotClassSignal(in godot_string_name signal)\n {\n"); - bool isFirstEntry = true; foreach (var signal in godotSignalDelegates) { - GenerateHasSignalEntry(signal.Name, source, isFirstEntry); - isFirstEntry = false; + GenerateHasSignalEntry(signal.Name, source); } source.Append(" return base.HasGodotClassSignal(signal);\n"); @@ -473,13 +471,10 @@ namespace Godot.SourceGenerators private static void GenerateHasSignalEntry( string signalName, - StringBuilder source, - bool isFirstEntry + StringBuilder source ) { source.Append(" "); - if (!isFirstEntry) - source.Append("else "); source.Append("if (signal == SignalName."); source.Append(signalName); source.Append(") {\n return true;\n }\n"); diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj index fd836f9ad2..f807132509 100644 --- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{6CE9A984-37B1-4F8A-8FE9-609F05F071B3}</ProjectGuid> <TargetFramework>net6.0</TargetFramework> diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj index 0755484465..f692f26a8b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</ProjectGuid> <TargetFramework>net6.0</TargetFramework> diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj index 3bf678e9f9..0174b25b3f 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{B06C2951-C8E3-4F28-80B2-717CF327EB19}</ProjectGuid> <OutputType>Exe</OutputType> diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj index be6af398e2..2ee28715bf 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{92600954-25F0-4291-8E11-1FEE9FC4BE20}</ProjectGuid> <TargetFramework>netstandard2.0</TargetFramework> @@ -12,6 +12,7 @@ <PackageTags>godot</PackageTags> <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/GodotTools/GodotTools.IdeMessaging</RepositoryUrl> <PackageLicenseExpression>MIT</PackageLicenseExpression> + <Copyright>Copyright (c) Godot Engine contributors</Copyright> <Description> This library enables communication with the Godot Engine editor (the version with .NET support). It's intended for use in IDEs/editors plugins for a better experience working with Godot C# projects. diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj index 09908c85a1..f23f2b9a8c 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid> <OutputType>Exe</OutputType> @@ -7,6 +7,7 @@ <Nullable>enable</Nullable> <RuntimeIdentifier>win-x86</RuntimeIdentifier> <SelfContained>False</SelfContained> + <RollForward>LatestMajor</RollForward> </PropertyGroup> <PropertyGroup Condition="Exists('$(SolutionDir)/../../../../bin/GodotSharp/Api/Debug/GodotSharp.dll') And ('$(GodotPlatform)' == 'windows' Or ('$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT'))"> <OutputPath>$(SolutionDir)/../../../../bin/GodotSharp/Tools</OutputPath> diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj index 623475e11a..5547ffcf19 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid> <TargetFramework>net6.0</TargetFramework> diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj index d60e6343ea..7c19fabaf6 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj @@ -1,8 +1,8 @@ -<Project Sdk="Microsoft.NET.Sdk"> - <PropertyGroup> - <TargetFramework>net6.0</TargetFramework> - <!-- Specify compile items manually to avoid including dangling generated items. --> - <EnableDefaultCompileItems>false</EnableDefaultCompileItems> - </PropertyGroup> - <Import Project="GenerateGodotNupkgsVersions.targets" /> +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <TargetFramework>net6.0</TargetFramework> + <!-- Specify compile items manually to avoid including dangling generated items. --> + <EnableDefaultCompileItems>false</EnableDefaultCompileItems> + </PropertyGroup> + <Import Project="GenerateGodotNupkgsVersions.targets" /> </Project> diff --git a/modules/mono/editor/GodotTools/GodotTools.sln b/modules/mono/editor/GodotTools/GodotTools.sln index 564775635d..1182e2467b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.sln +++ b/modules/mono/editor/GodotTools/GodotTools.sln @@ -1,6 +1,8 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.ProjectEditor", "GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools", "GodotTools\GodotTools.csproj", "{27B00618-A6F2-4828-B922-05CAEB08C286}" @@ -62,4 +64,10 @@ Global {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {521EC35A-F7F0-46A9-92CE-680D2F5B02B8} + EndGlobalSection EndGlobal diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs index b6d6d9ebf8..35a62a0eab 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs @@ -280,7 +280,7 @@ namespace GodotTools.Build if (_problemsContextMenu.ItemCount > 0) { - _problemsContextMenu.Position = (Vector2I)(_problemsTree.GlobalPosition + position); + _problemsContextMenu.Position = (Vector2I)(GetScreenPosition() + position); _problemsContextMenu.Popup(); } } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 35b3f5a710..96d2c5c75f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid> <TargetFramework>net6.0</TargetFramework> diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index e1ce41edd5..9a76a25639 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -330,6 +330,8 @@ String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInter output.append("'" BINDINGS_NAMESPACE ".Vector3[]'"); } else if (tag == "PackedColorArray") { output.append("'" BINDINGS_NAMESPACE ".Color[]'"); + } else if (tag == "PackedVector4Array") { + output.append("'" BINDINGS_NAMESPACE ".Vector4[]'"); } else { const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag)); @@ -646,6 +648,8 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>[]"); } else if (tag == "PackedColorArray") { xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>[]"); + } else if (tag == "PackedVector4Array") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector4\"/>[]"); } else { const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag)); @@ -869,7 +873,7 @@ void BindingsGenerator::_append_text_method(StringBuilder &p_output, const TypeI } void BindingsGenerator::_append_text_member(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { - if (p_link_target.find("/") >= 0) { + if (p_link_target.contains("/")) { // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference. _append_text_undeclared(p_output, p_link_target); } else if (!p_target_itype || !p_target_itype->is_object_type) { @@ -1150,7 +1154,7 @@ void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const Ty } void BindingsGenerator::_append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { - if (p_link_target.find("/") >= 0) { + if (p_link_target.contains("/")) { // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference. _append_xml_undeclared(p_xml_output, p_link_target); } else if (!p_target_itype || !p_target_itype->is_object_type) { @@ -2304,8 +2308,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << imethod.proxy_name << "("; - for (int i = 0; i < imethod.arguments.size(); i++) { - const ArgumentInterface &iarg = imethod.arguments[i]; + int i = 0; + for (List<BindingsGenerator::ArgumentInterface>::ConstIterator itr = imethod.arguments.begin(); itr != imethod.arguments.end(); ++itr, ++i) { + const ArgumentInterface &iarg = *itr; const TypeInterface *arg_type = _get_type_or_null(iarg.type); ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found @@ -3516,6 +3521,7 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant & case Variant::PACKED_STRING_ARRAY: case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_VECTOR4_ARRAY: case Variant::PACKED_COLOR_ARRAY: case Variant::CALLABLE: case Variant::SIGNAL: @@ -3648,7 +3654,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { continue; } - if (property.name.find("/") >= 0) { + if (property.name.contains("/")) { // Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector. continue; } @@ -3722,8 +3728,6 @@ bool BindingsGenerator::_populate_object_type_interfaces() { const MethodInfo &method_info = E.first; const uint32_t hash = E.second; - int argc = method_info.arguments.size(); - if (method_info.name.is_empty()) { continue; } @@ -3815,8 +3819,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { imethod.return_type.cname = _get_type_name_from_meta(return_info.type, m ? m->get_argument_meta(-1) : (GodotTypeInfo::Metadata)method_info.return_val_metadata); } - for (int i = 0; i < argc; i++) { - PropertyInfo arginfo = method_info.arguments[i]; + int idx = 0; + for (List<PropertyInfo>::ConstIterator itr = method_info.arguments.begin(); itr != method_info.arguments.end(); ++itr, ++idx) { + const PropertyInfo &arginfo = *itr; String orig_arg_name = arginfo.name; @@ -3836,13 +3841,13 @@ bool BindingsGenerator::_populate_object_type_interfaces() { } else if (arginfo.type == Variant::NIL) { iarg.type.cname = name_cache.type_Variant; } else { - iarg.type.cname = _get_type_name_from_meta(arginfo.type, m ? m->get_argument_meta(i) : (GodotTypeInfo::Metadata)method_info.get_argument_meta(i)); + iarg.type.cname = _get_type_name_from_meta(arginfo.type, m ? m->get_argument_meta(idx) : (GodotTypeInfo::Metadata)method_info.get_argument_meta(idx)); } iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); - if (m && m->has_default_argument(i)) { - bool defval_ok = _arg_default_value_from_variant(m->get_default_argument(i), iarg); + if (m && m->has_default_argument(idx)) { + bool defval_ok = _arg_default_value_from_variant(m->get_default_argument(idx), iarg); ERR_FAIL_COND_V_MSG(!defval_ok, false, "Cannot determine default value for argument '" + orig_arg_name + "' of method '" + itype.name + "." + imethod.name + "'."); } @@ -3941,10 +3946,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { isignal.name = method_info.name; isignal.cname = method_info.name; - int argc = method_info.arguments.size(); - - for (int i = 0; i < argc; i++) { - PropertyInfo arginfo = method_info.arguments[i]; + int idx = 0; + for (List<PropertyInfo>::ConstIterator itr = method_info.arguments.begin(); itr != method_info.arguments.end(); ++itr, ++idx) { + const PropertyInfo &arginfo = *itr; String orig_arg_name = arginfo.name; @@ -3964,7 +3968,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { } else if (arginfo.type == Variant::NIL) { iarg.type.cname = name_cache.type_Variant; } else { - iarg.type.cname = _get_type_name_from_meta(arginfo.type, (GodotTypeInfo::Metadata)method_info.get_argument_meta(i)); + iarg.type.cname = _get_type_name_from_meta(arginfo.type, (GodotTypeInfo::Metadata)method_info.get_argument_meta(idx)); } iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); @@ -4246,6 +4250,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar case Variant::PACKED_STRING_ARRAY: case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_VECTOR4_ARRAY: case Variant::PACKED_COLOR_ARRAY: r_iarg.default_argument = "Array.Empty<%s>()"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; @@ -4585,6 +4590,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { INSERT_ARRAY(PackedColorArray, godot_packed_color_array, Color); INSERT_ARRAY(PackedVector2Array, godot_packed_vector2_array, Vector2); INSERT_ARRAY(PackedVector3Array, godot_packed_vector3_array, Vector3); + INSERT_ARRAY(PackedVector4Array, godot_packed_vector4_array, Vector4); #undef INSERT_ARRAY @@ -4763,9 +4769,11 @@ bool BindingsGenerator::_method_has_conflicting_signature(const MethodInterface return false; } - for (int i = 0; i < p_imethod_left.arguments.size(); i++) { - const ArgumentInterface &iarg_left = p_imethod_left.arguments[i]; - const ArgumentInterface &iarg_right = p_imethod_right.arguments[i]; + List<BindingsGenerator::ArgumentInterface>::ConstIterator left_itr = p_imethod_left.arguments.begin(); + List<BindingsGenerator::ArgumentInterface>::ConstIterator right_itr = p_imethod_right.arguments.begin(); + for (; left_itr != p_imethod_left.arguments.end(); ++left_itr, ++right_itr) { + const ArgumentInterface &iarg_left = *left_itr; + const ArgumentInterface &iarg_right = *right_itr; if (iarg_left.type.cname != iarg_right.type.cname) { // Different types for arguments in the same position, so no conflict. @@ -4852,7 +4860,7 @@ static void handle_cmdline_options(String glue_dir_path) { } static void cleanup_and_exit_godot() { - // Exit once done + // Exit once done. Main::cleanup(true); ::exit(0); } @@ -4871,7 +4879,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) elem = elem->next(); } else { ERR_PRINT(generate_all_glue_option + ": No output directory specified (expected path to '{GODOT_ROOT}/modules/mono/glue')."); - // Exit once done with invalid command line arguments + // Exit once done with invalid command line arguments. cleanup_and_exit_godot(); } @@ -4882,8 +4890,14 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) } if (glue_dir_path.length()) { - handle_cmdline_options(glue_dir_path); - // Exit once done + if (Engine::get_singleton()->is_editor_hint() || + Engine::get_singleton()->is_project_manager_hint()) { + handle_cmdline_options(glue_dir_path); + } else { + // Running from a project folder, which doesn't make sense and crashes. + ERR_PRINT(generate_all_glue_option + ": Cannot generate Mono glue while running a game project. Change current directory or enable --editor."); + } + // Exit once done. cleanup_and_exit_godot(); } } diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index a397dcb026..556d287af4 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -705,7 +705,7 @@ class BindingsGenerator { StringName type_Vector4i = StaticCString::create("Vector4i"); // Object not included as it must be checked for all derived classes - static constexpr int nullable_types_count = 18; + static constexpr int nullable_types_count = 19; StringName nullable_types[nullable_types_count] = { type_String, type_StringName, @@ -727,6 +727,7 @@ class BindingsGenerator { StaticCString::create(_STR(PackedVector2Array)), StaticCString::create(_STR(PackedVector3Array)), StaticCString::create(_STR(PackedColorArray)), + StaticCString::create(_STR(PackedVector4Array)), }; bool is_nullable_type(const StringName &p_type) const { diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj index 4d1a5bb76c..81add0e44f 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <LangVersion>10</LangVersion> diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs index f3f6759e1d..08e293afcc 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs @@ -468,6 +468,7 @@ using Godot.NativeInterop; "Godot.NativeInterop.godot_packed_string_array", "Godot.NativeInterop.godot_packed_vector2_array", "Godot.NativeInterop.godot_packed_vector3_array", + "Godot.NativeInterop.godot_packed_vector4_array", "Godot.NativeInterop.godot_packed_color_array", }; } diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj index e58d730ee3..1e60743fb1 100644 --- a/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj +++ b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj @@ -1,18 +1,18 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> - <PropertyGroup> - <TargetFramework>net6.0</TargetFramework> - <LangVersion>10</LangVersion> - <Nullable>enable</Nullable> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <PropertyGroup> + <TargetFramework>net6.0</TargetFramework> + <LangVersion>10</LangVersion> + <Nullable>enable</Nullable> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <!-- To generate the .runtimeconfig.json file--> - <EnableDynamicLoading>true</EnableDynamicLoading> - <RollForward>LatestMajor</RollForward> - </PropertyGroup> + <!-- To generate the .runtimeconfig.json file--> + <EnableDynamicLoading>true</EnableDynamicLoading> + <RollForward>LatestMajor</RollForward> + </PropertyGroup> - <ItemGroup> - <ProjectReference Include="..\GodotSharp\GodotSharp.csproj" /> - </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\GodotSharp\GodotSharp.csproj" /> + </ItemGroup> </Project> diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln b/modules/mono/glue/GodotSharp/GodotSharp.sln index 8db42c2d1a..81ff7d7550 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp.sln +++ b/modules/mono/glue/GodotSharp/GodotSharp.sln @@ -1,5 +1,8 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "GodotSharp\GodotSharp.csproj", "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpEditor", "GodotSharpEditor\GodotSharpEditor.csproj", "{8FBEC238-D944-4074-8548-B3B524305905}" @@ -10,8 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Inte EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -31,4 +34,10 @@ Global {7749662B-E30C-419A-B745-13852573360A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7749662B-E30C-419A-B745-13852573360A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {371B0F03-042D-45FD-A270-F3141F2480CD} + EndGlobalSection EndGlobal diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs index feaa1d07da..ab7f8ede44 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs @@ -69,7 +69,7 @@ namespace Godot public readonly Aabb Abs() { Vector3 end = End; - Vector3 topLeft = new Vector3(Mathf.Min(_position.X, end.X), Mathf.Min(_position.Y, end.Y), Mathf.Min(_position.Z, end.Z)); + Vector3 topLeft = end.Min(_position); return new Aabb(topLeft, _size.Abs()); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 1b23276bbd..eef26cdd4e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -798,17 +798,17 @@ namespace Godot.Bridge GetScriptTypeInfo(scriptType, outTypeInfo); + Type native = GodotObject.InternalGetClassNativeBase(scriptType); + // Methods // Performance is not critical here as this will be replaced with source generators. using var methods = new Collections.Array(); Type? top = scriptType; - Type native = GodotObject.InternalGetClassNativeBase(top); - - while (top != null && top != native) + if (scriptType != native) { - var methodList = GetMethodListForType(top); + var methodList = GetMethodListForType(scriptType); if (methodList != null) { @@ -859,8 +859,6 @@ namespace Godot.Bridge methods.Add(methodInfo); } } - - top = top.BaseType; } *outMethodsDest = NativeFuncs.godotsharp_array_new_copy( @@ -912,11 +910,9 @@ namespace Godot.Bridge // Performance is not critical here as this will be replaced with source generators. using var signals = new Collections.Dictionary(); - top = scriptType; - - while (top != null && top != native) + if (scriptType != native) { - var signalList = GetSignalListForType(top); + var signalList = GetSignalListForType(scriptType); if (signalList != null) { @@ -951,8 +947,6 @@ namespace Godot.Bridge signals.Add(signalName, signalParams); } } - - top = top.BaseType; } *outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new_copy( diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs index afef20a7f2..171cf86edb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs @@ -296,6 +296,22 @@ public static class CustomUnsafe => ref *ReadOnlyRefAsPointer(in source); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe godot_packed_vector4_array* AsPointer(ref godot_packed_vector4_array value) + => value.GetUnsafeAddress(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe godot_packed_vector4_array* ReadOnlyRefAsPointer(in godot_packed_vector4_array value) + => value.GetUnsafeAddress(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ref godot_packed_vector4_array AsRef(godot_packed_vector4_array* source) + => ref *source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ref godot_packed_vector4_array AsRef(in godot_packed_vector4_array source) + => ref *ReadOnlyRefAsPointer(in source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe godot_packed_color_array* AsPointer(ref godot_packed_color_array value) => value.GetUnsafeAddress(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs index a019dd3513..7e5c01d0f8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs @@ -1134,6 +1134,39 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + public ref struct godot_packed_vector4_array + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly unsafe godot_packed_vector4_array* GetUnsafeAddress() + => (godot_packed_vector4_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy)); + + private IntPtr _writeProxy; + private unsafe Vector4* _ptr; + + public unsafe void Dispose() + { + if (_ptr == null) + return; + NativeFuncs.godotsharp_packed_vector4_array_destroy(ref this); + _ptr = null; + } + + public readonly unsafe Vector4* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? (int)(*((ulong*)_ptr - 1)) : 0; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming public ref struct godot_packed_color_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 9f7fa53e24..15b7ce7c73 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -133,6 +133,9 @@ namespace Godot.NativeInterop if (type == typeof(Vector3[])) return Variant.Type.PackedVector3Array; + if (type == typeof(Vector4[])) + return Variant.Type.PackedVector4Array; + if (type == typeof(Color[])) return Variant.Type.PackedColorArray; @@ -574,6 +577,30 @@ namespace Godot.NativeInterop return NativeFuncs.godotsharp_packed_vector3_array_new_mem_copy(src, p_array.Length); } + // PackedVector4Array + + public static unsafe Vector4[] ConvertNativePackedVector4ArrayToSystemArray(godot_packed_vector4_array p_array) + { + Vector4* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<Vector4>(); + int sizeInBytes = size * sizeof(Vector4); + var array = new Vector4[size]; + fixed (Vector4* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_vector4_array ConvertSystemArrayToNativePackedVector4Array( + Span<Vector4> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_vector4_array(); + fixed (Vector4* src = p_array) + return NativeFuncs.godotsharp_packed_vector4_array_new_mem_copy(src, p_array.Length); + } + // PackedColorArray public static unsafe Color[] ConvertNativePackedColorArrayToSystemArray(godot_packed_color_array p_array) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index fef21fae46..c4fd639cce 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -144,6 +144,9 @@ namespace Godot.NativeInterop public static partial godot_packed_vector3_array godotsharp_packed_vector3_array_new_mem_copy(Vector3* p_src, int p_length); + public static partial godot_packed_vector4_array godotsharp_packed_vector4_array_new_mem_copy(Vector4* p_src, + int p_length); + public static partial godot_packed_color_array godotsharp_packed_color_array_new_mem_copy(Color* p_src, int p_length); @@ -224,6 +227,9 @@ namespace Godot.NativeInterop public static partial void godotsharp_variant_new_packed_vector3_array(out godot_variant r_dest, in godot_packed_vector3_array p_pv3a); + public static partial void godotsharp_variant_new_packed_vector4_array(out godot_variant r_dest, + in godot_packed_vector4_array p_pv4a); + public static partial void godotsharp_variant_new_packed_color_array(out godot_variant r_dest, in godot_packed_color_array p_pca); @@ -302,6 +308,9 @@ namespace Godot.NativeInterop public static partial godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array( in godot_variant p_self); + public static partial godot_packed_vector4_array godotsharp_variant_as_packed_vector4_array( + in godot_variant p_self); + public static partial godot_packed_color_array godotsharp_variant_as_packed_color_array(in godot_variant p_self); public static partial godot_bool godotsharp_variant_equals(in godot_variant p_a, in godot_variant p_b); @@ -352,6 +361,8 @@ namespace Godot.NativeInterop public static partial void godotsharp_packed_vector3_array_destroy(ref godot_packed_vector3_array p_self); + public static partial void godotsharp_packed_vector4_array_destroy(ref godot_packed_vector4_array p_self); + public static partial void godotsharp_packed_color_array_destroy(ref godot_packed_color_array p_self); public static partial void godotsharp_variant_destroy(ref godot_variant p_self); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index 94609984ac..dc151e2c3e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -165,6 +165,12 @@ namespace Godot.NativeInterop return ret; } + public static godot_variant CreateFromPackedVector4Array(in godot_packed_vector4_array from) + { + NativeFuncs.godotsharp_variant_new_packed_vector4_array(out godot_variant ret, from); + return ret; + } + public static godot_variant CreateFromPackedColorArray(in godot_packed_color_array from) { NativeFuncs.godotsharp_variant_new_packed_color_array(out godot_variant ret, from); @@ -228,6 +234,13 @@ namespace Godot.NativeInterop } [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedVector4Array(Span<Vector4> from) + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector4Array(from); + return CreateFromPackedVector4Array(nativePackedArray); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedColorArray(Span<Color> from) { using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedColorArray(from); @@ -605,6 +618,12 @@ namespace Godot.NativeInterop return Marshaling.ConvertNativePackedVector3ArrayToSystemArray(packedArray); } + public static Vector4[] ConvertAsPackedVector4ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector4_array(p_var); + return Marshaling.ConvertNativePackedVector4ArrayToSystemArray(packedArray); + } + public static Color[] ConvertAsPackedColorArrayToSystemArray(in godot_variant p_var) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs index d8f7214c2f..2897cc4199 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs @@ -155,6 +155,9 @@ public partial class VariantUtils if (typeof(T) == typeof(Vector3[])) return CreateFromPackedVector3Array(UnsafeAs<Vector3[]>(from)); + if (typeof(T) == typeof(Vector4[])) + return CreateFromPackedVector4Array(UnsafeAs<Vector4[]>(from)); + if (typeof(T) == typeof(Color[])) return CreateFromPackedColorArray(UnsafeAs<Color[]>(from)); @@ -343,6 +346,9 @@ public partial class VariantUtils if (typeof(T) == typeof(Vector3[])) return UnsafeAsT(ConvertAsPackedVector3ArrayToSystemArray(variant)); + if (typeof(T) == typeof(Vector4[])) + return UnsafeAsT(ConvertAsPackedVector4ArrayToSystemArray(variant)); + if (typeof(T) == typeof(Color[])) return UnsafeAsT(ConvertAsPackedColorArrayToSystemArray(variant)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index 9d9065911e..19721b6cca 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -69,7 +69,7 @@ namespace Godot public readonly Rect2 Abs() { Vector2 end = End; - Vector2 topLeft = new Vector2(Mathf.Min(_position.X, end.X), Mathf.Min(_position.Y, end.Y)); + Vector2 topLeft = end.Min(_position); return new Rect2(topLeft, _size.Abs()); } @@ -91,14 +91,12 @@ namespace Godot return new Rect2(); } - newRect._position.X = Mathf.Max(b._position.X, _position.X); - newRect._position.Y = Mathf.Max(b._position.Y, _position.Y); + newRect._position = b._position.Max(_position); Vector2 bEnd = b._position + b._size; Vector2 end = _position + _size; - newRect._size.X = Mathf.Min(bEnd.X, end.X) - newRect._position.X; - newRect._size.Y = Mathf.Min(bEnd.Y, end.Y) - newRect._position.Y; + newRect._size = bEnd.Min(end) - newRect._position; return newRect; } @@ -338,11 +336,9 @@ namespace Godot { Rect2 newRect; - newRect._position.X = Mathf.Min(b._position.X, _position.X); - newRect._position.Y = Mathf.Min(b._position.Y, _position.Y); + newRect._position = b._position.Min(_position); - newRect._size.X = Mathf.Max(b._position.X + b._size.X, _position.X + _size.X); - newRect._size.Y = Mathf.Max(b._position.Y + b._size.Y, _position.Y + _size.Y); + newRect._size = (b._position + b._size).Max(_position + _size); newRect._size -= newRect._position; // Make relative again diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs index 65704b3da7..7ee9ff8552 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs @@ -69,7 +69,7 @@ namespace Godot public readonly Rect2I Abs() { Vector2I end = End; - Vector2I topLeft = new Vector2I(Mathf.Min(_position.X, end.X), Mathf.Min(_position.Y, end.Y)); + Vector2I topLeft = end.Min(_position); return new Rect2I(topLeft, _size.Abs()); } @@ -91,14 +91,12 @@ namespace Godot return new Rect2I(); } - newRect._position.X = Mathf.Max(b._position.X, _position.X); - newRect._position.Y = Mathf.Max(b._position.Y, _position.Y); + newRect._position = b._position.Max(_position); Vector2I bEnd = b._position + b._size; Vector2I end = _position + _size; - newRect._size.X = Mathf.Min(bEnd.X, end.X) - newRect._position.X; - newRect._size.Y = Mathf.Min(bEnd.Y, end.Y) - newRect._position.Y; + newRect._size = bEnd.Min(end) - newRect._position; return newRect; } @@ -295,11 +293,9 @@ namespace Godot { Rect2I newRect; - newRect._position.X = Mathf.Min(b._position.X, _position.X); - newRect._position.Y = Mathf.Min(b._position.Y, _position.Y); + newRect._position = b._position.Min(_position); - newRect._size.X = Mathf.Max(b._position.X + b._size.X, _position.X + _size.X); - newRect._size.Y = Mathf.Max(b._position.Y + b._size.Y, _position.Y + _size.Y); + newRect._size = (b._position + b._size).Max(_position + _size); newRect._size -= newRect._position; // Make relative again diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 37f319b697..ad75195f0f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -417,76 +417,35 @@ namespace Godot } /// <summary> - /// Performs a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// Performs a case-sensitive comparison to another string and returns an integer that indicates their relative position in the sort order. /// </summary> /// <seealso cref="NocasecmpTo(string, string)"/> /// <seealso cref="CompareTo(string, string, bool)"/> /// <param name="instance">The string to compare.</param> /// <param name="to">The other string to compare.</param> - /// <returns>-1 if less, 0 if equal and +1 if greater.</returns> + /// <returns>An integer that indicates the lexical relationship between the two comparands.</returns> public static int CasecmpTo(this string instance, string to) { - return instance.CompareTo(to, caseSensitive: true); +#pragma warning disable CA1309 // Use ordinal string comparison + return string.Compare(instance, to, ignoreCase: false, null); +#pragma warning restore CA1309 } /// <summary> - /// Performs a comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// Performs a comparison to another string and returns an integer that indicates their relative position in the sort order. /// </summary> /// <param name="instance">The string to compare.</param> /// <param name="to">The other string to compare.</param> /// <param name="caseSensitive"> /// If <see langword="true"/>, the comparison will be case sensitive. /// </param> - /// <returns>-1 if less, 0 if equal and +1 if greater.</returns> + /// <returns>An integer that indicates the lexical relationship between the two comparands.</returns> + [Obsolete("Use string.Compare instead.")] public static int CompareTo(this string instance, string to, bool caseSensitive = true) { - if (string.IsNullOrEmpty(instance)) - return string.IsNullOrEmpty(to) ? 0 : -1; - - if (string.IsNullOrEmpty(to)) - return 1; - - int instanceIndex = 0; - int toIndex = 0; - - if (caseSensitive) // Outside while loop to avoid checking multiple times, despite some code duplication. - { - while (true) - { - if (to[toIndex] == 0 && instance[instanceIndex] == 0) - return 0; // We're equal - if (instance[instanceIndex] == 0) - return -1; // If this is empty, and the other one is not, then we're less... I think? - if (to[toIndex] == 0) - return 1; // Otherwise the other one is smaller... - if (instance[instanceIndex] < to[toIndex]) // More than - return -1; - if (instance[instanceIndex] > to[toIndex]) // Less than - return 1; - - instanceIndex++; - toIndex++; - } - } - else - { - while (true) - { - if (to[toIndex] == 0 && instance[instanceIndex] == 0) - return 0; // We're equal - if (instance[instanceIndex] == 0) - return -1; // If this is empty, and the other one is not, then we're less... I think? - if (to[toIndex] == 0) - return 1; // Otherwise the other one is smaller.. - if (char.ToUpperInvariant(instance[instanceIndex]) < char.ToUpperInvariant(to[toIndex])) // More than - return -1; - if (char.ToUpperInvariant(instance[instanceIndex]) > char.ToUpperInvariant(to[toIndex])) // Less than - return 1; - - instanceIndex++; - toIndex++; - } - } +#pragma warning disable CA1309 // Use ordinal string comparison + return string.Compare(instance, to, ignoreCase: !caseSensitive, null); +#pragma warning restore CA1309 } /// <summary> @@ -1297,16 +1256,18 @@ namespace Godot } /// <summary> - /// Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// Performs a case-insensitive comparison to another string and returns an integer that indicates their relative position in the sort order. /// </summary> /// <seealso cref="CasecmpTo(string, string)"/> /// <seealso cref="CompareTo(string, string, bool)"/> /// <param name="instance">The string to compare.</param> /// <param name="to">The other string to compare.</param> - /// <returns>-1 if less, 0 if equal and +1 if greater.</returns> + /// <returns>An integer that indicates the lexical relationship between the two comparands.</returns> public static int NocasecmpTo(this string instance, string to) { - return instance.CompareTo(to, caseSensitive: false); +#pragma warning disable CA1309 // Use ordinal string comparison + return string.Compare(instance, to, ignoreCase: true, null); +#pragma warning restore CA1309 } /// <summary> @@ -1739,7 +1700,7 @@ namespace Godot } /// <summary> - /// Converts the string (which is an array of characters) to an UTF-16 encoded array of bytes. + /// Converts the string (which is an array of characters) to a UTF-16 encoded array of bytes. /// </summary> /// <seealso cref="ToAsciiBuffer(string)"/> /// <seealso cref="ToUtf32Buffer(string)"/> @@ -1752,7 +1713,7 @@ namespace Godot } /// <summary> - /// Converts the string (which is an array of characters) to an UTF-32 encoded array of bytes. + /// Converts the string (which is an array of characters) to a UTF-32 encoded array of bytes. /// </summary> /// <seealso cref="ToAsciiBuffer(string)"/> /// <seealso cref="ToUtf16Buffer(string)"/> @@ -1765,7 +1726,7 @@ namespace Godot } /// <summary> - /// Converts the string (which is an array of characters) to an UTF-8 encoded array of bytes. + /// Converts the string (which is an array of characters) to a UTF-8 encoded array of bytes. /// The conversion is a bit slower than <see cref="ToAsciiBuffer(string)"/>, /// but supports all UTF-8 characters. Therefore, you should prefer this function /// over <see cref="ToAsciiBuffer(string)"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs index c2d3050adc..b40f524859 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs @@ -149,6 +149,7 @@ public partial struct Variant : IDisposable Type.PackedStringArray => AsStringArray(), Type.PackedVector2Array => AsVector2Array(), Type.PackedVector3Array => AsVector3Array(), + Type.PackedVector4Array => AsVector4Array(), Type.PackedColorArray => AsColorArray(), Type.Nil => null, Type.Max or _ => @@ -320,6 +321,10 @@ public partial struct Variant : IDisposable VariantUtils.ConvertAsPackedVector3ArrayToSystemArray((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4[] AsVector4Array() => + VariantUtils.ConvertAsPackedVector4ArrayToSystemArray((godot_variant)NativeVar); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Color[] AsColorArray() => VariantUtils.ConvertAsPackedColorArrayToSystemArray((godot_variant)NativeVar); @@ -492,6 +497,9 @@ public partial struct Variant : IDisposable public static explicit operator Vector3[](Variant from) => from.AsVector3Array(); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator Vector4[](Variant from) => from.AsVector4Array(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Color[](Variant from) => from.AsColorArray(); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -642,6 +650,9 @@ public partial struct Variant : IDisposable public static Variant CreateFrom(Span<Vector3> from) => from; [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span<Vector4> from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Variant CreateFrom(Span<Color> from) => from; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -841,6 +852,10 @@ public partial struct Variant : IDisposable (Variant)from.AsSpan(); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Variant(Vector4[] from) => + (Variant)from.AsSpan(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Variant(Color[] from) => (Variant)from.AsSpan(); @@ -893,6 +908,10 @@ public partial struct Variant : IDisposable CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedVector3Array(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Variant(Span<Vector4> from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedVector4Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Variant(Span<Color> from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedColorArray(from)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 856fd54352..50bf56d832 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -192,6 +192,23 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. + /// </summary> + /// <param name="min">The minimum allowed value.</param> + /// <param name="max">The maximum allowed value.</param> + /// <returns>The vector with all components clamped.</returns> + public readonly Vector2 Clamp(real_t min, real_t max) + { + return new Vector2 + ( + Mathf.Clamp(X, min, max), + Mathf.Clamp(Y, min, max) + ); + } + + /// <summary> /// Returns the cross product of this vector and <paramref name="with"/>. /// </summary> /// <param name="with">The other vector.</param> @@ -413,6 +430,70 @@ namespace Godot } /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector2 Max(Vector2 with) + { + return new Vector2 + ( + Mathf.Max(X, with.X), + Mathf.Max(Y, with.Y) + ); + } + + /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2(Mathf.Max(X, with), Mathf.Max(Y, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector2 Max(real_t with) + { + return new Vector2 + ( + Mathf.Max(X, with), + Mathf.Max(Y, with) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector2 Min(Vector2 with) + { + return new Vector2 + ( + Mathf.Min(X, with.X), + Mathf.Min(Y, with.Y) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2(Mathf.Min(X, with), Mathf.Min(Y, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector2 Min(real_t with) + { + return new Vector2 + ( + Mathf.Min(X, with), + Mathf.Min(Y, with) + ); + } + + /// <summary> /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. /// If both components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -600,7 +681,7 @@ namespace Godot } /// <summary> - /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// Returns a new vector with each component snapped to the nearest multiple of the corresponding component in <paramref name="step"/>. /// This can also be used to round to an arbitrary number of decimals. /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> @@ -611,6 +692,17 @@ namespace Godot } /// <summary> + /// Returns a new vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// This can also be used to round to an arbitrary number of decimals. + /// </summary> + /// <param name="step">The step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector2 Snapped(real_t step) + { + return new Vector2(Mathf.Snapped(X, step), Mathf.Snapped(Y, step)); + } + + /// <summary> /// Returns a perpendicular vector rotated 90 degrees counter-clockwise /// compared to the original, with the same length. /// </summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs index 511cc7971c..9442db4d86 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs @@ -125,6 +125,23 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The minimum allowed value.</param> + /// <param name="max">The maximum allowed value.</param> + /// <returns>The vector with all components clamped.</returns> + public readonly Vector2I Clamp(int min, int max) + { + return new Vector2I + ( + Mathf.Clamp(X, min, max), + Mathf.Clamp(Y, min, max) + ); + } + + /// <summary> /// Returns the squared distance between this vector and <paramref name="to"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. @@ -175,6 +192,70 @@ namespace Godot } /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2I(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector2I Max(Vector2I with) + { + return new Vector2I + ( + Mathf.Max(X, with.X), + Mathf.Max(Y, with.Y) + ); + } + + /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2I(Mathf.Max(X, with), Mathf.Max(Y, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector2I Max(int with) + { + return new Vector2I + ( + Mathf.Max(X, with), + Mathf.Max(Y, with) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2I(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector2I Min(Vector2I with) + { + return new Vector2I + ( + Mathf.Min(X, with.X), + Mathf.Min(Y, with.Y) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector2I(Mathf.Min(X, with), Mathf.Min(Y, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector2I Min(int with) + { + return new Vector2I + ( + Mathf.Min(X, with), + Mathf.Min(Y, with) + ); + } + + /// <summary> /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. /// If both components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -208,6 +289,34 @@ namespace Godot return v; } + /// <summary> + /// Returns a new vector with each component snapped to the closest multiple of the corresponding component in <paramref name="step"/>. + /// </summary> + /// <param name="step">A vector value representing the step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector2I Snapped(Vector2I step) + { + return new Vector2I + ( + (int)Mathf.Snapped((double)X, (double)step.X), + (int)Mathf.Snapped((double)Y, (double)step.Y) + ); + } + + /// <summary> + /// Returns a new vector with each component snapped to the closest multiple of <paramref name="step"/>. + /// </summary> + /// <param name="step">The step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector2I Snapped(int step) + { + return new Vector2I + ( + (int)Mathf.Snapped((double)X, (double)step), + (int)Mathf.Snapped((double)Y, (double)step) + ); + } + // Constants private static readonly Vector2I _minValue = new Vector2I(int.MinValue, int.MinValue); private static readonly Vector2I _maxValue = new Vector2I(int.MaxValue, int.MaxValue); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 6300705107..27f2713efa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -179,6 +179,24 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. + /// </summary> + /// <param name="min">The minimum allowed value.</param> + /// <param name="max">The maximum allowed value.</param> + /// <returns>The vector with all components clamped.</returns> + public readonly Vector3 Clamp(real_t min, real_t max) + { + return new Vector3 + ( + Mathf.Clamp(X, min, max), + Mathf.Clamp(Y, min, max), + Mathf.Clamp(Z, min, max) + ); + } + + /// <summary> /// Returns the cross product of this vector and <paramref name="with"/>. /// </summary> /// <param name="with">The other vector.</param> @@ -419,6 +437,57 @@ namespace Godot } /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y), Mathf.Max(Z, with.Z))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector3 Max(Vector3 with) + { + return new Vector3 + ( + Mathf.Max(X, with.X), + Mathf.Max(Y, with.Y), + Mathf.Max(Z, with.Z) + ); + } + + /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3(Mathf.Max(X, with), Mathf.Max(Y, with), Mathf.Max(Z, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector3 Max(real_t with) + { + return new Vector3 + ( + Mathf.Max(X, with), + Mathf.Max(Y, with), + Mathf.Max(Z, with) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y), Mathf.Min(Z, with.Z))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector3 Min(Vector3 with) + { + return new Vector3 + ( + Mathf.Min(X, with.X), + Mathf.Min(Y, with.Y), + Mathf.Min(Z, with.Z) + ); + } + + /// <summary> /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -643,7 +712,7 @@ namespace Godot } /// <summary> - /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// Returns a new vector with each component snapped to the nearest multiple of the corresponding component in <paramref name="step"/>. /// This can also be used to round to an arbitrary number of decimals. /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> @@ -658,6 +727,22 @@ namespace Godot ); } + /// <summary> + /// Returns a new vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// This can also be used to round to an arbitrary number of decimals. + /// </summary> + /// <param name="step">The step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector3 Snapped(real_t step) + { + return new Vector3 + ( + Mathf.Snapped(X, step), + Mathf.Snapped(Y, step), + Mathf.Snapped(Z, step) + ); + } + // Constants private static readonly Vector3 _zero = new Vector3(0, 0, 0); private static readonly Vector3 _one = new Vector3(1, 1, 1); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs index aea46efc5b..8312e2c231 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs @@ -133,6 +133,24 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The minimum allowed value.</param> + /// <param name="max">The maximum allowed value.</param> + /// <returns>The vector with all components clamped.</returns> + public readonly Vector3I Clamp(int min, int max) + { + return new Vector3I + ( + Mathf.Clamp(X, min, max), + Mathf.Clamp(Y, min, max), + Mathf.Clamp(Z, min, max) + ); + } + + /// <summary> /// Returns the squared distance between this vector and <paramref name="to"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. @@ -185,6 +203,74 @@ namespace Godot } /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3I(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y), Mathf.Max(Z, with.Z))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector3I Max(Vector3I with) + { + return new Vector3I + ( + Mathf.Max(X, with.X), + Mathf.Max(Y, with.Y), + Mathf.Max(Z, with.Z) + ); + } + + /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3I(Mathf.Max(X, with), Mathf.Max(Y, with), Mathf.Max(Z, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector3I Max(int with) + { + return new Vector3I + ( + Mathf.Max(X, with), + Mathf.Max(Y, with), + Mathf.Max(Z, with) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3I(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y), Mathf.Min(Z, with.Z))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector3I Min(Vector3I with) + { + return new Vector3I + ( + Mathf.Min(X, with.X), + Mathf.Min(Y, with.Y), + Mathf.Min(Z, with.Z) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector3I(Mathf.Min(X, with), Mathf.Min(Y, with), Mathf.Min(Z, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector3I Min(int with) + { + return new Vector3I + ( + Mathf.Min(X, with), + Mathf.Min(Y, with), + Mathf.Min(Z, with) + ); + } + + /// <summary> /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -219,6 +305,36 @@ namespace Godot return v; } + /// <summary> + /// Returns a new vector with each component snapped to the closest multiple of the corresponding component in <paramref name="step"/>. + /// </summary> + /// <param name="step">A vector value representing the step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector3I Snapped(Vector3I step) + { + return new Vector3I + ( + (int)Mathf.Snapped((double)X, (double)step.X), + (int)Mathf.Snapped((double)Y, (double)step.Y), + (int)Mathf.Snapped((double)Z, (double)step.Z) + ); + } + + /// <summary> + /// Returns a new vector with each component snapped to the closest multiple of <paramref name="step"/>. + /// </summary> + /// <param name="step">The step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector3I Snapped(int step) + { + return new Vector3I + ( + (int)Mathf.Snapped((double)X, (double)step), + (int)Mathf.Snapped((double)Y, (double)step), + (int)Mathf.Snapped((double)Z, (double)step) + ); + } + // Constants private static readonly Vector3I _minValue = new Vector3I(int.MinValue, int.MinValue, int.MinValue); private static readonly Vector3I _maxValue = new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index 7c4832943c..ec59197fa3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -177,6 +177,25 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. + /// </summary> + /// <param name="min">The minimum allowed value.</param> + /// <param name="max">The maximum allowed value.</param> + /// <returns>The vector with all components clamped.</returns> + public readonly Vector4 Clamp(real_t min, real_t max) + { + return new Vector4 + ( + Mathf.Clamp(X, min, max), + Mathf.Clamp(Y, min, max), + Mathf.Clamp(Z, min, max), + Mathf.Clamp(W, min, max) + ); + } + + /// <summary> /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector, /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>. /// </summary> @@ -352,6 +371,78 @@ namespace Godot } /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y), Mathf.Max(Z, with.Z), Mathf.Max(W, with.W))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector4 Max(Vector4 with) + { + return new Vector4 + ( + Mathf.Max(X, with.X), + Mathf.Max(Y, with.Y), + Mathf.Max(Z, with.Z), + Mathf.Max(W, with.W) + ); + } + + /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4(Mathf.Max(X, with), Mathf.Max(Y, with), Mathf.Max(Z, with), Mathf.Max(W, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector4 Max(real_t with) + { + return new Vector4 + ( + Mathf.Max(X, with), + Mathf.Max(Y, with), + Mathf.Max(Z, with), + Mathf.Max(W, with) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y), Mathf.Min(Z, with.Z), Mathf.Min(W, with.W))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector4 Min(Vector4 with) + { + return new Vector4 + ( + Mathf.Min(X, with.X), + Mathf.Min(Y, with.Y), + Mathf.Min(Z, with.Z), + Mathf.Min(W, with.W) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4(Mathf.Min(X, with), Mathf.Min(Y, with), Mathf.Min(Z, with), Mathf.Min(W, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector4 Min(real_t with) + { + return new Vector4 + ( + Mathf.Min(X, with), + Mathf.Min(Y, with), + Mathf.Min(Z, with), + Mathf.Min(W, with) + ); + } + + /// <summary> /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -465,7 +556,7 @@ namespace Godot } /// <summary> - /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// Returns a new vector with each component snapped to the nearest multiple of the corresponding component in <paramref name="step"/>. /// This can also be used to round to an arbitrary number of decimals. /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> @@ -480,6 +571,22 @@ namespace Godot ); } + /// <summary> + /// Returns a new vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// This can also be used to round to an arbitrary number of decimals. + /// </summary> + /// <param name="step">The step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector4 Snapped(real_t step) + { + return new Vector4( + Mathf.Snapped(X, step), + Mathf.Snapped(Y, step), + Mathf.Snapped(Z, step), + Mathf.Snapped(W, step) + ); + } + // Constants private static readonly Vector4 _zero = new Vector4(0, 0, 0, 0); private static readonly Vector4 _one = new Vector4(1, 1, 1, 1); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs index 27aa86b7e4..ba8e54b88b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs @@ -150,6 +150,25 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between + /// <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The minimum allowed value.</param> + /// <param name="max">The maximum allowed value.</param> + /// <returns>The vector with all components clamped.</returns> + public readonly Vector4I Clamp(int min, int max) + { + return new Vector4I + ( + Mathf.Clamp(X, min, max), + Mathf.Clamp(Y, min, max), + Mathf.Clamp(Z, min, max), + Mathf.Clamp(W, min, max) + ); + } + + /// <summary> /// Returns the squared distance between this vector and <paramref name="to"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. @@ -204,6 +223,78 @@ namespace Godot } /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4I(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y), Mathf.Max(Z, with.Z), Mathf.Max(W, with.W))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector4I Max(Vector4I with) + { + return new Vector4I + ( + Mathf.Max(X, with.X), + Mathf.Max(Y, with.Y), + Mathf.Max(Z, with.Z), + Mathf.Max(W, with.W) + ); + } + + /// <summary> + /// Returns the result of the component-wise maximum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4I(Mathf.Max(X, with), Mathf.Max(Y, with), Mathf.Max(Z, with), Mathf.Max(W, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting maximum vector.</returns> + public readonly Vector4I Max(int with) + { + return new Vector4I + ( + Mathf.Max(X, with), + Mathf.Max(Y, with), + Mathf.Max(Z, with), + Mathf.Max(W, with) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4I(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y), Mathf.Min(Z, with.Z), Mathf.Min(W, with.W))</c>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector4I Min(Vector4I with) + { + return new Vector4I + ( + Mathf.Min(X, with.X), + Mathf.Min(Y, with.Y), + Mathf.Min(Z, with.Z), + Mathf.Min(W, with.W) + ); + } + + /// <summary> + /// Returns the result of the component-wise minimum between + /// this vector and <paramref name="with"/>. + /// Equivalent to <c>new Vector4I(Mathf.Min(X, with), Mathf.Min(Y, with), Mathf.Min(Z, with), Mathf.Min(W, with))</c>. + /// </summary> + /// <param name="with">The other value to use.</param> + /// <returns>The resulting minimum vector.</returns> + public readonly Vector4I Min(int with) + { + return new Vector4I + ( + Mathf.Min(X, with), + Mathf.Min(Y, with), + Mathf.Min(Z, with), + Mathf.Min(W, with) + ); + } + + /// <summary> /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -254,6 +345,36 @@ namespace Godot return new Vector4I(Mathf.Sign(X), Mathf.Sign(Y), Mathf.Sign(Z), Mathf.Sign(W)); } + /// <summary> + /// Returns a new vector with each component snapped to the closest multiple of the corresponding component in <paramref name="step"/>. + /// </summary> + /// <param name="step">A vector value representing the step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector4I Snapped(Vector4I step) + { + return new Vector4I( + (int)Mathf.Snapped((double)X, (double)step.X), + (int)Mathf.Snapped((double)Y, (double)step.Y), + (int)Mathf.Snapped((double)Z, (double)step.Z), + (int)Mathf.Snapped((double)W, (double)step.W) + ); + } + + /// <summary> + /// Returns a new vector with each component snapped to the closest multiple of <paramref name="step"/>. + /// </summary> + /// <param name="step">The step size to snap to.</param> + /// <returns>The snapped vector.</returns> + public readonly Vector4I Snapped(int step) + { + return new Vector4I( + (int)Mathf.Snapped((double)X, (double)step), + (int)Mathf.Snapped((double)Y, (double)step), + (int)Mathf.Snapped((double)Z, (double)step), + (int)Mathf.Snapped((double)W, (double)step) + ); + } + // Constants private static readonly Vector4I _minValue = new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue); private static readonly Vector4I _maxValue = new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index d4c11da963..6b25087c93 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{AEBF0036-DA76-4341-B651-A3F2856AB2FA}</ProjectGuid> <OutputPath>bin/$(Configuration)</OutputPath> @@ -22,6 +22,7 @@ <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharp</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> <PackageLicenseExpression>MIT</PackageLicenseExpression> + <Copyright>Copyright (c) Godot Engine contributors</Copyright> <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <IncludeSymbols>true</IncludeSymbols> diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj index c32cbcd3d1..4561fdaf2b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{8FBEC238-D944-4074-8548-B3B524305905}</ProjectGuid> <OutputPath>bin/$(Configuration)</OutputPath> @@ -20,6 +20,7 @@ <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharpEditor</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> <PackageLicenseExpression>MIT</PackageLicenseExpression> + <Copyright>Copyright (c) Godot Engine contributors</Copyright> <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <IncludeSymbols>true</IncludeSymbols> diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index 4bb324c0ee..1af462dafd 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -461,6 +461,16 @@ godot_packed_array godotsharp_packed_vector3_array_new_mem_copy(const Vector3 *p return ret; } +godot_packed_array godotsharp_packed_vector4_array_new_mem_copy(const Vector4 *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedVector4Array); + PackedVector4Array *array = reinterpret_cast<PackedVector4Array *>(&ret); + array->resize(p_length); + Vector4 *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(Vector4)); + return ret; +} + godot_packed_array godotsharp_packed_color_array_new_mem_copy(const Color *p_src, int32_t p_length) { godot_packed_array ret; memnew_placement(&ret, PackedColorArray); @@ -646,6 +656,10 @@ void godotsharp_variant_new_packed_vector3_array(godot_variant *r_dest, const Pa memnew_placement(r_dest, Variant(*p_pv3a)); } +void godotsharp_variant_new_packed_vector4_array(godot_variant *r_dest, const PackedVector4Array *p_pv4a) { + memnew_placement(r_dest, Variant(*p_pv4a)); +} + void godotsharp_variant_new_packed_color_array(godot_variant *r_dest, const PackedColorArray *p_pca) { memnew_placement(r_dest, Variant(*p_pca)); } @@ -886,6 +900,13 @@ godot_packed_array godotsharp_variant_as_packed_vector3_array(const Variant *p_s return raw_dest; } +godot_packed_array godotsharp_variant_as_packed_vector4_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedVector4Array *dest = (PackedVector4Array *)&raw_dest; + memnew_placement(dest, PackedVector4Array(p_self->operator PackedVector4Array())); + return raw_dest; +} + godot_packed_array godotsharp_variant_as_packed_color_array(const Variant *p_self) { godot_packed_array raw_dest; PackedColorArray *dest = (PackedColorArray *)&raw_dest; @@ -974,6 +995,10 @@ void godotsharp_packed_vector3_array_destroy(PackedVector3Array *p_self) { p_self->~PackedVector3Array(); } +void godotsharp_packed_vector4_array_destroy(PackedVector4Array *p_self) { + p_self->~PackedVector4Array(); +} + void godotsharp_packed_color_array_destroy(PackedColorArray *p_self) { p_self->~PackedColorArray(); } @@ -1456,6 +1481,7 @@ static const void *unmanaged_callbacks[]{ (void *)godotsharp_packed_float64_array_new_mem_copy, (void *)godotsharp_packed_vector2_array_new_mem_copy, (void *)godotsharp_packed_vector3_array_new_mem_copy, + (void *)godotsharp_packed_vector4_array_new_mem_copy, (void *)godotsharp_packed_color_array_new_mem_copy, (void *)godotsharp_packed_string_array_add, (void *)godotsharp_callable_new_with_delegate, @@ -1484,6 +1510,7 @@ static const void *unmanaged_callbacks[]{ (void *)godotsharp_variant_new_packed_string_array, (void *)godotsharp_variant_new_packed_vector2_array, (void *)godotsharp_variant_new_packed_vector3_array, + (void *)godotsharp_variant_new_packed_vector4_array, (void *)godotsharp_variant_new_packed_color_array, (void *)godotsharp_variant_as_bool, (void *)godotsharp_variant_as_int, @@ -1520,6 +1547,7 @@ static const void *unmanaged_callbacks[]{ (void *)godotsharp_variant_as_packed_string_array, (void *)godotsharp_variant_as_packed_vector2_array, (void *)godotsharp_variant_as_packed_vector3_array, + (void *)godotsharp_variant_as_packed_vector4_array, (void *)godotsharp_variant_as_packed_color_array, (void *)godotsharp_variant_equals, (void *)godotsharp_string_new_with_utf16_chars, @@ -1538,6 +1566,7 @@ static const void *unmanaged_callbacks[]{ (void *)godotsharp_packed_string_array_destroy, (void *)godotsharp_packed_vector2_array_destroy, (void *)godotsharp_packed_vector3_array_destroy, + (void *)godotsharp_packed_vector4_array_destroy, (void *)godotsharp_packed_color_array_destroy, (void *)godotsharp_variant_destroy, (void *)godotsharp_string_destroy, diff --git a/modules/multiplayer/editor/editor_network_profiler.cpp b/modules/multiplayer/editor/editor_network_profiler.cpp index a45e5ffdc0..75941207c7 100644 --- a/modules/multiplayer/editor/editor_network_profiler.cpp +++ b/modules/multiplayer/editor/editor_network_profiler.cpp @@ -260,12 +260,12 @@ EditorNetworkProfiler::EditorNetworkProfiler() { activate = memnew(Button); activate->set_toggle_mode(true); activate->set_text(TTR("Start")); - activate->connect("pressed", callable_mp(this, &EditorNetworkProfiler::_activate_pressed)); + activate->connect(SceneStringName(pressed), callable_mp(this, &EditorNetworkProfiler::_activate_pressed)); hb->add_child(activate); clear_button = memnew(Button); clear_button->set_text(TTR("Clear")); - clear_button->connect("pressed", callable_mp(this, &EditorNetworkProfiler::_clear_pressed)); + clear_button->connect(SceneStringName(pressed), callable_mp(this, &EditorNetworkProfiler::_clear_pressed)); hb->add_child(clear_button); hb->add_spacer(); diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp index 29ebc38edf..a496f5dfa2 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp @@ -116,7 +116,7 @@ MultiplayerEditorPlugin::MultiplayerEditorPlugin() { repl_editor = memnew(ReplicationEditor); button = EditorNode::get_bottom_panel()->add_item(TTR("Replication"), repl_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_replication_bottom_panel", TTR("Toggle Replication Bottom Panel"))); button->hide(); - repl_editor->get_pin()->connect("pressed", callable_mp(this, &MultiplayerEditorPlugin::_pinned)); + repl_editor->get_pin()->connect(SceneStringName(pressed), callable_mp(this, &MultiplayerEditorPlugin::_pinned)); debugger.instantiate(); debugger->connect("open_request", callable_mp(this, &MultiplayerEditorPlugin::_open_request)); } diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.h b/modules/multiplayer/editor/multiplayer_editor_plugin.h index a22144cdcf..e8ade539a7 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.h +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.h @@ -31,8 +31,8 @@ #ifndef MULTIPLAYER_EDITOR_PLUGIN_H #define MULTIPLAYER_EDITOR_PLUGIN_H -#include "editor/editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" +#include "editor/plugins/editor_plugin.h" class EditorNetworkProfiler; class MultiplayerEditorDebugger : public EditorDebuggerPlugin { diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index 8453a41473..3cc0a5ae53 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -81,7 +81,7 @@ void ReplicationEditor::_pick_node_select_recursive(TreeItem *p_item, const Stri NodePath np = p_item->get_metadata(0); Node *node = get_node(np); - if (!p_filter.is_empty() && ((String)node->get_name()).findn(p_filter) != -1) { + if (!p_filter.is_empty() && ((String)node->get_name()).containsn(p_filter)) { p_select_candidates.push_back(node); } @@ -234,7 +234,8 @@ ReplicationEditor::ReplicationEditor() { Variant::PACKED_STRING_ARRAY, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR3_ARRAY, - Variant::PACKED_COLOR_ARRAY + Variant::PACKED_COLOR_ARRAY, + Variant::PACKED_VECTOR4_ARRAY, }; prop_selector->set_type_filter(types); prop_selector->connect("selected", callable_mp(this, &ReplicationEditor::_pick_node_property_selected)); @@ -243,7 +244,7 @@ ReplicationEditor::ReplicationEditor() { vb->add_child(hb); add_pick_button = memnew(Button); - add_pick_button->connect("pressed", callable_mp(this, &ReplicationEditor::_pick_new_property)); + add_pick_button->connect(SceneStringName(pressed), callable_mp(this, &ReplicationEditor::_pick_new_property)); add_pick_button->set_text(TTR("Add property to sync...")); hb->add_child(add_pick_button); @@ -259,7 +260,7 @@ ReplicationEditor::ReplicationEditor() { hb->add_child(np_line_edit); add_from_path_button = memnew(Button); - add_from_path_button->connect("pressed", callable_mp(this, &ReplicationEditor::_add_pressed)); + add_from_path_button->connect(SceneStringName(pressed), callable_mp(this, &ReplicationEditor::_add_pressed)); add_from_path_button->set_text(TTR("Add from path")); hb->add_child(add_from_path_button); diff --git a/modules/multiplayer/editor/replication_editor.h b/modules/multiplayer/editor/replication_editor.h index 80c1892ec3..8f11774292 100644 --- a/modules/multiplayer/editor/replication_editor.h +++ b/modules/multiplayer/editor/replication_editor.h @@ -33,7 +33,7 @@ #include "../scene_replication_config.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" #include "scene/gui/box_container.h" class ConfirmationDialog; diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp index 6c0669b2f3..2408d7231b 100644 --- a/modules/multiplayer/multiplayer_spawner.cpp +++ b/modules/multiplayer/multiplayer_spawner.cpp @@ -33,7 +33,6 @@ #include "core/io/marshalls.h" #include "scene/main/multiplayer_api.h" #include "scene/main/window.h" -#include "scene/scene_string_names.h" #ifdef TOOLS_ENABLED /* This is editor only */ @@ -216,7 +215,7 @@ void MultiplayerSpawner::_notification(int p_what) { for (const KeyValue<ObjectID, SpawnInfo> &E : tracked_nodes) { Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E.key)); ERR_CONTINUE(!node); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit)); + node->disconnect(SceneStringName(tree_exiting), callable_mp(this, &MultiplayerSpawner::_node_exit)); get_multiplayer()->object_configuration_remove(node, this); } tracked_nodes.clear(); @@ -258,7 +257,7 @@ void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_s ObjectID oid = p_node->get_instance_id(); if (!tracked_nodes.has(oid)) { tracked_nodes[oid] = SpawnInfo(p_argument.duplicate(true), p_scene_id); - p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT); + p_node->connect(SceneStringName(tree_exiting), callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT); _spawn_notify(p_node->get_instance_id()); } } diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp index c2ce500af8..ca3fa43207 100644 --- a/modules/multiplayer/multiplayer_synchronizer.cpp +++ b/modules/multiplayer/multiplayer_synchronizer.cpp @@ -343,7 +343,7 @@ void MultiplayerSynchronizer::update_visibility(int p_for_peer) { #endif Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; if (node && get_multiplayer()->has_multiplayer_peer() && is_multiplayer_authority()) { - emit_signal(SNAME("visibility_changed"), p_for_peer); + emit_signal(SceneStringName(visibility_changed), p_for_peer); } } diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp index c08ccbe4cc..2ea9ce8819 100644 --- a/modules/multiplayer/scene_cache_interface.cpp +++ b/modules/multiplayer/scene_cache_interface.cpp @@ -35,14 +35,13 @@ #include "core/io/marshalls.h" #include "scene/main/node.h" #include "scene/main/window.h" -#include "scene/scene_string_names.h" SceneCacheInterface::NodeCache &SceneCacheInterface::_track(Node *p_node) { const ObjectID oid = p_node->get_instance_id(); NodeCache *nc = nodes_cache.getptr(oid); if (!nc) { nodes_cache[oid] = NodeCache(); - p_node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneCacheInterface::_remove_node_cache).bind(oid), Object::CONNECT_ONE_SHOT); + p_node->connect(SceneStringName(tree_exited), callable_mp(this, &SceneCacheInterface::_remove_node_cache).bind(oid), Object::CONNECT_ONE_SHOT); } return nodes_cache[oid]; } @@ -286,7 +285,7 @@ void SceneCacheInterface::clear() { for (KeyValue<ObjectID, NodeCache> &E : nodes_cache) { Object *obj = ObjectDB::get_instance(E.key); ERR_CONTINUE(!obj); - obj->disconnect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneCacheInterface::_remove_node_cache)); + obj->disconnect(SceneStringName(tree_exited), callable_mp(this, &SceneCacheInterface::_remove_node_cache)); } peers_info.clear(); nodes_cache.clear(); diff --git a/modules/multiplayer/scene_replication_config.cpp b/modules/multiplayer/scene_replication_config.cpp index 733540a0e4..ab92f7d90f 100644 --- a/modules/multiplayer/scene_replication_config.cpp +++ b/modules/multiplayer/scene_replication_config.cpp @@ -48,7 +48,7 @@ bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_val return true; } ERR_FAIL_INDEX_V(idx, properties.size(), false); - ReplicationProperty &prop = properties[idx]; + const ReplicationProperty &prop = properties.get(idx); if (what == "replication_mode") { ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false); ReplicationMode mode = (ReplicationMode)p_value.operator int(); @@ -80,7 +80,7 @@ bool SceneReplicationConfig::_get(const StringName &p_name, Variant &r_ret) cons int idx = prop_name.get_slicec('/', 1).to_int(); String what = prop_name.get_slicec('/', 2); ERR_FAIL_INDEX_V(idx, properties.size(), false); - const ReplicationProperty &prop = properties[idx]; + const ReplicationProperty &prop = properties.get(idx); if (what == "path") { r_ret = prop.name; return true; @@ -147,8 +147,8 @@ void SceneReplicationConfig::remove_property(const NodePath &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) { + for (const ReplicationProperty &property : properties) { + if (property.name == p_path) { return true; } } @@ -156,8 +156,9 @@ bool SceneReplicationConfig::has_property(const NodePath &p_path) const { } int SceneReplicationConfig::property_get_index(const NodePath &p_path) const { - for (int i = 0; i < properties.size(); i++) { - if (properties[i].name == p_path) { + int i = 0; + for (List<ReplicationProperty>::ConstIterator itr = properties.begin(); itr != properties.end(); ++itr, ++i) { + if (itr->name == p_path) { return i; } } diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index bb32eed1a9..edc66c876c 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -35,7 +35,6 @@ #include "core/debugger/engine_debugger.h" #include "core/io/marshalls.h" #include "scene/main/node.h" -#include "scene/scene_string_names.h" #define MAKE_ROOM(m_amount) \ if (packet_cache.size() < m_amount) \ @@ -57,7 +56,7 @@ SceneReplicationInterface::TrackedNode &SceneReplicationInterface::_track(const if (!tracked_nodes.has(p_id)) { tracked_nodes[p_id] = TrackedNode(p_id); Node *node = get_id_as<Node>(p_id); - node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationInterface::_untrack).bind(p_id), Node::CONNECT_ONE_SHOT); + node->connect(SceneStringName(tree_exited), callable_mp(this, &SceneReplicationInterface::_untrack).bind(p_id), Node::CONNECT_ONE_SHOT); } return tracked_nodes[p_id]; } @@ -135,8 +134,8 @@ void SceneReplicationInterface::on_network_process() { for (const ObjectID &oid : spawn_queue) { Node *node = get_id_as<Node>(oid); ERR_CONTINUE(!node); - if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready))) { - node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready)); + if (node->is_connected(SceneStringName(ready), callable_mp(this, &SceneReplicationInterface::_node_ready))) { + node->disconnect(SceneStringName(ready), callable_mp(this, &SceneReplicationInterface::_node_ready)); } } spawn_queue.clear(); @@ -168,7 +167,7 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) { ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); tobj.spawner = spawner->get_instance_id(); spawn_queue.insert(oid); - node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready).bind(oid), Node::CONNECT_ONE_SHOT); + node->connect(SceneStringName(ready), callable_mp(this, &SceneReplicationInterface::_node_ready).bind(oid), Node::CONNECT_ONE_SHOT); return OK; } @@ -236,14 +235,14 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c sync_nodes.insert(sid); // Update visibility. - sync->connect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed).bind(sync->get_instance_id())); + sync->connect(SceneStringName(visibility_changed), callable_mp(this, &SceneReplicationInterface::_visibility_changed).bind(sync->get_instance_id())); _update_sync_visibility(0, sync); if (pending_spawn == p_obj->get_instance_id() && sync->get_multiplayer_authority() == pending_spawn_remote) { // Try to apply synchronizer Net ID ERR_FAIL_COND_V_MSG(pending_sync_net_ids.is_empty(), ERR_INVALID_DATA, vformat("The MultiplayerSynchronizer at path \"%s\" is unable to process the pending spawn since it has no network ID. This might happen when changing the multiplayer authority during the \"_ready\" callback. Make sure to only change the authority of multiplayer synchronizers during \"_enter_tree\" or the \"_spawn_custom\" callback of their multiplayer spawner.", sync->get_path())); ERR_FAIL_COND_V(!peers_info.has(pending_spawn_remote), ERR_INVALID_DATA); - uint32_t net_id = pending_sync_net_ids[0]; + uint32_t net_id = pending_sync_net_ids.front()->get(); pending_sync_net_ids.pop_front(); peers_info[pending_spawn_remote].recv_sync_ids[net_id] = sync->get_instance_id(); sync->set_net_id(net_id); @@ -273,7 +272,7 @@ Error SceneReplicationInterface::on_replication_stop(Object *p_obj, Variant p_co ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); ERR_FAIL_NULL_V(sync, ERR_INVALID_PARAMETER); - sync->disconnect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed)); + sync->disconnect(SceneStringName(visibility_changed), callable_mp(this, &SceneReplicationInterface::_visibility_changed)); // Untrack synchronizer. const ObjectID oid = node->get_instance_id(); const ObjectID sid = sync->get_instance_id(); diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp index 15a645816c..2198158f9c 100644 --- a/modules/navigation/2d/nav_mesh_generator_2d.cpp +++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp @@ -243,7 +243,7 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_ generator_parse_multimeshinstance2d_node(p_navigation_mesh, p_source_geometry_data, p_node); generator_parse_polygon2d_node(p_navigation_mesh, p_source_geometry_data, p_node); generator_parse_staticbody2d_node(p_navigation_mesh, p_source_geometry_data, p_node); - generator_parse_tilemap_node(p_navigation_mesh, p_source_geometry_data, p_node); + generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, p_node); generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node); generator_rid_rwlock.read_lock(); @@ -259,6 +259,14 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_ for (int i = 0; i < p_node->get_child_count(); i++) { generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children); } + } else if (Object::cast_to<TileMap>(p_node)) { + // Special case for TileMap, so that internal layer get parsed even if p_recurse_children is false. + for (int i = 0; i < p_node->get_child_count(); i++) { + TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node->get_child(i)); + if (tile_map_layer->get_index_in_tile_map() >= 0) { + generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, tile_map_layer); + } + } } } @@ -580,141 +588,102 @@ void NavMeshGenerator2D::generator_parse_staticbody2d_node(const Ref<NavigationP } } -void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) { - TileMap *tilemap = Object::cast_to<TileMap>(p_node); - - if (tilemap == nullptr) { +void NavMeshGenerator2D::generator_parse_tile_map_layer_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) { + TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node); + if (tile_map_layer == nullptr) { return; } - NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type(); - uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask(); - - if (tilemap->get_layers_count() <= 0) { - return; - } - - Ref<TileSet> tile_set = tilemap->get_tileset(); + Ref<TileSet> tile_set = tile_map_layer->get_tile_set(); if (!tile_set.is_valid()) { return; } int physics_layers_count = tile_set->get_physics_layers_count(); int navigation_layers_count = tile_set->get_navigation_layers_count(); - if (physics_layers_count <= 0 && navigation_layers_count <= 0) { return; } - HashSet<Vector2i> cells_with_navigation_polygon; - HashSet<Vector2i> cells_with_collision_polygon; + NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type(); + uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask(); + + const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tile_map_layer->get_global_transform(); - const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform(); + TypedArray<Vector2i> used_cells = tile_map_layer->get_used_cells(); + for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) { + const Vector2i &cell = used_cells[used_cell_index]; -#ifdef DEBUG_ENABLED - int error_print_counter = 0; - int error_print_max = 10; -#endif // DEBUG_ENABLED + const TileData *tile_data = tile_map_layer->get_cell_tile_data(cell); + if (tile_data == nullptr) { + continue; + } - for (int tilemap_layer = 0; tilemap_layer < tilemap->get_layers_count(); tilemap_layer++) { - TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer); + // Transform flags. + const int alternative_id = tile_map_layer->get_cell_alternative_tile(cell); + bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + + Transform2D tile_transform; + tile_transform.set_origin(tile_map_layer->map_to_local(cell)); + + const Transform2D tile_transform_offset = tilemap_xform * tile_transform; + + // Parse traversable polygons. + for (int navigation_layer = 0; navigation_layer < navigation_layers_count; navigation_layer++) { + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer, flip_h, flip_v, transpose); + if (navigation_polygon.is_valid()) { + for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) { + const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index); + if (navigation_polygon_outline.is_empty()) { + continue; + } - for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) { - const Vector2i &cell = used_cells[used_cell_index]; + Vector<Vector2> traversable_outline; + traversable_outline.resize(navigation_polygon_outline.size()); - const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false); - if (tile_data == nullptr) { - continue; - } + const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr(); + Vector2 *traversable_outline_ptrw = traversable_outline.ptrw(); - // Transform flags. - const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false); - bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE); - - Transform2D tile_transform; - tile_transform.set_origin(tilemap->map_to_local(cell)); - - const Transform2D tile_transform_offset = tilemap_xform * tile_transform; - - if (navigation_layers_count > 0) { - Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose); - if (navigation_polygon.is_valid()) { - if (cells_with_navigation_polygon.has(cell)) { -#ifdef DEBUG_ENABLED - error_print_counter++; - if (error_print_counter <= error_print_max) { - WARN_PRINT(vformat("TileMap navigation mesh baking error. The TileMap cell key Vector2i(%s, %s) has navigation mesh from 2 or more different TileMap layers assigned. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y)); - } -#endif // DEBUG_ENABLED - } else { - cells_with_navigation_polygon.insert(cell); - - for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) { - const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index); - if (navigation_polygon_outline.size() == 0) { - continue; - } - - Vector<Vector2> traversable_outline; - traversable_outline.resize(navigation_polygon_outline.size()); - - const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr(); - Vector2 *traversable_outline_ptrw = traversable_outline.ptrw(); - - for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) { - traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]); - } - - p_source_geometry_data->_add_traversable_outline(traversable_outline); - } + for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) { + traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]); } + + p_source_geometry_data->_add_traversable_outline(traversable_outline); } } + } - if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) { - if (cells_with_collision_polygon.has(cell)) { -#ifdef DEBUG_ENABLED - error_print_counter++; - if (error_print_counter <= error_print_max) { - WARN_PRINT(vformat("TileMap navigation mesh baking error. The cell key Vector2i(%s, %s) has collision polygons from 2 or more different TileMap layers assigned that all match the parsed collision mask. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y)); + // Parse obstacles. + for (int physics_layer = 0; physics_layer < physics_layers_count; physics_layer++) { + if ((parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && + (tile_set->get_physics_layer_collision_layer(physics_layer) & parsed_collision_mask)) { + for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(physics_layer); collision_polygon_index++) { + PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(physics_layer, collision_polygon_index); + if (collision_polygon_points.is_empty()) { + continue; } -#endif // DEBUG_ENABLED - } else { - cells_with_collision_polygon.insert(cell); - - for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) { - PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index); - if (collision_polygon_points.size() == 0) { - continue; - } - - if (flip_h || flip_v || transpose) { - collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose); - } - Vector<Vector2> obstruction_outline; - obstruction_outline.resize(collision_polygon_points.size()); + if (flip_h || flip_v || transpose) { + collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose); + } - const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr(); - Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw(); + Vector<Vector2> obstruction_outline; + obstruction_outline.resize(collision_polygon_points.size()); - for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) { - obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]); - } + const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr(); + Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw(); - p_source_geometry_data->_add_obstruction_outline(obstruction_outline); + for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) { + obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]); } + + p_source_geometry_data->_add_obstruction_outline(obstruction_outline); } } } } -#ifdef DEBUG_ENABLED - if (error_print_counter > error_print_max) { - ERR_PRINT(vformat("TileMap navigation mesh baking error. A total of %s cells with navigation or collision polygons from 2 or more different TileMap layers overlap. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", error_print_counter)); - } -#endif // DEBUG_ENABLED } void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) { diff --git a/modules/navigation/2d/nav_mesh_generator_2d.h b/modules/navigation/2d/nav_mesh_generator_2d.h index 235a84d548..d5f9694242 100644 --- a/modules/navigation/2d/nav_mesh_generator_2d.h +++ b/modules/navigation/2d/nav_mesh_generator_2d.h @@ -89,7 +89,7 @@ class NavMeshGenerator2D : public Object { static void generator_parse_multimeshinstance2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node); static void generator_parse_polygon2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node); static void generator_parse_staticbody2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node); - static void generator_parse_tilemap_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node); + static void generator_parse_tile_map_layer_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node); static void generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node); static bool generator_emit_callback(const Callable &p_callback); diff --git a/modules/navigation/3d/godot_navigation_server_3d.cpp b/modules/navigation/3d/godot_navigation_server_3d.cpp index 61a128e004..6cbfd93088 100644 --- a/modules/navigation/3d/godot_navigation_server_3d.cpp +++ b/modules/navigation/3d/godot_navigation_server_3d.cpp @@ -136,7 +136,7 @@ bool GodotNavigationServer3D::map_is_active(RID p_map) const { NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL_V(map, false); - return active_maps.find(map) >= 0; + return active_maps.has(map); } COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) { diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp index d7bf1cdd38..d07d3cdff5 100644 --- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp @@ -138,14 +138,14 @@ NavigationMeshEditor::NavigationMeshEditor() { button_bake->set_toggle_mode(true); button_bake->set_text(TTR("Bake NavigationMesh")); button_bake->set_tooltip_text(TTR("Bakes the NavigationMesh by first parsing the scene for source geometry and then creating the navigation mesh vertices and polygons.")); - button_bake->connect("pressed", callable_mp(this, &NavigationMeshEditor::_bake_pressed)); + button_bake->connect(SceneStringName(pressed), callable_mp(this, &NavigationMeshEditor::_bake_pressed)); button_reset = memnew(Button); button_reset->set_theme_type_variation("FlatButton"); bake_hbox->add_child(button_reset); button_reset->set_text(TTR("Clear NavigationMesh")); button_reset->set_tooltip_text(TTR("Clears the internal NavigationMesh vertices and polygons.")); - button_reset->connect("pressed", callable_mp(this, &NavigationMeshEditor::_clear_pressed)); + button_reset->connect(SceneStringName(pressed), callable_mp(this, &NavigationMeshEditor::_clear_pressed)); bake_info = memnew(Label); bake_hbox->add_child(bake_info); diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.h b/modules/navigation/editor/navigation_mesh_editor_plugin.h index b73d8d2e69..6114c62ebf 100644 --- a/modules/navigation/editor/navigation_mesh_editor_plugin.h +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.h @@ -33,7 +33,7 @@ #ifdef TOOLS_ENABLED -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" class AcceptDialog; class Button; diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index a3f2ee2e61..dfbc92a919 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -734,7 +734,7 @@ void NavMap::remove_link(NavLink *p_link) { } bool NavMap::has_agent(NavAgent *agent) const { - return (agents.find(agent) >= 0); + return agents.has(agent); } void NavMap::add_agent(NavAgent *agent) { @@ -754,7 +754,7 @@ void NavMap::remove_agent(NavAgent *agent) { } bool NavMap::has_obstacle(NavObstacle *obstacle) const { - return (obstacles.find(obstacle) >= 0); + return obstacles.has(obstacle); } void NavMap::add_obstacle(NavObstacle *obstacle) { diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp index 917fa0cd15..200f31cca1 100644 --- a/modules/noise/editor/noise_editor_plugin.cpp +++ b/modules/noise/editor/noise_editor_plugin.cpp @@ -67,7 +67,7 @@ public: _3d_space_switch->set_toggle_mode(true); _3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH); _3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH); - _3d_space_switch->connect("pressed", callable_mp(this, &NoisePreview::_on_3d_button_pressed)); + _3d_space_switch->connect(SceneStringName(pressed), callable_mp(this, &NoisePreview::_on_3d_button_pressed)); add_child(_3d_space_switch); } diff --git a/modules/noise/editor/noise_editor_plugin.h b/modules/noise/editor/noise_editor_plugin.h index 948ccba29b..aa94cf4d23 100644 --- a/modules/noise/editor/noise_editor_plugin.h +++ b/modules/noise/editor/noise_editor_plugin.h @@ -33,7 +33,7 @@ #ifdef TOOLS_ENABLED -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" class NoiseEditorPlugin : public EditorPlugin { GDCLASS(NoiseEditorPlugin, EditorPlugin) diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp index 0443fec4a0..0960b2ad36 100644 --- a/modules/noise/noise_texture_2d.cpp +++ b/modules/noise/noise_texture_2d.cpp @@ -119,6 +119,7 @@ void NoiseTexture2D::_set_texture_image(const Ref<Image> &p_image) { } else { texture = RS::get_singleton()->texture_2d_create(p_image); } + RS::get_singleton()->texture_set_path(texture, get_path()); } emit_changed(); } diff --git a/modules/noise/register_types.cpp b/modules/noise/register_types.cpp index 29eb42522f..363b7bdc31 100644 --- a/modules/noise/register_types.cpp +++ b/modules/noise/register_types.cpp @@ -40,7 +40,7 @@ #endif #ifdef TOOLS_ENABLED -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" #endif void initialize_noise_module(ModuleInitializationLevel p_level) { diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index bbcb63a7e6..5430a41d6d 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -59,7 +59,7 @@ void OpenXRActionMap::set_action_sets(Array p_action_sets) { for (int i = 0; i < p_action_sets.size(); i++) { Ref<OpenXRActionSet> action_set = p_action_sets[i]; - if (action_set.is_valid() && action_sets.find(action_set) == -1) { + if (action_set.is_valid() && !action_sets.has(action_set)) { action_sets.push_back(action_set); } } @@ -93,7 +93,7 @@ Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const { void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) { ERR_FAIL_COND(p_action_set.is_null()); - if (action_sets.find(p_action_set) == -1) { + if (!action_sets.has(p_action_set)) { action_sets.push_back(p_action_set); emit_changed(); } @@ -112,7 +112,7 @@ void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) { for (int i = 0; i < p_interaction_profiles.size(); i++) { Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profiles[i]; - if (interaction_profile.is_valid() && interaction_profiles.find(interaction_profile) == -1) { + if (interaction_profile.is_valid() && !interaction_profiles.has(interaction_profile)) { interaction_profiles.push_back(interaction_profile); } } @@ -146,7 +146,7 @@ Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) { ERR_FAIL_COND(p_interaction_profile.is_null()); - if (interaction_profiles.find(p_interaction_profile) == -1) { + if (!interaction_profiles.has(p_interaction_profile)) { interaction_profiles.push_back(p_interaction_profile); emit_changed(); } @@ -167,11 +167,11 @@ void OpenXRActionMap::create_default_action_sets() { // we still want it to be part of our action map as we may deploy the same game to platforms that do and don't support it. // - the same applies for interaction profiles that are only supported if the relevant extension is supported. - // Create our Godot action set + // Create our Godot action set. Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set"); add_action_set(action_set); - // Create our actions + // Create our actions. Ref<OpenXRAction> trigger = action_set->add_new_action("trigger", "Trigger", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> trigger_click = action_set->add_new_action("trigger_click", "Trigger click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); @@ -193,7 +193,7 @@ void OpenXRActionMap::create_default_action_sets() { Ref<OpenXRAction> default_pose = action_set->add_new_action("default_pose", "Default pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left," "/user/hand/right," - // "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one + // "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one. "/user/vive_tracker_htcx/role/left_foot," "/user/vive_tracker_htcx/role/right_foot," "/user/vive_tracker_htcx/role/left_shoulder," @@ -213,7 +213,7 @@ void OpenXRActionMap::create_default_action_sets() { Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC, "/user/hand/left," "/user/hand/right," - // "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one + // "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one. "/user/vive_tracker_htcx/role/left_foot," "/user/vive_tracker_htcx/role/right_foot," "/user/vive_tracker_htcx/role/left_shoulder," @@ -227,7 +227,7 @@ void OpenXRActionMap::create_default_action_sets() { "/user/vive_tracker_htcx/role/camera," "/user/vive_tracker_htcx/role/keyboard"); - // Create our interaction profiles + // Create our interaction profiles. Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); @@ -235,11 +235,11 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click"); - // generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs + // generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs. profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our Vive controller profile + // Create our Vive controller profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); @@ -247,64 +247,64 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); - // wmr controller has no a/b/x/y buttons + // wmr controller has no a/b/x/y buttons. profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); - profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float. profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); - // primary on our vive controller is our trackpad + // primary on our vive controller is our trackpad. profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); - // vive controllers have no secondary input + // vive controllers have no secondary input. profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our WMR controller profile + // Create our WMR controller profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); - // wmr controllers have no select button we can use + // wmr controllers have no select button we can use. profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); - // wmr controller has no a/b/x/y buttons + // wmr controller has no a/b/x/y buttons. profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will convert float to bool - profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will convert float to bool. + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float. profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); - // primary on our wmr controller is our thumbstick, no touch + // primary on our wmr controller is our thumbstick, no touch. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); - // secondary on our wmr controller is our trackpad + // secondary on our wmr controller is our trackpad. profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our Meta touch controller profile + // Create our Meta touch controller profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); - // touch controllers have no select button we can use - profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + // touch controllers have no select button we can use. + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available. + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand. profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch"); - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand. profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch"); profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean. profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); - profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean. profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - // primary on our touch controller is our thumbstick + // primary on our touch controller is our thumbstick. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); - // touch controller has no secondary input + // touch controller has no secondary input. profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); @@ -314,73 +314,73 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); - profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); // system click may not be available + profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); // system click may not be available. profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand. profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch"); - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand. profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch"); profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean. profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); - profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean. profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - // primary on our pico controller is our thumbstick + // primary on our pico controller is our thumbstick. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); - // pico controller has no secondary input + // pico controller has no secondary input. profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our Valve index controller profile + // Create our Valve index controller profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); - // index controllers have no select button we can use + // index controllers have no select button we can use. profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); - profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers + profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers. profile->add_new_binding(ax_touch, "/user/hand/left/input/a/touch,/user/hand/right/input/a/touch"); - profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers + profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers. profile->add_new_binding(by_touch, "/user/hand/left/input/b/touch,/user/hand/right/input/b/touch"); profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion - profile->add_new_binding(grip_force, "/user/hand/left/input/squeeze/force,/user/hand/right/input/squeeze/force"); // grip force seems to be unique to the Valve Index - // primary on our index controller is our thumbstick + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion. + profile->add_new_binding(grip_force, "/user/hand/left/input/squeeze/force,/user/hand/right/input/squeeze/force"); // grip force seems to be unique to the Valve Index. + // primary on our index controller is our thumbstick. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); - // secondary on our index controller is our trackpad + // secondary on our index controller is our trackpad. profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/force,/user/hand/right/input/trackpad/force"); // not sure if this will work but doesn't seem to support click... profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our HP MR controller profile + // Create our HP MR controller profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); - // hpmr controllers have no select button we can use + // hpmr controllers have no select button we can use. profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); - // hpmr controllers only register click, not touch, on our a/b/x/y buttons - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + // hpmr controllers only register click, not touch, on our a/b/x/y buttons. + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand. + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand. profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - // primary on our hpmr controller is our thumbstick + // primary on our hpmr controller is our thumbstick. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); - // No secondary on our hpmr controller + // No secondary on our hpmr controller. profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); @@ -391,72 +391,72 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); - // Odyssey controllers have no select button we can use + // Odyssey controllers have no select button we can use. profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); - // Odyssey controller has no a/b/x/y buttons + // Odyssey controller has no a/b/x/y buttons. profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); - // primary on our Odyssey controller is our thumbstick, no touch + // primary on our Odyssey controller is our thumbstick, no touch. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); - // secondary on our Odyssey controller is our trackpad + // secondary on our Odyssey controller is our trackpad. profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our Vive Cosmos controller + // Create our Vive Cosmos controller. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); - profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select. + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand. + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand. profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); - // primary on our Cosmos controller is our thumbstick + // primary on our Cosmos controller is our thumbstick. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); - // No secondary on our cosmos controller + // No secondary on our cosmos controller. profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our Vive Focus 3 controller + // Create our Vive Focus 3 controller. // Note, Vive Focus 3 currently is not yet supported as a stand alone device - // however HTC currently has a beta OpenXR runtime in testing we may support in the near future + // however HTC currently has a beta OpenXR runtime in testing we may support in the near future. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); - profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select. + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand. + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand. profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); - // primary on our Focus 3 controller is our thumbstick + // primary on our Focus 3 controller is our thumbstick. profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); - // We only have a thumb rest + // We only have a thumb rest. profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our Huawei controller + // Create our Huawei controller. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); @@ -465,17 +465,17 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click"); profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); - // primary on our Huawei controller is our trackpad + // primary on our Huawei controller is our trackpad. profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our HTC Vive tracker profile + // Create our HTC Vive tracker profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_tracker_htcx"); profile->add_new_binding(default_pose, - // "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose," <-- getting errors on this one + // "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose," <-- getting errors on this one. "/user/vive_tracker_htcx/role/left_foot/input/grip/pose," "/user/vive_tracker_htcx/role/right_foot/input/grip/pose," "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose," @@ -489,7 +489,7 @@ void OpenXRActionMap::create_default_action_sets() { "/user/vive_tracker_htcx/role/camera/input/grip/pose," "/user/vive_tracker_htcx/role/keyboard/input/grip/pose"); profile->add_new_binding(haptic, - // "/user/vive_tracker_htcx/role/handheld_object/output/haptic," <-- getting errors on this one + // "/user/vive_tracker_htcx/role/handheld_object/output/haptic," <-- getting errors on this one. "/user/vive_tracker_htcx/role/left_foot/output/haptic," "/user/vive_tracker_htcx/role/right_foot/output/haptic," "/user/vive_tracker_htcx/role/left_shoulder/output/haptic," @@ -504,10 +504,30 @@ void OpenXRActionMap::create_default_action_sets() { "/user/vive_tracker_htcx/role/keyboard/output/haptic"); add_interaction_profile(profile); - // Create our eye gaze interaction profile + // Create our eye gaze interaction profile. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/ext/eye_gaze_interaction"); profile->add_new_binding(default_pose, "/user/eyes_ext/input/gaze_ext/pose"); add_interaction_profile(profile); + + // Create our hand interaction profile. + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/ext/hand_interaction_ext"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); + + // Use pinch as primary. + profile->add_new_binding(primary, "/user/hand/left/input/pinch_ext/value,/user/hand/right/input/pinch_ext/value"); + profile->add_new_binding(primary_click, "/user/hand/left/input/pinch_ext/ready_ext,/user/hand/right/input/pinch_ext/ready_ext"); + + // Use activation as secondary. + profile->add_new_binding(secondary, "/user/hand/left/input/aim_activate_ext/value,/user/hand/right/input/aim_activate_ext/value"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/aim_activate_ext/ready_ext,/user/hand/right/input/aim_activate_ext/ready_ext"); + + // We link grasp to our grip. + profile->add_new_binding(grip, "/user/hand/left/input/grasp_ext/value,/user/hand/right/input/grasp_ext/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/grasp_ext/ready_ext,/user/hand/right/input/grasp_ext/ready_ext"); + add_interaction_profile(profile); } void OpenXRActionMap::create_editor_action_sets() { diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp index 4855f9e4b7..d583af2b2f 100644 --- a/modules/openxr/action_map/openxr_action_set.cpp +++ b/modules/openxr/action_map/openxr_action_set.cpp @@ -124,7 +124,7 @@ Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const { void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) { ERR_FAIL_COND(p_action.is_null()); - if (actions.find(p_action) == -1) { + if (!actions.has(p_action)) { if (p_action->action_set && p_action->action_set != this) { // action should only relate to our action set p_action->action_set->remove_action(p_action); diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp index 65ee652732..2579697d05 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -172,7 +172,7 @@ Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref< void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) { ERR_FAIL_COND(p_binding.is_null()); - if (bindings.find(p_binding) == -1) { + if (!bindings.has(p_binding)) { ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile"); bindings.push_back(p_binding); diff --git a/modules/openxr/doc_classes/OpenXRAPIExtension.xml b/modules/openxr/doc_classes/OpenXRAPIExtension.xml index f737f3b642..4419d24dd3 100644 --- a/modules/openxr/doc_classes/OpenXRAPIExtension.xml +++ b/modules/openxr/doc_classes/OpenXRAPIExtension.xml @@ -54,7 +54,7 @@ <method name="get_next_frame_time"> <return type="int" /> <description> - Returns the timing for the next frame. + Returns the predicted display timing for the next frame. </description> </method> <method name="get_play_space"> @@ -63,6 +63,12 @@ Returns the play space, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html]XrSpace[/url] cast to an integer. </description> </method> + <method name="get_predicted_display_time"> + <return type="int" /> + <description> + Returns the predicted display timing for the current frame. + </description> + </method> <method name="get_session"> <return type="int" /> <description> diff --git a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml index b9c69075e1..6f4ac00f3e 100644 --- a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml +++ b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml @@ -32,6 +32,10 @@ Enables the blending the layer using its alpha channel. Can be combined with [member Viewport.transparent_bg] to give the layer a transparent background. </member> + <member name="enable_hole_punch" type="bool" setter="set_enable_hole_punch" getter="get_enable_hole_punch" default="false"> + Enables a technique called "hole punching", which allows putting the composition layer behind the main projection layer (i.e. setting [member sort_order] to a negative value) while "punching a hole" through everything rendered by Godot so that the layer is still visible. + This can be used to create the illusion that the composition layer exists in the same 3D space as everything rendered by Godot, allowing objects to appear to pass both behind or in front of the composition layer. + </member> <member name="layer_viewport" type="SubViewport" setter="set_layer_viewport" getter="get_layer_viewport"> The [SubViewport] to render on the composition layer. </member> diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 05dff7d6ae..309cbe0d72 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -106,6 +106,13 @@ [b]Note:[/b] This feature is only available on the compatibility renderer and currently only available on some stand alone headsets. For Vulkan set [member Viewport.vrs_mode] to [code]VRS_XR[/code] on desktop. </description> </method> + <method name="is_hand_interaction_supported" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if OpenXR's hand interaction profile is supported and enabled. + [b]Note:[/b] This only returns a valid value after OpenXR has been initialized. + </description> + </method> <method name="is_hand_tracking_supported"> <return type="bool" /> <description> @@ -145,8 +152,21 @@ <member name="render_target_size_multiplier" type="float" setter="set_render_target_size_multiplier" getter="get_render_target_size_multiplier" default="1.0"> The render size multiplier for the current HMD. Must be set before the interface has been initialized. </member> + <member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0"> + The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> + <member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0"> + The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. This improves performance at the cost of quality. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> </members> <signals> + <signal name="instance_exiting"> + <description> + Informs our OpenXR instance is exiting. + </description> + </signal> <signal name="pose_recentered"> <description> Informs the user queued a recenter of the player position. @@ -169,6 +189,11 @@ Informs our OpenXR session now has focus. </description> </signal> + <signal name="session_loss_pending"> + <description> + Informs our OpenXR session is in the process of being lost. + </description> + </signal> <signal name="session_stopping"> <description> Informs our OpenXR session is stopping. diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp index 4b188471a0..06d2e8dcc9 100644 --- a/modules/openxr/editor/openxr_action_editor.cpp +++ b/modules/openxr/editor/openxr_action_editor.cpp @@ -159,7 +159,7 @@ OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) { rem_action = memnew(Button); rem_action->set_tooltip_text(TTR("Remove action")); - rem_action->connect("pressed", callable_mp(this, &OpenXRActionEditor::_on_remove_action)); + rem_action->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionEditor::_on_remove_action)); rem_action->set_flat(true); add_child(rem_action); } diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 5dd737756a..62b4a427b9 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -402,13 +402,13 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() { add_action_set = memnew(Button); add_action_set->set_text(TTR("Add Action Set")); add_action_set->set_tooltip_text(TTR("Add an action set.")); - add_action_set->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set)); + add_action_set->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set)); top_hb->add_child(add_action_set); add_interaction_profile = memnew(Button); add_interaction_profile->set_text(TTR("Add profile")); add_interaction_profile->set_tooltip_text(TTR("Add an interaction profile.")); - add_interaction_profile->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile)); + add_interaction_profile->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile)); top_hb->add_child(add_interaction_profile); VSeparator *vseparator = memnew(VSeparator); @@ -417,13 +417,13 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() { save_as = memnew(Button); save_as->set_text(TTR("Save")); save_as->set_tooltip_text(TTR("Save this OpenXR action map.")); - save_as->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map)); + save_as->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map)); top_hb->add_child(save_as); _default = memnew(Button); _default->set_text(TTR("Reset to Default")); _default->set_tooltip_text(TTR("Reset to default OpenXR action map.")); - _default->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout)); + _default->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout)); top_hb->add_child(_default); tabs = memnew(TabContainer); diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h index 22e8853c8c..cfe5fed095 100644 --- a/modules/openxr/editor/openxr_action_map_editor.h +++ b/modules/openxr/editor/openxr_action_map_editor.h @@ -36,8 +36,8 @@ #include "openxr_interaction_profile_editor.h" #include "openxr_select_interaction_profile_dialog.h" -#include "editor/editor_plugin.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/editor_plugin.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/label.h" diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp index 8b4a0e989c..5d9a3155fb 100644 --- a/modules/openxr/editor/openxr_action_set_editor.cpp +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -229,7 +229,7 @@ OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, fold_btn = memnew(Button); fold_btn->set_v_size_flags(Control::SIZE_SHRINK_BEGIN); - fold_btn->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand)); + fold_btn->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand)); fold_btn->set_flat(true); panel_hb->add_child(fold_btn); @@ -262,13 +262,13 @@ OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, add_action = memnew(Button); add_action->set_tooltip_text(TTR("Add action.")); - add_action->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_add_action)); + add_action->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionSetEditor::_on_add_action)); add_action->set_flat(true); action_set_hb->add_child(add_action); rem_action_set = memnew(Button); rem_action_set->set_tooltip_text(TTR("Remove action set.")); - rem_action_set->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set)); + rem_action_set->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set)); rem_action_set->set_flat(true); action_set_hb->add_child(rem_action_set); diff --git a/modules/openxr/editor/openxr_editor_plugin.h b/modules/openxr/editor/openxr_editor_plugin.h index b80f20d049..672df0de28 100644 --- a/modules/openxr/editor/openxr_editor_plugin.h +++ b/modules/openxr/editor/openxr_editor_plugin.h @@ -34,7 +34,7 @@ #include "openxr_action_map_editor.h" #include "openxr_select_runtime.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" class OpenXREditorPlugin : public EditorPlugin { GDCLASS(OpenXREditorPlugin, EditorPlugin); diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index da6a9eed70..ab36c0744e 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -222,7 +222,7 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co Button *path_add = memnew(Button); path_add->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons))); path_add->set_flat(true); - path_add->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for).bind(String(p_io_path->openxr_path))); + path_add->connect(SceneStringName(pressed), callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for).bind(String(p_io_path->openxr_path))); path_hb->add_child(path_add); if (interaction_profile.is_valid()) { @@ -249,7 +249,7 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co Button *action_rem = memnew(Button); action_rem->set_flat(true); action_rem->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons))); - action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditor *)this, &OpenXRInteractionProfileEditor::_on_remove_pressed).bind(action->get_name_with_set(), String(p_io_path->openxr_path))); + action_rem->connect(SceneStringName(pressed), callable_mp((OpenXRInteractionProfileEditor *)this, &OpenXRInteractionProfileEditor::_on_remove_pressed).bind(action->get_name_with_set(), String(p_io_path->openxr_path))); action_hb->add_child(action_rem); } } diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp index 8eec54be63..de0ab40f9e 100644 --- a/modules/openxr/editor/openxr_select_action_dialog.cpp +++ b/modules/openxr/editor/openxr_select_action_dialog.cpp @@ -97,7 +97,7 @@ void OpenXRSelectActionDialog::open() { String action_name = action->get_name_with_set(); action_button->set_flat(true); action_button->set_text(action->get_name() + ": " + action->get_localized_name()); - action_button->connect("pressed", callable_mp(this, &OpenXRSelectActionDialog::_on_select_action).bind(action_name)); + action_button->connect(SceneStringName(pressed), callable_mp(this, &OpenXRSelectActionDialog::_on_select_action).bind(action_name)); action_hb->add_child(action_button); action_buttons[action_name] = action_button->get_path(); diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp index 8fd66fac04..e6705d5c82 100644 --- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -82,7 +82,7 @@ void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_inclu Button *ip_button = memnew(Button); ip_button->set_flat(true); ip_button->set_text(OpenXRInteractionProfileMetadata::get_singleton()->get_profile(path)->display_name); - ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile).bind(path)); + ip_button->connect(SceneStringName(pressed), callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile).bind(path)); main_vb->add_child(ip_button); ip_buttons[path] = ip_button->get_path(); diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp index 1fba8e5f8b..994b08af53 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp @@ -187,7 +187,7 @@ void OpenXRViewportCompositionLayerProvider::on_pre_render() { XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_composition_layer() { if (openxr_api == nullptr || composition_layer_extension == nullptr) { - // OpenXR not initialised or we're in the editor? + // OpenXR not initialized or we're in the editor? return nullptr; } @@ -209,6 +209,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos switch (composition_layer->type) { case XR_TYPE_COMPOSITION_LAYER_QUAD: { XrCompositionLayerQuad *quad_layer = (XrCompositionLayerQuad *)composition_layer; + quad_layer->space = openxr_api->get_play_space(); quad_layer->subImage.swapchain = swapchain_info.get_swapchain(); quad_layer->subImage.imageArrayIndex = 0; quad_layer->subImage.imageRect.offset.x = 0; @@ -219,6 +220,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: { XrCompositionLayerCylinderKHR *cylinder_layer = (XrCompositionLayerCylinderKHR *)composition_layer; + cylinder_layer->space = openxr_api->get_play_space(); cylinder_layer->subImage.swapchain = swapchain_info.get_swapchain(); cylinder_layer->subImage.imageArrayIndex = 0; cylinder_layer->subImage.imageRect.offset.x = 0; @@ -229,6 +231,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: { XrCompositionLayerEquirect2KHR *equirect_layer = (XrCompositionLayerEquirect2KHR *)composition_layer; + equirect_layer->space = openxr_api->get_play_space(); equirect_layer->subImage.swapchain = swapchain_info.get_swapchain(); equirect_layer->subImage.imageArrayIndex = 0; equirect_layer->subImage.imageRect.offset.x = 0; @@ -260,7 +263,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p_static_image) { if (openxr_api == nullptr || composition_layer_extension == nullptr) { - // OpenXR not initialised or we're in the editor? + // OpenXR not initialized or we're in the editor? return false; } if (!composition_layer_extension->is_available(composition_layer->type)) { @@ -274,7 +277,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p if (swapchain_size == viewport_size && !p_static_image && !static_image) { // We're all good! Just acquire it. // We can ignore should_render here, return will be false. - XrBool32 should_render = true; + bool should_render = true; return swapchain_info.acquire(should_render); } @@ -283,7 +286,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p // Create our new swap chain int64_t swapchain_format = openxr_api->get_color_swapchain_format(); - const uint32_t sample_count = 3; + const uint32_t sample_count = 1; const uint32_t array_size = 1; XrSwapchainCreateFlags create_flags = 0; if (p_static_image) { @@ -296,7 +299,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p // Acquire our image so we can start rendering into it, // we can ignore should_render here, ret will be false. - XrBool32 should_render = true; + bool should_render = true; bool ret = swapchain_info.acquire(should_render); swapchain_size = viewport_size; diff --git a/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp b/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp index 477a1c2609..eea996edd9 100644 --- a/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp +++ b/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp @@ -34,6 +34,7 @@ #include "core/os/os.h" #include "../action_map/openxr_interaction_profile_metadata.h" +#include "../openxr_api.h" OpenXREyeGazeInteractionExtension *OpenXREyeGazeInteractionExtension::singleton = nullptr; @@ -106,3 +107,38 @@ void OpenXREyeGazeInteractionExtension::on_register_metadata() { metadata->register_interaction_profile("Eye gaze", "/interaction_profiles/ext/eye_gaze_interaction", XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME); metadata->register_io_path("/interaction_profiles/ext/eye_gaze_interaction", "Gaze pose", "/user/eyes_ext", "/user/eyes_ext/input/gaze_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); } + +bool OpenXREyeGazeInteractionExtension::get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose) { + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL_V(openxr_api, false); + + if (!init_eye_gaze_pose) { + init_eye_gaze_pose = true; + + eye_tracker = openxr_api->find_tracker("/user/eyes_ext"); + if (eye_tracker.is_null()) { + WARN_PRINT("Couldn't obtain eye tracker"); + } + + eye_action = openxr_api->find_action("eye_gaze_pose"); + if (eye_action.is_null()) { + WARN_PRINT("Couldn't obtain pose action for `eye_gaze_pose`, make sure to add this to your action map."); + } + } + + if (eye_tracker.is_null() || eye_action.is_null()) { + return false; + } + + Transform3D eye_transform; + Vector3 linear_velocity; + Vector3 angular_velocity; + XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(eye_action, eye_tracker, eye_transform, linear_velocity, angular_velocity); + if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) { + return false; + } + + r_eye_pose = eye_transform.origin + eye_transform.basis[2] * p_dist; + + return true; +} diff --git a/modules/openxr/extensions/openxr_eye_gaze_interaction.h b/modules/openxr/extensions/openxr_eye_gaze_interaction.h index 2b99f8edff..114c1aacc7 100644 --- a/modules/openxr/extensions/openxr_eye_gaze_interaction.h +++ b/modules/openxr/extensions/openxr_eye_gaze_interaction.h @@ -50,11 +50,17 @@ public: virtual void on_register_metadata() override; + bool get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose); + private: static OpenXREyeGazeInteractionExtension *singleton; bool available = false; XrSystemEyeGazeInteractionPropertiesEXT properties; + + bool init_eye_gaze_pose = false; + RID eye_tracker; + RID eye_action; }; #endif // OPENXR_EYE_GAZE_INTERACTION_H diff --git a/modules/openxr/extensions/openxr_hand_interaction_extension.cpp b/modules/openxr/extensions/openxr_hand_interaction_extension.cpp new file mode 100644 index 0000000000..65de4b23c4 --- /dev/null +++ b/modules/openxr/extensions/openxr_hand_interaction_extension.cpp @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* openxr_hand_interaction_extension.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "openxr_hand_interaction_extension.h" + +#include "../action_map/openxr_interaction_profile_metadata.h" +#include "core/config/project_settings.h" + +OpenXRHandInteractionExtension *OpenXRHandInteractionExtension::singleton = nullptr; + +OpenXRHandInteractionExtension *OpenXRHandInteractionExtension::get_singleton() { + return singleton; +} + +OpenXRHandInteractionExtension::OpenXRHandInteractionExtension() { + singleton = this; +} + +OpenXRHandInteractionExtension::~OpenXRHandInteractionExtension() { + singleton = nullptr; +} + +HashMap<String, bool *> OpenXRHandInteractionExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + // Only enable this extension when requested. + // We still register our meta data or the action map editor will fail. + if (GLOBAL_GET("xr/openxr/extensions/hand_interaction_profile")) { + request_extensions[XR_EXT_HAND_INTERACTION_EXTENSION_NAME] = &available; + } + + return request_extensions; +} + +bool OpenXRHandInteractionExtension::is_available() { + return available; +} + +void OpenXRHandInteractionExtension::on_register_metadata() { + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); + ERR_FAIL_NULL(metadata); + + // Hand interaction profile + metadata->register_interaction_profile("Hand interaction", "/interaction_profiles/ext/hand_interaction_ext", XR_EXT_HAND_INTERACTION_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch pose", "/user/hand/left", "/user/hand/left/input/pinch_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch pose", "/user/hand/right", "/user/hand/right/input/pinch_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Poke pose", "/user/hand/left", "/user/hand/left/input/poke_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Poke pose", "/user/hand/right", "/user/hand/right/input/poke_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch", "/user/hand/left", "/user/hand/left/input/pinch_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch", "/user/hand/right", "/user/hand/right/input/pinch_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch ready", "/user/hand/left", "/user/hand/left/input/pinch_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch ready", "/user/hand/right", "/user/hand/right/input/pinch_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate", "/user/hand/left", "/user/hand/left/input/aim_activate_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate", "/user/hand/right", "/user/hand/right/input/aim_activate_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate ready", "/user/hand/left", "/user/hand/left/input/aim_activate_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate ready", "/user/hand/right", "/user/hand/right/input/aim_activate_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp", "/user/hand/left", "/user/hand/left/input/grasp_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp", "/user/hand/right", "/user/hand/right/input/grasp_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp ready", "/user/hand/left", "/user/hand/left/input/grasp_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp ready", "/user/hand/right", "/user/hand/right/input/grasp_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL); +} diff --git a/modules/openxr/extensions/openxr_hand_interaction_extension.h b/modules/openxr/extensions/openxr_hand_interaction_extension.h new file mode 100644 index 0000000000..789e300c0b --- /dev/null +++ b/modules/openxr/extensions/openxr_hand_interaction_extension.h @@ -0,0 +1,72 @@ +/**************************************************************************/ +/* openxr_hand_interaction_extension.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef OPENXR_HAND_INTERACTION_EXTENSION_H +#define OPENXR_HAND_INTERACTION_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +// When supported the hand interaction extension introduces an interaction +// profile that becomes active when the user either lets go of their +// controllers or isn't using controllers at all. +// +// The OpenXR specification states that all XR runtimes that support this +// interaction profile should also allow it's controller to use this +// interaction profile. +// This means that if you only supply this interaction profile in your +// action map, it should work both when the player is holding a controller +// or using visual hand tracking. +// +// This allows easier portability between games that use controller +// tracking or hand tracking. +// +// See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_hand_interaction +// for more information. + +class OpenXRHandInteractionExtension : public OpenXRExtensionWrapper { +public: + static OpenXRHandInteractionExtension *get_singleton(); + + OpenXRHandInteractionExtension(); + virtual ~OpenXRHandInteractionExtension() override; + + virtual HashMap<String, bool *> get_requested_extensions() override; + + bool is_available(); + + virtual void on_register_metadata() override; + +private: + static OpenXRHandInteractionExtension *singleton; + + bool available = false; +}; + +#endif // OPENXR_HAND_INTERACTION_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index 12fa3bed7e..b8a2f58935 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -128,7 +128,7 @@ void OpenXRHandTrackingExtension::on_process() { } // process our hands - const XrTime time = OpenXRAPI::get_singleton()->get_next_frame_time(); // This data will be used for the next frame we render + const XrTime time = OpenXRAPI::get_singleton()->get_predicted_display_time(); if (time == 0) { // we don't have timing info yet, or we're skipping a frame... return; diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 1fe402341b..32512070d6 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -54,6 +54,7 @@ #endif #include "extensions/openxr_composition_layer_depth_extension.h" +#include "extensions/openxr_eye_gaze_interaction.h" #include "extensions/openxr_fb_display_refresh_rate_extension.h" #include "extensions/openxr_fb_foveation_extension.h" #include "extensions/openxr_fb_update_swapchain_extension.h" @@ -160,7 +161,7 @@ void OpenXRAPI::OpenXRSwapChainInfo::free() { } } -bool OpenXRAPI::OpenXRSwapChainInfo::acquire(XrBool32 &p_should_render) { +bool OpenXRAPI::OpenXRSwapChainInfo::acquire(bool &p_should_render) { ERR_FAIL_COND_V(image_acquired, true); // This was not released when it should be, error out and reuse... OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); @@ -193,10 +194,18 @@ bool OpenXRAPI::OpenXRSwapChainInfo::acquire(XrBool32 &p_should_render) { XrSwapchainImageWaitInfo swapchain_image_wait_info = { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, // type nullptr, // next - 17000000 // timeout in nanoseconds + 1000000000 // 1s timeout in nanoseconds }; - result = openxr_api->xrWaitSwapchainImage(swapchain, &swapchain_image_wait_info); + // Wait for a maximum of 10 seconds before calling it a critical failure... + for (int retry = 0; retry < 10; retry++) { + result = openxr_api->xrWaitSwapchainImage(swapchain, &swapchain_image_wait_info); + if (result != XR_TIMEOUT_EXPIRED) { + break; + } + WARN_PRINT("OpenXR: timed out waiting for swapchain image."); + } + if (!XR_UNQUALIFIED_SUCCESS(result)) { // Make sure end_frame knows we need to submit an empty frame p_should_render = false; @@ -206,6 +215,8 @@ bool OpenXRAPI::OpenXRSwapChainInfo::acquire(XrBool32 &p_should_render) { print_line("OpenXR: failed to wait for swapchain image [", openxr_api->get_error_string(result), "]"); return false; } else { + WARN_PRINT("OpenXR: couldn't to wait for swapchain but not a complete error [" + openxr_api->get_error_string(result) + "]"); + // Make sure to skip trying to acquire the swapchain image in the next frame skip_acquire_swapchain = true; return false; @@ -760,21 +771,6 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType print_verbose(String(" - recommended render sample count: ") + itos(view_configuration_views[i].recommendedSwapchainSampleCount)); } - // Allocate buffers we'll be populating with view information. - views = (XrView *)memalloc(sizeof(XrView) * view_count); - ERR_FAIL_NULL_V_MSG(views, false, "OpenXR Couldn't allocate memory for views"); - memset(views, 0, sizeof(XrView) * view_count); - - projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count); - ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views"); - memset(projection_views, 0, sizeof(XrCompositionLayerProjectionView) * view_count); - - if (submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) { - depth_views = (XrCompositionLayerDepthInfoKHR *)memalloc(sizeof(XrCompositionLayerDepthInfoKHR) * view_count); - ERR_FAIL_NULL_V_MSG(depth_views, false, "OpenXR Couldn't allocate memory for depth views"); - memset(depth_views, 0, sizeof(XrCompositionLayerDepthInfoKHR) * view_count); - } - return true; } @@ -927,6 +923,9 @@ bool OpenXRAPI::setup_play_space() { // If we've previously created a play space, clean it up first. if (play_space != XR_NULL_HANDLE) { + // TODO Investigate if destroying our play space here is safe, + // it may still be used in the rendering thread. + xrDestroySpace(play_space); } play_space = new_play_space; @@ -936,7 +935,11 @@ bool OpenXRAPI::setup_play_space() { if (emulating_local_floor) { // We'll use the STAGE space to get the floor height, but we can't do that until // after xrWaitFrame(), so just set this flag for now. + // Render state will be updated then. should_reset_emulated_floor_height = true; + } else { + // Update render state so this play space is used rendering the upcoming frame. + set_render_play_space(play_space); } return true; @@ -1016,7 +1019,7 @@ bool OpenXRAPI::reset_emulated_floor_height() { identityPose, // pose }; - result = xrLocateSpace(stage_space, local_space, get_next_frame_time(), &stage_location); + result = xrLocateSpace(stage_space, local_space, get_predicted_display_time(), &stage_location); xrDestroySpace(local_space); xrDestroySpace(stage_space); @@ -1042,6 +1045,9 @@ bool OpenXRAPI::reset_emulated_floor_height() { // report that as the reference space to the outside world. reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT; + // Update render state so this play space is used rendering the upcoming frame. + set_render_play_space(play_space); + return true; } @@ -1136,6 +1142,7 @@ bool OpenXRAPI::obtain_swapchain_formats() { } bool OpenXRAPI::create_main_swapchains(Size2i p_size) { + ERR_NOT_ON_RENDER_THREAD_V(false); ERR_FAIL_NULL_V(graphics_extension, false); ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); @@ -1154,12 +1161,12 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) { as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support */ - main_swapchain_size = p_size; + render_state.main_swapchain_size = p_size; uint32_t sample_count = 1; // We start with our color swapchain... if (color_swapchain_format != 0) { - if (!main_swapchains[OPENXR_SWAPCHAIN_COLOR].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, color_swapchain_format, main_swapchain_size.width, main_swapchain_size.height, sample_count, view_count)) { + if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, color_swapchain_format, render_state.main_swapchain_size.width, render_state.main_swapchain_size.height, sample_count, view_count)) { return false; } } @@ -1169,7 +1176,7 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) { // - we support our depth layer extension // - we have our spacewarp extension (not yet implemented) if (depth_swapchain_format != 0 && submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) { - if (!main_swapchains[OPENXR_SWAPCHAIN_DEPTH].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, depth_swapchain_format, main_swapchain_size.width, main_swapchain_size.height, sample_count, view_count)) { + if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, depth_swapchain_format, render_state.main_swapchain_size.width, render_state.main_swapchain_size.height, sample_count, view_count)) { return false; } } @@ -1180,36 +1187,36 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) { // TBD } - for (uint32_t i = 0; i < view_count; i++) { - views[i].type = XR_TYPE_VIEW; - views[i].next = nullptr; - - projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; - projection_views[i].next = nullptr; - projection_views[i].subImage.swapchain = main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain(); - projection_views[i].subImage.imageArrayIndex = i; - projection_views[i].subImage.imageRect.offset.x = 0; - projection_views[i].subImage.imageRect.offset.y = 0; - projection_views[i].subImage.imageRect.extent.width = main_swapchain_size.width; - projection_views[i].subImage.imageRect.extent.height = main_swapchain_size.height; - - if (submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) { - projection_views[i].next = &depth_views[i]; - - depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; - depth_views[i].next = nullptr; - depth_views[i].subImage.swapchain = main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain(); - depth_views[i].subImage.imageArrayIndex = i; - depth_views[i].subImage.imageRect.offset.x = 0; - depth_views[i].subImage.imageRect.offset.y = 0; - depth_views[i].subImage.imageRect.extent.width = main_swapchain_size.width; - depth_views[i].subImage.imageRect.extent.height = main_swapchain_size.height; + for (uint32_t i = 0; i < render_state.view_count; i++) { + render_state.views[i].type = XR_TYPE_VIEW; + render_state.views[i].next = nullptr; + + render_state.projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; + render_state.projection_views[i].next = nullptr; + render_state.projection_views[i].subImage.swapchain = render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain(); + render_state.projection_views[i].subImage.imageArrayIndex = i; + render_state.projection_views[i].subImage.imageRect.offset.x = 0; + render_state.projection_views[i].subImage.imageRect.offset.y = 0; + render_state.projection_views[i].subImage.imageRect.extent.width = render_state.main_swapchain_size.width; + render_state.projection_views[i].subImage.imageRect.extent.height = render_state.main_swapchain_size.height; + + if (render_state.submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && render_state.depth_views) { + render_state.projection_views[i].next = &render_state.depth_views[i]; + + render_state.depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; + render_state.depth_views[i].next = nullptr; + render_state.depth_views[i].subImage.swapchain = render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain(); + render_state.depth_views[i].subImage.imageArrayIndex = i; + render_state.depth_views[i].subImage.imageRect.offset.x = 0; + render_state.depth_views[i].subImage.imageRect.offset.y = 0; + render_state.depth_views[i].subImage.imageRect.extent.width = render_state.main_swapchain_size.width; + render_state.depth_views[i].subImage.imageRect.extent.height = render_state.main_swapchain_size.height; // OpenXR spec says that: minDepth < maxDepth. - depth_views[i].minDepth = 0.0; - depth_views[i].maxDepth = 1.0; + render_state.depth_views[i].minDepth = 0.0; + render_state.depth_views[i].maxDepth = 1.0; // But we can reverse near and far for reverse-Z. - depth_views[i].nearZ = 100.0; // Near and far Z will be set to the correct values in fill_projection_matrix - depth_views[i].farZ = 0.01; + render_state.depth_views[i].nearZ = 100.0; // Near and far Z will be set to the correct values in fill_projection_matrix + render_state.depth_views[i].farZ = 0.01; } }; @@ -1217,23 +1224,33 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) { }; void OpenXRAPI::destroy_session() { - if (running && session != XR_NULL_HANDLE) { - xrEndSession(session); + // TODO need to figure out if we're still rendering our current frame + // in a separate rendering thread and if so, + // if we need to wait for completion. + // We could be pulling the rug from underneath rendering... + + if (running) { + if (session != XR_NULL_HANDLE) { + xrEndSession(session); + } + + running = false; + render_state.running = false; } - if (views != nullptr) { - memfree(views); - views = nullptr; + if (render_state.views != nullptr) { + memfree(render_state.views); + render_state.views = nullptr; } - if (projection_views != nullptr) { - memfree(projection_views); - projection_views = nullptr; + if (render_state.projection_views != nullptr) { + memfree(render_state.projection_views); + render_state.projection_views = nullptr; } - if (depth_views != nullptr) { - memfree(depth_views); - depth_views = nullptr; + if (render_state.depth_views != nullptr) { + memfree(render_state.depth_views); + render_state.depth_views = nullptr; } free_main_swapchains(); @@ -1248,6 +1265,7 @@ void OpenXRAPI::destroy_session() { if (play_space != XR_NULL_HANDLE) { xrDestroySpace(play_space); play_space = XR_NULL_HANDLE; + render_state.play_space = XR_NULL_HANDLE; } if (view_space != XR_NULL_HANDLE) { xrDestroySpace(view_space); @@ -1298,6 +1316,7 @@ bool OpenXRAPI::on_state_ready() { // we're running running = true; + set_render_session_running(true); for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { wrapper->on_state_ready(); @@ -1316,8 +1335,8 @@ bool OpenXRAPI::on_state_synchronized() { // Just in case, see if we already have active trackers... List<RID> trackers; tracker_owner.get_owned_list(&trackers); - for (int i = 0; i < trackers.size(); i++) { - tracker_check_profile(trackers[i]); + for (const RID &tracker : trackers) { + tracker_check_profile(tracker); } for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { @@ -1374,34 +1393,37 @@ bool OpenXRAPI::on_state_stopping() { } running = false; + set_render_session_running(false); } - // TODO further cleanup - return true; } bool OpenXRAPI::on_state_loss_pending() { print_verbose("On state loss pending"); + if (xr_interface) { + xr_interface->on_state_loss_pending(); + } + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { wrapper->on_state_loss_pending(); } - // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting) - return true; } bool OpenXRAPI::on_state_exiting() { print_verbose("On state existing"); + if (xr_interface) { + xr_interface->on_state_exiting(); + } + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { wrapper->on_state_exiting(); } - // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting) - return true; } @@ -1419,10 +1441,7 @@ void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configurat bool OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) { requested_reference_space = p_requested_reference_space; - - if (is_initialized()) { - return setup_play_space(); - } + play_space_is_dirty = true; return true; } @@ -1625,11 +1644,6 @@ bool OpenXRAPI::initialize_session() { return false; } - if (!setup_play_space()) { - destroy_session(); - return false; - } - if (!setup_view_space()) { destroy_session(); return false; @@ -1645,6 +1659,8 @@ bool OpenXRAPI::initialize_session() { return false; } + allocate_view_buffers(view_count, submit_depth_buffer); + return true; } @@ -1696,12 +1712,18 @@ XrHandTrackerEXT OpenXRAPI::get_hand_tracker(int p_hand_index) { } Size2 OpenXRAPI::get_recommended_target_size() { + RenderingServer *rendering_server = RenderingServer::get_singleton(); ERR_FAIL_NULL_V(view_configuration_views, Size2()); Size2 target_size; - target_size.width = view_configuration_views[0].recommendedImageRectWidth * render_target_size_multiplier; - target_size.height = view_configuration_views[0].recommendedImageRectHeight * render_target_size_multiplier; + if (rendering_server && rendering_server->is_on_render_thread()) { + target_size.width = view_configuration_views[0].recommendedImageRectWidth * render_state.render_target_size_multiplier; + target_size.height = view_configuration_views[0].recommendedImageRectHeight * render_state.render_target_size_multiplier; + } else { + target_size.width = view_configuration_views[0].recommendedImageRectWidth * render_target_size_multiplier; + target_size.height = view_configuration_views[0].recommendedImageRectHeight * render_target_size_multiplier; + } return target_size; } @@ -1713,14 +1735,12 @@ XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, return XRPose::XR_TRACKING_CONFIDENCE_NONE; } - // xrWaitFrame not run yet - if (frame_state.predictedDisplayTime == 0) { + // Get display time + XrTime display_time = get_predicted_display_time(); + if (display_time == 0) { return XRPose::XR_TRACKING_CONFIDENCE_NONE; } - // Get timing for the next frame, as that is the current frame we're processing - XrTime display_time = get_next_frame_time(); - XrSpaceVelocity velocity = { XR_TYPE_SPACE_VELOCITY, // type nullptr, // next @@ -1764,54 +1784,87 @@ XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, } bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) { - if (!running) { - return false; - } + ERR_NOT_ON_RENDER_THREAD_V(false); - // xrWaitFrame not run yet - if (frame_state.predictedDisplayTime == 0) { + if (!render_state.running) { return false; } // we don't have valid view info - if (views == nullptr || !view_pose_valid) { + if (render_state.views == nullptr || !render_state.view_pose_valid) { return false; } // Note, the timing of this is set right before rendering, which is what we need here. - r_transform = transform_from_pose(views[p_view].pose); + r_transform = transform_from_pose(render_state.views[p_view].pose); return true; } bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix) { + ERR_NOT_ON_RENDER_THREAD_V(false); ERR_FAIL_NULL_V(graphics_extension, false); - if (!running) { - return false; - } - - // xrWaitFrame not run yet - if (frame_state.predictedDisplayTime == 0) { + if (!render_state.running) { return false; } // we don't have valid view info - if (views == nullptr || !view_pose_valid) { + if (render_state.views == nullptr || !render_state.view_pose_valid) { return false; } // if we're using depth views, make sure we update our near and far there... - if (depth_views != nullptr) { - for (uint32_t i = 0; i < view_count; i++) { + if (render_state.depth_views != nullptr) { + for (uint32_t i = 0; i < render_state.view_count; i++) { // As we are using reverse-Z these need to be flipped. - depth_views[i].nearZ = p_z_far; - depth_views[i].farZ = p_z_near; + render_state.depth_views[i].nearZ = p_z_far; + render_state.depth_views[i].farZ = p_z_near; } } // now update our projection - return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); + return graphics_extension->create_projection_fov(render_state.views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); +} + +Vector2 OpenXRAPI::get_eye_focus(uint32_t p_view, float p_aspect) { + ERR_FAIL_NULL_V(graphics_extension, Vector2()); + + if (!render_state.running) { + return Vector2(); + } + + // xrWaitFrame not run yet + if (render_state.predicted_display_time == 0) { + return Vector2(); + } + + // we don't have valid view info + if (render_state.views == nullptr || !render_state.view_pose_valid) { + return Vector2(); + } + + Projection cm; + if (!graphics_extension->create_projection_fov(render_state.views[p_view].fov, 0.1, 1000.0, cm)) { + return Vector2(); + } + + // Default focus to center... + Vector3 focus = cm.xform(Vector3(0.0, 0.0, 999.9)); + + // Lets check for eye tracking... + OpenXREyeGazeInteractionExtension *eye_gaze_interaction = OpenXREyeGazeInteractionExtension::get_singleton(); + if (eye_gaze_interaction && eye_gaze_interaction->supports_eye_gaze_interaction()) { + Vector3 eye_gaze_pose; + if (eye_gaze_interaction->get_eye_gaze_pose(1.0, eye_gaze_pose)) { + Transform3D view_transform = transform_from_pose(render_state.views[p_view].pose); + + eye_gaze_pose = view_transform.xform_inv(eye_gaze_pose); + focus = cm.xform(eye_gaze_pose); + } + } + + return Vector2(focus.x, focus.y); } bool OpenXRAPI::poll_events() { @@ -1910,8 +1963,8 @@ bool OpenXRAPI::poll_events() { List<RID> trackers; tracker_owner.get_owned_list(&trackers); - for (int i = 0; i < trackers.size(); i++) { - tracker_check_profile(trackers[i], event->session); + for (const RID &tracker : trackers) { + tracker_check_profile(tracker, event->session); } } break; @@ -1934,53 +1987,85 @@ bool OpenXRAPI::poll_events() { } } -bool OpenXRAPI::process() { - ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); +void OpenXRAPI::_allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; - if (!poll_events()) { - return false; - } + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); - if (!running) { - return false; - } + openxr_api->render_state.view_count = p_view_count; + openxr_api->render_state.submit_depth_buffer = p_submit_depth_buffer; - for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { - wrapper->on_process(); + // Allocate buffers we'll be populating with view information. + openxr_api->render_state.views = (XrView *)memalloc(sizeof(XrView) * p_view_count); + ERR_FAIL_NULL_MSG(openxr_api->render_state.views, "OpenXR Couldn't allocate memory for views"); + memset(openxr_api->render_state.views, 0, sizeof(XrView) * p_view_count); + + openxr_api->render_state.projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * p_view_count); + ERR_FAIL_NULL_MSG(openxr_api->render_state.projection_views, "OpenXR Couldn't allocate memory for projection views"); + memset(openxr_api->render_state.projection_views, 0, sizeof(XrCompositionLayerProjectionView) * p_view_count); + + if (p_submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) { + openxr_api->render_state.depth_views = (XrCompositionLayerDepthInfoKHR *)memalloc(sizeof(XrCompositionLayerDepthInfoKHR) * p_view_count); + ERR_FAIL_NULL_MSG(openxr_api->render_state.depth_views, "OpenXR Couldn't allocate memory for depth views"); + memset(openxr_api->render_state.depth_views, 0, sizeof(XrCompositionLayerDepthInfoKHR) * p_view_count); } +} - return true; +void OpenXRAPI::_set_render_session_running(bool p_is_running) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; + + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); + openxr_api->render_state.running = p_is_running; } -void OpenXRAPI::free_main_swapchains() { - for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { - main_swapchains[i].queue_free(); - } +void OpenXRAPI::_set_render_display_info(XrTime p_predicted_display_time, bool p_should_render) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; + + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); + openxr_api->render_state.predicted_display_time = p_predicted_display_time; + openxr_api->render_state.should_render = p_should_render; } -void OpenXRAPI::pre_render() { - ERR_FAIL_COND(instance == XR_NULL_HANDLE); +void OpenXRAPI::_set_render_play_space(uint64_t p_play_space) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; - if (!running) { - return; - } + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); + openxr_api->render_state.play_space = XrSpace(p_play_space); +} - // Process any swapchains that were queued to be freed - OpenXRSwapChainInfo::free_queued(); +void OpenXRAPI::_set_render_state_multiplier(double p_render_target_size_multiplier) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; - Size2i swapchain_size = get_recommended_target_size(); - if (swapchain_size != main_swapchain_size) { - // Out with the old. - free_main_swapchains(); + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); + openxr_api->render_state.render_target_size_multiplier = p_render_target_size_multiplier; +} - // In with the new. - create_main_swapchains(swapchain_size); +bool OpenXRAPI::process() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + if (!poll_events()) { + return false; + } + + if (!running) { + return false; } - // Waitframe does 2 important things in our process: - // 1) It provides us with predictive timing, telling us when OpenXR expects to display the frame we're about to commit - // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible - // This must thus be called as close to when we start rendering as possible + // We call xrWaitFrame as early as possible, this will allow OpenXR to get + // proper timing info between this point, and when we're ready to start rendering. + // As the name suggests, OpenXR can pause the thread to minimize the time between + // retrieving tracking data and using that tracking data to render. + // OpenXR thus works best if rendering is performed on a separate thread. XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr }; frame_state.predictedDisplayTime = 0; frame_state.predictedDisplayPeriod = 0; @@ -1995,7 +2080,9 @@ void OpenXRAPI::pre_render() { frame_state.predictedDisplayPeriod = 0; frame_state.shouldRender = false; - return; + set_render_display_info(0, false); + + return false; } if (frame_state.predictedDisplayPeriod > 500000000) { @@ -2004,12 +2091,54 @@ void OpenXRAPI::pre_render() { frame_state.predictedDisplayPeriod = 0; } + set_render_display_info(frame_state.predictedDisplayTime, frame_state.shouldRender); + + if (unlikely(play_space_is_dirty)) { + setup_play_space(); + play_space_is_dirty = false; + } + if (unlikely(should_reset_emulated_floor_height)) { reset_emulated_floor_height(); should_reset_emulated_floor_height = false; } for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_process(); + } + + return true; +} + +void OpenXRAPI::free_main_swapchains() { + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + render_state.main_swapchains[i].queue_free(); + } +} + +void OpenXRAPI::pre_render() { + ERR_FAIL_COND(session == XR_NULL_HANDLE); + + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; + + if (!render_state.running) { + return; + } + + // Process any swapchains that were queued to be freed + OpenXRSwapChainInfo::free_queued(); + + Size2i swapchain_size = get_recommended_target_size(); + if (swapchain_size != render_state.main_swapchain_size) { + // Out with the old. + free_main_swapchains(); + + // In with the new. + create_main_swapchains(swapchain_size); + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { wrapper->on_pre_render(); } @@ -2028,8 +2157,8 @@ void OpenXRAPI::pre_render() { XR_TYPE_VIEW_LOCATE_INFO, // type nullptr, // next view_configuration, // viewConfigurationType - frame_state.predictedDisplayTime, // displayTime - play_space // space + render_state.predicted_display_time, // displayTime + render_state.play_space // space }; XrViewState view_state = { XR_TYPE_VIEW_STATE, // type @@ -2037,7 +2166,7 @@ void OpenXRAPI::pre_render() { 0 // viewStateFlags }; uint32_t view_count_output; - result = xrLocateViews(session, &view_locate_info, &view_state, view_count, &view_count_output, views); + XrResult result = xrLocateViews(session, &view_locate_info, &view_state, render_state.view_count, &view_count_output, render_state.views); if (XR_FAILED(result)) { print_line("OpenXR: Couldn't locate views [", get_error_string(result), "]"); return; @@ -2050,9 +2179,9 @@ void OpenXRAPI::pre_render() { pose_valid = false; } } - if (view_pose_valid != pose_valid) { - view_pose_valid = pose_valid; - if (!view_pose_valid) { + if (render_state.view_pose_valid != pose_valid) { + render_state.view_pose_valid = pose_valid; + if (!render_state.view_pose_valid) { print_verbose("OpenXR View pose became invalid"); } else { print_verbose("OpenXR View pose became valid"); @@ -2071,23 +2200,24 @@ void OpenXRAPI::pre_render() { } // Reset this, we haven't found a viewport for output yet - has_xr_viewport = false; + render_state.has_xr_viewport = false; } bool OpenXRAPI::pre_draw_viewport(RID p_render_target) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD_V(false); + // We found an XR viewport! - has_xr_viewport = true; + render_state.has_xr_viewport = true; - if (!can_render()) { + if (instance == XR_NULL_HANDLE || session == XR_NULL_HANDLE || !render_state.running || !render_state.view_pose_valid || !render_state.should_render) { return false; } - // TODO: at some point in time we may support multiple viewports in which case we need to handle that... - // Acquire our images for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { - if (!main_swapchains[i].is_image_acquired() && main_swapchains[i].get_swapchain() != XR_NULL_HANDLE) { - if (!main_swapchains[i].acquire(frame_state.shouldRender)) { + if (!render_state.main_swapchains[i].is_image_acquired() && render_state.main_swapchains[i].get_swapchain() != XR_NULL_HANDLE) { + if (!render_state.main_swapchains[i].acquire(render_state.should_render)) { return false; } } @@ -2101,24 +2231,33 @@ bool OpenXRAPI::pre_draw_viewport(RID p_render_target) { } XrSwapchain OpenXRAPI::get_color_swapchain() { - return main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain(); + ERR_NOT_ON_RENDER_THREAD_V(XR_NULL_HANDLE); + + return render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain(); } RID OpenXRAPI::get_color_texture() { - return main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_image(); + ERR_NOT_ON_RENDER_THREAD_V(RID()); + + return render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_image(); } RID OpenXRAPI::get_depth_texture() { + ERR_NOT_ON_RENDER_THREAD_V(RID()); + // Note, image will not be acquired if we didn't have a suitable swap chain format. - if (submit_depth_buffer) { - return main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_image(); + if (render_state.submit_depth_buffer && render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].is_image_acquired()) { + return render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_image(); } else { return RID(); } } void OpenXRAPI::post_draw_viewport(RID p_render_target) { - if (!can_render()) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; + + if (instance == XR_NULL_HANDLE || session == XR_NULL_HANDLE || !render_state.running || !render_state.view_pose_valid || !render_state.should_render) { return; } @@ -2130,37 +2269,40 @@ void OpenXRAPI::post_draw_viewport(RID p_render_target) { void OpenXRAPI::end_frame() { XrResult result; - ERR_FAIL_COND(instance == XR_NULL_HANDLE); + ERR_FAIL_COND(session == XR_NULL_HANDLE); - if (!running) { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; + + if (!render_state.running) { return; } - if (frame_state.shouldRender && view_pose_valid) { - if (!has_xr_viewport) { + if (render_state.should_render && render_state.view_pose_valid) { + if (!render_state.has_xr_viewport) { print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!"); - } else if (!main_swapchains[OPENXR_SWAPCHAIN_COLOR].is_image_acquired()) { + } else if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].is_image_acquired()) { print_line("OpenXR: No swapchain could be acquired to render to!"); } } // must have: - // - shouldRender set to true + // - should_render set to true // - a valid view pose for projection_views[eye].pose to submit layer // - an image to render - if (!frame_state.shouldRender || !view_pose_valid || !main_swapchains[OPENXR_SWAPCHAIN_COLOR].is_image_acquired()) { + if (!render_state.should_render || !render_state.view_pose_valid || !render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].is_image_acquired()) { // submit 0 layers when we shouldn't render XrFrameEndInfo frame_end_info = { XR_TYPE_FRAME_END_INFO, // type nullptr, // next - frame_state.predictedDisplayTime, // displayTime + render_state.predicted_display_time, // displayTime environment_blend_mode, // environmentBlendMode 0, // layerCount nullptr // layers }; result = xrEndFrame(session, &frame_end_info); if (XR_FAILED(result)) { - print_line("OpenXR: failed to end frame! [", get_error_string(result), "]"); + print_line("OpenXR: rendering skipped and failed to end frame! [", get_error_string(result), "]"); return; } @@ -2170,14 +2312,14 @@ void OpenXRAPI::end_frame() { // release our swapchain image if we acquired it for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { - if (main_swapchains[i].is_image_acquired()) { - main_swapchains[i].release(); + if (render_state.main_swapchains[i].is_image_acquired()) { + render_state.main_swapchains[i].release(); } } - for (uint32_t eye = 0; eye < view_count; eye++) { - projection_views[eye].fov = views[eye].fov; - projection_views[eye].pose = views[eye].pose; + for (uint32_t eye = 0; eye < render_state.view_count; eye++) { + render_state.projection_views[eye].fov = render_state.views[eye].fov; + render_state.projection_views[eye].pose = render_state.views[eye].pose; } Vector<OrderedCompositionLayer> ordered_layers_list; @@ -2210,9 +2352,9 @@ void OpenXRAPI::end_frame() { XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type nullptr, // next layer_flags, // layerFlags - play_space, // space - view_count, // viewCount - projection_views, // views + render_state.play_space, // space + render_state.view_count, // viewCount + render_state.projection_views, // views }; ordered_layers_list.push_back({ (const XrCompositionLayerBaseHeader *)&projection_layer, 0 }); @@ -2228,7 +2370,7 @@ void OpenXRAPI::end_frame() { XrFrameEndInfo frame_end_info = { XR_TYPE_FRAME_END_INFO, // type nullptr, // next - frame_state.predictedDisplayTime, // displayTime + render_state.predicted_display_time, // displayTime environment_blend_mode, // environmentBlendMode static_cast<uint32_t>(layers_list.size()), // layerCount layers_list.ptr() // layers @@ -2271,6 +2413,7 @@ double OpenXRAPI::get_render_target_size_multiplier() const { void OpenXRAPI::set_render_target_size_multiplier(double multiplier) { render_target_size_multiplier = multiplier; + set_render_state_multiplier(multiplier); } bool OpenXRAPI::is_foveation_supported() const { @@ -2414,10 +2557,6 @@ OpenXRAPI::OpenXRAPI() { submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer"); } - - // Reset a few things that can't be done in our class definition. - frame_state.predictedDisplayTime = 0; - frame_state.predictedDisplayPeriod = 0; } OpenXRAPI::~OpenXRAPI() { @@ -2535,10 +2674,23 @@ bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const RID OpenXRAPI::get_tracker_rid(XrPath p_path) { List<RID> current; tracker_owner.get_owned_list(¤t); - for (int i = 0; i < current.size(); i++) { - Tracker *tracker = tracker_owner.get_or_null(current[i]); + for (const RID &E : current) { + Tracker *tracker = tracker_owner.get_or_null(E); if (tracker && tracker->toplevel_path == p_path) { - return current[i]; + return E; + } + } + + return RID(); +} + +RID OpenXRAPI::find_tracker(const String &p_name) { + List<RID> current; + tracker_owner.get_owned_list(¤t); + for (const RID &E : current) { + Tracker *tracker = tracker_owner.get_or_null(E); + if (tracker && tracker->name == p_name) { + return E; } } @@ -2729,10 +2881,23 @@ void OpenXRAPI::action_set_free(RID p_action_set) { RID OpenXRAPI::get_action_rid(XrAction p_action) { List<RID> current; action_owner.get_owned_list(¤t); - for (int i = 0; i < current.size(); i++) { - Action *action = action_owner.get_or_null(current[i]); + for (const RID &E : current) { + Action *action = action_owner.get_or_null(E); if (action && action->handle == p_action) { - return current[i]; + return E; + } + } + + return RID(); +} + +RID OpenXRAPI::find_action(const String &p_name) { + List<RID> current; + action_owner.get_owned_list(¤t); + for (const RID &E : current) { + Action *action = action_owner.get_or_null(E); + if (action && action->name == p_name) { + return E; } } @@ -2833,10 +2998,10 @@ void OpenXRAPI::action_free(RID p_action) { RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) { List<RID> current; interaction_profile_owner.get_owned_list(¤t); - for (int i = 0; i < current.size(); i++) { - InteractionProfile *ip = interaction_profile_owner.get_or_null(current[i]); + for (const RID &E : current) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(E); if (ip && ip->path == p_path) { - return current[i]; + return E; } } @@ -3132,7 +3297,7 @@ XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracke return XRPose::XR_TRACKING_CONFIDENCE_NONE; } - XrTime display_time = get_next_frame_time(); + XrTime display_time = get_predicted_display_time(); if (display_time == 0) { return XRPose::XR_TRACKING_CONFIDENCE_NONE; } diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index e835366200..f9d2e60148 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -46,13 +46,11 @@ #include "core/templates/rb_map.h" #include "core/templates/rid_owner.h" #include "core/templates/vector.h" +#include "servers/rendering_server.h" #include "servers/xr/xr_pose.h" #include <openxr/openxr.h> -// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initializing structs which ensures zeroing out unspecified members. -// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set. - // forward declarations, we don't want to include these fully class OpenXRInterface; @@ -77,7 +75,7 @@ public: static void free_queued(); void free(); - bool acquire(XrBool32 &p_should_render); + bool acquire(bool &p_should_render); bool release(); RID get_image(); }; @@ -151,9 +149,6 @@ private: uint32_t view_count = 0; XrViewConfigurationView *view_configuration_views = nullptr; - XrView *views = nullptr; - XrCompositionLayerProjectionView *projection_views = nullptr; - XrCompositionLayerDepthInfoKHR *depth_views = nullptr; // Only used by Composition Layer Depth Extension if available enum OpenXRSwapChainTypes { OPENXR_SWAPCHAIN_COLOR, @@ -164,14 +159,11 @@ private: int64_t color_swapchain_format = 0; int64_t depth_swapchain_format = 0; - Size2i main_swapchain_size = { 0, 0 }; - OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX]; + bool play_space_is_dirty = true; XrSpace play_space = XR_NULL_HANDLE; XrSpace view_space = XR_NULL_HANDLE; - bool view_pose_valid = false; XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; - bool has_xr_viewport = false; bool emulating_local_floor = false; bool should_reset_emulated_floor_height = false; @@ -328,6 +320,72 @@ private: // convenience void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len); + // Render state, Only accessible in rendering thread + struct RenderState { + bool running = false; + bool should_render = false; + bool has_xr_viewport = false; + XrTime predicted_display_time = 0; + XrSpace play_space = XR_NULL_HANDLE; + double render_target_size_multiplier = 1.0; + + uint32_t view_count = 0; + XrView *views = nullptr; + XrCompositionLayerProjectionView *projection_views = nullptr; + XrCompositionLayerDepthInfoKHR *depth_views = nullptr; // Only used by Composition Layer Depth Extension if available + bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled. + bool view_pose_valid = false; + + Size2i main_swapchain_size; + OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX]; + } render_state; + + static void _allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer); + static void _set_render_session_running(bool p_is_running); + static void _set_render_display_info(XrTime p_predicted_display_time, bool p_should_render); + static void _set_render_play_space(uint64_t p_play_space); + static void _set_render_state_multiplier(double p_render_target_size_multiplier); + + _FORCE_INLINE_ void allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) { + // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_allocate_view_buffers).bind(p_view_count, p_submit_depth_buffer)); + } + + _FORCE_INLINE_ void set_render_session_running(bool p_is_running) { + // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_session_running).bind(p_is_running)); + } + + _FORCE_INLINE_ void set_render_display_info(XrTime p_predicted_display_time, bool p_should_render) { + // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_display_info).bind(p_predicted_display_time, p_should_render)); + } + + _FORCE_INLINE_ void set_render_play_space(XrSpace p_play_space) { + // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_play_space).bind(uint64_t(p_play_space))); + } + + _FORCE_INLINE_ void set_render_state_multiplier(double p_render_target_size_multiplier) { + // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_multiplier).bind(p_render_target_size_multiplier)); + } + public: XrInstance get_instance() const { return instance; }; XrSystemId get_system_id() const { return system_id; }; @@ -384,9 +442,13 @@ public: bool initialize_session(); void finish(); - XrSpace get_play_space() const { return play_space; } - XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; } - bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; } + _FORCE_INLINE_ XrSpace get_play_space() const { return play_space; } + _FORCE_INLINE_ XrTime get_predicted_display_time() { return frame_state.predictedDisplayTime; } + _FORCE_INLINE_ XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; } + _FORCE_INLINE_ bool can_render() { + ERR_ON_RENDER_THREAD_V(false); + return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && frame_state.shouldRender; + } XrHandTrackerEXT get_hand_tracker(int p_hand_index); @@ -394,6 +456,7 @@ public: XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); bool get_view_transform(uint32_t p_view, Transform3D &r_transform); bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix); + Vector2 get_eye_focus(uint32_t p_view, float p_aspect); bool process(); void pre_render(); @@ -453,6 +516,9 @@ public: bool interaction_profile_suggest_bindings(RID p_interaction_profile); void interaction_profile_free(RID p_interaction_profile); + RID find_tracker(const String &p_name); + RID find_action(const String &p_name); + bool sync_action_sets(const Vector<RID> p_active_sets); bool get_action_bool(RID p_action, RID p_tracker); float get_action_float(RID p_action, RID p_tracker); diff --git a/modules/openxr/openxr_api_extension.cpp b/modules/openxr/openxr_api_extension.cpp index fae0fc13d3..a1744fa1db 100644 --- a/modules/openxr/openxr_api_extension.cpp +++ b/modules/openxr/openxr_api_extension.cpp @@ -48,6 +48,7 @@ void OpenXRAPIExtension::_bind_methods() { ClassDB::bind_method(D_METHOD("is_running"), &OpenXRAPIExtension::is_running); ClassDB::bind_method(D_METHOD("get_play_space"), &OpenXRAPIExtension::get_play_space); + ClassDB::bind_method(D_METHOD("get_predicted_display_time"), &OpenXRAPIExtension::get_predicted_display_time); ClassDB::bind_method(D_METHOD("get_next_frame_time"), &OpenXRAPIExtension::get_next_frame_time); ClassDB::bind_method(D_METHOD("can_render"), &OpenXRAPIExtension::can_render); @@ -130,8 +131,17 @@ uint64_t OpenXRAPIExtension::get_play_space() { return (uint64_t)OpenXRAPI::get_singleton()->get_play_space(); } +int64_t OpenXRAPIExtension::get_predicted_display_time() { + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0); + return (XrTime)OpenXRAPI::get_singleton()->get_predicted_display_time(); +} + int64_t OpenXRAPIExtension::get_next_frame_time() { ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0); + + // In the past we needed to look a frame ahead, may be calling this unintentionally so lets warn the dev. + WARN_PRINT_ONCE("OpenXR: Next frame timing called, verify this is intended."); + return (XrTime)OpenXRAPI::get_singleton()->get_next_frame_time(); } diff --git a/modules/openxr/openxr_api_extension.h b/modules/openxr/openxr_api_extension.h index 576e497798..cff2c4738e 100644 --- a/modules/openxr/openxr_api_extension.h +++ b/modules/openxr/openxr_api_extension.h @@ -69,6 +69,7 @@ public: bool is_running(); uint64_t get_play_space(); + int64_t get_predicted_display_time(); int64_t get_next_frame_time(); bool can_render(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index aa68441f03..fbbc61a91c 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -35,6 +35,7 @@ #include "servers/rendering/rendering_server_globals.h" #include "extensions/openxr_eye_gaze_interaction.h" +#include "extensions/openxr_hand_interaction_extension.h" #include "thirdparty/openxr/include/openxr/openxr.h" void OpenXRInterface::_bind_methods() { @@ -43,6 +44,8 @@ void OpenXRInterface::_bind_methods() { ADD_SIGNAL(MethodInfo("session_stopping")); ADD_SIGNAL(MethodInfo("session_focussed")); ADD_SIGNAL(MethodInfo("session_visible")); + ADD_SIGNAL(MethodInfo("session_loss_pending")); + ADD_SIGNAL(MethodInfo("instance_exiting")); ADD_SIGNAL(MethodInfo("pose_recentered")); ADD_SIGNAL(MethodInfo("refresh_rate_changed", PropertyInfo(Variant::FLOAT, "refresh_rate"))); @@ -91,8 +94,19 @@ void OpenXRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_hand_joint_angular_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_angular_velocity); ClassDB::bind_method(D_METHOD("is_hand_tracking_supported"), &OpenXRInterface::is_hand_tracking_supported); + ClassDB::bind_method(D_METHOD("is_hand_interaction_supported"), &OpenXRInterface::is_hand_interaction_supported); ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported); + // VRS + ClassDB::bind_method(D_METHOD("get_vrs_min_radius"), &OpenXRInterface::get_vrs_min_radius); + ClassDB::bind_method(D_METHOD("set_vrs_min_radius", "radius"), &OpenXRInterface::set_vrs_min_radius); + ClassDB::bind_method(D_METHOD("get_vrs_strength"), &OpenXRInterface::get_vrs_strength); + ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &OpenXRInterface::set_vrs_strength); + + ADD_GROUP("Vulkan VRS", "vrs_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_min_radius", PROPERTY_HINT_RANGE, "1.0,100.0,1.0"), "set_vrs_min_radius", "get_vrs_min_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); + BIND_ENUM_CONSTANT(HAND_LEFT); BIND_ENUM_CONSTANT(HAND_RIGHT); BIND_ENUM_CONSTANT(HAND_MAX); @@ -377,7 +391,7 @@ OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set, // we link our actions back to our trackers so we know which actions to check when we're processing our trackers for (int i = 0; i < p_trackers.size(); i++) { - if (p_trackers[i]->actions.find(action) == -1) { + if (!p_trackers[i]->actions.has(action)) { p_trackers[i]->actions.push_back(action); } } @@ -806,6 +820,21 @@ bool OpenXRInterface::is_hand_tracking_supported() { } } +bool OpenXRInterface::is_hand_interaction_supported() const { + if (openxr_api == nullptr) { + return false; + } else if (!openxr_api->is_initialized()) { + return false; + } else { + OpenXRHandInteractionExtension *hand_interaction_ext = OpenXRHandInteractionExtension::get_singleton(); + if (hand_interaction_ext == nullptr) { + return false; + } else { + return hand_interaction_ext->is_available(); + } + } +} + bool OpenXRInterface::is_eye_gaze_interaction_supported() { if (openxr_api == nullptr) { return false; @@ -853,6 +882,22 @@ Array OpenXRInterface::get_action_sets() const { return arr; } +float OpenXRInterface::get_vrs_min_radius() const { + return xr_vrs.get_vrs_min_radius(); +} + +void OpenXRInterface::set_vrs_min_radius(float p_vrs_min_radius) { + xr_vrs.set_vrs_min_radius(p_vrs_min_radius); +} + +float OpenXRInterface::get_vrs_strength() const { + return xr_vrs.get_vrs_strength(); +} + +void OpenXRInterface::set_vrs_strength(float p_vrs_strength) { + xr_vrs.set_vrs_strength(p_vrs_strength); +} + double OpenXRInterface::get_render_target_size_multiplier() const { if (openxr_api == nullptr) { return 1.0; @@ -1258,6 +1303,14 @@ void OpenXRInterface::on_state_stopping() { emit_signal(SNAME("session_stopping")); } +void OpenXRInterface::on_state_loss_pending() { + emit_signal(SNAME("session_loss_pending")); +} + +void OpenXRInterface::on_state_exiting() { + emit_signal(SNAME("instance_exiting")); +} + void OpenXRInterface::on_pose_recentered() { emit_signal(SNAME("pose_recentered")); } @@ -1408,6 +1461,24 @@ Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints return Vector3(); } +RID OpenXRInterface::get_vrs_texture() { + if (!openxr_api) { + return RID(); + } + + PackedVector2Array eye_foci; + + Size2 target_size = get_render_target_size(); + real_t aspect_ratio = target_size.x / target_size.y; + uint32_t view_count = get_view_count(); + + for (uint32_t v = 0; v < view_count; v++) { + eye_foci.push_back(openxr_api->get_eye_focus(v, aspect_ratio)); + } + + return xr_vrs.make_vrs_texture(target_size, eye_foci); +} + OpenXRInterface::OpenXRInterface() { openxr_api = OpenXRAPI::get_singleton(); if (openxr_api) { diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index e916c7dac2..f0ee0dc3c4 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -31,6 +31,29 @@ #ifndef OPENXR_INTERFACE_H #define OPENXR_INTERFACE_H +// A note on multithreading and thread safety in OpenXR. +// +// Most entry points will be called from the main thread in Godot +// however a number of entry points will be called from the +// rendering thread, potentially while we're already processing +// the next frame on the main thread. +// +// OpenXR itself has been designed with threading in mind including +// a high likelihood that the XR runtime runs in separate threads +// as well. +// Hence all the frame timing information, use of swapchains and +// sync functions. +// Do note that repeated calls to tracking APIs will provide +// increasingly more accurate data for the same timestamp as +// tracking data is continuously updated. +// +// For our code we mostly implement this in our OpenXRAPI class. +// We store data accessed from the rendering thread in a separate +// struct, setting values through our renderer command queue. +// +// As some data is setup before we start rendering, and cleaned up +// after we've stopped, that is accessed directly from both threads. + #include "action_map/openxr_action_map.h" #include "extensions/openxr_hand_tracking_extension.h" #include "openxr_api.h" @@ -57,6 +80,8 @@ private: XRPose::TrackingConfidence head_confidence; Transform3D transform_for_view[2]; // We currently assume 2, but could be 4 for VARJO which we do not support yet + XRVRS xr_vrs; + void _load_action_map(); struct Action { // An action we've registered with OpenXR @@ -110,6 +135,7 @@ public: virtual TrackingStatus get_tracking_status() const override; bool is_hand_tracking_supported(); + bool is_hand_interaction_supported() const; bool is_eye_gaze_interaction_supported(); bool initialize_on_startup() const; @@ -144,6 +170,12 @@ public: bool get_foveation_dynamic() const; void set_foveation_dynamic(bool p_foveation_dynamic); + float get_vrs_min_radius() const; + void set_vrs_min_radius(float p_vrs_min_radius); + + float get_vrs_strength() const; + void set_vrs_strength(float p_vrs_strength); + virtual Size2 get_render_target_size() override; virtual uint32_t get_view_count() override; virtual Transform3D get_camera_transform() override; @@ -173,6 +205,8 @@ public: void on_state_visible(); void on_state_focused(); void on_state_stopping(); + void on_state_loss_pending(); + void on_state_exiting(); void on_pose_recentered(); void on_refresh_rate_changes(float p_new_rate); void tracker_profile_changed(RID p_tracker, RID p_interaction_profile); @@ -250,6 +284,8 @@ public: Vector3 get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const; Vector3 get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const; + virtual RID get_vrs_texture() override; + OpenXRInterface(); ~OpenXRInterface(); }; diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index eb0527f07c..85514737f2 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -49,6 +49,7 @@ #include "extensions/openxr_composition_layer_extension.h" #include "extensions/openxr_eye_gaze_interaction.h" #include "extensions/openxr_fb_display_refresh_rate_extension.h" +#include "extensions/openxr_hand_interaction_extension.h" #include "extensions/openxr_hand_tracking_extension.h" #include "extensions/openxr_htc_controller_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" @@ -124,6 +125,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRMetaControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXREyeGazeInteractionExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandInteractionExtension)); // register gated extensions if (GLOBAL_GET("xr/openxr/extensions/hand_tracking")) { diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp index ce883b79b3..50cc7b9e7b 100644 --- a/modules/openxr/scene/openxr_composition_layer.cpp +++ b/modules/openxr/scene/openxr_composition_layer.cpp @@ -38,7 +38,14 @@ #include "scene/3d/xr_nodes.h" #include "scene/main/viewport.h" -HashSet<SubViewport *> OpenXRCompositionLayer::viewports_in_use; +Vector<OpenXRCompositionLayer *> OpenXRCompositionLayer::composition_layer_nodes; + +static const char *HOLE_PUNCH_SHADER_CODE = + "shader_type spatial;\n" + "render_mode blend_mix, depth_draw_opaque, cull_back, shadow_to_opacity, shadows_disabled;\n" + "void fragment() {\n" + "\tALBEDO = vec3(0.0, 0.0, 0.0);\n" + "}\n"; OpenXRCompositionLayer::OpenXRCompositionLayer() { openxr_api = OpenXRAPI::get_singleton(); @@ -66,9 +73,7 @@ OpenXRCompositionLayer::~OpenXRCompositionLayer() { openxr_interface->disconnect("session_stopping", callable_mp(this, &OpenXRCompositionLayer::_on_openxr_session_stopping)); } - if (layer_viewport) { - viewports_in_use.erase(layer_viewport); - } + composition_layer_nodes.erase(this); if (openxr_layer_provider != nullptr) { memdelete(openxr_layer_provider); @@ -80,6 +85,9 @@ void OpenXRCompositionLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer_viewport", "viewport"), &OpenXRCompositionLayer::set_layer_viewport); ClassDB::bind_method(D_METHOD("get_layer_viewport"), &OpenXRCompositionLayer::get_layer_viewport); + ClassDB::bind_method(D_METHOD("set_enable_hole_punch", "enable"), &OpenXRCompositionLayer::set_enable_hole_punch); + ClassDB::bind_method(D_METHOD("get_enable_hole_punch"), &OpenXRCompositionLayer::get_enable_hole_punch); + ClassDB::bind_method(D_METHOD("set_sort_order", "order"), &OpenXRCompositionLayer::set_sort_order); ClassDB::bind_method(D_METHOD("get_sort_order"), &OpenXRCompositionLayer::get_sort_order); @@ -93,6 +101,16 @@ void OpenXRCompositionLayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_hole_punch", PROPERTY_HINT_NONE, ""), "set_enable_hole_punch", "get_enable_hole_punch"); +} + +bool OpenXRCompositionLayer::_should_use_fallback_node() { + if (Engine::get_singleton()->is_editor_hint()) { + return true; + } else if (openxr_session_running) { + return enable_hole_punch || !is_natively_supported(); + } + return false; } void OpenXRCompositionLayer::_create_fallback_node() { @@ -103,21 +121,27 @@ void OpenXRCompositionLayer::_create_fallback_node() { should_update_fallback_mesh = true; } +void OpenXRCompositionLayer::_remove_fallback_node() { + ERR_FAIL_COND(fallback != nullptr); + remove_child(fallback); + fallback->queue_free(); + fallback = nullptr; +} + void OpenXRCompositionLayer::_on_openxr_session_begun() { - if (!is_natively_supported()) { - if (!fallback) { - _create_fallback_node(); - } - } else if (layer_viewport && is_visible() && is_inside_tree()) { + openxr_session_running = true; + if (layer_viewport && is_natively_supported() && is_visible() && is_inside_tree()) { openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); } + if (!fallback && _should_use_fallback_node()) { + _create_fallback_node(); + } } void OpenXRCompositionLayer::_on_openxr_session_stopping() { - if (fallback && !Engine::get_singleton()->is_editor_hint()) { - fallback->queue_free(); - remove_child(fallback); - fallback = nullptr; + openxr_session_running = false; + if (fallback && !_should_use_fallback_node()) { + _remove_fallback_node(); } else { openxr_layer_provider->set_viewport(RID(), Size2i()); } @@ -127,22 +151,25 @@ void OpenXRCompositionLayer::update_fallback_mesh() { should_update_fallback_mesh = true; } +bool OpenXRCompositionLayer::is_viewport_in_use(SubViewport *p_viewport) { + for (const OpenXRCompositionLayer *other_composition_layer : composition_layer_nodes) { + if (other_composition_layer != this && other_composition_layer->is_inside_tree() && other_composition_layer->get_layer_viewport() == p_viewport) { + return true; + } + } + return false; +} + void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) { if (layer_viewport == p_viewport) { return; } - ERR_FAIL_COND_EDMSG(viewports_in_use.has(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first.")); - - if (layer_viewport) { - viewports_in_use.erase(layer_viewport); - } + ERR_FAIL_COND_EDMSG(is_viewport_in_use(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first.")); layer_viewport = p_viewport; if (layer_viewport) { - viewports_in_use.insert(layer_viewport); - SubViewport::UpdateMode update_mode = layer_viewport->get_update_mode(); if (update_mode == SubViewport::UPDATE_WHEN_VISIBLE || update_mode == SubViewport::UPDATE_WHEN_PARENT_VISIBLE) { WARN_PRINT_ONCE("OpenXR composition layers cannot use SubViewports with UPDATE_WHEN_VISIBLE or UPDATE_WHEN_PARENT_VISIBLE. Switching to UPDATE_ALWAYS."); @@ -152,7 +179,7 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) { if (fallback) { _reset_fallback_material(); - } else if (openxr_api && openxr_api->is_running() && is_visible() && is_inside_tree()) { + } else if (openxr_session_running && is_visible() && is_inside_tree()) { if (layer_viewport) { openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); } else { @@ -165,9 +192,33 @@ SubViewport *OpenXRCompositionLayer::get_layer_viewport() const { return layer_viewport; } +void OpenXRCompositionLayer::set_enable_hole_punch(bool p_enable) { + if (enable_hole_punch == p_enable) { + return; + } + + enable_hole_punch = p_enable; + if (_should_use_fallback_node()) { + if (fallback) { + _reset_fallback_material(); + } else { + _create_fallback_node(); + } + } else if (fallback) { + _remove_fallback_node(); + } + + update_configuration_warnings(); +} + +bool OpenXRCompositionLayer::get_enable_hole_punch() const { + return enable_hole_punch; +} + void OpenXRCompositionLayer::set_sort_order(int p_order) { if (openxr_layer_provider) { openxr_layer_provider->set_sort_order(p_order); + update_configuration_warnings(); } } @@ -212,15 +263,28 @@ void OpenXRCompositionLayer::_reset_fallback_material() { return; } - if (layer_viewport) { + if (enable_hole_punch && !Engine::get_singleton()->is_editor_hint() && is_natively_supported()) { + Ref<ShaderMaterial> material = fallback->get_surface_override_material(0); + if (material.is_null()) { + Ref<Shader> shader; + shader.instantiate(); + shader->set_code(HOLE_PUNCH_SHADER_CODE); + + material.instantiate(); + material->set_shader(shader); + + fallback->set_surface_override_material(0, material); + } + } else if (layer_viewport) { Ref<StandardMaterial3D> material = fallback->get_surface_override_material(0); if (material.is_null()) { material.instantiate(); material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true); material->set_local_to_scene(true); fallback->set_surface_override_material(0, material); } + + material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, !enable_hole_punch); material->set_transparency(get_alpha_blend() ? StandardMaterial3D::TRANSPARENCY_ALPHA : StandardMaterial3D::TRANSPARENCY_DISABLED); Ref<ViewportTexture> texture = material->get_texture(StandardMaterial3D::TEXTURE_ALBEDO); @@ -243,6 +307,8 @@ void OpenXRCompositionLayer::_reset_fallback_material() { void OpenXRCompositionLayer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_POSTINITIALIZE: { + composition_layer_nodes.push_back(this); + if (openxr_layer_provider) { for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { extension_property_values.merge(extension->get_viewport_composition_layer_extension_property_defaults()); @@ -260,7 +326,7 @@ void OpenXRCompositionLayer::_notification(int p_what) { } } break; case NOTIFICATION_VISIBILITY_CHANGED: { - if (!fallback && openxr_api && openxr_api->is_running() && is_inside_tree()) { + if (!fallback && openxr_session_running && is_inside_tree()) { if (layer_viewport && is_visible()) { openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); } else { @@ -277,7 +343,9 @@ void OpenXRCompositionLayer::_notification(int p_what) { composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider); } - if (!fallback && layer_viewport && openxr_api && openxr_api->is_running() && is_visible()) { + if (is_viewport_in_use(layer_viewport)) { + set_layer_viewport(nullptr); + } else if (!fallback && layer_viewport && openxr_session_running && is_visible()) { openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); } } break; @@ -286,12 +354,7 @@ void OpenXRCompositionLayer::_notification(int p_what) { composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider); } - // When a node is removed in the editor, we need to clear the layer viewport, because otherwise - // there will be issues with the tracking in viewports_in_use, since nodes deleted in the editor - // aren't really deleted in order to support undo. - if (Engine::get_singleton()->is_editor_hint() && layer_viewport) { - set_layer_viewport(nullptr); - } else if (!fallback) { + if (!fallback) { // This will clean up existing resources. openxr_layer_provider->set_viewport(RID(), Size2i()); } @@ -347,5 +410,9 @@ PackedStringArray OpenXRCompositionLayer::get_configuration_warnings() const { warnings.push_back(RTR("OpenXR composition layers must have orthonormalized transforms (ie. no scale or shearing).")); } + if (enable_hole_punch && get_sort_order() >= 0) { + warnings.push_back(RTR("Hole punching won't work as expected unless the sort order is less than zero.")); + } + return warnings; } diff --git a/modules/openxr/scene/openxr_composition_layer.h b/modules/openxr/scene/openxr_composition_layer.h index 9f064379d3..6792364295 100644 --- a/modules/openxr/scene/openxr_composition_layer.h +++ b/modules/openxr/scene/openxr_composition_layer.h @@ -46,13 +46,17 @@ class OpenXRCompositionLayer : public Node3D { GDCLASS(OpenXRCompositionLayer, Node3D); SubViewport *layer_viewport = nullptr; + bool enable_hole_punch = false; MeshInstance3D *fallback = nullptr; bool should_update_fallback_mesh = false; + bool openxr_session_running = false; Dictionary extension_property_values; + bool _should_use_fallback_node(); void _create_fallback_node(); void _reset_fallback_material(); + void _remove_fallback_node(); protected: OpenXRAPI *openxr_api = nullptr; @@ -73,12 +77,16 @@ protected: void update_fallback_mesh(); - static HashSet<SubViewport *> viewports_in_use; + static Vector<OpenXRCompositionLayer *> composition_layer_nodes; + bool is_viewport_in_use(SubViewport *p_viewport); public: void set_layer_viewport(SubViewport *p_viewport); SubViewport *get_layer_viewport() const; + void set_enable_hole_punch(bool p_enable); + bool get_enable_hole_punch() const; + void set_sort_order(int p_order); int get_sort_order() const; diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp index ae5a8da5f3..728ba71006 100644 --- a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp +++ b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp @@ -76,13 +76,6 @@ void OpenXRCompositionLayerCylinder::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_segments", PROPERTY_HINT_NONE, ""), "set_fallback_segments", "get_fallback_segments"); } -void OpenXRCompositionLayerCylinder::_on_openxr_session_begun() { - OpenXRCompositionLayer::_on_openxr_session_begun(); - if (openxr_api) { - composition_layer.space = openxr_api->get_play_space(); - } -} - Ref<Mesh> OpenXRCompositionLayerCylinder::_create_fallback_mesh() { Ref<ArrayMesh> mesh; mesh.instantiate(); diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.h b/modules/openxr/scene/openxr_composition_layer_cylinder.h index aed0fabd78..bb1d242267 100644 --- a/modules/openxr/scene/openxr_composition_layer_cylinder.h +++ b/modules/openxr/scene/openxr_composition_layer_cylinder.h @@ -50,7 +50,6 @@ protected: void _notification(int p_what); - virtual void _on_openxr_session_begun() override; virtual Ref<Mesh> _create_fallback_mesh() override; public: diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.cpp b/modules/openxr/scene/openxr_composition_layer_equirect.cpp index d67e71443c..14cfea8da6 100644 --- a/modules/openxr/scene/openxr_composition_layer_equirect.cpp +++ b/modules/openxr/scene/openxr_composition_layer_equirect.cpp @@ -81,13 +81,6 @@ void OpenXRCompositionLayerEquirect::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_segments", PROPERTY_HINT_NONE, ""), "set_fallback_segments", "get_fallback_segments"); } -void OpenXRCompositionLayerEquirect::_on_openxr_session_begun() { - OpenXRCompositionLayer::_on_openxr_session_begun(); - if (openxr_api) { - composition_layer.space = openxr_api->get_play_space(); - } -} - Ref<Mesh> OpenXRCompositionLayerEquirect::_create_fallback_mesh() { Ref<ArrayMesh> mesh; mesh.instantiate(); diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.h b/modules/openxr/scene/openxr_composition_layer_equirect.h index 7a002a48dc..66f8b0a91c 100644 --- a/modules/openxr/scene/openxr_composition_layer_equirect.h +++ b/modules/openxr/scene/openxr_composition_layer_equirect.h @@ -51,7 +51,6 @@ protected: void _notification(int p_what); - virtual void _on_openxr_session_begun() override; virtual Ref<Mesh> _create_fallback_mesh() override; public: diff --git a/modules/openxr/scene/openxr_composition_layer_quad.cpp b/modules/openxr/scene/openxr_composition_layer_quad.cpp index 17d57851e4..8c5b8ec26b 100644 --- a/modules/openxr/scene/openxr_composition_layer_quad.cpp +++ b/modules/openxr/scene/openxr_composition_layer_quad.cpp @@ -62,13 +62,6 @@ void OpenXRCompositionLayerQuad::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "quad_size", PROPERTY_HINT_NONE, ""), "set_quad_size", "get_quad_size"); } -void OpenXRCompositionLayerQuad::_on_openxr_session_begun() { - OpenXRCompositionLayer::_on_openxr_session_begun(); - if (openxr_api) { - composition_layer.space = openxr_api->get_play_space(); - } -} - Ref<Mesh> OpenXRCompositionLayerQuad::_create_fallback_mesh() { Ref<QuadMesh> mesh; mesh.instantiate(); diff --git a/modules/openxr/scene/openxr_composition_layer_quad.h b/modules/openxr/scene/openxr_composition_layer_quad.h index d88b596984..21bb9b2d85 100644 --- a/modules/openxr/scene/openxr_composition_layer_quad.h +++ b/modules/openxr/scene/openxr_composition_layer_quad.h @@ -47,7 +47,6 @@ protected: void _notification(int p_what); - virtual void _on_openxr_session_begun() override; virtual Ref<Mesh> _create_fallback_mesh() override; public: diff --git a/modules/raycast/config.py b/modules/raycast/config.py index 26329d813a..0fd35af528 100644 --- a/modules/raycast/config.py +++ b/modules/raycast/config.py @@ -1,8 +1,9 @@ def can_build(env, platform): - # Supported architectures depend on the Embree library. + # Supported architectures and platforms depend on the Embree library. + if env["arch"] == "arm64" and platform == "windows": + return False if env["arch"] in ["x86_64", "arm64", "wasm32"]: return True - # x86_32 only seems supported on Windows for now. if env["arch"] == "x86_32" and platform == "windows": return True return False diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 4a1037431a..9f34a6ca6a 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -370,7 +370,7 @@ PackedStringArray RegEx::get_names() const { for (uint32_t i = 0; i < count; i++) { String name = &table[i * entry_size + 1]; - if (result.find(name) < 0) { + if (!result.has(name)) { result.append(name); } } diff --git a/modules/svg/SCsub b/modules/svg/SCsub index ff0c3c9141..a32be0e41a 100644 --- a/modules/svg/SCsub +++ b/modules/svg/SCsub @@ -12,8 +12,8 @@ thirdparty_obj = [] thirdparty_dir = "#thirdparty/thorvg/" thirdparty_sources = [ # common - "src/common/tvgBezier.cpp", "src/common/tvgCompressor.cpp", + "src/common/tvgLines.cpp", "src/common/tvgMath.cpp", "src/common/tvgStr.cpp", # SVG parser @@ -24,6 +24,7 @@ thirdparty_sources = [ "src/loaders/svg/tvgSvgUtil.cpp", "src/loaders/svg/tvgXmlParser.cpp", "src/loaders/raw/tvgRawLoader.cpp", + # image loaders "src/loaders/external_png/tvgPngLoader.cpp", "src/loaders/jpg/tvgJpgd.cpp", "src/loaders/jpg/tvgJpgLoader.cpp", @@ -57,6 +58,10 @@ thirdparty_sources = [ "src/renderer/sw_engine/tvgSwStroke.cpp", ] +if env["module_webp_enabled"]: + thirdparty_sources += ["src/loaders/external_webp/tvgWebpLoader.cpp"] + env_svg.Append(CPPDEFINES=["THORVG_WEBP_LOADER_SUPPORT"]) + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_svg.Prepend(CPPPATH=[thirdparty_dir + "inc"]) @@ -77,6 +82,12 @@ env_thirdparty.Prepend( thirdparty_dir + "src/loaders/jpg", ] ) +if env["builtin_libpng"]: + env_thirdparty.Prepend(CPPPATH=["#thirdparty/libpng"]) +if env["module_webp_enabled"]: + env_thirdparty.Prepend(CPPPATH=[thirdparty_dir + "src/loaders/external_webp"]) + if env["builtin_libwebp"]: + env_thirdparty.Prepend(CPPPATH=["#thirdparty/libwebp/src"]) env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) env.modules_sources += thirdparty_obj diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 15695476de..68a5d499d4 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -468,7 +468,7 @@ if env["builtin_icu4c"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - icu_data_name = "icudt74l.dat" + icu_data_name = "icudt75l.dat" if env.editor_build: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 1d9d36fbbf..018984a52f 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -1,10 +1,20 @@ #!/usr/bin/env python import atexit -import os import sys import methods import time +# Enable ANSI escape code support on Windows 10 and later (for colored console output). +# <https://github.com/python/cpython/issues/73245> +if sys.platform == "win32": + from ctypes import windll, c_int, byref + + stdout_handle = windll.kernel32.GetStdHandle(c_int(-11)) + mode = c_int(0) + windll.kernel32.GetConsoleMode(c_int(stdout_handle), byref(mode)) + mode = c_int(mode.value | 4) + windll.kernel32.SetConsoleMode(c_int(stdout_handle), mode) + # For the reference: # - CCFLAGS are compilation flags shared between C and C++ # - CFLAGS are for C-specific compilation flags @@ -30,7 +40,7 @@ opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", Fa opts.Update(env) if not env["verbose"]: - methods.no_verbose(sys, env) + methods.no_verbose(env) if env["platform"] == "windows" and not env["use_mingw"]: env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. @@ -693,7 +703,7 @@ thirdparty_icu_sources = [ ] thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources] -icu_data_name = "icudt74l.dat" +icu_data_name = "icudt75l.dat" if env["static_icu_data"]: env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name) @@ -764,9 +774,16 @@ Default(library) def print_elapsed_time(): - elapsed_time_sec = round(time.time() - time_at_start, 3) - time_ms = round((elapsed_time_sec % 1) * 1000) - print("[Time elapsed: {}.{:03}]".format(time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), time_ms)) + elapsed_time_sec = round(time.time() - time_at_start, 2) + time_centiseconds = round((elapsed_time_sec % 1) * 100) + print( + "{}[Time elapsed: {}.{:02}]{}".format( + methods.ANSI.GRAY, + time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), + time_centiseconds, + methods.ANSI.RESET, + ) + ) atexit.register(print_elapsed_time) diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py index 32dbc59fd4..3453c3e8f0 100644 --- a/modules/text_server_adv/gdextension_build/methods.py +++ b/modules/text_server_adv/gdextension_build/methods.py @@ -1,66 +1,75 @@ import os import sys +from enum import Enum +# Colors are disabled in non-TTY environments such as pipes. This means +# that if output is redirected to a file, it won't contain color codes. +# Colors are always enabled on continuous integration. +_colorize = bool(sys.stdout.isatty() or os.environ.get("CI")) -def no_verbose(sys, env): - colors = {} - # Colors are disabled in non-TTY environments such as pipes. This means - # that if output is redirected to a file, it will not contain color codes - if sys.stdout.isatty(): - colors["blue"] = "\033[0;94m" - colors["bold_blue"] = "\033[1;94m" - colors["reset"] = "\033[0m" - else: - colors["blue"] = "" - colors["bold_blue"] = "" - colors["reset"] = "" +class ANSI(Enum): + """ + Enum class for adding ansi colorcodes directly into strings. + Automatically converts values to strings representing their + internal value, or an empty string in a non-colorized scope. + """ + + RESET = "\x1b[0m" + + BOLD = "\x1b[1m" + ITALIC = "\x1b[3m" + UNDERLINE = "\x1b[4m" + STRIKETHROUGH = "\x1b[9m" + REGULAR = "\x1b[22;23;24;29m" + + BLACK = "\x1b[30m" + RED = "\x1b[31m" + GREEN = "\x1b[32m" + YELLOW = "\x1b[33m" + BLUE = "\x1b[34m" + MAGENTA = "\x1b[35m" + CYAN = "\x1b[36m" + WHITE = "\x1b[37m" + + PURPLE = "\x1b[38;5;93m" + PINK = "\x1b[38;5;206m" + ORANGE = "\x1b[38;5;214m" + GRAY = "\x1b[38;5;244m" + + def __str__(self) -> str: + global _colorize + return str(self.value) if _colorize else "" + + +def no_verbose(env): + colors = [ANSI.BLUE, ANSI.BOLD, ANSI.REGULAR, ANSI.RESET] # There is a space before "..." to ensure that source file names can be # Ctrl + clicked in the VS Code terminal. - compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - link_program_message = "{}Linking Program {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - generated_file_message = "{}Generating {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - - env.Append(CXXCOMSTR=[compile_source_message]) - env.Append(CCCOMSTR=[compile_source_message]) - env.Append(SHCCCOMSTR=[compile_shared_source_message]) - env.Append(SHCXXCOMSTR=[compile_shared_source_message]) - env.Append(ARCOMSTR=[link_library_message]) - env.Append(RANLIBCOMSTR=[ranlib_library_message]) - env.Append(SHLINKCOMSTR=[link_shared_library_message]) - env.Append(LINKCOMSTR=[link_program_message]) - env.Append(JARCOMSTR=[java_library_message]) - env.Append(JAVACCOMSTR=[java_compile_source_message]) - env.Append(RCCOMSTR=[compiled_resource_message]) - env.Append(GENCOMSTR=[generated_file_message]) + compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors) + java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors) + compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(*colors) + link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(*colors) + link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(*colors) + ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(*colors) + link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(*colors) + java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(*colors) + compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(*colors) + generated_file_message = "{}Generating {}$TARGET{} ...{}".format(*colors) + + env["CXXCOMSTR"] = compile_source_message + env["CCCOMSTR"] = compile_source_message + env["SHCCCOMSTR"] = compile_shared_source_message + env["SHCXXCOMSTR"] = compile_shared_source_message + env["ARCOMSTR"] = link_library_message + env["RANLIBCOMSTR"] = ranlib_library_message + env["SHLINKCOMSTR"] = link_shared_library_message + env["LINKCOMSTR"] = link_program_message + env["JARCOMSTR"] = java_library_message + env["JAVACCOMSTR"] = java_compile_source_message + env["RCCOMSTR"] = compiled_resource_message + env["GENCOMSTR"] = generated_file_message def disable_warnings(self): diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 1ed335fe99..09a037fd28 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -7342,6 +7342,16 @@ bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const { return true; } +bool TextServerAdvanced::_is_valid_letter(char32_t p_unicode) const { +#ifndef ICU_STATIC_DATA + if (!icu_data_loaded) { + return TextServer::is_valid_letter(p_unicode); + } +#endif + + return u_isalpha(p_unicode); +} + TextServerAdvanced::TextServerAdvanced() { _insert_num_systems_lang(); _insert_feature_sets(); diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 1cd73a6999..8895a83089 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -389,54 +389,54 @@ class TextServerAdvanced : public TextServerExtension { _FORCE_INLINE_ bool _get_tag_hidden(int64_t p_tag) const; _FORCE_INLINE_ int _font_get_weight_by_name(const String &p_sty_name) const { String sty_name = p_sty_name.replace(" ", "").replace("-", ""); - if (sty_name.find("thin") >= 0 || sty_name.find("hairline") >= 0) { + if (sty_name.contains("thin") || sty_name.contains("hairline")) { return 100; - } else if (sty_name.find("extralight") >= 0 || sty_name.find("ultralight") >= 0) { + } else if (sty_name.contains("extralight") || sty_name.contains("ultralight")) { return 200; - } else if (sty_name.find("light") >= 0) { + } else if (sty_name.contains("light")) { return 300; - } else if (sty_name.find("semilight") >= 0) { + } else if (sty_name.contains("semilight")) { return 350; - } else if (sty_name.find("regular") >= 0) { + } else if (sty_name.contains("regular")) { return 400; - } else if (sty_name.find("medium") >= 0) { + } else if (sty_name.contains("medium")) { return 500; - } else if (sty_name.find("semibold") >= 0 || sty_name.find("demibold") >= 0) { + } else if (sty_name.contains("semibold") || sty_name.contains("demibold")) { return 600; - } else if (sty_name.find("bold") >= 0) { + } else if (sty_name.contains("bold")) { return 700; - } else if (sty_name.find("extrabold") >= 0 || sty_name.find("ultrabold") >= 0) { + } else if (sty_name.contains("extrabold") || sty_name.contains("ultrabold")) { return 800; - } else if (sty_name.find("black") >= 0 || sty_name.find("heavy") >= 0) { + } else if (sty_name.contains("black") || sty_name.contains("heavy")) { return 900; - } else if (sty_name.find("extrablack") >= 0 || sty_name.find("ultrablack") >= 0) { + } else if (sty_name.contains("extrablack") || sty_name.contains("ultrablack")) { return 950; } return 400; } _FORCE_INLINE_ int _font_get_stretch_by_name(const String &p_sty_name) const { String sty_name = p_sty_name.replace(" ", "").replace("-", ""); - if (sty_name.find("ultracondensed") >= 0) { + if (sty_name.contains("ultracondensed")) { return 50; - } else if (sty_name.find("extracondensed") >= 0) { + } else if (sty_name.contains("extracondensed")) { return 63; - } else if (sty_name.find("condensed") >= 0) { + } else if (sty_name.contains("condensed")) { return 75; - } else if (sty_name.find("semicondensed") >= 0) { + } else if (sty_name.contains("semicondensed")) { return 87; - } else if (sty_name.find("semiexpanded") >= 0) { + } else if (sty_name.contains("semiexpanded")) { return 113; - } else if (sty_name.find("expanded") >= 0) { + } else if (sty_name.contains("expanded")) { return 125; - } else if (sty_name.find("extraexpanded") >= 0) { + } else if (sty_name.contains("extraexpanded")) { return 150; - } else if (sty_name.find("ultraexpanded") >= 0) { + } else if (sty_name.contains("ultraexpanded")) { return 200; } return 100; } _FORCE_INLINE_ bool _is_ital_style(const String &p_sty_name) const { - return (p_sty_name.find("italic") >= 0) || (p_sty_name.find("oblique") >= 0); + return p_sty_name.contains("italic") || p_sty_name.contains("oblique"); } // Shaped text cache data. @@ -988,6 +988,7 @@ public: MODBIND1RC(String, strip_diacritics, const String &); MODBIND1RC(bool, is_valid_identifier, const String &); + MODBIND1RC(bool, is_valid_letter, char32_t); MODBIND2RC(String, string_to_upper, const String &, const String &); MODBIND2RC(String, string_to_lower, const String &, const String &); diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index 29801ede8e..07940719eb 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -1,10 +1,20 @@ #!/usr/bin/env python import atexit -import os import sys import methods import time +# Enable ANSI escape code support on Windows 10 and later (for colored console output). +# <https://github.com/python/cpython/issues/73245> +if sys.platform == "win32": + from ctypes import windll, c_int, byref + + stdout_handle = windll.kernel32.GetStdHandle(c_int(-11)) + mode = c_int(0) + windll.kernel32.GetConsoleMode(c_int(stdout_handle), byref(mode)) + mode = c_int(mode.value | 4) + windll.kernel32.SetConsoleMode(c_int(stdout_handle), mode) + # For the reference: # - CCFLAGS are compilation flags shared between C and C++ # - CFLAGS are for C-specific compilation flags @@ -28,7 +38,7 @@ opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", Fa opts.Update(env) if not env["verbose"]: - methods.no_verbose(sys, env) + methods.no_verbose(env) # ThorVG if env["thorvg_enabled"] and env["freetype_enabled"]: @@ -311,9 +321,16 @@ Default(library) def print_elapsed_time(): - elapsed_time_sec = round(time.time() - time_at_start, 3) - time_ms = round((elapsed_time_sec % 1) * 1000) - print("[Time elapsed: {}.{:03}]".format(time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), time_ms)) + elapsed_time_sec = round(time.time() - time_at_start, 2) + time_centiseconds = round((elapsed_time_sec % 1) * 100) + print( + "{}[Time elapsed: {}.{:02}]{}".format( + methods.ANSI.GRAY, + time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), + time_centiseconds, + methods.ANSI.RESET, + ) + ) atexit.register(print_elapsed_time) diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py index 32dbc59fd4..3453c3e8f0 100644 --- a/modules/text_server_fb/gdextension_build/methods.py +++ b/modules/text_server_fb/gdextension_build/methods.py @@ -1,66 +1,75 @@ import os import sys +from enum import Enum +# Colors are disabled in non-TTY environments such as pipes. This means +# that if output is redirected to a file, it won't contain color codes. +# Colors are always enabled on continuous integration. +_colorize = bool(sys.stdout.isatty() or os.environ.get("CI")) -def no_verbose(sys, env): - colors = {} - # Colors are disabled in non-TTY environments such as pipes. This means - # that if output is redirected to a file, it will not contain color codes - if sys.stdout.isatty(): - colors["blue"] = "\033[0;94m" - colors["bold_blue"] = "\033[1;94m" - colors["reset"] = "\033[0m" - else: - colors["blue"] = "" - colors["bold_blue"] = "" - colors["reset"] = "" +class ANSI(Enum): + """ + Enum class for adding ansi colorcodes directly into strings. + Automatically converts values to strings representing their + internal value, or an empty string in a non-colorized scope. + """ + + RESET = "\x1b[0m" + + BOLD = "\x1b[1m" + ITALIC = "\x1b[3m" + UNDERLINE = "\x1b[4m" + STRIKETHROUGH = "\x1b[9m" + REGULAR = "\x1b[22;23;24;29m" + + BLACK = "\x1b[30m" + RED = "\x1b[31m" + GREEN = "\x1b[32m" + YELLOW = "\x1b[33m" + BLUE = "\x1b[34m" + MAGENTA = "\x1b[35m" + CYAN = "\x1b[36m" + WHITE = "\x1b[37m" + + PURPLE = "\x1b[38;5;93m" + PINK = "\x1b[38;5;206m" + ORANGE = "\x1b[38;5;214m" + GRAY = "\x1b[38;5;244m" + + def __str__(self) -> str: + global _colorize + return str(self.value) if _colorize else "" + + +def no_verbose(env): + colors = [ANSI.BLUE, ANSI.BOLD, ANSI.REGULAR, ANSI.RESET] # There is a space before "..." to ensure that source file names can be # Ctrl + clicked in the VS Code terminal. - compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - link_program_message = "{}Linking Program {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - generated_file_message = "{}Generating {}$TARGET{} ...{}".format( - colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] - ) - - env.Append(CXXCOMSTR=[compile_source_message]) - env.Append(CCCOMSTR=[compile_source_message]) - env.Append(SHCCCOMSTR=[compile_shared_source_message]) - env.Append(SHCXXCOMSTR=[compile_shared_source_message]) - env.Append(ARCOMSTR=[link_library_message]) - env.Append(RANLIBCOMSTR=[ranlib_library_message]) - env.Append(SHLINKCOMSTR=[link_shared_library_message]) - env.Append(LINKCOMSTR=[link_program_message]) - env.Append(JARCOMSTR=[java_library_message]) - env.Append(JAVACCOMSTR=[java_compile_source_message]) - env.Append(RCCOMSTR=[compiled_resource_message]) - env.Append(GENCOMSTR=[generated_file_message]) + compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors) + java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors) + compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(*colors) + link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(*colors) + link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(*colors) + ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(*colors) + link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(*colors) + java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(*colors) + compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(*colors) + generated_file_message = "{}Generating {}$TARGET{} ...{}".format(*colors) + + env["CXXCOMSTR"] = compile_source_message + env["CCCOMSTR"] = compile_source_message + env["SHCCCOMSTR"] = compile_shared_source_message + env["SHCXXCOMSTR"] = compile_shared_source_message + env["ARCOMSTR"] = link_library_message + env["RANLIBCOMSTR"] = ranlib_library_message + env["SHLINKCOMSTR"] = link_shared_library_message + env["LINKCOMSTR"] = link_program_message + env["JARCOMSTR"] = java_library_message + env["JAVACCOMSTR"] = java_compile_source_message + env["RCCOMSTR"] = compiled_resource_message + env["GENCOMSTR"] = generated_file_message def disable_warnings(self): diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 31370c7da7..9ad20c7b26 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -335,54 +335,54 @@ class TextServerFallback : public TextServerExtension { _FORCE_INLINE_ int _font_get_weight_by_name(const String &p_sty_name) const { String sty_name = p_sty_name.replace(" ", "").replace("-", ""); - if (sty_name.find("thin") >= 0 || sty_name.find("hairline") >= 0) { + if (sty_name.contains("thin") || sty_name.contains("hairline")) { return 100; - } else if (sty_name.find("extralight") >= 0 || sty_name.find("ultralight") >= 0) { + } else if (sty_name.contains("extralight") || sty_name.contains("ultralight")) { return 200; - } else if (sty_name.find("light") >= 0) { + } else if (sty_name.contains("light")) { return 300; - } else if (sty_name.find("semilight") >= 0) { + } else if (sty_name.contains("semilight")) { return 350; - } else if (sty_name.find("regular") >= 0) { + } else if (sty_name.contains("regular")) { return 400; - } else if (sty_name.find("medium") >= 0) { + } else if (sty_name.contains("medium")) { return 500; - } else if (sty_name.find("semibold") >= 0 || sty_name.find("demibold") >= 0) { + } else if (sty_name.contains("semibold") || sty_name.contains("demibold")) { return 600; - } else if (sty_name.find("bold") >= 0) { + } else if (sty_name.contains("bold")) { return 700; - } else if (sty_name.find("extrabold") >= 0 || sty_name.find("ultrabold") >= 0) { + } else if (sty_name.contains("extrabold") || sty_name.contains("ultrabold")) { return 800; - } else if (sty_name.find("black") >= 0 || sty_name.find("heavy") >= 0) { + } else if (sty_name.contains("black") || sty_name.contains("heavy")) { return 900; - } else if (sty_name.find("extrablack") >= 0 || sty_name.find("ultrablack") >= 0) { + } else if (sty_name.contains("extrablack") || sty_name.contains("ultrablack")) { return 950; } return 400; } _FORCE_INLINE_ int _font_get_stretch_by_name(const String &p_sty_name) const { String sty_name = p_sty_name.replace(" ", "").replace("-", ""); - if (sty_name.find("ultracondensed") >= 0) { + if (sty_name.contains("ultracondensed")) { return 50; - } else if (sty_name.find("extracondensed") >= 0) { + } else if (sty_name.contains("extracondensed")) { return 63; - } else if (sty_name.find("condensed") >= 0) { + } else if (sty_name.contains("condensed")) { return 75; - } else if (sty_name.find("semicondensed") >= 0) { + } else if (sty_name.contains("semicondensed")) { return 87; - } else if (sty_name.find("semiexpanded") >= 0) { + } else if (sty_name.contains("semiexpanded")) { return 113; - } else if (sty_name.find("expanded") >= 0) { + } else if (sty_name.contains("expanded")) { return 125; - } else if (sty_name.find("extraexpanded") >= 0) { + } else if (sty_name.contains("extraexpanded")) { return 150; - } else if (sty_name.find("ultraexpanded") >= 0) { + } else if (sty_name.contains("ultraexpanded")) { return 200; } return 100; } _FORCE_INLINE_ bool _is_ital_style(const String &p_sty_name) const { - return (p_sty_name.find("italic") >= 0) || (p_sty_name.find("oblique") >= 0); + return p_sty_name.contains("italic") || p_sty_name.contains("oblique"); } // Shaped text cache data. diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub index 4b385b820d..98c03e9ee9 100644 --- a/modules/upnp/SCsub +++ b/modules/upnp/SCsub @@ -30,7 +30,8 @@ if env["builtin_miniupnpc"]: env_upnp.Prepend(CPPPATH=[thirdparty_dir + "include"]) env_upnp.Append(CPPDEFINES=["MINIUPNP_STATICLIB"]) - env_upnp.Append(CPPDEFINES=["MINIUPNPC_SET_SOCKET_TIMEOUT"]) + if env["platform"] != "windows": + env_upnp.Append(CPPDEFINES=["MINIUPNPC_SET_SOCKET_TIMEOUT"]) env_thirdparty = env_upnp.Clone() env_thirdparty.disable_warnings() diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 95453c1ecd..70f0ea346b 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -37,10 +37,10 @@ bool UPNP::is_common_device(const String &dev) const { return dev.is_empty() || - dev.find("InternetGatewayDevice") >= 0 || - dev.find("WANIPConnection") >= 0 || - dev.find("WANPPPConnection") >= 0 || - dev.find("rootdevice") >= 0; + dev.contains("InternetGatewayDevice") || + dev.contains("WANIPConnection") || + dev.contains("WANPPPConnection") || + dev.contains("rootdevice"); } int UPNP::discover(int timeout, int ttl, const String &device_filter) { diff --git a/modules/webp/SCsub b/modules/webp/SCsub index e78236a60b..dde4450c23 100644 --- a/modules/webp/SCsub +++ b/modules/webp/SCsub @@ -128,6 +128,7 @@ if env["builtin_libwebp"]: "src/utils/filters_utils.c", "src/utils/huffman_encode_utils.c", "src/utils/huffman_utils.c", + "src/utils/palette.c", "src/utils/quant_levels_dec_utils.c", "src/utils/quant_levels_utils.c", "src/utils/random_utils.c", diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 9224760c5b..45fa9f46ca 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -59,7 +59,7 @@ int WebRTCMultiplayerPeer::get_packet_channel() const { MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_packet_mode() const { ERR_FAIL_INDEX_V(next_packet_channel, channels_modes.size(), TRANSFER_MODE_RELIABLE); - return channels_modes[next_packet_channel]; + return channels_modes.get(next_packet_channel); } bool WebRTCMultiplayerPeer::is_server() const { @@ -308,18 +308,18 @@ Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_pe cfg["ordered"] = true; cfg["id"] = 1; - peer->channels[CH_RELIABLE] = p_peer->create_data_channel("reliable", cfg); - ERR_FAIL_COND_V(peer->channels[CH_RELIABLE].is_null(), FAILED); + peer->channels.get(CH_RELIABLE) = p_peer->create_data_channel("reliable", cfg); + ERR_FAIL_COND_V(peer->channels.get(CH_RELIABLE).is_null(), FAILED); cfg["id"] = 2; cfg["maxPacketLifetime"] = p_unreliable_lifetime; - peer->channels[CH_ORDERED] = p_peer->create_data_channel("ordered", cfg); - ERR_FAIL_COND_V(peer->channels[CH_ORDERED].is_null(), FAILED); + peer->channels.get(CH_ORDERED) = p_peer->create_data_channel("ordered", cfg); + ERR_FAIL_COND_V(peer->channels.get(CH_ORDERED).is_null(), FAILED); cfg["id"] = 3; cfg["ordered"] = false; - peer->channels[CH_UNRELIABLE] = p_peer->create_data_channel("unreliable", cfg); - ERR_FAIL_COND_V(peer->channels[CH_UNRELIABLE].is_null(), FAILED); + peer->channels.get(CH_UNRELIABLE) = p_peer->create_data_channel("unreliable", cfg); + ERR_FAIL_COND_V(peer->channels.get(CH_UNRELIABLE).is_null(), FAILED); for (const Dictionary &dict : channels_config) { Ref<WebRTCDataChannel> ch = p_peer->create_data_channel(String::num_int64(dict["id"]), dict); @@ -400,8 +400,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + "."); ERR_FAIL_COND_V_MSG(E->value->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value->channels.size())); - ERR_FAIL_COND_V(E->value->channels[ch].is_null(), ERR_BUG); - return E->value->channels[ch]->put_packet(p_buffer, p_buffer_size); + ERR_FAIL_COND_V(E->value->channels.get(ch).is_null(), ERR_BUG); + return E->value->channels.get(ch)->put_packet(p_buffer, p_buffer_size); } else { int exclude = -target_peer; @@ -413,8 +413,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si } ERR_CONTINUE_MSG(F.value->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, F.value->channels.size())); - ERR_CONTINUE(F.value->channels[ch].is_null()); - F.value->channels[ch]->put_packet(p_buffer, p_buffer_size); + ERR_CONTINUE(F.value->channels.get(ch).is_null()); + F.value->channels.get(ch)->put_packet(p_buffer, p_buffer_size); } } return OK; diff --git a/modules/websocket/remote_debugger_peer_websocket.cpp b/modules/websocket/remote_debugger_peer_websocket.cpp index dc6833e8c3..a40ea0205e 100644 --- a/modules/websocket/remote_debugger_peer_websocket.cpp +++ b/modules/websocket/remote_debugger_peer_websocket.cpp @@ -74,7 +74,7 @@ void RemoteDebuggerPeerWebSocket::poll() { } while (ws_peer->get_ready_state() == WebSocketPeer::STATE_OPEN && out_queue.size() > 0) { - Array var = out_queue[0]; + Array var = out_queue.front()->get(); Error err = ws_peer->put_var(var); ERR_BREAK(err != OK); // Peer buffer full? out_queue.pop_front(); @@ -92,7 +92,7 @@ bool RemoteDebuggerPeerWebSocket::has_message() { Array RemoteDebuggerPeerWebSocket::get_message() { ERR_FAIL_COND_V(in_queue.is_empty(), Array()); - Array msg = in_queue[0]; + Array msg = in_queue.front()->get(); in_queue.pop_front(); return msg; } diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 45c1d8ec06..916566fc1b 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -39,6 +39,7 @@ #include "drivers/gles3/storage/texture_storage.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" +#include "scene/scene_string_names.h" #include "servers/rendering/renderer_compositor.h" #include "servers/rendering/rendering_server_globals.h" #include "servers/xr/xr_hand_tracker.h" @@ -641,7 +642,7 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) { } Transform3D aim_transform = _js_matrix_to_transform(target_pose); - tracker->set_pose(SNAME("default"), aim_transform, Vector3(), Vector3()); + tracker->set_pose(SceneStringName(default_), aim_transform, Vector3(), Vector3()); tracker->set_pose(SNAME("aim"), aim_transform, Vector3(), Vector3()); if (has_grip_pose) { tracker->set_pose(SNAME("grip"), _js_matrix_to_transform(grip_pose), Vector3(), Vector3()); |