diff options
Diffstat (limited to 'modules')
173 files changed, 6333 insertions, 1285 deletions
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 9c178997c5..6082b468f7 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -2226,7 +2226,7 @@ void CSGPolygon3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_interval_type", PROPERTY_HINT_ENUM, "Distance,Subdivide"), "set_path_interval_type", "get_path_interval_type"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.01,1.0,0.01,exp,or_greater"), "set_path_interval", "get_path_interval"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1,exp"), "set_path_simplify_angle", "get_path_simplify_angle"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1"), "set_path_simplify_angle", "get_path_simplify_angle"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u"); diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index 338adc9b52..5d35c04e25 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -39,7 +39,7 @@ When [member mode] is [constant MODE_PATH], the location of the [Path3D] object used to extrude the [member polygon]. </member> <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation"> - When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded. + When [member mode] is [constant MODE_PATH], the path rotation method used to rotate the [member polygon] as it is extruded. </member> <member name="path_simplify_angle" type="float" setter="set_path_simplify_angle" getter="get_path_simplify_angle"> When [member mode] is [constant MODE_PATH], extrusions that are less than this angle, will be merged together to reduce polygon count. diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index ebf0f5a91f..ea7b6d225e 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -44,7 +44,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { helper.instantiate(); - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15)); create_material("shape_union_material", gizmo_color); create_material("shape_union_solid_material", gizmo_color); gizmo_color.invert(); diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 481bb46c24..b2de6b656e 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -44,24 +44,79 @@ enum { DDSD_MIPMAPCOUNT = 0x00020000, DDPF_FOURCC = 0x00000004, DDPF_ALPHAPIXELS = 0x00000001, - DDPF_INDEXED = 0x00000020, - DDPF_RGB = 0x00000040, + DDPF_RGB = 0x00000040 }; +enum DDSFourCC { + DDFCC_DXT1 = PF_FOURCC("DXT1"), + DDFCC_DXT3 = PF_FOURCC("DXT3"), + DDFCC_DXT5 = PF_FOURCC("DXT5"), + DDFCC_ATI1 = PF_FOURCC("ATI1"), + DDFCC_BC4U = PF_FOURCC("BC4U"), + DDFCC_ATI2 = PF_FOURCC("ATI2"), + DDFCC_BC5U = PF_FOURCC("BC5U"), + DDFCC_A2XY = PF_FOURCC("A2XY"), + DDFCC_DX10 = PF_FOURCC("DX10"), + DDFCC_R16F = 111, + DDFCC_RG16F = 112, + DDFCC_RGBA16F = 113, + DDFCC_R32F = 114, + DDFCC_RG32F = 115, + DDFCC_RGBA32F = 116 +}; + +// Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format +enum DXGIFormat { + DXGI_R32G32B32A32_FLOAT = 2, + DXGI_R16G16B16A16_FLOAT = 10, + DXGI_R32G32_FLOAT = 16, + DXGI_R10G10B10A2_UNORM = 24, + DXGI_R8G8B8A8_UNORM = 28, + DXGI_R16G16_FLOAT = 34, + DXGI_R32_FLOAT = 41, + DXGI_R16_FLOAT = 54, + DXGI_R9G9B9E5 = 67, + DXGI_BC1_UNORM = 71, + DXGI_BC2_UNORM = 74, + DXGI_BC3_UNORM = 77, + DXGI_BC4_UNORM = 80, + DXGI_BC5_UNORM = 83, + DXGI_B5G6R5_UNORM = 85, + DXGI_B5G5R5A1_UNORM = 86, + DXGI_B8G8R8A8_UNORM = 87, + DXGI_BC6H_UF16 = 95, + DXGI_BC6H_SF16 = 96, + DXGI_BC7_UNORM = 98, + DXGI_B4G4R4A4_UNORM = 115 +}; + +// The legacy bitmasked format names here represent the actual data layout in the files, +// while their official names are flipped (e.g. RGBA8 layout is officially called ABGR8). enum DDSFormat { DDS_DXT1, DDS_DXT3, DDS_DXT5, DDS_ATI1, DDS_ATI2, - DDS_A2XY, + DDS_BC6U, + DDS_BC6S, + DDS_BC7U, + DDS_R16F, + DDS_RG16F, + DDS_RGBA16F, + DDS_R32F, + DDS_RG32F, + DDS_RGBA32F, + DDS_RGB9E5, DDS_BGRA8, DDS_BGR8, - DDS_RGBA8, //flipped in dds - DDS_RGB8, //flipped in dds + DDS_RGBA8, + DDS_RGB8, DDS_BGR5A1, DDS_BGR565, DDS_BGR10A2, + DDS_RGB10A2, + DDS_BGRA4, DDS_LUMINANCE, DDS_LUMINANCE_ALPHA, DDS_MAX @@ -70,30 +125,112 @@ enum DDSFormat { struct DDSFormatInfo { const char *name = nullptr; bool compressed = false; - bool palette = false; uint32_t divisor = 0; uint32_t block_size = 0; Image::Format format = Image::Format::FORMAT_BPTC_RGBA; }; static const DDSFormatInfo dds_format_info[DDS_MAX] = { - { "DXT1/BC1", true, false, 4, 8, Image::FORMAT_DXT1 }, - { "DXT3/BC2", true, false, 4, 16, Image::FORMAT_DXT3 }, - { "DXT5/BC3", true, false, 4, 16, Image::FORMAT_DXT5 }, - { "ATI1/BC4", true, false, 4, 8, Image::FORMAT_RGTC_R }, - { "ATI2/3DC/BC5", true, false, 4, 16, Image::FORMAT_RGTC_RG }, - { "A2XY/DXN/BC5", true, false, 4, 16, Image::FORMAT_RGTC_RG }, - { "BGRA8", false, false, 1, 4, Image::FORMAT_RGBA8 }, - { "BGR8", false, false, 1, 3, Image::FORMAT_RGB8 }, - { "RGBA8", false, false, 1, 4, Image::FORMAT_RGBA8 }, - { "RGB8", false, false, 1, 3, Image::FORMAT_RGB8 }, - { "BGR5A1", false, false, 1, 2, Image::FORMAT_RGBA8 }, - { "BGR565", false, false, 1, 2, Image::FORMAT_RGB8 }, - { "BGR10A2", false, false, 1, 4, Image::FORMAT_RGBA8 }, - { "GRAYSCALE", false, false, 1, 1, Image::FORMAT_L8 }, - { "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 } + { "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 }, + { "DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 }, + { "DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 }, + { "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R }, + { "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG }, + { "BC6U", true, 4, 16, Image::FORMAT_BPTC_RGBFU }, + { "BC6S", true, 4, 16, Image::FORMAT_BPTC_RGBF }, + { "BC7U", true, 4, 16, Image::FORMAT_BPTC_RGBA }, + { "R16F", false, 1, 2, Image::FORMAT_RH }, + { "RG16F", false, 1, 4, Image::FORMAT_RGH }, + { "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH }, + { "R32F", false, 1, 4, Image::FORMAT_RF }, + { "RG32F", false, 1, 8, Image::FORMAT_RGF }, + { "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF }, + { "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 }, + { "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 }, + { "BGR8", false, 1, 3, Image::FORMAT_RGB8 }, + { "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 }, + { "RGB8", false, 1, 3, Image::FORMAT_RGB8 }, + { "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 }, + { "BGR565", false, 1, 2, Image::FORMAT_RGB8 }, + { "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 }, + { "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 }, + { "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 }, + { "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 }, + { "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 } }; +static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) { + switch (p_dxgi_format) { + case DXGI_R32G32B32A32_FLOAT: { + return DDS_RGBA32F; + } + case DXGI_R16G16B16A16_FLOAT: { + return DDS_RGBA16F; + } + case DXGI_R32G32_FLOAT: { + return DDS_RG32F; + } + case DXGI_R10G10B10A2_UNORM: { + return DDS_RGB10A2; + } + case DXGI_R8G8B8A8_UNORM: { + return DDS_RGBA8; + } + case DXGI_R16G16_FLOAT: { + return DDS_RG16F; + } + case DXGI_R32_FLOAT: { + return DDS_R32F; + } + case DXGI_R16_FLOAT: { + return DDS_R16F; + } + case DXGI_R9G9B9E5: { + return DDS_RGB9E5; + } + case DXGI_BC1_UNORM: { + return DDS_DXT1; + } + case DXGI_BC2_UNORM: { + return DDS_DXT3; + } + case DXGI_BC3_UNORM: { + return DDS_DXT5; + } + case DXGI_BC4_UNORM: { + return DDS_ATI1; + } + case DXGI_BC5_UNORM: { + return DDS_ATI2; + } + case DXGI_B5G6R5_UNORM: { + return DDS_BGR565; + } + case DXGI_B5G5R5A1_UNORM: { + return DDS_BGR5A1; + } + case DXGI_B8G8R8A8_UNORM: { + return DDS_BGRA8; + } + case DXGI_BC6H_UF16: { + return DDS_BC6U; + } + case DXGI_BC6H_SF16: { + return DDS_BC6S; + } + case DXGI_BC7_UNORM: { + return DDS_BC7U; + } + case DXGI_B4G4R4A4_UNORM: { + return DDS_BGRA4; + } + + default: { + return DDS_MAX; + } + } +} + Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_CANT_OPEN; @@ -121,15 +258,14 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig /* uint32_t depth = */ f->get_32(); uint32_t mipmaps = f->get_32(); - //skip 11 + // Skip reserved. for (int i = 0; i < 11; i++) { f->get_32(); } - //validate - + // Validate. // We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing, - // but non-mandatory when reading (as some writers don't set them)... + // but non-mandatory when reading (as some writers don't set them). if (magic != DDS_MAGIC || hsize != 124) { ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid or unsupported DDS texture file '" + p_path + "'."); } @@ -145,65 +281,112 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig /* uint32_t caps_1 = */ f->get_32(); /* uint32_t caps_2 = */ f->get_32(); - /* uint32_t caps_ddsx = */ f->get_32(); + /* uint32_t caps_3 = */ f->get_32(); + /* uint32_t caps_4 = */ f->get_32(); - //reserved skip - f->get_32(); + // Skip reserved. f->get_32(); - /* - print_line("DDS width: "+itos(width)); - print_line("DDS height: "+itos(height)); - print_line("DDS mipmaps: "+itos(mipmaps)); + if (f->get_position() < 128) { + f->seek(128); + } - printf("fourcc: %x fflags: %x, rgbbits: %x, fsize: %x\n",format_fourcc,format_flags,format_rgb_bits,format_size); - printf("rmask: %x gmask: %x, bmask: %x, amask: %x\n",format_red_mask,format_green_mask,format_blue_mask,format_alpha_mask); - */ + DDSFormat dds_format = DDS_MAX; - //must avoid this later - while (f->get_position() < 128) { - f->get_8(); - } + if (format_flags & DDPF_FOURCC) { + // FourCC formats. + switch (format_fourcc) { + case DDFCC_DXT1: { + dds_format = DDS_DXT1; + } break; + case DDFCC_DXT3: { + dds_format = DDS_DXT3; + } break; + case DDFCC_DXT5: { + dds_format = DDS_DXT5; + } break; + case DDFCC_ATI1: + case DDFCC_BC4U: { + dds_format = DDS_ATI1; + } break; + case DDFCC_ATI2: + case DDFCC_BC5U: + case DDFCC_A2XY: { + dds_format = DDS_ATI2; + } break; + case DDFCC_R16F: { + dds_format = DDS_R16F; + } break; + case DDFCC_RG16F: { + dds_format = DDS_RG16F; + } break; + case DDFCC_RGBA16F: { + dds_format = DDS_RGBA16F; + } break; + case DDFCC_R32F: { + dds_format = DDS_R32F; + } break; + case DDFCC_RG32F: { + dds_format = DDS_RG32F; + } break; + case DDFCC_RGBA32F: { + dds_format = DDS_RGBA32F; + } break; + case DDFCC_DX10: { + uint32_t dxgi_format = f->get_32(); + /* uint32_t dimension = */ f->get_32(); + /* uint32_t misc_flags_1 = */ f->get_32(); + /* uint32_t array_size = */ f->get_32(); + /* uint32_t misc_flags_2 = */ f->get_32(); + + dds_format = dxgi_to_dds_format(dxgi_format); + } break; + + default: { + ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported FourCC in DDS '" + p_path + "'."); + } + } + + } else if (format_flags & DDPF_RGB) { + // Channel-bitmasked formats. + if (format_flags & DDPF_ALPHAPIXELS) { + // With alpha. + if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff && format_alpha_mask == 0xff000000) { + dds_format = DDS_BGRA8; + } else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000 && format_alpha_mask == 0xff000000) { + dds_format = DDS_RGBA8; + } else if (format_rgb_bits == 16 && format_red_mask == 0x00007c00 && format_green_mask == 0x000003e0 && format_blue_mask == 0x0000001f && format_alpha_mask == 0x00008000) { + dds_format = DDS_BGR5A1; + } else if (format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) { + dds_format = DDS_BGR10A2; + } else if (format_rgb_bits == 32 && format_red_mask == 0x3ff && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff00000 && format_alpha_mask == 0xc0000000) { + dds_format = DDS_RGB10A2; + } else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) { + dds_format = DDS_BGRA4; + } + + } else { + // Without alpha. + if (format_rgb_bits == 24 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) { + dds_format = DDS_BGR8; + } else if (format_rgb_bits == 24 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) { + dds_format = DDS_RGB8; + } else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) { + dds_format = DDS_BGR565; + } + } - DDSFormat dds_format; - - if (format_flags & DDPF_FOURCC && format_fourcc == PF_FOURCC("DXT1")) { - dds_format = DDS_DXT1; - } else if (format_flags & DDPF_FOURCC && format_fourcc == PF_FOURCC("DXT3")) { - dds_format = DDS_DXT3; - - } else if (format_flags & DDPF_FOURCC && format_fourcc == PF_FOURCC("DXT5")) { - dds_format = DDS_DXT5; - } else if (format_flags & DDPF_FOURCC && format_fourcc == PF_FOURCC("ATI1")) { - dds_format = DDS_ATI1; - } else if (format_flags & DDPF_FOURCC && format_fourcc == PF_FOURCC("ATI2")) { - dds_format = DDS_ATI2; - } else if (format_flags & DDPF_FOURCC && format_fourcc == PF_FOURCC("A2XY")) { - dds_format = DDS_A2XY; - - } else if (format_flags & DDPF_RGB && format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff && format_alpha_mask == 0xff000000) { - dds_format = DDS_BGRA8; - } else if (format_flags & DDPF_RGB && !(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 24 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) { - dds_format = DDS_BGR8; - } else if (format_flags & DDPF_RGB && format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000 && format_alpha_mask == 0xff000000) { - dds_format = DDS_RGBA8; - } else if (format_flags & DDPF_RGB && !(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 24 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) { - dds_format = DDS_RGB8; - - } else if (format_flags & DDPF_RGB && format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 16 && format_red_mask == 0x00007c00 && format_green_mask == 0x000003e0 && format_blue_mask == 0x0000001f && format_alpha_mask == 0x00008000) { - dds_format = DDS_BGR5A1; - } else if (format_flags & DDPF_RGB && format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) { - dds_format = DDS_BGR10A2; - } else if (format_flags & DDPF_RGB && !(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) { - dds_format = DDS_BGR565; - } else if (!(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 8 && format_red_mask == 0xff) { - dds_format = DDS_LUMINANCE; - } else if ((format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) { - dds_format = DDS_LUMINANCE_ALPHA; - } else if (format_flags & DDPF_INDEXED && format_rgb_bits == 8) { - dds_format = DDS_BGR565; } else { - //printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n", format_fourcc, format_flags, format_rgb_bits, format_red_mask, format_green_mask, format_blue_mask, format_alpha_mask); + // Other formats. + if (format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) { + dds_format = DDS_LUMINANCE_ALPHA; + } else if (!(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 8 && format_red_mask == 0xff) { + dds_format = DDS_LUMINANCE; + } + } + + // No format detected, error. + if (dds_format == DDS_MAX) { ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'."); } @@ -218,17 +401,20 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig uint32_t h = height; if (info.compressed) { - //compressed bc - + // BC compressed. uint32_t size = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size; - ERR_FAIL_COND_V(size != pitch, Ref<Resource>()); - ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), Ref<Resource>()); + + if (flags & DDSD_LINEARSIZE) { + ERR_FAIL_COND_V_MSG(size != pitch, Ref<Resource>(), "DDS header flags specify that a linear size of the top-level image is present, but the specified size does not match the expected value."); + } else { + ERR_FAIL_COND_V_MSG(pitch != 0, Ref<Resource>(), "DDS header flags specify that no linear size will given for the top-level image, but a non-zero linear size value is present in the header."); + } for (uint32_t i = 1; i < mipmaps; i++) { w = MAX(1u, w >> 1); h = MAX(1u, h >> 1); + uint32_t bsize = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size; - //printf("%i x %i - block: %i\n",w,h,bsize); size += bsize; } @@ -236,50 +422,8 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig uint8_t *wb = src_data.ptrw(); f->get_buffer(wb, size); - } else if (info.palette) { - //indexed - ERR_FAIL_COND_V(!(flags & DDSD_PITCH), Ref<Resource>()); - ERR_FAIL_COND_V(format_rgb_bits != 8, Ref<Resource>()); - - uint32_t size = pitch * height; - ERR_FAIL_COND_V(size != width * height * info.block_size, Ref<Resource>()); - - uint8_t palette[256 * 4]; - f->get_buffer(palette, 256 * 4); - - int colsize = 3; - for (int i = 0; i < 256; i++) { - if (palette[i * 4 + 3] < 255) { - colsize = 4; - } - } - - int w2 = width; - int h2 = height; - - for (uint32_t i = 1; i < mipmaps; i++) { - w2 = (w2 + 1) >> 1; - h2 = (h2 + 1) >> 1; - size += w2 * h2 * info.block_size; - } - - src_data.resize(size + 256 * colsize); - uint8_t *wb = src_data.ptrw(); - f->get_buffer(wb, size); - - for (int i = 0; i < 256; i++) { - int dst_ofs = size + i * colsize; - int src_ofs = i * 4; - wb[dst_ofs + 0] = palette[src_ofs + 2]; - wb[dst_ofs + 1] = palette[src_ofs + 1]; - wb[dst_ofs + 2] = palette[src_ofs + 0]; - if (colsize == 4) { - wb[dst_ofs + 3] = palette[src_ofs + 3]; - } - } } else { - //uncompressed generic... - + // Generic uncompressed. uint32_t size = width * height * info.block_size; for (uint32_t i = 1; i < mipmaps; i++) { @@ -288,9 +432,10 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig size += w * h * info.block_size; } + // Calculate the space these formats will take up after decoding. if (dds_format == DDS_BGR565) { size = size * 3 / 2; - } else if (dds_format == DDS_BGR5A1) { + } else if (dds_format == DDS_BGR5A1 || dds_format == DDS_BGRA4) { size = size * 2; } @@ -298,9 +443,10 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig uint8_t *wb = src_data.ptrw(); f->get_buffer(wb, size); + // Decode nonstandard formats. switch (dds_format) { case DDS_BGR5A1: { - // TO RGBA + // To RGBA8. int colcount = size / 4; for (int i = colcount - 1; i >= 0; i--) { @@ -311,13 +457,16 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig uint8_t b = wb[src_ofs] & 0x1F; uint8_t g = (wb[src_ofs] >> 5) | ((wb[src_ofs + 1] & 0x3) << 3); uint8_t r = (wb[src_ofs + 1] >> 2) & 0x1F; + wb[dst_ofs + 0] = r << 3; wb[dst_ofs + 1] = g << 3; wb[dst_ofs + 2] = b << 3; wb[dst_ofs + 3] = a ? 255 : 0; } + } break; case DDS_BGR565: { + // To RGB8. int colcount = size / 3; for (int i = colcount - 1; i >= 0; i--) { @@ -327,21 +476,67 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig uint8_t b = wb[src_ofs] & 0x1F; uint8_t g = (wb[src_ofs] >> 5) | ((wb[src_ofs + 1] & 0x7) << 3); uint8_t r = wb[src_ofs + 1] >> 3; + wb[dst_ofs + 0] = r << 3; wb[dst_ofs + 1] = g << 2; - wb[dst_ofs + 2] = b << 3; //b<<3; + wb[dst_ofs + 2] = b << 3; } } break; - case DDS_BGR10A2: { - // TO RGBA + case DDS_BGRA4: { + // To RGBA8. int colcount = size / 4; for (int i = colcount - 1; i >= 0; i--) { + int src_ofs = i * 2; + int dst_ofs = i * 4; + + uint8_t b = wb[src_ofs] & 0x0F; + uint8_t g = wb[src_ofs] & 0xF0; + uint8_t r = wb[src_ofs + 1] & 0x0F; + uint8_t a = wb[src_ofs + 1] & 0xF0; + + wb[dst_ofs] = (r << 4) | r; + wb[dst_ofs + 1] = g | (g >> 4); + wb[dst_ofs + 2] = (b << 4) | b; + wb[dst_ofs + 3] = a | (a >> 4); + } + + } break; + case DDS_RGB10A2: { + // To RGBA8. + int colcount = size / 4; + + for (int i = 0; i < colcount; i++) { int ofs = i * 4; uint32_t w32 = uint32_t(wb[ofs + 0]) | (uint32_t(wb[ofs + 1]) << 8) | (uint32_t(wb[ofs + 2]) << 16) | (uint32_t(wb[ofs + 3]) << 24); + // This method follows the 'standard' way of decoding 10-bit dds files, + // which means the ones created with DirectXTex will be loaded incorrectly. + uint8_t a = (w32 & 0xc0000000) >> 24; + uint8_t r = (w32 & 0x3ff) >> 2; + uint8_t g = (w32 & 0xffc00) >> 12; + uint8_t b = (w32 & 0x3ff00000) >> 22; + + wb[ofs + 0] = r; + wb[ofs + 1] = g; + wb[ofs + 2] = b; + wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque. + } + + } break; + case DDS_BGR10A2: { + // To RGBA8. + int colcount = size / 4; + + for (int i = 0; i < colcount; i++) { + int ofs = i * 4; + + uint32_t w32 = uint32_t(wb[ofs + 0]) | (uint32_t(wb[ofs + 1]) << 8) | (uint32_t(wb[ofs + 2]) << 16) | (uint32_t(wb[ofs + 3]) << 24); + + // This method follows the 'standard' way of decoding 10-bit dds files, + // which means the ones created with DirectXTex will be loaded incorrectly. uint8_t a = (w32 & 0xc0000000) >> 24; uint8_t r = (w32 & 0x3ff00000) >> 22; uint8_t g = (w32 & 0xffc00) >> 12; @@ -350,10 +545,12 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig wb[ofs + 0] = r; wb[ofs + 1] = g; wb[ofs + 2] = b; - wb[ofs + 3] = a == 0xc0 ? 255 : a; //0xc0 should be opaque + wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque. } + } break; case DDS_BGRA8: { + // To RGBA8. int colcount = size / 4; for (int i = 0; i < colcount; i++) { @@ -362,44 +559,12 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig } break; case DDS_BGR8: { + // To RGB8. int colcount = size / 3; for (int i = 0; i < colcount; i++) { SWAP(wb[i * 3 + 0], wb[i * 3 + 2]); } - } break; - case DDS_RGBA8: { - /* do nothing either - int colcount = size/4; - - for(int i=0;i<colcount;i++) { - uint8_t r = wb[i*4+1]; - uint8_t g = wb[i*4+2]; - uint8_t b = wb[i*4+3]; - uint8_t a = wb[i*4+0]; - - wb[i*4+0]=r; - wb[i*4+1]=g; - wb[i*4+2]=b; - wb[i*4+3]=a; - } - */ - } break; - case DDS_RGB8: { - // do nothing - /* - int colcount = size/3; - - for(int i=0;i<colcount;i++) { - SWAP( wb[i*3+0],wb[i*3+2] ); - }*/ - } break; - case DDS_LUMINANCE: { - // do nothing i guess? - - } break; - case DDS_LUMINANCE_ALPHA: { - // do nothing i guess? } break; diff --git a/modules/etcpak/SCsub b/modules/etcpak/SCsub index 2d3b69be75..3a4bff8e87 100644 --- a/modules/etcpak/SCsub +++ b/modules/etcpak/SCsub @@ -13,6 +13,7 @@ thirdparty_dir = "#thirdparty/etcpak/" thirdparty_sources = [ "Dither.cpp", "ProcessDxtc.cpp", + "ProcessRgtc.cpp", "ProcessRGB.cpp", "Tables.cpp", ] diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp index 14cce2686c..f528b92cf2 100644 --- a/modules/etcpak/image_compress_etcpak.cpp +++ b/modules/etcpak/image_compress_etcpak.cpp @@ -35,6 +35,7 @@ #include <ProcessDxtc.hpp> #include <ProcessRGB.hpp> +#include <ProcessRgtc.hpp> EtcpakType _determine_etc_type(Image::UsedChannels p_channels) { switch (p_channels) { @@ -62,9 +63,9 @@ EtcpakType _determine_dxt_type(Image::UsedChannels p_channels) { case Image::USED_CHANNELS_LA: return EtcpakType::ETCPAK_TYPE_DXT5; case Image::USED_CHANNELS_R: - return EtcpakType::ETCPAK_TYPE_DXT5; + return EtcpakType::ETCPAK_TYPE_RGTC_R; case Image::USED_CHANNELS_RG: - return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG; + return EtcpakType::ETCPAK_TYPE_RGTC_RG; case Image::USED_CHANNELS_RGB: return EtcpakType::ETCPAK_TYPE_DXT1; case Image::USED_CHANNELS_RGBA: @@ -127,6 +128,10 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img) { r_img->convert_rg_to_ra_rgba8(); } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) { target_format = Image::FORMAT_DXT5; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_R) { + target_format = Image::FORMAT_RGTC_R; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_RG) { + target_format = Image::FORMAT_RGTC_RG; } else { ERR_FAIL_MSG("Invalid or unsupported etcpak compression format, not ETC or DXT."); } @@ -229,6 +234,10 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img) { CompressDxt1Dither(src_mip_read, dest_mip_write, blocks, mip_w); } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) { CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_RG) { + CompressRgtcRG(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_R) { + CompressRgtcR(src_mip_read, dest_mip_write, blocks, mip_w); } else { ERR_FAIL_MSG("etcpak: Invalid or unsupported compression format."); } diff --git a/modules/etcpak/image_compress_etcpak.h b/modules/etcpak/image_compress_etcpak.h index ff267631a6..ff8bb635b4 100644 --- a/modules/etcpak/image_compress_etcpak.h +++ b/modules/etcpak/image_compress_etcpak.h @@ -41,6 +41,8 @@ enum class EtcpakType { ETCPAK_TYPE_DXT1, ETCPAK_TYPE_DXT5, ETCPAK_TYPE_DXT5_RA_AS_RG, + ETCPAK_TYPE_RGTC_R, + ETCPAK_TYPE_RGTC_RG, }; void _compress_etc1(Image *r_img); diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 3da6bcf10c..933bfba5ba 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -148,7 +148,7 @@ <return type="int" /> <param index="0" name="var" type="Variant" /> <description> - Returns the length of the given Variant [param var]. The length can be the character count of a [String], the element count of any array type or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped. + Returns the length of the given Variant [param var]. The length can be the character count of a [String] or [StringName], the element count of any array type, or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped. [codeblock] a = [1, 2, 3, 4] len(a) # Returns 4 @@ -162,7 +162,7 @@ <return type="Resource" /> <param index="0" name="path" type="String" /> <description> - Returns a [Resource] from the filesystem located at the absolute [param path]. Unless it's already referenced elsewhere (such as in another script or in the scene), the resource is loaded from disk on function call, which might cause a slight delay, especially when loading large scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload]. + Returns a [Resource] from the filesystem located at the absolute [param path]. Unless it's already referenced elsewhere (such as in another script or in the scene), the resource is loaded from disk on function call, which might cause a slight delay, especially when loading large scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload]. This method is equivalent of using [method ResourceLoader.load] with [constant ResourceLoader.CACHE_MODE_REUSE]. [b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path", or by dragging the file from the FileSystem dock into the current script. [codeblock] # Load a scene called "main" located in the root of the project directory and cache it in a variable. diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp index c3979dd290..00179109a3 100644 --- a/modules/gdscript/editor/gdscript_docgen.cpp +++ b/modules/gdscript/editor/gdscript_docgen.cpp @@ -64,8 +64,8 @@ void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type r_type = p_is_return ? "void" : "null"; return; } - if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type()) { - _doctype_from_gdtype(p_gdtype.get_container_element_type(), r_type, r_enum); + if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type(0)) { + _doctype_from_gdtype(p_gdtype.get_container_element_type(0), r_type, r_enum); if (!r_enum.is_empty()) { r_type = "int[]"; r_enum += "[]"; diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 8dbd262b22..3df07f9794 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -494,7 +494,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_function_arg_dicts = 0; } - if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[' && str[j] != '.') { + if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[' && str[j] != ',' && str[j] != '.') { expect_type = false; } diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 9128f104b8..f55b00ebe1 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -80,7 +80,7 @@ bool GDScriptEditorTranslationParserPlugin::_is_constant_string(const GDScriptPa void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser::ClassNode *p_class) { for (int i = 0; i < p_class->members.size(); i++) { const GDScriptParser::ClassNode::Member &m = p_class->members[i]; - // There are 7 types of Member, but only class, function and variable can contain translatable strings. + // Other member types can't contain translatable strings. switch (m.type) { case GDScriptParser::ClassNode::Member::CLASS: _traverse_class(m.m_class); @@ -89,7 +89,11 @@ void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser _traverse_function(m.function); break; case GDScriptParser::ClassNode::Member::VARIABLE: - _read_variable(m.variable); + _assess_expression(m.variable->initializer); + if (m.variable->property == GDScriptParser::VariableNode::PROP_INLINE) { + _traverse_function(m.variable->setter); + _traverse_function(m.variable->getter); + } break; default: break; @@ -98,11 +102,14 @@ void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser } void GDScriptEditorTranslationParserPlugin::_traverse_function(const GDScriptParser::FunctionNode *p_func) { - _traverse_block(p_func->body); -} + if (!p_func) { + return; + } -void GDScriptEditorTranslationParserPlugin::_read_variable(const GDScriptParser::VariableNode *p_var) { - _assess_expression(p_var->initializer); + for (int i = 0; i < p_func->parameters.size(); i++) { + _assess_expression(p_func->parameters[i]->initializer); + } + _traverse_block(p_func->body); } void GDScriptEditorTranslationParserPlugin::_traverse_block(const GDScriptParser::SuiteNode *p_suite) { @@ -114,53 +121,51 @@ void GDScriptEditorTranslationParserPlugin::_traverse_block(const GDScriptParser for (int i = 0; i < statements.size(); i++) { const GDScriptParser::Node *statement = statements[i]; - // Statements with Node type constant, break, continue, pass, breakpoint are skipped because they can't contain translatable strings. + // BREAK, BREAKPOINT, CONSTANT, CONTINUE, and PASS are skipped because they can't contain translatable strings. switch (statement->type) { - case GDScriptParser::Node::VARIABLE: - _assess_expression(static_cast<const GDScriptParser::VariableNode *>(statement)->initializer); - break; + case GDScriptParser::Node::ASSERT: { + const GDScriptParser::AssertNode *assert_node = static_cast<const GDScriptParser::AssertNode *>(statement); + _assess_expression(assert_node->condition); + _assess_expression(assert_node->message); + } break; + case GDScriptParser::Node::ASSIGNMENT: { + _assess_assignment(static_cast<const GDScriptParser::AssignmentNode *>(statement)); + } break; + case GDScriptParser::Node::FOR: { + const GDScriptParser::ForNode *for_node = static_cast<const GDScriptParser::ForNode *>(statement); + _assess_expression(for_node->list); + _traverse_block(for_node->loop); + } break; case GDScriptParser::Node::IF: { const GDScriptParser::IfNode *if_node = static_cast<const GDScriptParser::IfNode *>(statement); _assess_expression(if_node->condition); - //FIXME : if the elif logic is changed in GDScriptParser, then this probably will have to change as well. See GDScriptParser::TreePrinter::print_if(). _traverse_block(if_node->true_block); _traverse_block(if_node->false_block); - break; - } - case GDScriptParser::Node::FOR: { - const GDScriptParser::ForNode *for_node = static_cast<const GDScriptParser::ForNode *>(statement); - _assess_expression(for_node->list); - _traverse_block(for_node->loop); - break; - } - case GDScriptParser::Node::WHILE: { - const GDScriptParser::WhileNode *while_node = static_cast<const GDScriptParser::WhileNode *>(statement); - _assess_expression(while_node->condition); - _traverse_block(while_node->loop); - break; - } + } break; case GDScriptParser::Node::MATCH: { const GDScriptParser::MatchNode *match_node = static_cast<const GDScriptParser::MatchNode *>(statement); _assess_expression(match_node->test); for (int j = 0; j < match_node->branches.size(); j++) { + _traverse_block(match_node->branches[j]->guard_body); _traverse_block(match_node->branches[j]->block); } - break; - } - case GDScriptParser::Node::RETURN: + } break; + case GDScriptParser::Node::RETURN: { _assess_expression(static_cast<const GDScriptParser::ReturnNode *>(statement)->return_value); - break; - case GDScriptParser::Node::ASSERT: - _assess_expression((static_cast<const GDScriptParser::AssertNode *>(statement))->condition); - break; - case GDScriptParser::Node::ASSIGNMENT: - _assess_assignment(static_cast<const GDScriptParser::AssignmentNode *>(statement)); - break; - default: + } break; + case GDScriptParser::Node::VARIABLE: { + _assess_expression(static_cast<const GDScriptParser::VariableNode *>(statement)->initializer); + } break; + case GDScriptParser::Node::WHILE: { + const GDScriptParser::WhileNode *while_node = static_cast<const GDScriptParser::WhileNode *>(statement); + _assess_expression(while_node->condition); + _traverse_block(while_node->loop); + } break; + default: { if (statement->is_expression()) { _assess_expression(static_cast<const GDScriptParser::ExpressionNode *>(statement)); } - break; + } break; } } } @@ -172,25 +177,25 @@ void GDScriptEditorTranslationParserPlugin::_assess_expression(const GDScriptPar return; } - // ExpressionNode of type await, cast, get_node, identifier, literal, preload, self, subscript, unary are ignored as they can't be CallNode - // containing translation strings. + // GET_NODE, IDENTIFIER, LITERAL, PRELOAD, SELF, and TYPE are skipped because they can't contain translatable strings. switch (p_expression->type) { case GDScriptParser::Node::ARRAY: { const GDScriptParser::ArrayNode *array_node = static_cast<const GDScriptParser::ArrayNode *>(p_expression); for (int i = 0; i < array_node->elements.size(); i++) { _assess_expression(array_node->elements[i]); } - break; - } - case GDScriptParser::Node::ASSIGNMENT: + } break; + case GDScriptParser::Node::ASSIGNMENT: { _assess_assignment(static_cast<const GDScriptParser::AssignmentNode *>(p_expression)); - break; + } break; + case GDScriptParser::Node::AWAIT: { + _assess_expression(static_cast<const GDScriptParser::AwaitNode *>(p_expression)->to_await); + } break; case GDScriptParser::Node::BINARY_OPERATOR: { const GDScriptParser::BinaryOpNode *binary_op_node = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression); _assess_expression(binary_op_node->left_operand); _assess_expression(binary_op_node->right_operand); - break; - } + } break; case GDScriptParser::Node::CALL: { const GDScriptParser::CallNode *call_node = static_cast<const GDScriptParser::CallNode *>(p_expression); _extract_from_call(call_node); @@ -198,23 +203,40 @@ void GDScriptEditorTranslationParserPlugin::_assess_expression(const GDScriptPar _assess_expression(call_node->arguments[i]); } } break; + case GDScriptParser::Node::CAST: { + _assess_expression(static_cast<const GDScriptParser::CastNode *>(p_expression)->operand); + } break; case GDScriptParser::Node::DICTIONARY: { const GDScriptParser::DictionaryNode *dict_node = static_cast<const GDScriptParser::DictionaryNode *>(p_expression); for (int i = 0; i < dict_node->elements.size(); i++) { _assess_expression(dict_node->elements[i].key); _assess_expression(dict_node->elements[i].value); } - break; - } + } break; + case GDScriptParser::Node::LAMBDA: { + _traverse_function(static_cast<const GDScriptParser::LambdaNode *>(p_expression)->function); + } break; + case GDScriptParser::Node::SUBSCRIPT: { + const GDScriptParser::SubscriptNode *subscript_node = static_cast<const GDScriptParser::SubscriptNode *>(p_expression); + _assess_expression(subscript_node->base); + if (!subscript_node->is_attribute) { + _assess_expression(subscript_node->index); + } + } break; case GDScriptParser::Node::TERNARY_OPERATOR: { const GDScriptParser::TernaryOpNode *ternary_op_node = static_cast<const GDScriptParser::TernaryOpNode *>(p_expression); _assess_expression(ternary_op_node->condition); _assess_expression(ternary_op_node->true_expr); _assess_expression(ternary_op_node->false_expr); - break; - } - default: - break; + } break; + case GDScriptParser::Node::TYPE_TEST: { + _assess_expression(static_cast<const GDScriptParser::TypeTestNode *>(p_expression)->operand); + } break; + case GDScriptParser::Node::UNARY_OPERATOR: { + _assess_expression(static_cast<const GDScriptParser::UnaryOpNode *>(p_expression)->operand); + } break; + default: { + } break; } } diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index 580c2a80cd..fab79a925f 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -59,7 +59,6 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug void _traverse_function(const GDScriptParser::FunctionNode *p_func); void _traverse_block(const GDScriptParser::SuiteNode *p_suite); - void _read_variable(const GDScriptParser::VariableNode *p_var); void _assess_expression(const GDScriptParser::ExpressionNode *p_expression); void _assess_assignment(const GDScriptParser::AssignmentNode *p_assignment); void _extract_from_call(const GDScriptParser::CallNode *p_call); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 4accdb4d21..a999acd1bd 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1117,8 +1117,7 @@ GDScript *GDScript::find_class(const String &p_qualified_name) { // Starts at index 1 because index 0 was handled above. for (int i = 1; result != nullptr && i < class_names.size(); i++) { - String current_name = class_names[i]; - if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(current_name)) { + if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(class_names[i])) { result = E->value.ptr(); } else { // Couldn't find inner class. @@ -1156,8 +1155,8 @@ RBSet<GDScript *> GDScript::get_dependencies() { return dependencies; } -RBSet<GDScript *> GDScript::get_inverted_dependencies() { - RBSet<GDScript *> inverted_dependencies; +HashMap<GDScript *, RBSet<GDScript *>> GDScript::get_all_dependencies() { + HashMap<GDScript *, RBSet<GDScript *>> all_dependencies; List<GDScript *> scripts; { @@ -1171,51 +1170,42 @@ RBSet<GDScript *> GDScript::get_inverted_dependencies() { } for (GDScript *scr : scripts) { - if (scr == nullptr || scr == this || scr->destructing) { + if (scr == nullptr || scr->destructing) { continue; } - - RBSet<GDScript *> scr_dependencies = scr->get_dependencies(); - if (scr_dependencies.has(this)) { - inverted_dependencies.insert(scr); - } + all_dependencies.insert(scr, scr->get_dependencies()); } - return inverted_dependencies; + return all_dependencies; } RBSet<GDScript *> GDScript::get_must_clear_dependencies() { RBSet<GDScript *> dependencies = get_dependencies(); RBSet<GDScript *> must_clear_dependencies; - HashMap<GDScript *, RBSet<GDScript *>> inverted_dependencies; - - for (GDScript *E : dependencies) { - inverted_dependencies.insert(E, E->get_inverted_dependencies()); - } + HashMap<GDScript *, RBSet<GDScript *>> all_dependencies = get_all_dependencies(); RBSet<GDScript *> cant_clear; - for (KeyValue<GDScript *, RBSet<GDScript *>> &E : inverted_dependencies) { + for (KeyValue<GDScript *, RBSet<GDScript *>> &E : all_dependencies) { + if (dependencies.has(E.key)) { + continue; + } for (GDScript *F : E.value) { - if (!dependencies.has(F)) { - cant_clear.insert(E.key); - for (GDScript *G : E.key->get_dependencies()) { - cant_clear.insert(G); - } - break; + if (dependencies.has(F)) { + cant_clear.insert(F); } } } - for (KeyValue<GDScript *, RBSet<GDScript *>> &E : inverted_dependencies) { - if (cant_clear.has(E.key) || ScriptServer::is_global_class(E.key->get_fully_qualified_name())) { + for (GDScript *E : dependencies) { + if (cant_clear.has(E) || ScriptServer::is_global_class(E->get_fully_qualified_name())) { continue; } - must_clear_dependencies.insert(E.key); + must_clear_dependencies.insert(E); } cant_clear.clear(); dependencies.clear(); - inverted_dependencies.clear(); + all_dependencies.clear(); return must_clear_dependencies; } @@ -1391,106 +1381,51 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) { } #endif -thread_local GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_thread_local; -GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_main_thread = &func_ptrs_to_update_thread_local; +GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_main_thread; +thread_local GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_thread_local = nullptr; -GDScript::UpdatableFuncPtrElement *GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { - MutexLock lock(func_ptrs_to_update_mutex); - - List<UpdatableFuncPtrElement>::Element *result = func_ptrs_to_update_elems.push_back(UpdatableFuncPtrElement()); +GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { + UpdatableFuncPtrElement result = {}; { - MutexLock lock2(func_ptrs_to_update_thread_local.mutex); - result->get().element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr); - result->get().mutex = &func_ptrs_to_update_thread_local.mutex; + MutexLock lock(func_ptrs_to_update_thread_local->mutex); + result.element = func_ptrs_to_update_thread_local->ptrs.push_back(p_func_ptr_ptr); + result.func_ptr = func_ptrs_to_update_thread_local; - if (likely(func_ptrs_to_update_thread_local.initialized)) { - return &result->get(); + if (likely(func_ptrs_to_update_thread_local->initialized)) { + return result; } - func_ptrs_to_update_thread_local.initialized = true; + func_ptrs_to_update_thread_local->initialized = true; } - func_ptrs_to_update.push_back(&func_ptrs_to_update_thread_local); + MutexLock lock(func_ptrs_to_update_mutex); + func_ptrs_to_update.push_back(func_ptrs_to_update_thread_local); + func_ptrs_to_update_thread_local->rc++; - return &result->get(); + return result; } -void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement *p_func_ptr_element) { - // None of these checks should ever fail, unless there's a bug. - // They can be removed once we are sure they never catch anything. - // Left here now due to extra safety needs late in the release cycle. - ERR_FAIL_NULL(p_func_ptr_element); - MutexLock lock(*p_func_ptr_element->mutex); - ERR_FAIL_NULL(p_func_ptr_element->element); - ERR_FAIL_NULL(p_func_ptr_element->mutex); - p_func_ptr_element->element->erase(); +void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element) { + ERR_FAIL_NULL(p_func_ptr_element.element); + ERR_FAIL_NULL(p_func_ptr_element.func_ptr); + MutexLock lock(p_func_ptr_element.func_ptr->mutex); + p_func_ptr_element.element->erase(); } void GDScript::_fixup_thread_function_bookkeeping() { // Transfer the ownership of these update items to the main thread, // because the current one is dying, leaving theirs orphan, dangling. - HashSet<GDScript *> scripts; - DEV_ASSERT(!Thread::is_main_thread()); - MutexLock lock(func_ptrs_to_update_main_thread->mutex); - { - MutexLock lock2(func_ptrs_to_update_thread_local.mutex); - - while (!func_ptrs_to_update_thread_local.ptrs.is_empty()) { - // Transfer the thread-to-script records from the dying thread to the main one. - - List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local.ptrs.front(); - List<GDScriptFunction **>::Element *new_E = func_ptrs_to_update_main_thread->ptrs.push_front(E->get()); - - GDScript *script = (*E->get())->get_script(); - if (!scripts.has(script)) { - scripts.insert(script); - - // Replace dying thread by the main thread in the script-to-thread records. - - MutexLock lock3(script->func_ptrs_to_update_mutex); - DEV_ASSERT(script->func_ptrs_to_update.find(&func_ptrs_to_update_thread_local)); - { - for (List<UpdatableFuncPtrElement>::Element *F = script->func_ptrs_to_update_elems.front(); F; F = F->next()) { - bool is_dying_thread_entry = F->get().mutex == &func_ptrs_to_update_thread_local.mutex; - if (is_dying_thread_entry) { - // This may lead to multiple main-thread entries, but that's not a problem - // and allows to reuse the element, which is needed, since it's tracked by pointer. - F->get().element = new_E; - F->get().mutex = &func_ptrs_to_update_main_thread->mutex; - } - } - } - } + MutexLock lock(func_ptrs_to_update_main_thread.mutex); + MutexLock lock2(func_ptrs_to_update_thread_local->mutex); - E->erase(); - } - } - func_ptrs_to_update_main_thread->initialized = true; - - { - // Remove orphan thread-to-script entries from every script. - // FIXME: This involves iterating through every script whenever a thread dies. - // While it's OK that thread creation/destruction are heavy operations, - // additional bookkeeping can be used to outperform this brute-force approach. - - GDScriptLanguage *gd_lang = GDScriptLanguage::get_singleton(); - - MutexLock lock2(gd_lang->mutex); - - for (SelfList<GDScript> *s = gd_lang->script_list.first(); s; s = s->next()) { - GDScript *script = s->self(); - for (List<UpdatableFuncPtr *>::Element *E = script->func_ptrs_to_update.front(); E; E = E->next()) { - bool is_dying_thread_entry = &E->get()->mutex == &func_ptrs_to_update_thread_local.mutex; - if (is_dying_thread_entry) { - E->erase(); - break; - } - } - } + while (!func_ptrs_to_update_thread_local->ptrs.is_empty()) { + List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local->ptrs.front(); + E->transfer_to_back(&func_ptrs_to_update_main_thread.ptrs); + func_ptrs_to_update_thread_local->transferred = true; } } @@ -1514,12 +1449,29 @@ void GDScript::clear(ClearData *p_clear_data) { { MutexLock outer_lock(func_ptrs_to_update_mutex); for (UpdatableFuncPtr *updatable : func_ptrs_to_update) { - MutexLock inner_lock(updatable->mutex); - for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) { - *func_ptr_ptr = nullptr; + bool destroy = false; + { + MutexLock inner_lock(updatable->mutex); + if (updatable->transferred) { + func_ptrs_to_update_main_thread.mutex.lock(); + } + for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) { + *func_ptr_ptr = nullptr; + } + DEV_ASSERT(updatable->rc != 0); + updatable->rc--; + if (updatable->rc == 0) { + destroy = true; + } + if (updatable->transferred) { + func_ptrs_to_update_main_thread.mutex.unlock(); + } + } + if (destroy) { + DEV_ASSERT(updatable != &func_ptrs_to_update_main_thread); + memdelete(updatable); } } - func_ptrs_to_update_elems.clear(); } RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies(); @@ -2139,8 +2091,31 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { named_globals.erase(p_name); } +void GDScriptLanguage::thread_enter() { + GDScript::func_ptrs_to_update_thread_local = memnew(GDScript::UpdatableFuncPtr); +} + void GDScriptLanguage::thread_exit() { + // This thread may have been created before GDScript was up + // (which also means it can't have run any GDScript code at all). + if (!GDScript::func_ptrs_to_update_thread_local) { + return; + } + GDScript::_fixup_thread_function_bookkeeping(); + + bool destroy = false; + { + MutexLock lock(GDScript::func_ptrs_to_update_thread_local->mutex); + DEV_ASSERT(GDScript::func_ptrs_to_update_thread_local->rc != 0); + GDScript::func_ptrs_to_update_thread_local->rc--; + if (GDScript::func_ptrs_to_update_thread_local->rc == 0) { + destroy = true; + } + } + if (destroy) { + memdelete(GDScript::func_ptrs_to_update_thread_local); + } } void GDScriptLanguage::init() { @@ -2175,6 +2150,8 @@ void GDScriptLanguage::init() { _add_global(E.name, E.ptr); } + GDScript::func_ptrs_to_update_thread_local = &GDScript::func_ptrs_to_update_main_thread; + #ifdef TESTS_ENABLED GDScriptTests::GDScriptTestRunner::handle_cmdline(); #endif @@ -2224,6 +2201,8 @@ void GDScriptLanguage::finish() { } script_list.clear(); function_list.clear(); + + DEV_ASSERT(GDScript::func_ptrs_to_update_main_thread.rc == 1); } void GDScriptLanguage::profiling_start() { @@ -2241,6 +2220,8 @@ void GDScriptLanguage::profiling_start() { elem->self()->profile.last_frame_call_count = 0; elem->self()->profile.last_frame_self_time = 0; elem->self()->profile.last_frame_total_time = 0; + elem->self()->profile.native_calls.clear(); + elem->self()->profile.last_native_calls.clear(); elem = elem->next(); } @@ -2248,6 +2229,13 @@ void GDScriptLanguage::profiling_start() { #endif } +void GDScriptLanguage::profiling_set_save_native_calls(bool p_enable) { +#ifdef DEBUG_ENABLED + MutexLock lock(mutex); + profile_native_calls = p_enable; +#endif +} + void GDScriptLanguage::profiling_stop() { #ifdef DEBUG_ENABLED MutexLock lock(this->mutex); @@ -2262,17 +2250,32 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, MutexLock lock(this->mutex); + profiling_collate_native_call_data(true); SelfList<GDScriptFunction> *elem = function_list.first(); while (elem) { if (current >= p_info_max) { break; } + int last_non_internal = current; p_info_arr[current].call_count = elem->self()->profile.call_count.get(); p_info_arr[current].self_time = elem->self()->profile.self_time.get(); p_info_arr[current].total_time = elem->self()->profile.total_time.get(); p_info_arr[current].signature = elem->self()->profile.signature; - elem = elem->next(); current++; + + int nat_time = 0; + HashMap<String, GDScriptFunction::Profile::NativeProfile>::ConstIterator nat_calls = elem->self()->profile.native_calls.begin(); + while (nat_calls) { + p_info_arr[current].call_count = nat_calls->value.call_count; + p_info_arr[current].total_time = nat_calls->value.total_time; + p_info_arr[current].self_time = nat_calls->value.total_time; + p_info_arr[current].signature = nat_calls->value.signature; + nat_time += nat_calls->value.total_time; + current++; + ++nat_calls; + } + p_info_arr[last_non_internal].internal_time = nat_time; + elem = elem->next(); } #endif @@ -2285,17 +2288,33 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_ #ifdef DEBUG_ENABLED MutexLock lock(this->mutex); + profiling_collate_native_call_data(false); SelfList<GDScriptFunction> *elem = function_list.first(); while (elem) { if (current >= p_info_max) { break; } if (elem->self()->profile.last_frame_call_count > 0) { + int last_non_internal = current; p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count; p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time; p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time; p_info_arr[current].signature = elem->self()->profile.signature; current++; + + int nat_time = 0; + HashMap<String, GDScriptFunction::Profile::NativeProfile>::ConstIterator nat_calls = elem->self()->profile.last_native_calls.begin(); + while (nat_calls) { + p_info_arr[current].call_count = nat_calls->value.call_count; + p_info_arr[current].total_time = nat_calls->value.total_time; + p_info_arr[current].self_time = nat_calls->value.total_time; + p_info_arr[current].internal_time = nat_calls->value.total_time; + p_info_arr[current].signature = nat_calls->value.signature; + nat_time += nat_calls->value.total_time; + current++; + ++nat_calls; + } + p_info_arr[last_non_internal].internal_time = nat_time; } elem = elem->next(); } @@ -2304,6 +2323,33 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_ return current; } +void GDScriptLanguage::profiling_collate_native_call_data(bool p_accumulated) { +#ifdef DEBUG_ENABLED + // The same native call can be called from multiple functions, so join them together here. + // Only use the name of the function (ie signature.split[2]). + HashMap<String, GDScriptFunction::Profile::NativeProfile *> seen_nat_calls; + SelfList<GDScriptFunction> *elem = function_list.first(); + while (elem) { + HashMap<String, GDScriptFunction::Profile::NativeProfile> *nat_calls = p_accumulated ? &elem->self()->profile.native_calls : &elem->self()->profile.last_native_calls; + HashMap<String, GDScriptFunction::Profile::NativeProfile>::Iterator it = nat_calls->begin(); + + while (it != nat_calls->end()) { + Vector<String> sig = it->value.signature.split("::"); + HashMap<String, GDScriptFunction::Profile::NativeProfile *>::ConstIterator already_found = seen_nat_calls.find(sig[2]); + if (already_found) { + already_found->value->total_time += it->value.total_time; + already_found->value->call_count += it->value.call_count; + elem->self()->profile.last_native_calls.remove(it); + } else { + seen_nat_calls.insert(sig[2], &it->value); + } + ++it; + } + elem = elem->next(); + } +#endif +} + struct GDScriptDepSort { //must support sorting so inheritance works properly (parent must be reloaded first) bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const { @@ -2340,6 +2386,19 @@ void GDScriptLanguage::reload_all_scripts() { } elem = elem->next(); } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + // Reload all pointers to existing singletons so that tool scripts can work with the reloaded extensions. + List<Engine::Singleton> singletons; + Engine::get_singleton()->get_singletons(&singletons); + for (const Engine::Singleton &E : singletons) { + if (globals.has(E.name)) { + _add_global(E.name, E.ptr); + } + } + } +#endif } //as scripts are going to be reloaded, must proceed without locking here @@ -2490,9 +2549,11 @@ void GDScriptLanguage::frame() { elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count.get(); elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time.get(); elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time.get(); + elem->self()->profile.last_native_calls = elem->self()->profile.native_calls; elem->self()->profile.frame_call_count.set(0); elem->self()->profile.frame_self_time.set(0); elem->self()->profile.frame_total_time.set(0); + elem->self()->profile.native_calls.clear(); elem = elem->next(); } } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 9b99f5ca0b..31811bba47 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -121,21 +121,23 @@ class GDScript : public Script { struct UpdatableFuncPtr { List<GDScriptFunction **> ptrs; Mutex mutex; - bool initialized = false; + bool initialized : 1; + bool transferred : 1; + uint32_t rc = 1; + UpdatableFuncPtr() : + initialized(false), transferred(false) {} }; struct UpdatableFuncPtrElement { List<GDScriptFunction **>::Element *element = nullptr; - Mutex *mutex = nullptr; + UpdatableFuncPtr *func_ptr = nullptr; }; - static thread_local UpdatableFuncPtr func_ptrs_to_update_thread_local; - static thread_local LocalVector<List<UpdatableFuncPtr *>::Element> func_ptrs_to_update_entries_thread_local; - static UpdatableFuncPtr *func_ptrs_to_update_main_thread; + static UpdatableFuncPtr func_ptrs_to_update_main_thread; + static thread_local UpdatableFuncPtr *func_ptrs_to_update_thread_local; List<UpdatableFuncPtr *> func_ptrs_to_update; - List<UpdatableFuncPtrElement> func_ptrs_to_update_elems; Mutex func_ptrs_to_update_mutex; - UpdatableFuncPtrElement *_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); - static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement *p_func_ptr_element); + UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); + static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element); static void _fixup_thread_function_bookkeeping(); @@ -252,7 +254,7 @@ public: const Ref<GDScriptNativeClass> &get_native() const { return native; } RBSet<GDScript *> get_dependencies(); - RBSet<GDScript *> get_inverted_dependencies(); + HashMap<GDScript *, RBSet<GDScript *>> get_all_dependencies(); RBSet<GDScript *> get_must_clear_dependencies(); virtual bool has_script_signal(const StringName &p_signal) const override; @@ -437,6 +439,7 @@ class GDScriptLanguage : public ScriptLanguage { SelfList<GDScriptFunction>::List function_list; bool profiling; + bool profile_native_calls; uint64_t script_frame_time; HashMap<String, ObjectID> orphan_subclasses; @@ -561,6 +564,7 @@ public: /* MULTITHREAD FUNCTIONS */ + virtual void thread_enter() override; virtual void thread_exit() override; /* DEBUGGER FUNCTIONS */ @@ -587,6 +591,8 @@ public: virtual void profiling_start() override; virtual void profiling_stop() override; + virtual void profiling_set_save_native_calls(bool p_enable) override; + void profiling_collate_native_call_data(bool p_accumulated); virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override; virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 983a19470a..cf537bde16 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -685,10 +685,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type result.builtin_type = GDScriptParser::get_builtin_type(first); if (result.builtin_type == Variant::ARRAY) { - GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->container_type)); + GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0))); if (container_type.kind != GDScriptParser::DataType::VARIANT) { container_type.is_constant = false; - result.set_container_element_type(container_type); + result.set_container_element_type(0, container_type); } } } else if (class_exists(first)) { @@ -829,8 +829,16 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } - if (result.builtin_type != Variant::ARRAY && p_type->container_type != nullptr) { - push_error("Only arrays can specify the collection element type.", p_type); + if (!p_type->container_types.is_empty()) { + if (result.builtin_type == Variant::ARRAY) { + if (p_type->container_types.size() != 1) { + push_error("Arrays require exactly one collection element type.", p_type); + return bad_type; + } + } else { + push_error("Only arrays can specify collection element types.", p_type); + return bad_type; + } } p_type->set_datatype(result); @@ -1891,8 +1899,8 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi if (p_assignable->initializer->type == GDScriptParser::Node::ARRAY) { GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_assignable->initializer); - if (has_specified_type && specified_type.has_container_element_type()) { - update_array_literal_element_type(array, specified_type.get_container_element_type()); + if (has_specified_type && specified_type.has_container_element_type(0)) { + update_array_literal_element_type(array, specified_type.get_container_element_type(0)); } } @@ -1955,7 +1963,7 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi } else { push_error(vformat(R"(Cannot assign a value of type %s to %s "%s" with specified type %s.)", initializer_type.to_string(), p_kind, p_assignable->identifier->name, specified_type.to_string()), p_assignable->initializer); } - } else if (specified_type.has_container_element_type() && !initializer_type.has_container_element_type()) { + } else if (specified_type.has_container_element_type(0) && !initializer_type.has_container_element_type(0)) { mark_node_unsafe(p_assignable->initializer); #ifdef DEBUG_ENABLED } else if (specified_type.builtin_type == Variant::INT && initializer_type.builtin_type == Variant::FLOAT) { @@ -2127,8 +2135,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { if (list_type.is_variant()) { variable_type.kind = GDScriptParser::DataType::VARIANT; mark_node_unsafe(p_for->list); - } else if (list_type.has_container_element_type()) { - variable_type = list_type.get_container_element_type(); + } else if (list_type.has_container_element_type(0)) { + variable_type = list_type.get_container_element_type(0); variable_type.type_source = list_type.type_source; } else if (list_type.is_typed_container_type()) { variable_type = list_type.get_typed_container_type(); @@ -2377,8 +2385,8 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { result.builtin_type = Variant::NIL; result.is_constant = true; } else { - if (p_return->return_value->type == GDScriptParser::Node::ARRAY && has_expected_type && expected_type.has_container_element_type()) { - update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_return->return_value), expected_type.get_container_element_type()); + if (p_return->return_value->type == GDScriptParser::Node::ARRAY && has_expected_type && expected_type.has_container_element_type(0)) { + update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_return->return_value), expected_type.get_container_element_type(0)); } if (has_expected_type && expected_type.is_hard_type() && p_return->return_value->is_constant) { update_const_expression_builtin_type(p_return->return_value, expected_type, "return"); @@ -2598,7 +2606,7 @@ void GDScriptAnalyzer::update_const_expression_builtin_type(GDScriptParser::Expr // This function determines which type is that (if any). void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNode *p_array, const GDScriptParser::DataType &p_element_type) { GDScriptParser::DataType expected_type = p_element_type; - expected_type.unset_container_element_type(); // Nested types (like `Array[Array[int]]`) are not currently supported. + expected_type.container_element_types.clear(); // Nested types (like `Array[Array[int]]`) are not currently supported. for (int i = 0; i < p_array->elements.size(); i++) { GDScriptParser::ExpressionNode *element_node = p_array->elements[i]; @@ -2621,7 +2629,7 @@ void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNo } GDScriptParser::DataType array_type = p_array->get_datatype(); - array_type.set_container_element_type(expected_type); + array_type.set_container_element_type(0, expected_type); p_array->set_datatype(array_type); } @@ -2668,8 +2676,8 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } // Check if assigned value is an array literal, so we can make it a typed array too if appropriate. - if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type()) { - update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value), assignee_type.get_container_element_type()); + if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type(0)) { + update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value), assignee_type.get_container_element_type(0)); } if (p_assignment->operation == GDScriptParser::AssignmentNode::OP_NONE && assignee_type.is_hard_type() && p_assignment->assigned_value->is_constant) { @@ -2747,7 +2755,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig // weak non-variant assignee and incompatible result downgrades_assignee = true; } - } else if (assignee_type.has_container_element_type() && !op_type.has_container_element_type()) { + } else if (assignee_type.has_container_element_type(0) && !op_type.has_container_element_type(0)) { // typed array assignee and untyped array result mark_node_unsafe(p_assignment); } @@ -3311,8 +3319,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()) { - update_array_literal_element_type(E.value, par_types[index].get_container_element_type()); + 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)); } } validate_call_arg(par_types, default_arg_count, method_flags.has_flag(METHOD_FLAG_VARARG), p_call); @@ -3444,8 +3452,8 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) { } } - if (p_cast->operand->type == GDScriptParser::Node::ARRAY && cast_type.has_container_element_type()) { - update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_cast->operand), cast_type.get_container_element_type()); + if (p_cast->operand->type == GDScriptParser::Node::ARRAY && cast_type.has_container_element_type(0)) { + update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_cast->operand), cast_type.get_container_element_type(0)); } if (!cast_type.is_variant()) { @@ -3650,6 +3658,10 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod return; } } + if (Variant::has_builtin_method(base.builtin_type, name)) { + p_identifier->set_datatype(make_callable_type(Variant::get_builtin_method_info(base.builtin_type, name))); + return; + } if (base.is_hard_type()) { #ifdef SUGGEST_GODOT4_RENAMES String rename_hint = String(); @@ -3769,6 +3781,60 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod } } + // Check non-GDScript scripts. + Ref<Script> script_type = base.script_type; + + if (base_class == nullptr && script_type.is_valid()) { + List<PropertyInfo> property_list; + script_type->get_script_property_list(&property_list); + + for (const PropertyInfo &property_info : property_list) { + if (property_info.name != p_identifier->name) { + continue; + } + + const GDScriptParser::DataType property_type = GDScriptAnalyzer::type_from_property(property_info, false, false); + + p_identifier->set_datatype(property_type); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE; + return; + } + + MethodInfo method_info = script_type->get_method_info(p_identifier->name); + + if (method_info.name == p_identifier->name) { + p_identifier->set_datatype(make_callable_type(method_info)); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_FUNCTION; + return; + } + + List<MethodInfo> signal_list; + script_type->get_script_signal_list(&signal_list); + + for (const MethodInfo &signal_info : signal_list) { + if (signal_info.name != p_identifier->name) { + continue; + } + + const GDScriptParser::DataType signal_type = make_signal_type(signal_info); + + p_identifier->set_datatype(signal_type); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_SIGNAL; + return; + } + + HashMap<StringName, Variant> constant_map; + script_type->get_constants(&constant_map); + + if (constant_map.has(p_identifier->name)) { + Variant constant = constant_map.get(p_identifier->name); + + p_identifier->set_datatype(make_builtin_meta_type(constant.get_type())); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; + return; + } + } + // Check native members. No need for native class recursion because Node exposes all Object's properties. const StringName &native = base.native_type; @@ -4432,8 +4498,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri break; // Can have an element type. case Variant::ARRAY: - if (base_type.has_container_element_type()) { - result_type = base_type.get_container_element_type(); + if (base_type.has_container_element_type(0)) { + result_type = base_type.get_container_element_type(0); result_type.type_source = base_type.type_source; } else { result_type.kind = GDScriptParser::DataType::VARIANT; @@ -4597,7 +4663,7 @@ Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::Expressi } Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &is_reduced) { - Array array = p_array->get_datatype().has_container_element_type() ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type()) : Array(); + Array array = p_array->get_datatype().has_container_element_type(0) ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type(0)) : Array(); array.resize(p_array->elements.size()); for (int i = 0; i < p_array->elements.size(); i++) { @@ -4719,8 +4785,8 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo GDScriptParser::DataType datatype = p_variable->get_datatype(); if (datatype.is_hard_type()) { if (datatype.kind == GDScriptParser::DataType::BUILTIN && datatype.builtin_type != Variant::OBJECT) { - if (datatype.builtin_type == Variant::ARRAY && datatype.has_container_element_type()) { - result = make_array_from_element_datatype(datatype.get_container_element_type()); + if (datatype.builtin_type == Variant::ARRAY && datatype.has_container_element_type(0)) { + result = make_array_from_element_datatype(datatype.get_container_element_type(0)); } else { VariantInternal::initialize(&result, datatype.builtin_type); } @@ -4747,11 +4813,11 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va if (p_value.get_type() == Variant::ARRAY) { const Array &array = p_value; if (array.get_typed_script()) { - result.set_container_element_type(type_from_metatype(make_script_meta_type(array.get_typed_script()))); + result.set_container_element_type(0, type_from_metatype(make_script_meta_type(array.get_typed_script()))); } else if (array.get_typed_class_name()) { - result.set_container_element_type(type_from_metatype(make_native_meta_type(array.get_typed_class_name()))); + result.set_container_element_type(0, type_from_metatype(make_native_meta_type(array.get_typed_class_name()))); } else if (array.get_typed_builtin() != Variant::NIL) { - result.set_container_element_type(type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin()))); + result.set_container_element_type(0, type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin()))); } } else if (p_value.get_type() == Variant::OBJECT) { // Object is treated as a native type, not a builtin type. @@ -4873,7 +4939,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array."); } elem_type.is_constant = false; - result.set_container_element_type(elem_type); + result.set_container_element_type(0, elem_type); } else if (p_property.type == Variant::INT) { // Check if it's enum. if ((p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) && p_property.class_name != StringName()) { @@ -5225,7 +5291,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type(); if (p_operation == Variant::OP_ADD && a_type == Variant::ARRAY && b_type == Variant::ARRAY) { - if (p_a.has_container_element_type() && p_b.has_container_element_type() && p_a.get_container_element_type() == p_b.get_container_element_type()) { + if (p_a.has_container_element_type(0) && p_b.has_container_element_type(0) && p_a.get_container_element_type(0) == p_b.get_container_element_type(0)) { r_valid = true; result = p_a; result.type_source = hard_operation ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED; @@ -5276,8 +5342,8 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ } if (valid && p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) { // Check the element type. - if (p_target.has_container_element_type() && p_source.has_container_element_type()) { - valid = p_target.get_container_element_type() == p_source.get_container_element_type(); + if (p_target.has_container_element_type(0) && p_source.has_container_element_type(0)) { + valid = p_target.get_container_element_type(0) == p_source.get_container_element_type(0); } } return valid; diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 25e20c0e76..27766115d5 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -623,8 +623,8 @@ void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, V void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) { switch (p_type.kind) { case GDScriptDataType::BUILTIN: { - if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type()) { - const GDScriptDataType &element_type = p_type.get_container_element_type(); + if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_ARRAY); append(p_target); append(p_source); @@ -878,8 +878,8 @@ void GDScriptByteCodeGenerator::write_get_static_variable(const Address &p_targe void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) { switch (p_target.type.kind) { case GDScriptDataType::BUILTIN: { - if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { - const GDScriptDataType &element_type = p_target.type.get_container_element_type(); + if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_target.type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY); append(p_target); append(p_source); @@ -924,8 +924,8 @@ void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_ta } void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) { - if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { - const GDScriptDataType &element_type = p_target.type.get_container_element_type(); + if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_target.type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY); append(p_target); append(p_source); @@ -1666,9 +1666,9 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { // If this is a typed function, then we need to check for potential conversions. if (function->return_type.has_type) { - if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { + if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) { // Typed array. - const GDScriptDataType &element_type = function->return_type.get_container_element_type(); + const GDScriptDataType &element_type = function->return_type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY); append(p_return_value); append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); @@ -1691,8 +1691,8 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { } else { switch (function->return_type.kind) { case GDScriptDataType::BUILTIN: { - if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { - const GDScriptDataType &element_type = function->return_type.get_container_element_type(); + if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) { + const GDScriptDataType &element_type = function->return_type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY); append(p_return_value); append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 7980f020b8..ee360e581b 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -196,8 +196,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D } } - if (p_datatype.has_container_element_type()) { - result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner, false)); + for (int i = 0; i < p_datatype.container_element_types.size(); i++) { + result.set_container_element_type(i, _gdtype_from_datatype(p_datatype.get_container_element_type_or_variant(i), p_owner, false)); } return result; @@ -322,9 +322,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) { // Get like it was a property. GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here. - GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF); - gen->write_get_named(temp, identifier, self); + GDScriptCodeGenerator::Address base(GDScriptCodeGenerator::Address::SELF); + if (member.type == GDScriptParser::ClassNode::Member::FUNCTION && member.function->is_static) { + base = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS); + } + + gen->write_get_named(temp, identifier, base); return temp; } } @@ -507,8 +511,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code values.push_back(val); } - if (array_type.has_container_element_type()) { - gen->write_construct_typed_array(result, array_type.get_container_element_type(), values); + if (array_type.has_container_element_type(0)) { + gen->write_construct_typed_array(result, array_type.get_container_element_type(0), values); } else { gen->write_construct_array(result, values); } @@ -2133,8 +2137,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui initialized = true; } else if (local_type.has_type) { // Initialize with default for type. - if (local_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); + if (local_type.has_container_element_type(0)) { + codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>()); initialized = true; } else if (local_type.kind == GDScriptDataType::BUILTIN) { codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); @@ -2276,8 +2280,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type); - if (field_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); + if (field_type.has_container_element_type(0)) { + codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>()); } else if (field_type.kind == GDScriptDataType::BUILTIN) { codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); } @@ -2466,9 +2470,9 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS if (field_type.has_type) { codegen.generator->write_newline(field->start_line); - if (field_type.has_container_element_type()) { + if (field_type.has_container_element_type(0)) { GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type); - codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); + codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>()); codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index); codegen.generator->pop_temporary(); } else if (field_type.kind == GDScriptDataType::BUILTIN) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 724715d9e5..9eb6fe8744 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1083,6 +1083,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<PropertyInfo> members; scr->get_script_property_list(&members); for (const PropertyInfo &E : members) { + if (E.usage & (PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP)) { + continue; + } + if (E.name.contains("/")) { + continue; + } int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.name); ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); @@ -1152,7 +1158,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<PropertyInfo> pinfo; ClassDB::get_property_list(type, &pinfo); for (const PropertyInfo &E : pinfo) { - if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { + if (E.usage & (PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP)) { continue; } if (E.name.contains("/")) { @@ -1213,6 +1219,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } for (const PropertyInfo &E : members) { + if (E.usage & (PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP)) { + continue; + } if (!String(E.name).contains("/")) { ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); if (GDScriptParser::theme_color_names.has(E.name)) { @@ -1485,11 +1494,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } break; case GDScriptParser::Node::SELF: { if (p_context.current_class) { - if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) { - r_type.type = p_context.current_class->get_datatype(); - } else { - r_type.type = p_context.current_class->base_type; - } + r_type.type = p_context.current_class->get_datatype(); + r_type.type.is_meta_type = false; found = true; } } break; @@ -2601,6 +2607,64 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_arghint = _make_arguments_hint(info, p_argidx); } + if (p_argidx == 1 && p_context.node && p_context.node->type == GDScriptParser::Node::CALL && ClassDB::is_parent_class(class_name, SNAME("Tween")) && p_method == SNAME("tween_property")) { + // Get tweened objects properties. + GDScriptParser::ExpressionNode *tweened_object = static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments[0]; + StringName native_type = tweened_object->datatype.native_type; + switch (tweened_object->datatype.kind) { + case GDScriptParser::DataType::SCRIPT: { + Ref<Script> script = tweened_object->datatype.script_type; + native_type = script->get_instance_base_type(); + int n = 0; + while (script.is_valid()) { + List<PropertyInfo> properties; + script->get_script_property_list(&properties); + for (const PropertyInfo &E : properties) { + if (E.usage & (PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_INTERNAL)) { + continue; + } + ScriptLanguage::CodeCompletionOption option(E.name.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n); + r_result.insert(option.display, option); + } + script = script->get_base_script(); + n++; + } + } break; + case GDScriptParser::DataType::CLASS: { + GDScriptParser::ClassNode *clss = tweened_object->datatype.class_type; + native_type = clss->base_type.native_type; + int n = 0; + while (clss) { + for (GDScriptParser::ClassNode::Member member : clss->members) { + if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) { + ScriptLanguage::CodeCompletionOption option(member.get_name().quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n); + r_result.insert(option.display, option); + } + } + if (clss->base_type.kind == GDScriptParser::DataType::Kind::CLASS) { + clss = clss->base_type.class_type; + n++; + } else { + native_type = clss->base_type.native_type; + clss = nullptr; + } + } + } break; + default: + break; + } + + List<PropertyInfo> properties; + ClassDB::get_property_list(native_type, &properties); + for (const PropertyInfo &E : properties) { + if (E.usage & (PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_INTERNAL)) { + continue; + } + ScriptLanguage::CodeCompletionOption option(E.name.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); + r_result.insert(option.display, option); + } + } + if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (p_method == SNAME("get_node") || p_method == SNAME("has_node"))) { // Get autoloads List<PropertyInfo> props; @@ -2667,6 +2731,7 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co if (p_context.base == nullptr) { return false; } + const GDScriptParser::GetNodeNode *get_node = nullptr; switch (p_subscript->base->type) { @@ -2675,6 +2740,11 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co } break; case GDScriptParser::Node::IDENTIFIER: { + if (p_subscript->base->datatype.type_source == GDScriptParser::DataType::ANNOTATED_EXPLICIT) { + // Annotated type takes precedence. + return false; + } + const GDScriptParser::IdentifierNode *identifier_node = static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base); switch (identifier_node->source) { @@ -2715,10 +2785,19 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co if (r_base != nullptr) { *r_base = node; } - r_base_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - r_base_type.kind = GDScriptParser::DataType::NATIVE; + + r_base_type.type_source = GDScriptParser::DataType::INFERRED; r_base_type.builtin_type = Variant::OBJECT; r_base_type.native_type = node->get_class_name(); + + Ref<Script> scr = node->get_script(); + if (scr.is_null()) { + r_base_type.kind = GDScriptParser::DataType::NATIVE; + } else { + r_base_type.kind = GDScriptParser::DataType::SCRIPT; + r_base_type.script_type = scr; + } + return true; } } @@ -2745,8 +2824,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call); GDScriptParser::Node::Type callee_type = call->get_callee_type(); - GDScriptCompletionIdentifier connect_base; - if (callee_type == GDScriptParser::Node::SUBSCRIPT) { const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index c9b543fbb9..177c68533e 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -45,10 +45,9 @@ class GDScriptInstance; class GDScript; class GDScriptDataType { -private: - GDScriptDataType *container_element_type = nullptr; - public: + Vector<GDScriptDataType> container_element_types; + enum Kind { UNINITIALIZED, BUILTIN, @@ -76,19 +75,20 @@ public: case BUILTIN: { Variant::Type var_type = p_variant.get_type(); bool valid = builtin_type == var_type; - if (valid && builtin_type == Variant::ARRAY && has_container_element_type()) { + if (valid && builtin_type == Variant::ARRAY && has_container_element_type(0)) { Array array = p_variant; if (array.is_typed()) { + GDScriptDataType array_container_type = get_container_element_type(0); Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin(); StringName array_native_type = array.get_typed_class_name(); Ref<Script> array_script_type_ref = array.get_typed_script(); if (array_script_type_ref.is_valid()) { - valid = (container_element_type->kind == SCRIPT || container_element_type->kind == GDSCRIPT) && container_element_type->script_type == array_script_type_ref.ptr(); + valid = (array_container_type.kind == SCRIPT || array_container_type.kind == GDSCRIPT) && array_container_type.script_type == array_script_type_ref.ptr(); } else if (array_native_type != StringName()) { - valid = container_element_type->kind == NATIVE && container_element_type->native_type == array_native_type; + valid = array_container_type.kind == NATIVE && array_container_type.native_type == array_native_type; } else { - valid = container_element_type->kind == BUILTIN && container_element_type->builtin_type == array_builtin_type; + valid = array_container_type.kind == BUILTIN && array_container_type.builtin_type == array_builtin_type; } } else { valid = false; @@ -147,24 +147,32 @@ public: return false; } - void set_container_element_type(const GDScriptDataType &p_element_type) { - container_element_type = memnew(GDScriptDataType(p_element_type)); + void set_container_element_type(int p_index, const GDScriptDataType &p_element_type) { + ERR_FAIL_COND(p_index < 0); + while (p_index >= container_element_types.size()) { + container_element_types.push_back(GDScriptDataType()); + } + container_element_types.write[p_index] = GDScriptDataType(p_element_type); + } + + GDScriptDataType get_container_element_type(int p_index) const { + ERR_FAIL_INDEX_V(p_index, container_element_types.size(), GDScriptDataType()); + return container_element_types[p_index]; } - GDScriptDataType get_container_element_type() const { - ERR_FAIL_NULL_V(container_element_type, GDScriptDataType()); - return *container_element_type; + GDScriptDataType get_container_element_type_or_variant(int p_index) const { + if (p_index < 0 || p_index >= container_element_types.size()) { + return GDScriptDataType(); + } + return container_element_types[p_index]; } - bool has_container_element_type() const { - return container_element_type != nullptr; + bool has_container_element_type(int p_index) const { + return p_index >= 0 && p_index < container_element_types.size(); } - void unset_container_element_type() { - if (container_element_type) { - memdelete(container_element_type); - } - container_element_type = nullptr; + bool has_container_element_types() const { + return !container_element_types.is_empty(); } GDScriptDataType() = default; @@ -176,19 +184,14 @@ public: native_type = p_other.native_type; script_type = p_other.script_type; script_type_ref = p_other.script_type_ref; - unset_container_element_type(); - if (p_other.has_container_element_type()) { - set_container_element_type(p_other.get_container_element_type()); - } + container_element_types = p_other.container_element_types; } GDScriptDataType(const GDScriptDataType &p_other) { *this = p_other; } - ~GDScriptDataType() { - unset_container_element_type(); - } + ~GDScriptDataType() {} }; class GDScriptFunction { @@ -471,6 +474,13 @@ private: uint64_t last_frame_call_count = 0; uint64_t last_frame_self_time = 0; uint64_t last_frame_total_time = 0; + typedef struct NativeProfile { + uint64_t call_count; + uint64_t total_time; + String signature; + } NativeProfile; + HashMap<String, NativeProfile> native_calls; + HashMap<String, NativeProfile> last_native_calls; } profile; #endif @@ -511,6 +521,7 @@ public: void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const; #ifdef DEBUG_ENABLED + void _profile_native_call(uint64_t p_t_taken, const String &p_function_name, const String &p_instance_class_name = String()); void disassemble(const Vector<String> &p_code_lines) const; #endif diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp index 339d1ac08e..547f5607d3 100644 --- a/modules/gdscript/gdscript_lambda_callable.cpp +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -296,7 +296,5 @@ GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptF } GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() { - if (updatable_func_ptr_element) { - GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); - } + GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); } diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index d961f18852..ee7d547544 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -45,7 +45,7 @@ class GDScriptLambdaCallable : public CallableCustom { GDScriptFunction *function = nullptr; Ref<GDScript> script; uint32_t h; - GDScript::UpdatableFuncPtrElement *updatable_func_ptr_element = nullptr; + GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; Vector<Variant> captures; @@ -72,7 +72,7 @@ class GDScriptLambdaSelfCallable : public CallableCustom { Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference. Object *object = nullptr; // For non RefCounted objects, use a direct pointer. uint32_t h; - GDScript::UpdatableFuncPtrElement *updatable_func_ptr_element = nullptr; + GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; Vector<Variant> captures; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index db7b3e7ace..f3a4f2eaa6 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -73,8 +73,11 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { HashMap<String, String> GDScriptParser::theme_color_names; #endif +HashMap<StringName, GDScriptParser::AnnotationInfo> GDScriptParser::valid_annotations; + void GDScriptParser::cleanup() { builtin_types.clear(); + valid_annotations.clear(); } void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const { @@ -89,41 +92,42 @@ bool GDScriptParser::annotation_exists(const String &p_annotation_name) const { GDScriptParser::GDScriptParser() { // Register valid annotations. - // TODO: Should this be static? - register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation); - register_annotation(MethodInfo("@icon", PropertyInfo(Variant::STRING, "icon_path")), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation); - register_annotation(MethodInfo("@static_unload"), AnnotationInfo::SCRIPT, &GDScriptParser::static_unload_annotation); - - 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_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>); - register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true); - register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>); - register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); - register_annotation(MethodInfo("@export_placeholder", PropertyInfo(Variant::STRING, "placeholder")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); - register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true); - register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true); - register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); - register_annotation(MethodInfo("@export_node_path", PropertyInfo(Variant::STRING, "type")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, varray(""), true); - register_annotation(MethodInfo("@export_flags", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, varray(), true); - register_annotation(MethodInfo("@export_flags_2d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_RENDER, Variant::INT>); - register_annotation(MethodInfo("@export_flags_2d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_PHYSICS, Variant::INT>); - register_annotation(MethodInfo("@export_flags_2d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_NAVIGATION, Variant::INT>); - register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>); - 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>); - // Export grouping annotations. - register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); - register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray("")); - register_annotation(MethodInfo("@export_subgroup", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_SUBGROUP>, varray("")); - // Warning annotations. - register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true); - // Networking. - register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("authority", "call_remote", "unreliable", 0)); + if (unlikely(valid_annotations.is_empty())) { + register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation); + register_annotation(MethodInfo("@icon", PropertyInfo(Variant::STRING, "icon_path")), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation); + register_annotation(MethodInfo("@static_unload"), AnnotationInfo::SCRIPT, &GDScriptParser::static_unload_annotation); + + 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_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>); + register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true); + register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>); + register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); + register_annotation(MethodInfo("@export_placeholder", PropertyInfo(Variant::STRING, "placeholder")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); + register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true); + register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true); + register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); + register_annotation(MethodInfo("@export_node_path", PropertyInfo(Variant::STRING, "type")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, varray(""), true); + register_annotation(MethodInfo("@export_flags", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, varray(), true); + register_annotation(MethodInfo("@export_flags_2d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_RENDER, Variant::INT>); + register_annotation(MethodInfo("@export_flags_2d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_PHYSICS, Variant::INT>); + register_annotation(MethodInfo("@export_flags_2d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_NAVIGATION, Variant::INT>); + register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>); + 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>); + // Export grouping annotations. + register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); + register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray("")); + register_annotation(MethodInfo("@export_subgroup", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_SUBGROUP>, varray("")); + // Warning annotations. + register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true); + // Networking. + register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("authority", "call_remote", "unreliable", 0)); + } #ifdef DEBUG_ENABLED is_ignoring_warnings = !(bool)GLOBAL_GET("debug/gdscript/warnings/enable"); @@ -3337,14 +3341,21 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) { if (match(GDScriptTokenizer::Token::BRACKET_OPEN)) { // Typed collection (like Array[int]). - type->container_type = parse_type(false); // Don't allow void for array element type. - if (type->container_type == nullptr) { - push_error(R"(Expected type for collection after "[".)"); - complete_extents(type); - type = nullptr; - } else if (type->container_type->container_type != nullptr) { - push_error("Nested typed collections are not supported."); - } + bool first_pass = true; + do { + TypeNode *container_type = parse_type(false); // Don't allow void for element type. + if (container_type == nullptr) { + push_error(vformat(R"(Expected type for collection after "%s".)", first_pass ? "[" : ",")); + complete_extents(type); + type = nullptr; + break; + } else if (container_type->container_types.size() > 0) { + push_error("Nested typed collections are not supported."); + } else { + type->container_types.append(container_type); + } + first_pass = false; + } while (match(GDScriptTokenizer::Token::COMMA)); consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after collection type.)"); if (type != nullptr) { complete_extents(type); @@ -3996,8 +4007,8 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.type = Variant::INT; } } else if (p_annotation->name == SNAME("@export_multiline")) { - if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) { - DataType inner_type = export_type.get_container_element_type(); + if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) { + DataType inner_type = export_type.get_container_element_type(0); if (inner_type.builtin_type != Variant::STRING) { push_error(vformat(R"("%s" annotation on arrays requires a string type but type "%s" was given instead.)", p_annotation->name.operator String(), inner_type.to_string()), variable); return false; @@ -4033,8 +4044,8 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node bool is_array = false; - if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) { - export_type = export_type.get_container_element_type(); // Use inner type for. + if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) { + export_type = export_type.get_container_element_type(0); // Use inner type for. is_array = true; } @@ -4344,8 +4355,8 @@ String GDScriptParser::DataType::to_string() const { if (builtin_type == Variant::NIL) { return "null"; } - if (builtin_type == Variant::ARRAY && has_container_element_type()) { - return vformat("Array[%s]", container_element_type->to_string()); + if (builtin_type == Variant::ARRAY && has_container_element_type(0)) { + return vformat("Array[%s]", container_element_types[0].to_string()); } return Variant::get_type_name(builtin_type); case NATIVE: @@ -4398,36 +4409,36 @@ PropertyInfo GDScriptParser::DataType::to_property_info(const String &p_name) co switch (kind) { case BUILTIN: result.type = builtin_type; - if (builtin_type == Variant::ARRAY && has_container_element_type()) { - const DataType *elem_type = container_element_type; - switch (elem_type->kind) { + if (builtin_type == Variant::ARRAY && has_container_element_type(0)) { + const DataType elem_type = get_container_element_type(0); + switch (elem_type.kind) { case BUILTIN: result.hint = PROPERTY_HINT_ARRAY_TYPE; - result.hint_string = Variant::get_type_name(elem_type->builtin_type); + result.hint_string = Variant::get_type_name(elem_type.builtin_type); break; case NATIVE: result.hint = PROPERTY_HINT_ARRAY_TYPE; - result.hint_string = elem_type->native_type; + result.hint_string = elem_type.native_type; break; case SCRIPT: result.hint = PROPERTY_HINT_ARRAY_TYPE; - if (elem_type->script_type.is_valid() && elem_type->script_type->get_global_name() != StringName()) { - result.hint_string = elem_type->script_type->get_global_name(); + if (elem_type.script_type.is_valid() && elem_type.script_type->get_global_name() != StringName()) { + result.hint_string = elem_type.script_type->get_global_name(); } else { - result.hint_string = elem_type->native_type; + result.hint_string = elem_type.native_type; } break; case CLASS: result.hint = PROPERTY_HINT_ARRAY_TYPE; - if (elem_type->class_type != nullptr && elem_type->class_type->get_global_name() != StringName()) { - result.hint_string = elem_type->class_type->get_global_name(); + if (elem_type.class_type != nullptr && elem_type.class_type->get_global_name() != StringName()) { + result.hint_string = elem_type.class_type->get_global_name(); } else { - result.hint_string = elem_type->native_type; + result.hint_string = elem_type.native_type; } break; case ENUM: result.hint = PROPERTY_HINT_ARRAY_TYPE; - result.hint_string = String(elem_type->native_type).replace("::", "."); + result.hint_string = String(elem_type.native_type).replace("::", "."); break; case VARIANT: case RESOLVING: diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 4b46b98baa..88b5bdc43f 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -101,11 +101,9 @@ public: struct WhileNode; class DataType { - private: - // Private access so we can control memory management. - DataType *container_element_type = nullptr; - public: + Vector<DataType> container_element_types; + enum Kind { BUILTIN, NATIVE, @@ -152,24 +150,39 @@ public: _FORCE_INLINE_ String to_string_strict() const { return is_hard_type() ? to_string() : "Variant"; } PropertyInfo to_property_info(const String &p_name) const; - _FORCE_INLINE_ void set_container_element_type(const DataType &p_type) { - container_element_type = memnew(DataType(p_type)); + _FORCE_INLINE_ static DataType get_variant_type() { // Default DataType for container elements. + DataType datatype; + datatype.kind = VARIANT; + datatype.type_source = INFERRED; + return datatype; } - _FORCE_INLINE_ DataType get_container_element_type() const { - ERR_FAIL_NULL_V(container_element_type, DataType()); - return *container_element_type; + _FORCE_INLINE_ void set_container_element_type(int p_index, const DataType &p_type) { + ERR_FAIL_COND(p_index < 0); + while (p_index >= container_element_types.size()) { + container_element_types.push_back(get_variant_type()); + } + container_element_types.write[p_index] = DataType(p_type); } - _FORCE_INLINE_ bool has_container_element_type() const { - return container_element_type != nullptr; + _FORCE_INLINE_ DataType get_container_element_type(int p_index) const { + ERR_FAIL_INDEX_V(p_index, container_element_types.size(), get_variant_type()); + return container_element_types[p_index]; } - _FORCE_INLINE_ void unset_container_element_type() { - if (container_element_type) { - memdelete(container_element_type); - }; - container_element_type = nullptr; + _FORCE_INLINE_ DataType get_container_element_type_or_variant(int p_index) const { + if (p_index < 0 || p_index >= container_element_types.size()) { + return get_variant_type(); + } + return container_element_types[p_index]; + } + + _FORCE_INLINE_ bool has_container_element_type(int p_index) const { + return p_index >= 0 && p_index < container_element_types.size(); + } + + _FORCE_INLINE_ bool has_container_element_types() const { + return !container_element_types.is_empty(); } bool is_typed_container_type() const; @@ -229,10 +242,7 @@ public: class_type = p_other.class_type; method_info = p_other.method_info; enum_values = p_other.enum_values; - unset_container_element_type(); - if (p_other.has_container_element_type()) { - set_container_element_type(p_other.get_container_element_type()); - } + container_element_types = p_other.container_element_types; } DataType() = default; @@ -241,9 +251,7 @@ public: *this = p_other; } - ~DataType() { - unset_container_element_type(); - } + ~DataType() {} }; struct ParserError { @@ -1183,7 +1191,11 @@ public: struct TypeNode : public Node { Vector<IdentifierNode *> type_chain; - TypeNode *container_type = nullptr; + Vector<TypeNode *> container_types; + + TypeNode *get_container_type_or_null(int p_index) const { + return p_index >= 0 && p_index < container_types.size() ? container_types[p_index] : nullptr; + } TypeNode() { type = TYPE; @@ -1358,7 +1370,7 @@ private: AnnotationAction apply = nullptr; MethodInfo info; }; - HashMap<StringName, AnnotationInfo> valid_annotations; + static HashMap<StringName, AnnotationInfo> valid_annotations; List<AnnotationNode *> annotation_stack; typedef ExpressionNode *(GDScriptParser::*ParseFunction)(ExpressionNode *p_previous_operand, bool p_can_assign); @@ -1458,7 +1470,7 @@ private: SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false); // Annotations AnnotationNode *parse_annotation(uint32_t p_valid_targets); - bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, const Vector<Variant> &p_default_arguments = Vector<Variant>(), bool p_is_vararg = false); + static bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, const Vector<Variant> &p_default_arguments = Vector<Variant>(), bool p_is_vararg = false); bool validate_annotation_arguments(AnnotationNode *p_annotation); void clear_unused_annotations(); bool tool_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index 6dd8a98652..a64aaf6820 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -37,6 +37,12 @@ #include "core/templates/vector.h" #include "core/variant/variant.h" +#ifdef MINGW_ENABLED +#undef CONST +#undef IN +#undef VOID +#endif + class GDScriptTokenizer { public: enum CursorPlace { diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 40c564c36b..f8cb460e40 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -194,9 +194,9 @@ struct GDScriptUtilityFunctionsDefinitions { // Calculate how many. int count = 0; if (incr > 0) { - count = ((to - from - 1) / incr) + 1; + count = Math::division_round_up(to - from, incr); } else { - count = ((from - to - 1) / -incr) + 1; + count = Math::division_round_up(from - to, -incr); } Error err = arr.resize(count); @@ -470,7 +470,8 @@ struct GDScriptUtilityFunctionsDefinitions { static inline void len(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(1); switch (p_args[0]->get_type()) { - case Variant::STRING: { + case Variant::STRING: + case Variant::STRING_NAME: { String d = *p_args[0]; *r_ret = d.length(); } break; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index d31411b26b..3abfc7f8e3 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -36,6 +36,18 @@ #include "core/os/os.h" #ifdef DEBUG_ENABLED + +static bool _profile_count_as_native(const Object *p_base_obj, const StringName &p_methodname) { + if (!p_base_obj) { + return false; + } + StringName cname = p_base_obj->get_class_name(); + if ((p_methodname == "new" && cname == "GDScript") || p_methodname == "call") { + return false; + } + return ClassDB::class_exists(cname) && ClassDB::has_method(cname, p_methodname, false); +} + static String _get_element_type(Variant::Type builtin_type, const StringName &native_type, const Ref<Script> &script_type) { if (script_type.is_valid() && script_type->is_valid()) { return GDScript::debug_get_script_name(script_type); @@ -84,6 +96,18 @@ static String _get_var_type(const Variant *p_var) { return basestr; } + +void GDScriptFunction::_profile_native_call(uint64_t p_t_taken, const String &p_func_name, const String &p_instance_class_name) { + HashMap<String, Profile::NativeProfile>::Iterator inner_prof = profile.native_calls.find(p_func_name); + if (inner_prof) { + inner_prof->value.call_count += 1; + } else { + String sig = vformat("%s::0::%s%s%s", get_script()->get_script_path(), p_instance_class_name, p_instance_class_name.is_empty() ? "" : ".", p_func_name); + inner_prof = profile.native_calls.insert(p_func_name, Profile::NativeProfile{ 1, 0, sig }); + } + inner_prof->value.total_time += p_t_taken; +} + #endif // DEBUG_ENABLED Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataType &p_data_type) { @@ -91,8 +115,8 @@ Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataT if (p_data_type.builtin_type == Variant::ARRAY) { Array array; // Typed array. - if (p_data_type.has_container_element_type()) { - const GDScriptDataType &element_type = p_data_type.get_container_element_type(); + if (p_data_type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_data_type.get_container_element_type(0); array.set_typed(element_type.builtin_type, element_type.native_type, element_type.script_type); } @@ -631,9 +655,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } bool exit_ok = false; bool awaited = false; -#endif - -#ifdef DEBUG_ENABLED int variant_address_limits[ADDR_TYPE_MAX] = { _stack_size, _constant_count, p_instance ? p_instance->members.size() : 0 }; #endif @@ -1661,16 +1682,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (GDScriptLanguage::get_singleton()->profiling) { call_time = OS::get_singleton()->get_ticks_usec(); } - + Variant::Type base_type = base->get_type(); + Object *base_obj = base->get_validated_object(); + StringName base_class = base_obj ? base_obj->get_class_name() : StringName(); #endif + Callable::CallError err; if (call_ret) { GET_INSTRUCTION_ARG(ret, argc + 1); -#ifdef DEBUG_ENABLED - Variant::Type base_type = base->get_type(); - Object *base_obj = base->get_validated_object(); - StringName base_class = base_obj ? base_obj->get_class_name() : StringName(); -#endif base->callp(*methodname, (const Variant **)argptrs, argc, *ret, err); #ifdef DEBUG_ENABLED if (ret->get_type() == Variant::NIL) { @@ -1704,8 +1723,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a base->callp(*methodname, (const Variant **)argptrs, argc, ret, err); } #ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time; + if (GDScriptLanguage::get_singleton()->profile_native_calls && _profile_count_as_native(base_obj, *methodname)) { + _profile_native_call(t_taken, *methodname, base_class); + } + function_call_time += t_taken; } if (err.error != Callable::CallError::CALL_OK) { @@ -1782,8 +1806,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED uint64_t call_time = 0; - - if (GDScriptLanguage::get_singleton()->profiling) { + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { call_time = OS::get_singleton()->get_ticks_usec(); } #endif @@ -1797,8 +1820,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } #ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + + 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; } if (err.error != Callable::CallError::CALL_OK) { @@ -1851,22 +1877,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a const Variant **argptrs = const_cast<const Variant **>(instruction_args); -#ifdef DEBUG_ENABLED - uint64_t call_time = 0; - - if (GDScriptLanguage::get_singleton()->profiling) { - call_time = OS::get_singleton()->get_ticks_usec(); - } -#endif - Callable::CallError err; Variant::call_static(builtin_type, *methodname, argptrs, argc, *ret, err); #ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; - } - if (err.error != Callable::CallError::CALL_OK) { err_text = _get_call_error(err, "static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs); OPCODE_BREAK; @@ -1895,8 +1909,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED uint64_t call_time = 0; - - if (GDScriptLanguage::get_singleton()->profiling) { + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { call_time = OS::get_singleton()->get_ticks_usec(); } #endif @@ -1905,15 +1918,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a *ret = method->call(nullptr, argptrs, argc, err); #ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + 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 if (err.error != Callable::CallError::CALL_OK) { err_text = _get_call_error(err, "static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs); OPCODE_BREAK; } -#endif ip += 3; } @@ -1951,8 +1966,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED uint64_t call_time = 0; - - if (GDScriptLanguage::get_singleton()->profiling) { + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { call_time = OS::get_singleton()->get_ticks_usec(); } #endif @@ -1961,10 +1975,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a method->validated_call(base_obj, (const Variant **)argptrs, ret); #ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + 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; @@ -1998,8 +2015,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Variant **argptrs = instruction_args; #ifdef DEBUG_ENABLED uint64_t call_time = 0; - - if (GDScriptLanguage::get_singleton()->profiling) { + if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) { call_time = OS::get_singleton()->get_ticks_usec(); } #endif @@ -2009,10 +2025,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a method->validated_call(base_obj, (const Variant **)argptrs, nullptr); #ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + 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; @@ -2033,22 +2052,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Variant::ValidatedBuiltInMethod method = _builtin_methods_ptr[_code_ptr[ip + 2]]; Variant **argptrs = instruction_args; -#ifdef DEBUG_ENABLED - uint64_t call_time = 0; - if (GDScriptLanguage::get_singleton()->profiling) { - call_time = OS::get_singleton()->get_ticks_usec(); - } -#endif - GET_INSTRUCTION_ARG(ret, argc + 1); method(base, (const Variant **)argptrs, argc, ret); -#ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->profiling) { - function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; - } -#endif - ip += 3; } DISPATCH_OPCODE; diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 44f605232d..0b1371851b 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -315,9 +315,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { Vector<String> param_symbols = query.split(SYMBOL_SEPERATOR, false); if (param_symbols.size() >= 2) { - String class_ = param_symbols[0]; - StringName class_name = class_; - String member_name = param_symbols[param_symbols.size() - 1]; + StringName class_name = param_symbols[0]; + const String &member_name = param_symbols[param_symbols.size() - 1]; String inner_class_name; if (param_symbols.size() >= 3) { inner_class_name = param_symbols[1]; diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index f91dc83f2c..361ca276bb 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -78,31 +78,30 @@ void init_autoloads() { scn.instantiate(); scn->set_path(info.path); scn->reload_from_file(); - ERR_CONTINUE_MSG(!scn.is_valid(), vformat("Can't autoload: %s.", info.path)); + ERR_CONTINUE_MSG(!scn.is_valid(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path)); if (scn.is_valid()) { n = scn->instantiate(); } } else { Ref<Resource> res = ResourceLoader::load(info.path); - ERR_CONTINUE_MSG(res.is_null(), vformat("Can't autoload: %s.", info.path)); + ERR_CONTINUE_MSG(res.is_null(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path)); Ref<Script> scr = res; if (scr.is_valid()) { StringName ibt = scr->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_CONTINUE_MSG(!valid_type, vformat("Script does not inherit from Node: %s.", info.path)); + ERR_CONTINUE_MSG(!valid_type, vformat("Failed to instantiate an autoload, script '%s' does not inherit from 'Node'.", info.path)); Object *obj = ClassDB::instantiate(ibt); - - ERR_CONTINUE_MSG(!obj, vformat("Cannot instance script for Autoload, expected 'Node' inheritance, got: %s.", ibt)); + ERR_CONTINUE_MSG(!obj, vformat("Failed to instantiate an autoload, cannot instantiate '%s'.", ibt)); n = Object::cast_to<Node>(obj); n->set_script(scr); } } - ERR_CONTINUE_MSG(!n, vformat("Path in autoload not a node or script: %s.", info.path)); + ERR_CONTINUE_MSG(!n, vformat("Failed to instantiate an autoload, path is not pointing to a scene or a script: %s.", info.path)); n->set_name(info.name); for (int i = 0; i < ScriptServer::get_language_count(); i++) { diff --git a/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.gd new file mode 100644 index 0000000000..e4016c0119 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.gd @@ -0,0 +1,6 @@ +func test(): + var array: Array = [1, 2, 3] + print(array) + var callable: Callable = array.clear + callable.call() + print(array) diff --git a/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.out new file mode 100644 index 0000000000..c4182b38e9 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.out @@ -0,0 +1,3 @@ +GDTEST_OK +[1, 2, 3] +[] diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd index f6aa58737f..97e9da3b26 100644 --- a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd @@ -1,12 +1,18 @@ -# GH-79521 +# GH-79521, GH-86032 class_name TestStaticMethodAsCallable static func static_func() -> String: return "Test" +static func another_static_func(): + prints("another_static_func:", static_func.call(), static_func.is_valid()) + func test(): var a: Callable = TestStaticMethodAsCallable.static_func var b: Callable = static_func prints(a.call(), a.is_valid()) prints(b.call(), b.is_valid()) + @warning_ignore("static_called_on_instance") + another_static_func() + TestStaticMethodAsCallable.another_static_func() diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out index e6d461b8f9..2b773ce8ee 100644 --- a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out @@ -1,3 +1,5 @@ GDTEST_OK Test true Test true +another_static_func: Test true +another_static_func: Test true diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index 7fe3a57880..d7e5ddd32c 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -67,6 +67,13 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage } else { // use defaults } + } else if (capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_DIRECTX) { + // NIR-DXIL is Vulkan 1.1-conformant. + ClientVersion = glslang::EShTargetVulkan_1_1; + // The SPIR-V part of Mesa supports 1.6, but: + // - SPIRV-Reflect won't be able to parse the compute workgroup size. + // - We want to play it safe with NIR-DXIL. + TargetVersion = glslang::EShTargetSpv_1_3; } else { // once we support other backends we'll need to do something here if (r_error) { diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index 8e4a72e6ae..f678a11319 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> <member name="buffer_view" type="int" setter="set_buffer_view" getter="get_buffer_view" default="-1"> diff --git a/modules/gltf/doc_classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml index c1fe85c1c0..65335250aa 100644 --- a/modules/gltf/doc_classes/GLTFAnimation.xml +++ b/modules/gltf/doc_classes/GLTFAnimation.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> <member name="loop" type="bool" setter="set_loop" getter="get_loop" default="false"> diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml index ce19650b5b..d0f76a9af3 100644 --- a/modules/gltf/doc_classes/GLTFBufferView.xml +++ b/modules/gltf/doc_classes/GLTFBufferView.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> <member name="buffer" type="int" setter="set_buffer" getter="get_buffer" default="-1"> diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml index c2ed4d08e3..b334bf2867 100644 --- a/modules/gltf/doc_classes/GLTFCamera.xml +++ b/modules/gltf/doc_classes/GLTFCamera.xml @@ -7,6 +7,7 @@ Represents a camera as defined by the base GLTF spec. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="GLTF camera detailed specification">https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera</link> <link title="GLTF camera spec and example file">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md</link> </tutorials> diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 5c10b76e0a..1b52a82298 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -9,6 +9,7 @@ GLTFDocument can be extended with arbitrary functionality by extending the [GLTFDocumentExtension] class and registering it with GLTFDocument via [method register_gltf_document_extension]. This allows for custom data to be imported and exported. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="glTF 'What the duck?' guide">https://www.khronos.org/files/gltf20-reference-guide.pdf</link> <link title="Khronos glTF specification">https://registry.khronos.org/glTF/</link> </tutorials> @@ -83,7 +84,7 @@ <param index="1" name="path" type="String" /> <description> Takes a [GLTFState] object through the [param state] parameter and writes a glTF file to the filesystem. - [b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf file. + [b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf text file. </description> </method> </methods> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index eee62845ca..aaa55e772a 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -9,6 +9,7 @@ [b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode]. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <methods> <method name="_convert_scene_node" qualifiers="virtual"> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml index 3ca0359311..04075caba5 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml @@ -5,5 +5,6 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> </class> diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index c55962eeaa..653a394ebb 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -7,6 +7,7 @@ Represents a light as defined by the [code]KHR_lights_punctual[/code] GLTF extension. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="KHR_lights_punctual GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual</link> </tutorials> <methods> diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index df4d436f5c..da05474ab9 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> <member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()"> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index 2ec39801f3..184ced4312 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -8,6 +8,7 @@ GLTF nodes generally exist inside of [GLTFState] which represents all data of a GLTF file. Most of GLTFNode's properties are indices of other data in the GLTF file. You can extend a GLTF node with additional properties by using [method get_additional_data] and [method set_additional_data]. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link> </tutorials> <methods> diff --git a/modules/gltf/doc_classes/GLTFPhysicsBody.xml b/modules/gltf/doc_classes/GLTFPhysicsBody.xml index d364069193..cf39721ce8 100644 --- a/modules/gltf/doc_classes/GLTFPhysicsBody.xml +++ b/modules/gltf/doc_classes/GLTFPhysicsBody.xml @@ -7,6 +7,7 @@ Represents a physics body as defined by the [code]OMI_physics_body[/code] GLTF extension. This class is an intermediary between the GLTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different GLTF physics extensions in the future. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="OMI_physics_body GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_physics_body</link> </tutorials> <methods> diff --git a/modules/gltf/doc_classes/GLTFPhysicsShape.xml b/modules/gltf/doc_classes/GLTFPhysicsShape.xml index 2891fab115..67382f3295 100644 --- a/modules/gltf/doc_classes/GLTFPhysicsShape.xml +++ b/modules/gltf/doc_classes/GLTFPhysicsShape.xml @@ -7,6 +7,7 @@ Represents a physics shape as defined by the [code]OMI_collider[/code] GLTF extension. This class is an intermediary between the GLTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different GLTF physics extensions in the future. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="OMI_collider GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider</link> </tutorials> <methods> diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml index c7b8cb2ac3..ac03a6ee9e 100644 --- a/modules/gltf/doc_classes/GLTFSkeleton.xml +++ b/modules/gltf/doc_classes/GLTFSkeleton.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <methods> <method name="get_bone_attachment"> diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml index 98436ea2e7..0835a2d510 100644 --- a/modules/gltf/doc_classes/GLTFSkin.xml +++ b/modules/gltf/doc_classes/GLTFSkin.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <methods> <method name="get_inverse_binds"> diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml index d64a918920..722fa5e9ae 100644 --- a/modules/gltf/doc_classes/GLTFSpecGloss.xml +++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml @@ -7,6 +7,7 @@ KHR_materials_pbrSpecularGlossiness is an archived GLTF extension. This means that it is deprecated and not recommended for new files. However, it is still supported for loading old files. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="KHR_materials_pbrSpecularGlossiness GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness</link> </tutorials> <members> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index ba1c531283..e256041737 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -8,6 +8,7 @@ GLTFState can be populated by [GLTFDocument] reading a file or by converting a Godot scene. Then the data can either be used to create a Godot scene or save to a GLTF file. The code that converts to/from a Godot scene can be intercepted at arbitrary points by [GLTFDocumentExtension] classes. This allows for custom data to be stored in the GLTF file or for custom data to be converted to/from Godot nodes. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> <link title="GLTF asset header schema">https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/asset.schema.json"</link> </tutorials> <methods> diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml index 41c20439ea..dd323b753b 100644 --- a/modules/gltf/doc_classes/GLTFTexture.xml +++ b/modules/gltf/doc_classes/GLTFTexture.xml @@ -5,6 +5,7 @@ <description> </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> <member name="sampler" type="int" setter="set_sampler" getter="get_sampler" default="-1"> diff --git a/modules/gltf/doc_classes/GLTFTextureSampler.xml b/modules/gltf/doc_classes/GLTFTextureSampler.xml index 027d35e9d2..2b5bad6724 100644 --- a/modules/gltf/doc_classes/GLTFTextureSampler.xml +++ b/modules/gltf/doc_classes/GLTFTextureSampler.xml @@ -7,6 +7,7 @@ Represents a texture sampler as defined by the base GLTF spec. Texture samplers in GLTF specify how to sample data from the texture's base image, when rendering the texture on an object. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> <member name="mag_filter" type="int" setter="set_mag_filter" getter="get_mag_filter" default="9729"> diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp index 83c7f463df..6975bc1228 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp @@ -32,12 +32,14 @@ #ifdef TOOLS_ENABLED -#include "../gltf_document.h" +#include "editor_scene_exporter_gltf_settings.h" #include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" #include "editor/editor_node.h" +#include "editor/editor_scale.h" #include "editor/gui/editor_file_dialog.h" -#include "scene/gui/popup_menu.h" +#include "editor/import/scene_import_settings.h" String SceneExporterGLTFPlugin::get_name() const { return "ConvertGLTF2"; @@ -48,59 +50,72 @@ bool SceneExporterGLTFPlugin::has_main_screen() const { } SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() { - file_export_lib = memnew(EditorFileDialog); - EditorNode::get_singleton()->get_gui_base()->add_child(file_export_lib); - file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action)); - file_export_lib->set_title(TTR("Export Library")); - file_export_lib->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - file_export_lib->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - file_export_lib->clear_filters(); - file_export_lib->add_filter("*.glb"); - file_export_lib->add_filter("*.gltf"); - file_export_lib->set_title(TTR("Export Scene to glTF 2.0 File")); - + _gltf_document.instantiate(); + // Set up the file dialog. + _file_dialog = memnew(EditorFileDialog); + _file_dialog->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_export_scene_as_gltf)); + _file_dialog->set_title(TTR("Export Library")); + _file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + _file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + _file_dialog->clear_filters(); + _file_dialog->add_filter("*.glb"); + _file_dialog->add_filter("*.gltf"); + _file_dialog->set_title(TTR("Export Scene to glTF 2.0 File")); + EditorNode::get_singleton()->get_gui_base()->add_child(_file_dialog); + // Set up the export settings menu. + _export_settings.instantiate(); + _export_settings->generate_property_list(_gltf_document); + _settings_inspector = memnew(EditorInspector); + _settings_inspector->set_custom_minimum_size(Size2(350, 300) * EDSCALE); + _file_dialog->add_side_menu(_settings_inspector, TTR("Export Settings:")); + // Add a button to the Scene -> Export menu to pop up the settings dialog. PopupMenu *menu = get_export_as_menu(); int idx = menu->get_item_count(); menu->add_item(TTR("glTF 2.0 Scene...")); - menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2)); + menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::_popup_gltf_export_dialog)); +} + +void SceneExporterGLTFPlugin::_popup_gltf_export_dialog() { + Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); + if (!root) { + EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); + return; + } + // Set the file dialog's file name to the scene name. + String filename = String(root->get_scene_file_path().get_file().get_basename()); + if (filename.is_empty()) { + filename = root->get_name(); + } + _file_dialog->set_current_file(filename + String(".gltf")); + // Generate and refresh the export settings. + _export_settings->generate_property_list(_gltf_document); + _settings_inspector->edit(nullptr); + _settings_inspector->edit(_export_settings.ptr()); + // Show the file dialog. + _file_dialog->popup_centered_ratio(); } -void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) { +void SceneExporterGLTFPlugin::_export_scene_as_gltf(const String &p_file_path) { Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); if (!root) { EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); return; } List<String> deps; - Ref<GLTFDocument> doc; - doc.instantiate(); Ref<GLTFState> state; state.instantiate(); + state->set_copyright(_export_settings->get_copyright()); int32_t flags = 0; flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; - Error err = doc->append_from_scene(root, state, flags); + Error err = _gltf_document->append_from_scene(root, state, flags); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } - err = doc->write_to_filesystem(state, p_file); + err = _gltf_document->write_to_filesystem(state, p_file_path); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } EditorFileSystem::get_singleton()->scan_changes(); } -void SceneExporterGLTFPlugin::convert_scene_to_gltf2() { - Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); - if (!root) { - EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); - return; - } - String filename = String(root->get_scene_file_path().get_file().get_basename()); - if (filename.is_empty()) { - filename = root->get_name(); - } - file_export_lib->set_current_file(filename + String(".gltf")); - file_export_lib->popup_centered_ratio(); -} - #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h index f92b3c5180..683ff6d4f6 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h @@ -33,18 +33,23 @@ #ifdef TOOLS_ENABLED -#include "editor_scene_importer_gltf.h" +#include "../gltf_document.h" +#include "editor_scene_exporter_gltf_settings.h" #include "editor/editor_plugin.h" class EditorFileDialog; +class EditorInspector; class SceneExporterGLTFPlugin : public EditorPlugin { GDCLASS(SceneExporterGLTFPlugin, EditorPlugin); - EditorFileDialog *file_export_lib = nullptr; - void _gltf2_dialog_action(String p_file); - void convert_scene_to_gltf2(); + Ref<GLTFDocument> _gltf_document; + Ref<EditorSceneExporterGLTFSettings> _export_settings; + EditorInspector *_settings_inspector = nullptr; + EditorFileDialog *_file_dialog = nullptr; + void _popup_gltf_export_dialog(); + void _export_scene_as_gltf(const String &p_file_path); public: virtual String get_name() const override; diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp new file mode 100644 index 0000000000..b0283b0c55 --- /dev/null +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp @@ -0,0 +1,176 @@ +/**************************************************************************/ +/* editor_scene_exporter_gltf_settings.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 "editor_scene_exporter_gltf_settings.h" + +const uint32_t PROP_EDITOR_SCRIPT_VAR = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE; + +bool EditorSceneExporterGLTFSettings::_set(const StringName &p_name, const Variant &p_value) { + String name_str = String(p_name); + if (name_str.contains("/")) { + return _set_extension_setting(name_str, p_value); + } + if (p_name == StringName("image_format")) { + _document->set_image_format(p_value); + emit_signal("property_list_changed"); + return true; + } + if (p_name == StringName("lossy_quality")) { + _document->set_lossy_quality(p_value); + return true; + } + if (p_name == StringName("root_node_mode")) { + _document->set_root_node_mode((GLTFDocument::RootNodeMode)(int64_t)p_value); + return true; + } + return false; +} + +bool EditorSceneExporterGLTFSettings::_get(const StringName &p_name, Variant &r_ret) const { + String name_str = String(p_name); + if (name_str.contains("/")) { + return _get_extension_setting(name_str, r_ret); + } + if (p_name == StringName("image_format")) { + r_ret = _document->get_image_format(); + return true; + } + if (p_name == StringName("lossy_quality")) { + r_ret = _document->get_lossy_quality(); + return true; + } + if (p_name == StringName("root_node_mode")) { + r_ret = _document->get_root_node_mode(); + return true; + } + return false; +} + +void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_list) const { + 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; + prop.usage = is_image_format_lossy ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE; + } + p_list->push_back(prop); + } +} + +bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) { + PackedStringArray split = String(p_name_str).split("/", true, 1); + if (!_config_name_to_extension_map.has(split[0])) { + return false; + } + Ref<GLTFDocumentExtension> extension = _config_name_to_extension_map[split[0]]; + bool valid; + extension->set(split[1], p_value, &valid); + return valid; +} + +bool EditorSceneExporterGLTFSettings::_get_extension_setting(const String &p_name_str, Variant &r_ret) const { + PackedStringArray split = String(p_name_str).split("/", true, 1); + if (!_config_name_to_extension_map.has(split[0])) { + return false; + } + Ref<GLTFDocumentExtension> extension = _config_name_to_extension_map[split[0]]; + bool valid; + r_ret = extension->get(split[1], &valid); + return valid; +} + +String get_friendly_config_prefix(Ref<GLTFDocumentExtension> p_extension) { + String config_prefix = p_extension->get_name(); + if (!config_prefix.is_empty()) { + return config_prefix; + } + const String class_name = p_extension->get_class_name(); + config_prefix = class_name.trim_prefix("GLTFDocumentExtension").capitalize(); + if (!config_prefix.is_empty()) { + return config_prefix; + } + PackedStringArray supported_extensions = p_extension->get_supported_extensions(); + if (supported_extensions.size() > 0) { + return supported_extensions[0]; + } + return "Unknown GLTFDocumentExtension"; +} + +// Run this before popping up the export settings, because the extensions may have changed. +void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document) { + _property_list.clear(); + _document = p_document; + String image_format_hint_string = "None,PNG,JPEG"; + // Add properties from all document extensions. + for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) { + const String config_prefix = get_friendly_config_prefix(extension); + _config_name_to_extension_map[config_prefix] = extension; + // If the extension allows saving in different image formats, add to the enum. + PackedStringArray saveable_image_formats = extension->get_saveable_image_formats(); + for (int i = 0; i < saveable_image_formats.size(); i++) { + image_format_hint_string += "," + saveable_image_formats[i]; + } + // Look through the extension's properties and find the relevant ones. + List<PropertyInfo> ext_prop_list; + extension->get_property_list(&ext_prop_list); + for (const PropertyInfo &prop : ext_prop_list) { + // We only want properties that will show up in the exporter + // settings list. Exclude Resource's properties, as they are + // not relevant to the exporter. Include any user-defined script + // variables exposed to the editor (PROP_EDITOR_SCRIPT_VAR). + if ((prop.usage & PROP_EDITOR_SCRIPT_VAR) == PROP_EDITOR_SCRIPT_VAR) { + PropertyInfo ext_prop = prop; + ext_prop.name = config_prefix + "/" + prop.name; + _property_list.push_back(ext_prop); + } + } + } + // Add top-level properties (in addition to what _bind_methods registers). + PropertyInfo image_format_prop = PropertyInfo(Variant::STRING, "image_format", PROPERTY_HINT_ENUM, image_format_hint_string); + _property_list.push_back(image_format_prop); + PropertyInfo lossy_quality_prop = PropertyInfo(Variant::FLOAT, "lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"); + _property_list.push_back(lossy_quality_prop); + PropertyInfo root_node_mode_prop = PropertyInfo(Variant::INT, "root_node_mode", PROPERTY_HINT_ENUM, "Single Root,Keep Root,Multi Root"); + _property_list.push_back(root_node_mode_prop); +} + +String EditorSceneExporterGLTFSettings::get_copyright() const { + return _copyright; +} + +void EditorSceneExporterGLTFSettings::set_copyright(const String &p_copyright) { + _copyright = p_copyright; +} + +void EditorSceneExporterGLTFSettings::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_copyright"), &EditorSceneExporterGLTFSettings::get_copyright); + ClassDB::bind_method(D_METHOD("set_copyright", "copyright"), &EditorSceneExporterGLTFSettings::set_copyright); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "copyright", PROPERTY_HINT_PLACEHOLDER_TEXT, "Example: 2014 Godette"), "set_copyright", "get_copyright"); +} diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h new file mode 100644 index 0000000000..6032932367 --- /dev/null +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* editor_scene_exporter_gltf_settings.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 EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H +#define EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H + +#ifdef TOOLS_ENABLED + +#include "../gltf_document.h" + +class EditorSceneExporterGLTFSettings : public RefCounted { + GDCLASS(EditorSceneExporterGLTFSettings, RefCounted); + List<PropertyInfo> _property_list; + Ref<GLTFDocument> _document; + HashMap<String, Ref<GLTFDocumentExtension>> _config_name_to_extension_map; + + String _copyright; + +protected: + static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + bool _set_extension_setting(const String &p_name_str, const Variant &p_value); + bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const; + +public: + void generate_property_list(Ref<GLTFDocument> p_document); + + String get_copyright() const; + void set_copyright(const String &p_copyright); +}; + +#endif // TOOLS_ENABLED + +#endif // EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 2fad475e92..9587604e56 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -45,6 +45,11 @@ #include "main/main.h" #include "scene/gui/line_edit.h" +#ifdef MINGW_ENABLED +#define near +#define far +#endif + #ifdef WINDOWS_ENABLED #include <shlwapi.h> #endif diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 4060f7f626..e3824562bf 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3218,7 +3218,7 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector< bool must_import = true; Vector<uint8_t> img_data = p_image->get_data(); Dictionary generator_parameters; - String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + p_image->get_name(); + String file_path = p_state->get_base_path().path_join(p_state->filename.get_basename() + "_" + p_image->get_name()); file_path += p_file_extension.is_empty() ? ".png" : p_file_extension; if (FileAccess::exists(file_path + ".import")) { Ref<ConfigFile> config; @@ -3230,6 +3230,8 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector< if (!generator_parameters.has("md5")) { must_import = false; // Didn't come from a gltf document; don't overwrite. } + } + if (must_import) { String existing_md5 = generator_parameters["md5"]; unsigned char md5_hash[16]; CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash); @@ -3658,141 +3660,143 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { mr["metallicFactor"] = base_material->get_metallic(); mr["roughnessFactor"] = base_material->get_roughness(); - bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; - if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); - } - if (ao_image->is_compressed()) { - ao_image->decompress(); - } - } - Ref<Image> roughness_image; - if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); - } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); - } - } - Ref<Image> metallness_image; - if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); - } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); + if (_image_format != "None") { + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); + } + if (ao_image->is_compressed()) { + ao_image->decompress(); + } } - } - Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); - } - orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; - } + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; - } + if (roughness_image->is_compressed()) { + roughness_image->decompress(); + } + } + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); + } + if (metallness_image->is_compressed()) { + metallness_image->decompress(); } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; + } + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); + } + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); + if (has_ao) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; + } } + if (has_roughness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; + } + } + if (has_metalness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; + } + } + orm_image->set_pixel(w, h, c); } - orm_image->set_pixel(w, h, c); } - } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - p_state->use_khr_texture_transform = true; + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + p_state->use_khr_texture_transform = true; + } + mr["metallicRoughnessTexture"] = mrt; } - mr["metallicRoughnessTexture"] = mrt; } } d["pbrMetallicRoughness"] = mr; - if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING) && _image_format != "None") { Dictionary nt; Ref<ImageTexture> tex; tex.instantiate(); @@ -3845,7 +3849,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { d["emissiveFactor"] = arr; } - if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && _image_format != "None") { Dictionary et; Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; @@ -7336,6 +7340,10 @@ void GLTFDocument::unregister_all_gltf_document_extensions() { all_document_extensions.clear(); } +Vector<Ref<GLTFDocumentExtension>> GLTFDocument::get_all_gltf_document_extensions() { + return all_document_extensions; +} + PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) { Error err = _encode_buffer_glb(p_state, ""); if (r_err) { diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 7e378fe94d..f321bb7111 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -86,6 +86,7 @@ public: static void register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority = false); static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension); static void unregister_all_gltf_document_extensions(); + static Vector<Ref<GLTFDocumentExtension>> get_all_gltf_document_extensions(); void set_naming_version(int p_version); int get_naming_version() const; diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index fecea45fc9..0bf02cf890 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -51,7 +51,7 @@ static void _editor_init() { Ref<EditorSceneFormatImporterGLTF> import_gltf; import_gltf.instantiate(); - ResourceImporterScene::add_importer(import_gltf); + ResourceImporterScene::add_scene_importer(import_gltf); // Blend to glTF importer. @@ -66,7 +66,7 @@ static void _editor_init() { } else { Ref<EditorSceneFormatImporterBlend> importer; importer.instantiate(); - ResourceImporterScene::add_importer(importer); + ResourceImporterScene::add_scene_importer(importer); Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query; blend_import_query.instantiate(); @@ -82,7 +82,7 @@ static void _editor_init() { if (fbx_enabled) { Ref<EditorSceneFormatImporterFBX> importer; importer.instantiate(); - ResourceImporterScene::get_scene_singleton()->add_importer(importer); + ResourceImporterScene::add_scene_importer(importer); Ref<EditorFileSystemImportFormatSupportQueryFBX> fbx_import_query; fbx_import_query.instantiate(); diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index e05979efbc..348ac5194c 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -155,7 +155,6 @@ class GridMap : public Node3D { Ref<PhysicsMaterial> physics_material; bool bake_navigation = false; RID map_override; - uint32_t navigation_layers = 1; Transform3D last_transform; diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index a4ecb767a7..74dc54641d 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -756,7 +756,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade rd->compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1); push_constant.region_ofs[0] = 0; push_constant.region_ofs[1] = 0; - Vector3i group_size((atlas_size.x - 1) / 8 + 1, (atlas_size.y - 1) / 8 + 1, 1); //restore group size + Vector3i group_size(Math::division_round_up(atlas_size.x, 8), Math::division_round_up(atlas_size.y, 8), 1); //restore group size for (int i = 0; i < atlas_slices; i++) { push_constant.atlas_slice = i; @@ -939,8 +939,8 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh // We use a region with 1/4 the amount of pixels if we're denoising SH lightmaps, as // all four of them are denoised in the shader in one dispatch. const int max_region_size = p_bake_sh ? 512 : 1024; - int x_regions = (p_atlas_size.width - 1) / max_region_size + 1; - int y_regions = (p_atlas_size.height - 1) / max_region_size + 1; + int x_regions = Math::division_round_up(p_atlas_size.width, max_region_size); + int y_regions = Math::division_round_up(p_atlas_size.height, max_region_size); for (int s = 0; s < p_atlas_slices; s++) { p_push_constant.atlas_slice = s; @@ -958,7 +958,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh p_rd->compute_list_bind_uniform_set(compute_list, p_compute_base_uniform_set, 0); p_rd->compute_list_bind_uniform_set(compute_list, denoise_uniform_set, 1); p_rd->compute_list_set_push_constant(compute_list, &p_push_constant, sizeof(PushConstant)); - p_rd->compute_list_dispatch(compute_list, (w - 1) / 8 + 1, (h - 1) / 8 + 1, 1); + p_rd->compute_list_dispatch(compute_list, Math::division_round_up(w, 8), Math::division_round_up(h, 8), 1); p_rd->compute_list_end(); p_rd->submit(); @@ -1399,7 +1399,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d rd->free(compute_shader_secondary); \ rd->free(compute_shader_light_probes); - Vector3i group_size((atlas_size.x - 1) / 8 + 1, (atlas_size.y - 1) / 8 + 1, 1); + Vector3i group_size(Math::division_round_up(atlas_size.x, 8), Math::division_round_up(atlas_size.y, 8), 1); rd->submit(); rd->sync(); @@ -1592,10 +1592,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/lightmapping/bake_performance/region_size"))); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_pass"); - int x_regions = (atlas_size.width - 1) / max_region_size + 1; - int y_regions = (atlas_size.height - 1) / max_region_size + 1; + int x_regions = Math::division_round_up(atlas_size.width, max_region_size); + int y_regions = Math::division_round_up(atlas_size.height, max_region_size); - int ray_iterations = (push_constant.ray_count - 1) / max_rays + 1; + int ray_iterations = Math::division_round_up((int32_t)push_constant.ray_count, max_rays); rd->submit(); rd->sync(); @@ -1614,7 +1614,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.region_ofs[0] = x; push_constant.region_ofs[1] = y; - group_size = Vector3i((w - 1) / 8 + 1, (h - 1) / 8 + 1, 1); + group_size = Vector3i(Math::division_round_up(w, 8), Math::division_round_up(h, 8), 1); for (int k = 0; k < ray_iterations; k++) { RD::ComputeListID compute_list = rd->compute_list_begin(); @@ -1700,7 +1700,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.probe_count = probe_positions.size(); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_probe_pass"); - int ray_iterations = (push_constant.ray_count - 1) / max_rays + 1; + int ray_iterations = Math::division_round_up((int32_t)push_constant.ray_count, max_rays); for (int i = 0; i < ray_iterations; i++) { RD::ComputeListID compute_list = rd->compute_list_begin(); @@ -1711,7 +1711,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.ray_from = i * max_rays; push_constant.ray_to = MIN((i + 1) * max_rays, int32_t(push_constant.ray_count)); rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); - rd->compute_list_dispatch(compute_list, (probe_positions.size() - 1) / 64 + 1, 1, 1); + rd->compute_list_dispatch(compute_list, Math::division_round_up(probe_positions.size(), 64), 1, 1); rd->compute_list_end(); //done rd->submit(); diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp index 8103799974..4fe8f20723 100644 --- a/modules/lightmapper_rd/register_types.cpp +++ b/modules/lightmapper_rd/register_types.cpp @@ -46,18 +46,18 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) { return; } - GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_ray_count", 32); - GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_ray_count", 128); - GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_ray_count", 512); - GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_ray_count", 2048); - GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_pass", 32); - GLOBAL_DEF("rendering/lightmapping/bake_performance/region_size", 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 32); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 128); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/high_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 32); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/region_size", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); - GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_probe_ray_count", 64); - GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", 256); - GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512); - GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048); - GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 256); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/high_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_probe_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/denoising/denoiser", PROPERTY_HINT_ENUM, "JNLM,OIDN"), 0); #ifndef _3D_DISABLED diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp index 627d093bc1..c85f0b3389 100644 --- a/modules/minimp3/register_types.cpp +++ b/modules/minimp3/register_types.cpp @@ -52,8 +52,13 @@ void initialize_minimp3_module(ModuleInitializationLevel p_level) { ResourceFormatImporter::get_singleton()->add_importer(mp3_import); } + ClassDB::APIType prev_api = ClassDB::get_current_api(); + ClassDB::set_current_api(ClassDB::API_EDITOR); + // Required to document import options in the class reference. GDREGISTER_CLASS(ResourceImporterMP3); + + ClassDB::set_current_api(prev_api); #endif GDREGISTER_CLASS(AudioStreamMP3); diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index d60b979c3f..33c926689a 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -89,7 +89,7 @@ bool ResourceImporterMP3::has_advanced_options() const { void ResourceImporterMP3::show_advanced_options(const String &p_path) { Ref<AudioStreamMP3> mp3_stream = import_mp3(p_path); if (mp3_stream.is_valid()) { - AudioStreamImportSettings::get_singleton()->edit(p_path, "mp3", mp3_stream); + AudioStreamImportSettingsDialog::get_singleton()->edit(p_path, "mp3", mp3_stream); } } #endif diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 56e4fa53d0..8e1587997b 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2620,12 +2620,12 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const { } Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - ERR_FAIL_COND_V(!valid, Variant()); - - Variant ret; - bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CallStatic(this, &p_method, p_args, p_argcount, &r_error, &ret); - if (ok) { - return ret; + if (valid) { + Variant ret; + bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CallStatic(this, &p_method, p_args, p_argcount, &r_error, &ret); + if (ok) { + return ret; + } } return Script::callp(p_method, p_args, p_argcount, r_error); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index e381f0e840..401f5c62e5 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -463,6 +463,7 @@ public: /* PROFILING FUNCTIONS */ /* TODO */ void profiling_start() override {} /* TODO */ void profiling_stop() override {} + /* TODO */ void profiling_set_save_native_calls(bool p_enable) override {} /* TODO */ int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override { return 0; } 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 ad3a10ba49..ccef90c911 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 @@ -7,7 +7,7 @@ <Authors>Godot Engine contributors</Authors> <PackageId>Godot.NET.Sdk</PackageId> - <Version>4.2.0</Version> + <Version>4.3.0</Version> <PackageVersion>$(PackageVersion_Godot_NET_Sdk)</PackageVersion> <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> 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 d8129a6652..b51ce5cb8c 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 @@ -33,9 +33,9 @@ <Message Importance="normal" Text="Found XCode at $(XcodeSelect)" Condition=" '$(FindXCode)' == 'true' "/> <ItemGroup> - <LinkerArg Include="-isysroot %22$(XCodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22" + <LinkerArg Include="-mios-simulator-version-min=12.0 -isysroot %22$(XCodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22" Condition=" $(RuntimeIdentifier.Contains('simulator')) "/> - <LinkerArg Include="-isysroot %22$(XCodePath)Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk%22" + <LinkerArg Include="-miphoneos-version-min=12.0 -isysroot %22$(XCodePath)Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk%22" Condition=" !$(RuntimeIdentifier.Contains('simulator')) "/> </ItemGroup> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs new file mode 100644 index 0000000000..d75922481c --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.Text; + +namespace Godot.SourceGenerators.Tests; + +public static class CSharpSourceGeneratorVerifier<TSourceGenerator> +where TSourceGenerator : ISourceGenerator, new() +{ + public class Test : CSharpSourceGeneratorTest<TSourceGenerator, XUnitVerifier> + { + public Test() + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net60; + + SolutionTransforms.Add((Solution solution, ProjectId projectId) => + { + Project project = solution.GetProject(projectId)! + .AddMetadataReference(Constants.GodotSharpAssembly.CreateMetadataReference()); + + return project.Solution; + }); + } + } + + public static Task Verify(string source, params string[] generatedSources) + { + return Verify(new string[] { source }, generatedSources); + } + + public static Task VerifyNoCompilerDiagnostics(string source, params string[] generatedSources) + { + return VerifyNoCompilerDiagnostics(new string[] { source }, generatedSources); + } + + public static Task Verify(ICollection<string> sources, params string[] generatedSources) + { + return MakeVerifier(sources, generatedSources).RunAsync(); + } + + public static Task VerifyNoCompilerDiagnostics(ICollection<string> sources, params string[] generatedSources) + { + var verifier = MakeVerifier(sources, generatedSources); + verifier.CompilerDiagnostics = CompilerDiagnostics.None; + return verifier.RunAsync(); + } + + public static Test MakeVerifier(ICollection<string> sources, ICollection<string> generatedSources) + { + var verifier = new Test(); + + verifier.TestState.AnalyzerConfigFiles.Add(("/.globalconfig", $""" + is_global = true + build_property.GodotProjectDir = {Constants.ExecutingAssemblyPath} + """)); + + verifier.TestState.Sources.AddRange(sources.Select(source => + { + return (source, SourceText.From(File.ReadAllText(Path.Combine(Constants.SourceFolderPath, source)))); + })); + + verifier.TestState.GeneratedSources.AddRange(generatedSources.Select(generatedSource => + { + return (FullGeneratedSourceName(generatedSource), SourceText.From(File.ReadAllText(Path.Combine(Constants.GeneratedSourceFolderPath, generatedSource)), Encoding.UTF8)); + })); + + return verifier; + } + + private static string FullGeneratedSourceName(string name) + { + var generatorType = typeof(TSourceGenerator); + return Path.Combine(generatorType.Namespace!, generatorType.FullName!, name); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Constants.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Constants.cs new file mode 100644 index 0000000000..783b1e4298 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Constants.cs @@ -0,0 +1,23 @@ +using System.IO; +using System.Reflection; + +namespace Godot.SourceGenerators.Tests; + +public static class Constants +{ + public static Assembly GodotSharpAssembly => typeof(GodotObject).Assembly; + + public static string ExecutingAssemblyPath { get; } + public static string SourceFolderPath { get; } + public static string GeneratedSourceFolderPath { get; } + + static Constants() + { + ExecutingAssemblyPath = Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!); + + var testDataPath = Path.Combine(ExecutingAssemblyPath, "TestData"); + + SourceFolderPath = Path.Combine(testDataPath, "Sources"); + GeneratedSourceFolderPath = Path.Combine(testDataPath, "GeneratedSources"); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Extensions.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Extensions.cs new file mode 100644 index 0000000000..6ff890e5d8 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Extensions.cs @@ -0,0 +1,12 @@ +using System.Reflection; +using Microsoft.CodeAnalysis; + +namespace Godot.SourceGenerators.Tests; + +public static class Extensions +{ + public static MetadataReference CreateMetadataReference(this Assembly assembly) + { + return MetadataReference.CreateFromFile(assembly.Location); + } +} 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 new file mode 100644 index 0000000000..e39c14f049 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj @@ -0,0 +1,40 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net6.0</TargetFramework> + + <LangVersion>11</LangVersion> + + <Nullable>enable</Nullable> + <IsPackable>false</IsPackable> + <IsTestProject>true</IsTestProject> + </PropertyGroup> + + <PropertyGroup> + <DefaultItemExcludesInProjectFolder>$(DefaultItemExcludesInProjectFolder);TestData\**</DefaultItemExcludesInProjectFolder> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" /> + <PackageReference Include="xunit" Version="2.4.2" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + <PackageReference Include="coverlet.collector" Version="3.2.0"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\..\glue\GodotSharp\GodotSharp\GodotSharp.csproj" /> + <ProjectReference Include="..\Godot.SourceGenerators\Godot.SourceGenerators.csproj" /> + </ItemGroup> + + <ItemGroup> + <None Include="TestData\**\*.cs" CopyToOutputDirectory="PreserveNewest" /> + </ItemGroup> + +</Project> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptMethodsGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptMethodsGeneratorTests.cs new file mode 100644 index 0000000000..294932eb9a --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptMethodsGeneratorTests.cs @@ -0,0 +1,24 @@ +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ScriptMethodsGeneratorTests +{ + [Fact] + public async void Methods() + { + await CSharpSourceGeneratorVerifier<ScriptMethodsGenerator>.Verify( + "Methods.cs", + "Methods_ScriptMethods.generated.cs" + ); + } + + [Fact] + public async void ScriptBoilerplate() + { + await CSharpSourceGeneratorVerifier<ScriptMethodsGenerator>.Verify( + "ScriptBoilerplate.cs", + "ScriptBoilerplate_ScriptMethods.generated.cs", "OuterClass.NestedClass_ScriptMethods.generated.cs" + ); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs new file mode 100644 index 0000000000..b7ad4217aa --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ScriptPathAttributeGeneratorTests +{ + private static (string, SourceText) MakeAssemblyScriptTypesGeneratedSource(ICollection<string> types) + { + return ( + Path.Combine("Godot.SourceGenerators", "Godot.SourceGenerators.ScriptPathAttributeGenerator", "AssemblyScriptTypes.generated.cs"), + SourceText.From($$""" + [assembly:Godot.AssemblyHasScriptsAttribute(new System.Type[] {{{string.Join(", ", types.Select(type => $"typeof({type})"))}}})] + + """, Encoding.UTF8) + ); + } + + [Fact] + public async void ScriptBoilerplate() + { + var verifier = CSharpSourceGeneratorVerifier<ScriptPathAttributeGenerator>.MakeVerifier( + new string[] { "ScriptBoilerplate.cs" }, + new string[] { "ScriptBoilerplate_ScriptPath.generated.cs" } + ); + verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::ScriptBoilerplate" })); + await verifier.RunAsync(); + } + + [Fact] + public async void FooBar() + { + var verifier = CSharpSourceGeneratorVerifier<ScriptPathAttributeGenerator>.MakeVerifier( + new string[] { "Foo.cs", "Bar.cs" }, + new string[] { "Foo_ScriptPath.generated.cs", "Bar_ScriptPath.generated.cs" } + ); + verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::Foo", "global::Bar" })); + await verifier.RunAsync(); + } + + [Fact] + public async void Generic() + { + var verifier = CSharpSourceGeneratorVerifier<ScriptPathAttributeGenerator>.MakeVerifier( + new string[] { "Generic.cs" }, + new string[] { "Generic_ScriptPath.generated.cs" } + ); + verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::Generic" })); + await verifier.RunAsync(); + } +} 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 new file mode 100644 index 0000000000..d20b354b9e --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs @@ -0,0 +1,60 @@ +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ScriptPropertiesGeneratorTests +{ + [Fact] + public async void ExportedFields() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + new string[] { "ExportedFields.cs", "MoreExportedFields.cs" }, + new string[] { "ExportedFields_ScriptProperties.generated.cs" } + ); + } + + [Fact] + public async void ExportedProperties() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + "ExportedProperties.cs", + "ExportedProperties_ScriptProperties.generated.cs" + ); + } + + [Fact] + public async void OneWayPropertiesAllReadOnly() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + "AllReadOnly.cs", + "AllReadOnly_ScriptProperties.generated.cs" + ); + } + + [Fact] + public async void OneWayPropertiesAllWriteOnly() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + "AllWriteOnly.cs", + "AllWriteOnly_ScriptProperties.generated.cs" + ); + } + + [Fact] + public async void OneWayPropertiesMixedReadonlyWriteOnly() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + "MixedReadOnlyWriteOnly.cs", + "MixedReadOnlyWriteOnly_ScriptProperties.generated.cs" + ); + } + + [Fact] + public async void ScriptBoilerplate() + { + await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( + "ScriptBoilerplate.cs", + "ScriptBoilerplate_ScriptProperties.generated.cs", "OuterClass.NestedClass_ScriptProperties.generated.cs" + ); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs new file mode 100644 index 0000000000..ae5fb86d77 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs @@ -0,0 +1,24 @@ +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ScriptPropertyDefValGeneratorTests +{ + [Fact] + public async void ExportedFields() + { + await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify( + new string[] { "ExportedFields.cs", "MoreExportedFields.cs" }, + new string[] { "ExportedFields_ScriptPropertyDefVal.generated.cs" } + ); + } + + [Fact] + public async void ExportedProperties() + { + await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify( + "ExportedProperties.cs", + "ExportedProperties_ScriptPropertyDefVal.generated.cs" + ); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptSerializationGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptSerializationGeneratorTests.cs new file mode 100644 index 0000000000..24cd446087 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptSerializationGeneratorTests.cs @@ -0,0 +1,15 @@ +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ScriptSerializationGeneratorTests +{ + [Fact] + public async void ScriptBoilerplate() + { + await CSharpSourceGeneratorVerifier<ScriptSerializationGenerator>.VerifyNoCompilerDiagnostics( + "ScriptBoilerplate.cs", + "ScriptBoilerplate_ScriptSerialization.generated.cs", "OuterClass.NestedClass_ScriptSerialization.generated.cs" + ); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptSignalsGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptSignalsGeneratorTests.cs new file mode 100644 index 0000000000..2a783cedce --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptSignalsGeneratorTests.cs @@ -0,0 +1,15 @@ +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ScriptSignalsGeneratorTests +{ + [Fact] + public async void EventSignals() + { + await CSharpSourceGeneratorVerifier<ScriptSignalsGenerator>.Verify( + "EventSignals.cs", + "EventSignals_ScriptSignals.generated.cs" + ); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/.editorconfig b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/.editorconfig new file mode 100644 index 0000000000..9e2014e16c --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.cs] +exclude = true +generated_code = true 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 new file mode 100644 index 0000000000..db56ac30a3 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs @@ -0,0 +1,66 @@ +using Godot; +using Godot.NativeInterop; + +partial class AllReadOnly +{ +#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.GodotObject.PropertyName { + /// <summary> + /// Cached name for the 'readonly_auto_property' property. + /// </summary> + public new static readonly global::Godot.StringName readonly_auto_property = "readonly_auto_property"; + /// <summary> + /// Cached name for the 'readonly_property' property. + /// </summary> + public new static readonly global::Godot.StringName readonly_property = "readonly_property"; + /// <summary> + /// Cached name for the 'initonly_auto_property' property. + /// </summary> + public new static readonly global::Godot.StringName initonly_auto_property = "initonly_auto_property"; + /// <summary> + /// Cached name for the 'readonly_field' field. + /// </summary> + public new static readonly global::Godot.StringName readonly_field = "readonly_field"; + } + /// <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.readonly_auto_property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_auto_property); + return true; + } + else if (name == PropertyName.readonly_property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_property); + return true; + } + else if (name == PropertyName.initonly_auto_property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.initonly_auto_property); + return true; + } + else if (name == PropertyName.readonly_field) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_field); + 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)4, name: PropertyName.readonly_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.initonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + return properties; + } +#pragma warning restore CS0109 +} 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 new file mode 100644 index 0000000000..256420fe87 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs @@ -0,0 +1,58 @@ +using Godot; +using Godot.NativeInterop; + +partial class AllWriteOnly +{ +#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.GodotObject.PropertyName { + /// <summary> + /// Cached name for the 'writeonly_property' property. + /// </summary> + public new static readonly global::Godot.StringName writeonly_property = "writeonly_property"; + /// <summary> + /// Cached name for the 'writeonly_backing_field' field. + /// </summary> + public new static readonly global::Godot.StringName writeonly_backing_field = "writeonly_backing_field"; + } + /// <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.writeonly_property) { + this.writeonly_property = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + return true; + } + else if (name == PropertyName.writeonly_backing_field) { + this.writeonly_backing_field = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(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.writeonly_backing_field) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.writeonly_backing_field); + 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)1, name: PropertyName.writeonly_backing_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + return properties; + } +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Bar_ScriptPath.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Bar_ScriptPath.generated.cs new file mode 100644 index 0000000000..9096da1b42 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Bar_ScriptPath.generated.cs @@ -0,0 +1,5 @@ +using Godot; +[ScriptPathAttribute("res://Bar.cs")] +partial class Bar +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs new file mode 100644 index 0000000000..b1c57e6b26 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs @@ -0,0 +1,54 @@ +using Godot; +using Godot.NativeInterop; + +partial class EventSignals +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword + /// <summary> + /// Cached StringNames for the signals contained in this class, for fast lookup. + /// </summary> + public new class SignalName : global::Godot.GodotObject.SignalName { + /// <summary> + /// Cached name for the 'MySignal' signal. + /// </summary> + public new static readonly global::Godot.StringName MySignal = "MySignal"; + } + /// <summary> + /// Get the signal information for all the signals declared in this class. + /// This method is used by Godot to register the available signals 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.MethodInfo> GetGodotSignalList() + { + var signals = new global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>(1); + signals.Add(new(name: SignalName.MySignal, returnVal: new(type: (global::Godot.Variant.Type)0, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), flags: (global::Godot.MethodFlags)1, arguments: new() { new(type: (global::Godot.Variant.Type)4, name: "str", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), new(type: (global::Godot.Variant.Type)2, name: "num", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), }, defaultArguments: null)); + return signals; + } +#pragma warning restore CS0109 + private global::EventSignals.MySignalEventHandler backing_MySignal; + /// <inheritdoc cref="global::EventSignals.MySignalEventHandler"/> + public event global::EventSignals.MySignalEventHandler MySignal { + add => backing_MySignal += value; + remove => backing_MySignal -= value; +} + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, NativeVariantPtrArgs args) + { + if (signal == SignalName.MySignal && args.Count == 2) { + backing_MySignal?.Invoke(global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(args[0]), global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[1])); + return; + } + base.RaiseGodotClassSignalCallbacks(signal, args); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool HasGodotClassSignal(in godot_string_name signal) + { + if (signal == SignalName.MySignal) { + return true; + } + return base.HasGodotClassSignal(signal); + } +} 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 new file mode 100644 index 0000000000..915c36525b --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs @@ -0,0 +1,816 @@ +using Godot; +using Godot.NativeInterop; + +partial class ExportedFields +{ +#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.GodotObject.PropertyName { + /// <summary> + /// Cached name for the 'field_Boolean' field. + /// </summary> + public new static readonly global::Godot.StringName field_Boolean = "field_Boolean"; + /// <summary> + /// Cached name for the 'field_Char' field. + /// </summary> + public new static readonly global::Godot.StringName field_Char = "field_Char"; + /// <summary> + /// Cached name for the 'field_SByte' field. + /// </summary> + public new static readonly global::Godot.StringName field_SByte = "field_SByte"; + /// <summary> + /// Cached name for the 'field_Int16' field. + /// </summary> + public new static readonly global::Godot.StringName field_Int16 = "field_Int16"; + /// <summary> + /// Cached name for the 'field_Int32' field. + /// </summary> + public new static readonly global::Godot.StringName field_Int32 = "field_Int32"; + /// <summary> + /// Cached name for the 'field_Int64' field. + /// </summary> + public new static readonly global::Godot.StringName field_Int64 = "field_Int64"; + /// <summary> + /// Cached name for the 'field_Byte' field. + /// </summary> + public new static readonly global::Godot.StringName field_Byte = "field_Byte"; + /// <summary> + /// Cached name for the 'field_UInt16' field. + /// </summary> + public new static readonly global::Godot.StringName field_UInt16 = "field_UInt16"; + /// <summary> + /// Cached name for the 'field_UInt32' field. + /// </summary> + public new static readonly global::Godot.StringName field_UInt32 = "field_UInt32"; + /// <summary> + /// Cached name for the 'field_UInt64' field. + /// </summary> + public new static readonly global::Godot.StringName field_UInt64 = "field_UInt64"; + /// <summary> + /// Cached name for the 'field_Single' field. + /// </summary> + public new static readonly global::Godot.StringName field_Single = "field_Single"; + /// <summary> + /// Cached name for the 'field_Double' field. + /// </summary> + public new static readonly global::Godot.StringName field_Double = "field_Double"; + /// <summary> + /// Cached name for the 'field_String' field. + /// </summary> + public new static readonly global::Godot.StringName field_String = "field_String"; + /// <summary> + /// Cached name for the 'field_Vector2' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector2 = "field_Vector2"; + /// <summary> + /// Cached name for the 'field_Vector2I' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector2I = "field_Vector2I"; + /// <summary> + /// Cached name for the 'field_Rect2' field. + /// </summary> + public new static readonly global::Godot.StringName field_Rect2 = "field_Rect2"; + /// <summary> + /// Cached name for the 'field_Rect2I' field. + /// </summary> + public new static readonly global::Godot.StringName field_Rect2I = "field_Rect2I"; + /// <summary> + /// Cached name for the 'field_Transform2D' field. + /// </summary> + public new static readonly global::Godot.StringName field_Transform2D = "field_Transform2D"; + /// <summary> + /// Cached name for the 'field_Vector3' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector3 = "field_Vector3"; + /// <summary> + /// Cached name for the 'field_Vector3I' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector3I = "field_Vector3I"; + /// <summary> + /// Cached name for the 'field_Basis' field. + /// </summary> + public new static readonly global::Godot.StringName field_Basis = "field_Basis"; + /// <summary> + /// Cached name for the 'field_Quaternion' field. + /// </summary> + public new static readonly global::Godot.StringName field_Quaternion = "field_Quaternion"; + /// <summary> + /// Cached name for the 'field_Transform3D' field. + /// </summary> + public new static readonly global::Godot.StringName field_Transform3D = "field_Transform3D"; + /// <summary> + /// Cached name for the 'field_Vector4' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector4 = "field_Vector4"; + /// <summary> + /// Cached name for the 'field_Vector4I' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector4I = "field_Vector4I"; + /// <summary> + /// Cached name for the 'field_Projection' field. + /// </summary> + public new static readonly global::Godot.StringName field_Projection = "field_Projection"; + /// <summary> + /// Cached name for the 'field_Aabb' field. + /// </summary> + public new static readonly global::Godot.StringName field_Aabb = "field_Aabb"; + /// <summary> + /// Cached name for the 'field_Color' field. + /// </summary> + public new static readonly global::Godot.StringName field_Color = "field_Color"; + /// <summary> + /// Cached name for the 'field_Plane' field. + /// </summary> + public new static readonly global::Godot.StringName field_Plane = "field_Plane"; + /// <summary> + /// Cached name for the 'field_Callable' field. + /// </summary> + public new static readonly global::Godot.StringName field_Callable = "field_Callable"; + /// <summary> + /// Cached name for the 'field_Signal' field. + /// </summary> + public new static readonly global::Godot.StringName field_Signal = "field_Signal"; + /// <summary> + /// Cached name for the 'field_Enum' field. + /// </summary> + public new static readonly global::Godot.StringName field_Enum = "field_Enum"; + /// <summary> + /// Cached name for the 'field_FlagsEnum' field. + /// </summary> + public new static readonly global::Godot.StringName field_FlagsEnum = "field_FlagsEnum"; + /// <summary> + /// Cached name for the 'field_ByteArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_ByteArray = "field_ByteArray"; + /// <summary> + /// Cached name for the 'field_Int32Array' field. + /// </summary> + public new static readonly global::Godot.StringName field_Int32Array = "field_Int32Array"; + /// <summary> + /// Cached name for the 'field_Int64Array' field. + /// </summary> + public new static readonly global::Godot.StringName field_Int64Array = "field_Int64Array"; + /// <summary> + /// Cached name for the 'field_SingleArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_SingleArray = "field_SingleArray"; + /// <summary> + /// Cached name for the 'field_DoubleArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_DoubleArray = "field_DoubleArray"; + /// <summary> + /// Cached name for the 'field_StringArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_StringArray = "field_StringArray"; + /// <summary> + /// Cached name for the 'field_StringArrayEnum' field. + /// </summary> + public new static readonly global::Godot.StringName field_StringArrayEnum = "field_StringArrayEnum"; + /// <summary> + /// Cached name for the 'field_Vector2Array' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector2Array = "field_Vector2Array"; + /// <summary> + /// Cached name for the 'field_Vector3Array' field. + /// </summary> + public new static readonly global::Godot.StringName field_Vector3Array = "field_Vector3Array"; + /// <summary> + /// Cached name for the 'field_ColorArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_ColorArray = "field_ColorArray"; + /// <summary> + /// Cached name for the 'field_GodotObjectOrDerivedArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotObjectOrDerivedArray = "field_GodotObjectOrDerivedArray"; + /// <summary> + /// Cached name for the 'field_StringNameArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_StringNameArray = "field_StringNameArray"; + /// <summary> + /// Cached name for the 'field_NodePathArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_NodePathArray = "field_NodePathArray"; + /// <summary> + /// Cached name for the 'field_RidArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_RidArray = "field_RidArray"; + /// <summary> + /// Cached name for the 'field_empty_Int32Array' field. + /// </summary> + public new static readonly global::Godot.StringName field_empty_Int32Array = "field_empty_Int32Array"; + /// <summary> + /// Cached name for the 'field_array_from_list' field. + /// </summary> + public new static readonly global::Godot.StringName field_array_from_list = "field_array_from_list"; + /// <summary> + /// Cached name for the 'field_Variant' field. + /// </summary> + public new static readonly global::Godot.StringName field_Variant = "field_Variant"; + /// <summary> + /// Cached name for the 'field_GodotObjectOrDerived' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotObjectOrDerived = "field_GodotObjectOrDerived"; + /// <summary> + /// Cached name for the 'field_GodotResourceTexture' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotResourceTexture = "field_GodotResourceTexture"; + /// <summary> + /// Cached name for the 'field_StringName' field. + /// </summary> + public new static readonly global::Godot.StringName field_StringName = "field_StringName"; + /// <summary> + /// Cached name for the 'field_NodePath' field. + /// </summary> + public new static readonly global::Godot.StringName field_NodePath = "field_NodePath"; + /// <summary> + /// Cached name for the 'field_Rid' field. + /// </summary> + public new static readonly global::Godot.StringName field_Rid = "field_Rid"; + /// <summary> + /// Cached name for the 'field_GodotDictionary' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotDictionary = "field_GodotDictionary"; + /// <summary> + /// Cached name for the 'field_GodotArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotArray = "field_GodotArray"; + /// <summary> + /// Cached name for the 'field_GodotGenericDictionary' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotGenericDictionary = "field_GodotGenericDictionary"; + /// <summary> + /// Cached name for the 'field_GodotGenericArray' field. + /// </summary> + public new static readonly global::Godot.StringName field_GodotGenericArray = "field_GodotGenericArray"; + /// <summary> + /// Cached name for the 'field_empty_Int64Array' field. + /// </summary> + public new static readonly global::Godot.StringName field_empty_Int64Array = "field_empty_Int64Array"; + } + /// <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.field_Boolean) { + this.field_Boolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + return true; + } + else if (name == PropertyName.field_Char) { + this.field_Char = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); + return true; + } + else if (name == PropertyName.field_SByte) { + this.field_SByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); + return true; + } + else if (name == PropertyName.field_Int16) { + this.field_Int16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); + return true; + } + else if (name == PropertyName.field_Int32) { + this.field_Int32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); + return true; + } + else if (name == PropertyName.field_Int64) { + this.field_Int64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); + return true; + } + else if (name == PropertyName.field_Byte) { + this.field_Byte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); + return true; + } + else if (name == PropertyName.field_UInt16) { + this.field_UInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); + return true; + } + else if (name == PropertyName.field_UInt32) { + this.field_UInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); + return true; + } + else if (name == PropertyName.field_UInt64) { + this.field_UInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); + return true; + } + else if (name == PropertyName.field_Single) { + this.field_Single = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); + return true; + } + else if (name == PropertyName.field_Double) { + this.field_Double = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); + return true; + } + else if (name == PropertyName.field_String) { + this.field_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.field_Vector2) { + this.field_Vector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); + return true; + } + else if (name == PropertyName.field_Vector2I) { + this.field_Vector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); + return true; + } + else if (name == PropertyName.field_Rect2) { + this.field_Rect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); + return true; + } + else if (name == PropertyName.field_Rect2I) { + this.field_Rect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); + return true; + } + else if (name == PropertyName.field_Transform2D) { + this.field_Transform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); + return true; + } + else if (name == PropertyName.field_Vector3) { + this.field_Vector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); + return true; + } + else if (name == PropertyName.field_Vector3I) { + this.field_Vector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); + return true; + } + else if (name == PropertyName.field_Basis) { + this.field_Basis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); + return true; + } + else if (name == PropertyName.field_Quaternion) { + this.field_Quaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); + return true; + } + else if (name == PropertyName.field_Transform3D) { + this.field_Transform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); + return true; + } + else if (name == PropertyName.field_Vector4) { + this.field_Vector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); + return true; + } + else if (name == PropertyName.field_Vector4I) { + this.field_Vector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); + return true; + } + else if (name == PropertyName.field_Projection) { + this.field_Projection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); + return true; + } + else if (name == PropertyName.field_Aabb) { + this.field_Aabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); + return true; + } + else if (name == PropertyName.field_Color) { + this.field_Color = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); + return true; + } + else if (name == PropertyName.field_Plane) { + this.field_Plane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); + return true; + } + else if (name == PropertyName.field_Callable) { + this.field_Callable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); + return true; + } + else if (name == PropertyName.field_Signal) { + this.field_Signal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); + return true; + } + else if (name == PropertyName.field_Enum) { + this.field_Enum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyEnum>(value); + return true; + } + else if (name == PropertyName.field_FlagsEnum) { + this.field_FlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyFlagsEnum>(value); + return true; + } + else if (name == PropertyName.field_ByteArray) { + this.field_ByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); + return true; + } + else if (name == PropertyName.field_Int32Array) { + this.field_Int32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + return true; + } + else if (name == PropertyName.field_Int64Array) { + this.field_Int64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); + return true; + } + else if (name == PropertyName.field_SingleArray) { + this.field_SingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); + return true; + } + else if (name == PropertyName.field_DoubleArray) { + this.field_DoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); + return true; + } + else if (name == PropertyName.field_StringArray) { + this.field_StringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + return true; + } + else if (name == PropertyName.field_StringArrayEnum) { + this.field_StringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + return true; + } + else if (name == PropertyName.field_Vector2Array) { + this.field_Vector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); + return true; + } + else if (name == PropertyName.field_Vector3Array) { + this.field_Vector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); + return true; + } + else if (name == PropertyName.field_ColorArray) { + this.field_ColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); + return true; + } + else if (name == PropertyName.field_GodotObjectOrDerivedArray) { + this.field_GodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); + return true; + } + else 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) { + this.field_NodePathArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath[]>(value); + return true; + } + else if (name == PropertyName.field_RidArray) { + this.field_RidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); + return true; + } + else if (name == PropertyName.field_empty_Int32Array) { + this.field_empty_Int32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + return true; + } + else if (name == PropertyName.field_array_from_list) { + this.field_array_from_list = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + return true; + } + else if (name == PropertyName.field_Variant) { + this.field_Variant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); + return true; + } + else if (name == PropertyName.field_GodotObjectOrDerived) { + this.field_GodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); + return true; + } + else if (name == PropertyName.field_GodotResourceTexture) { + this.field_GodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); + return true; + } + else if (name == PropertyName.field_StringName) { + this.field_StringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); + return true; + } + else if (name == PropertyName.field_NodePath) { + this.field_NodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); + return true; + } + else if (name == PropertyName.field_Rid) { + this.field_Rid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); + return true; + } + else if (name == PropertyName.field_GodotDictionary) { + this.field_GodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); + return true; + } + else if (name == PropertyName.field_GodotArray) { + this.field_GodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); + return true; + } + else if (name == PropertyName.field_GodotGenericDictionary) { + this.field_GodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); + return true; + } + else if (name == PropertyName.field_GodotGenericArray) { + this.field_GodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); + return true; + } + else if (name == PropertyName.field_empty_Int64Array) { + this.field_empty_Int64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(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.field_Boolean) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.field_Boolean); + return true; + } + else if (name == PropertyName.field_Char) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this.field_Char); + return true; + } + else if (name == PropertyName.field_SByte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this.field_SByte); + return true; + } + else if (name == PropertyName.field_Int16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this.field_Int16); + return true; + } + else if (name == PropertyName.field_Int32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this.field_Int32); + return true; + } + else if (name == PropertyName.field_Int64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this.field_Int64); + return true; + } + else if (name == PropertyName.field_Byte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this.field_Byte); + return true; + } + else if (name == PropertyName.field_UInt16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this.field_UInt16); + return true; + } + else if (name == PropertyName.field_UInt32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this.field_UInt32); + return true; + } + else if (name == PropertyName.field_UInt64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this.field_UInt64); + return true; + } + else if (name == PropertyName.field_Single) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this.field_Single); + return true; + } + else if (name == PropertyName.field_Double) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this.field_Double); + return true; + } + else if (name == PropertyName.field_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.field_String); + return true; + } + else if (name == PropertyName.field_Vector2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this.field_Vector2); + return true; + } + else if (name == PropertyName.field_Vector2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this.field_Vector2I); + return true; + } + else if (name == PropertyName.field_Rect2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this.field_Rect2); + return true; + } + else if (name == PropertyName.field_Rect2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this.field_Rect2I); + return true; + } + else if (name == PropertyName.field_Transform2D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this.field_Transform2D); + return true; + } + else if (name == PropertyName.field_Vector3) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this.field_Vector3); + return true; + } + else if (name == PropertyName.field_Vector3I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this.field_Vector3I); + return true; + } + else if (name == PropertyName.field_Basis) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this.field_Basis); + return true; + } + else if (name == PropertyName.field_Quaternion) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this.field_Quaternion); + return true; + } + else if (name == PropertyName.field_Transform3D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this.field_Transform3D); + return true; + } + else if (name == PropertyName.field_Vector4) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this.field_Vector4); + return true; + } + else if (name == PropertyName.field_Vector4I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this.field_Vector4I); + return true; + } + else if (name == PropertyName.field_Projection) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this.field_Projection); + return true; + } + else if (name == PropertyName.field_Aabb) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this.field_Aabb); + return true; + } + else if (name == PropertyName.field_Color) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this.field_Color); + return true; + } + else if (name == PropertyName.field_Plane) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this.field_Plane); + return true; + } + else if (name == PropertyName.field_Callable) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.field_Callable); + return true; + } + else if (name == PropertyName.field_Signal) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this.field_Signal); + return true; + } + else if (name == PropertyName.field_Enum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyEnum>(this.field_Enum); + return true; + } + else if (name == PropertyName.field_FlagsEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyFlagsEnum>(this.field_FlagsEnum); + return true; + } + else if (name == PropertyName.field_ByteArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this.field_ByteArray); + return true; + } + else if (name == PropertyName.field_Int32Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.field_Int32Array); + return true; + } + else if (name == PropertyName.field_Int64Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.field_Int64Array); + return true; + } + else if (name == PropertyName.field_SingleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this.field_SingleArray); + return true; + } + else if (name == PropertyName.field_DoubleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this.field_DoubleArray); + return true; + } + else if (name == PropertyName.field_StringArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.field_StringArray); + return true; + } + else if (name == PropertyName.field_StringArrayEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.field_StringArrayEnum); + return true; + } + else if (name == PropertyName.field_Vector2Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this.field_Vector2Array); + return true; + } + else if (name == PropertyName.field_Vector3Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this.field_Vector3Array); + return true; + } + else if (name == PropertyName.field_ColorArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this.field_ColorArray); + return true; + } + else if (name == PropertyName.field_GodotObjectOrDerivedArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this.field_GodotObjectOrDerivedArray); + return true; + } + else 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) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath[]>(this.field_NodePathArray); + return true; + } + else if (name == PropertyName.field_RidArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this.field_RidArray); + return true; + } + else if (name == PropertyName.field_empty_Int32Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.field_empty_Int32Array); + return true; + } + else if (name == PropertyName.field_array_from_list) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.field_array_from_list); + return true; + } + else if (name == PropertyName.field_Variant) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this.field_Variant); + return true; + } + else if (name == PropertyName.field_GodotObjectOrDerived) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this.field_GodotObjectOrDerived); + return true; + } + else if (name == PropertyName.field_GodotResourceTexture) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this.field_GodotResourceTexture); + return true; + } + else if (name == PropertyName.field_StringName) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this.field_StringName); + return true; + } + else if (name == PropertyName.field_NodePath) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this.field_NodePath); + return true; + } + else if (name == PropertyName.field_Rid) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this.field_Rid); + return true; + } + else if (name == PropertyName.field_GodotDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this.field_GodotDictionary); + return true; + } + else if (name == PropertyName.field_GodotArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this.field_GodotArray); + return true; + } + else if (name == PropertyName.field_GodotGenericDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this.field_GodotGenericDictionary); + return true; + } + else if (name == PropertyName.field_GodotGenericArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.field_GodotGenericArray); + return true; + } + else if (name == PropertyName.field_empty_Int64Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.field_empty_Int64Array); + 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)1, name: PropertyName.field_Boolean, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Char, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_SByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Int16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Int32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Int64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Byte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_UInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_UInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_UInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.field_Single, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.field_Double, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.field_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)5, name: PropertyName.field_Vector2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)6, name: PropertyName.field_Vector2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)7, name: PropertyName.field_Rect2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)8, name: PropertyName.field_Rect2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)11, name: PropertyName.field_Transform2D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)9, name: PropertyName.field_Vector3, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)10, name: PropertyName.field_Vector3I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)17, name: PropertyName.field_Basis, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)15, name: PropertyName.field_Quaternion, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)18, name: PropertyName.field_Transform3D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)12, name: PropertyName.field_Vector4, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)13, name: PropertyName.field_Vector4I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)19, name: PropertyName.field_Projection, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)16, name: PropertyName.field_Aabb, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)20, name: PropertyName.field_Color, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)14, name: PropertyName.field_Plane, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.field_Callable, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)26, name: PropertyName.field_Signal, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Enum, hint: (global::Godot.PropertyHint)2, hintString: "A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_FlagsEnum, hint: (global::Godot.PropertyHint)6, hintString: "A:0,B:1,C:2", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)29, name: PropertyName.field_ByteArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.field_Int32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.field_Int64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)32, name: PropertyName.field_SingleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)33, name: PropertyName.field_DoubleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.field_StringArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.field_StringArrayEnum, hint: (global::Godot.PropertyHint)23, hintString: "4/2:A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)35, name: PropertyName.field_Vector2Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)36, name: PropertyName.field_Vector3Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)37, name: PropertyName.field_ColorArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_GodotObjectOrDerivedArray, hint: (global::Godot.PropertyHint)23, hintString: "24/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_StringNameArray, hint: (global::Godot.PropertyHint)23, hintString: "21/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_NodePathArray, hint: (global::Godot.PropertyHint)23, hintString: "22/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_RidArray, hint: (global::Godot.PropertyHint)23, hintString: "23/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.field_empty_Int32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.field_array_from_list, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)0, name: PropertyName.field_Variant, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)135174, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.field_GodotObjectOrDerived, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.field_GodotResourceTexture, hint: (global::Godot.PropertyHint)17, hintString: "Texture", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)21, name: PropertyName.field_StringName, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)22, name: PropertyName.field_NodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.field_Rid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.field_GodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_GodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.field_GodotGenericDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_GodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.field_empty_Int64Array, 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/ExportedFields_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptPropertyDefVal.generated.cs new file mode 100644 index 0000000000..185b8e4ac6 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,139 @@ +partial class ExportedFields +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword +#if TOOLS + /// <summary> + /// Get the default values for all properties declared in this class. + /// This method is used by Godot to determine the value that will be + /// used by the inspector when resetting properties. + /// Do not call this method. + /// </summary> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues() + { + var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(60); + bool __field_Boolean_default_value = true; + values.Add(PropertyName.field_Boolean, global::Godot.Variant.From<bool>(__field_Boolean_default_value)); + char __field_Char_default_value = 'f'; + values.Add(PropertyName.field_Char, global::Godot.Variant.From<char>(__field_Char_default_value)); + sbyte __field_SByte_default_value = 10; + values.Add(PropertyName.field_SByte, global::Godot.Variant.From<sbyte>(__field_SByte_default_value)); + short __field_Int16_default_value = 10; + values.Add(PropertyName.field_Int16, global::Godot.Variant.From<short>(__field_Int16_default_value)); + int __field_Int32_default_value = 10; + values.Add(PropertyName.field_Int32, global::Godot.Variant.From<int>(__field_Int32_default_value)); + long __field_Int64_default_value = 10; + values.Add(PropertyName.field_Int64, global::Godot.Variant.From<long>(__field_Int64_default_value)); + byte __field_Byte_default_value = 10; + values.Add(PropertyName.field_Byte, global::Godot.Variant.From<byte>(__field_Byte_default_value)); + ushort __field_UInt16_default_value = 10; + values.Add(PropertyName.field_UInt16, global::Godot.Variant.From<ushort>(__field_UInt16_default_value)); + uint __field_UInt32_default_value = 10; + values.Add(PropertyName.field_UInt32, global::Godot.Variant.From<uint>(__field_UInt32_default_value)); + ulong __field_UInt64_default_value = 10; + values.Add(PropertyName.field_UInt64, global::Godot.Variant.From<ulong>(__field_UInt64_default_value)); + float __field_Single_default_value = 10; + values.Add(PropertyName.field_Single, global::Godot.Variant.From<float>(__field_Single_default_value)); + double __field_Double_default_value = 10; + values.Add(PropertyName.field_Double, global::Godot.Variant.From<double>(__field_Double_default_value)); + string __field_String_default_value = "foo"; + values.Add(PropertyName.field_String, global::Godot.Variant.From<string>(__field_String_default_value)); + global::Godot.Vector2 __field_Vector2_default_value = new(10f, 10f); + values.Add(PropertyName.field_Vector2, global::Godot.Variant.From<global::Godot.Vector2>(__field_Vector2_default_value)); + global::Godot.Vector2I __field_Vector2I_default_value = global::Godot.Vector2I.Up; + values.Add(PropertyName.field_Vector2I, global::Godot.Variant.From<global::Godot.Vector2I>(__field_Vector2I_default_value)); + global::Godot.Rect2 __field_Rect2_default_value = new(new global::Godot.Vector2(10f, 10f), new global::Godot.Vector2(10f, 10f)); + values.Add(PropertyName.field_Rect2, global::Godot.Variant.From<global::Godot.Rect2>(__field_Rect2_default_value)); + global::Godot.Rect2I __field_Rect2I_default_value = new(new global::Godot.Vector2I(10, 10), new global::Godot.Vector2I(10, 10)); + values.Add(PropertyName.field_Rect2I, global::Godot.Variant.From<global::Godot.Rect2I>(__field_Rect2I_default_value)); + global::Godot.Transform2D __field_Transform2D_default_value = global::Godot.Transform2D.Identity; + values.Add(PropertyName.field_Transform2D, global::Godot.Variant.From<global::Godot.Transform2D>(__field_Transform2D_default_value)); + global::Godot.Vector3 __field_Vector3_default_value = new(10f, 10f, 10f); + values.Add(PropertyName.field_Vector3, global::Godot.Variant.From<global::Godot.Vector3>(__field_Vector3_default_value)); + global::Godot.Vector3I __field_Vector3I_default_value = global::Godot.Vector3I.Back; + values.Add(PropertyName.field_Vector3I, global::Godot.Variant.From<global::Godot.Vector3I>(__field_Vector3I_default_value)); + global::Godot.Basis __field_Basis_default_value = new global::Godot.Basis(global::Godot.Quaternion.Identity); + values.Add(PropertyName.field_Basis, global::Godot.Variant.From<global::Godot.Basis>(__field_Basis_default_value)); + global::Godot.Quaternion __field_Quaternion_default_value = new global::Godot.Quaternion(global::Godot.Basis.Identity); + values.Add(PropertyName.field_Quaternion, global::Godot.Variant.From<global::Godot.Quaternion>(__field_Quaternion_default_value)); + global::Godot.Transform3D __field_Transform3D_default_value = global::Godot.Transform3D.Identity; + values.Add(PropertyName.field_Transform3D, global::Godot.Variant.From<global::Godot.Transform3D>(__field_Transform3D_default_value)); + global::Godot.Vector4 __field_Vector4_default_value = new(10f, 10f, 10f, 10f); + values.Add(PropertyName.field_Vector4, global::Godot.Variant.From<global::Godot.Vector4>(__field_Vector4_default_value)); + global::Godot.Vector4I __field_Vector4I_default_value = global::Godot.Vector4I.One; + values.Add(PropertyName.field_Vector4I, global::Godot.Variant.From<global::Godot.Vector4I>(__field_Vector4I_default_value)); + global::Godot.Projection __field_Projection_default_value = global::Godot.Projection.Identity; + values.Add(PropertyName.field_Projection, global::Godot.Variant.From<global::Godot.Projection>(__field_Projection_default_value)); + global::Godot.Aabb __field_Aabb_default_value = new global::Godot.Aabb(10f, 10f, 10f, new global::Godot.Vector3(1f, 1f, 1f)); + values.Add(PropertyName.field_Aabb, global::Godot.Variant.From<global::Godot.Aabb>(__field_Aabb_default_value)); + global::Godot.Color __field_Color_default_value = global::Godot.Colors.Aquamarine; + values.Add(PropertyName.field_Color, global::Godot.Variant.From<global::Godot.Color>(__field_Color_default_value)); + global::Godot.Plane __field_Plane_default_value = global::Godot.Plane.PlaneXZ; + values.Add(PropertyName.field_Plane, global::Godot.Variant.From<global::Godot.Plane>(__field_Plane_default_value)); + global::Godot.Callable __field_Callable_default_value = new global::Godot.Callable(global::Godot.Engine.GetMainLoop(), "_process"); + values.Add(PropertyName.field_Callable, global::Godot.Variant.From<global::Godot.Callable>(__field_Callable_default_value)); + global::Godot.Signal __field_Signal_default_value = new global::Godot.Signal(global::Godot.Engine.GetMainLoop(), "property_list_changed"); + values.Add(PropertyName.field_Signal, global::Godot.Variant.From<global::Godot.Signal>(__field_Signal_default_value)); + global::ExportedFields.MyEnum __field_Enum_default_value = global::ExportedFields.MyEnum.C; + values.Add(PropertyName.field_Enum, global::Godot.Variant.From<global::ExportedFields.MyEnum>(__field_Enum_default_value)); + global::ExportedFields.MyFlagsEnum __field_FlagsEnum_default_value = global::ExportedFields.MyFlagsEnum.C; + values.Add(PropertyName.field_FlagsEnum, global::Godot.Variant.From<global::ExportedFields.MyFlagsEnum>(__field_FlagsEnum_default_value)); + byte[] __field_ByteArray_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.field_ByteArray, global::Godot.Variant.From<byte[]>(__field_ByteArray_default_value)); + int[] __field_Int32Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.field_Int32Array, global::Godot.Variant.From<int[]>(__field_Int32Array_default_value)); + long[] __field_Int64Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.field_Int64Array, global::Godot.Variant.From<long[]>(__field_Int64Array_default_value)); + float[] __field_SingleArray_default_value = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + values.Add(PropertyName.field_SingleArray, global::Godot.Variant.From<float[]>(__field_SingleArray_default_value)); + double[] __field_DoubleArray_default_value = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + values.Add(PropertyName.field_DoubleArray, global::Godot.Variant.From<double[]>(__field_DoubleArray_default_value)); + string[] __field_StringArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.field_StringArray, global::Godot.Variant.From<string[]>(__field_StringArray_default_value)); + string[] __field_StringArrayEnum_default_value = { "foo", "bar" }; + values.Add(PropertyName.field_StringArrayEnum, global::Godot.Variant.From<string[]>(__field_StringArrayEnum_default_value)); + global::Godot.Vector2[] __field_Vector2Array_default_value = { global::Godot.Vector2.Up, global::Godot.Vector2.Down, global::Godot.Vector2.Left, global::Godot.Vector2.Right }; + values.Add(PropertyName.field_Vector2Array, global::Godot.Variant.From<global::Godot.Vector2[]>(__field_Vector2Array_default_value)); + global::Godot.Vector3[] __field_Vector3Array_default_value = { global::Godot.Vector3.Up, global::Godot.Vector3.Down, global::Godot.Vector3.Left, global::Godot.Vector3.Right }; + values.Add(PropertyName.field_Vector3Array, global::Godot.Variant.From<global::Godot.Vector3[]>(__field_Vector3Array_default_value)); + global::Godot.Color[] __field_ColorArray_default_value = { global::Godot.Colors.Aqua, global::Godot.Colors.Aquamarine, global::Godot.Colors.Azure, global::Godot.Colors.Beige }; + values.Add(PropertyName.field_ColorArray, global::Godot.Variant.From<global::Godot.Color[]>(__field_ColorArray_default_value)); + global::Godot.GodotObject[] __field_GodotObjectOrDerivedArray_default_value = { null }; + values.Add(PropertyName.field_GodotObjectOrDerivedArray, global::Godot.Variant.CreateFrom(__field_GodotObjectOrDerivedArray_default_value)); + global::Godot.StringName[] __field_StringNameArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.field_StringNameArray, global::Godot.Variant.From<global::Godot.StringName[]>(__field_StringNameArray_default_value)); + global::Godot.NodePath[] __field_NodePathArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.field_NodePathArray, global::Godot.Variant.From<global::Godot.NodePath[]>(__field_NodePathArray_default_value)); + global::Godot.Rid[] __field_RidArray_default_value = { default, default, default }; + values.Add(PropertyName.field_RidArray, global::Godot.Variant.From<global::Godot.Rid[]>(__field_RidArray_default_value)); + int[] __field_empty_Int32Array_default_value = global::System.Array.Empty<int>(); + values.Add(PropertyName.field_empty_Int32Array, global::Godot.Variant.From<int[]>(__field_empty_Int32Array_default_value)); + int[] __field_array_from_list_default_value = new global::System.Collections.Generic.List<int>(global::System.Array.Empty<int>()).ToArray(); + values.Add(PropertyName.field_array_from_list, global::Godot.Variant.From<int[]>(__field_array_from_list_default_value)); + global::Godot.Variant __field_Variant_default_value = "foo"; + values.Add(PropertyName.field_Variant, global::Godot.Variant.From<global::Godot.Variant>(__field_Variant_default_value)); + global::Godot.GodotObject __field_GodotObjectOrDerived_default_value = default; + values.Add(PropertyName.field_GodotObjectOrDerived, global::Godot.Variant.From<global::Godot.GodotObject>(__field_GodotObjectOrDerived_default_value)); + global::Godot.Texture __field_GodotResourceTexture_default_value = default; + values.Add(PropertyName.field_GodotResourceTexture, global::Godot.Variant.From<global::Godot.Texture>(__field_GodotResourceTexture_default_value)); + global::Godot.StringName __field_StringName_default_value = new global::Godot.StringName("foo"); + values.Add(PropertyName.field_StringName, global::Godot.Variant.From<global::Godot.StringName>(__field_StringName_default_value)); + global::Godot.NodePath __field_NodePath_default_value = new global::Godot.NodePath("foo"); + values.Add(PropertyName.field_NodePath, global::Godot.Variant.From<global::Godot.NodePath>(__field_NodePath_default_value)); + global::Godot.Rid __field_Rid_default_value = default; + values.Add(PropertyName.field_Rid, global::Godot.Variant.From<global::Godot.Rid>(__field_Rid_default_value)); + global::Godot.Collections.Dictionary __field_GodotDictionary_default_value = new() { { "foo", 10 }, { global::Godot.Vector2.Up, global::Godot.Colors.Chocolate } }; + values.Add(PropertyName.field_GodotDictionary, global::Godot.Variant.From<global::Godot.Collections.Dictionary>(__field_GodotDictionary_default_value)); + global::Godot.Collections.Array __field_GodotArray_default_value = new() { "foo", 10, global::Godot.Vector2.Up, global::Godot.Colors.Chocolate }; + values.Add(PropertyName.field_GodotArray, global::Godot.Variant.From<global::Godot.Collections.Array>(__field_GodotArray_default_value)); + global::Godot.Collections.Dictionary<string, bool> __field_GodotGenericDictionary_default_value = new() { { "foo", true }, { "bar", false } }; + values.Add(PropertyName.field_GodotGenericDictionary, global::Godot.Variant.CreateFrom(__field_GodotGenericDictionary_default_value)); + global::Godot.Collections.Array<int> __field_GodotGenericArray_default_value = new() { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.field_GodotGenericArray, global::Godot.Variant.CreateFrom(__field_GodotGenericArray_default_value)); + long[] __field_empty_Int64Array_default_value = global::System.Array.Empty<long>(); + values.Add(PropertyName.field_empty_Int64Array, global::Godot.Variant.From<long[]>(__field_empty_Int64Array_default_value)); + return values; + } +#endif // TOOLS +#pragma warning restore CS0109 +} 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 new file mode 100644 index 0000000000..b5ec9b5b49 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs @@ -0,0 +1,933 @@ +using Godot; +using Godot.NativeInterop; + +partial class ExportedProperties +{ +#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.GodotObject.PropertyName { + /// <summary> + /// Cached name for the 'NotGenerate_Complex_Lamda_Property' property. + /// </summary> + public new static readonly global::Godot.StringName NotGenerate_Complex_Lamda_Property = "NotGenerate_Complex_Lamda_Property"; + /// <summary> + /// Cached name for the 'NotGenerate_Lamda_NoField_Property' property. + /// </summary> + public new static readonly global::Godot.StringName NotGenerate_Lamda_NoField_Property = "NotGenerate_Lamda_NoField_Property"; + /// <summary> + /// Cached name for the 'NotGenerate_Complex_Return_Property' property. + /// </summary> + public new static readonly global::Godot.StringName NotGenerate_Complex_Return_Property = "NotGenerate_Complex_Return_Property"; + /// <summary> + /// Cached name for the 'NotGenerate_Returns_Property' property. + /// </summary> + public new static readonly global::Godot.StringName NotGenerate_Returns_Property = "NotGenerate_Returns_Property"; + /// <summary> + /// Cached name for the 'FullProperty_String' property. + /// </summary> + public new static readonly global::Godot.StringName FullProperty_String = "FullProperty_String"; + /// <summary> + /// Cached name for the 'FullProperty_String_Complex' property. + /// </summary> + public new static readonly global::Godot.StringName FullProperty_String_Complex = "FullProperty_String_Complex"; + /// <summary> + /// Cached name for the 'LamdaProperty_String' property. + /// </summary> + public new static readonly global::Godot.StringName LamdaProperty_String = "LamdaProperty_String"; + /// <summary> + /// Cached name for the 'property_Boolean' property. + /// </summary> + public new static readonly global::Godot.StringName property_Boolean = "property_Boolean"; + /// <summary> + /// Cached name for the 'property_Char' property. + /// </summary> + public new static readonly global::Godot.StringName property_Char = "property_Char"; + /// <summary> + /// Cached name for the 'property_SByte' property. + /// </summary> + public new static readonly global::Godot.StringName property_SByte = "property_SByte"; + /// <summary> + /// Cached name for the 'property_Int16' property. + /// </summary> + public new static readonly global::Godot.StringName property_Int16 = "property_Int16"; + /// <summary> + /// Cached name for the 'property_Int32' property. + /// </summary> + public new static readonly global::Godot.StringName property_Int32 = "property_Int32"; + /// <summary> + /// Cached name for the 'property_Int64' property. + /// </summary> + public new static readonly global::Godot.StringName property_Int64 = "property_Int64"; + /// <summary> + /// Cached name for the 'property_Byte' property. + /// </summary> + public new static readonly global::Godot.StringName property_Byte = "property_Byte"; + /// <summary> + /// Cached name for the 'property_UInt16' property. + /// </summary> + public new static readonly global::Godot.StringName property_UInt16 = "property_UInt16"; + /// <summary> + /// Cached name for the 'property_UInt32' property. + /// </summary> + public new static readonly global::Godot.StringName property_UInt32 = "property_UInt32"; + /// <summary> + /// Cached name for the 'property_UInt64' property. + /// </summary> + public new static readonly global::Godot.StringName property_UInt64 = "property_UInt64"; + /// <summary> + /// Cached name for the 'property_Single' property. + /// </summary> + public new static readonly global::Godot.StringName property_Single = "property_Single"; + /// <summary> + /// Cached name for the 'property_Double' property. + /// </summary> + public new static readonly global::Godot.StringName property_Double = "property_Double"; + /// <summary> + /// Cached name for the 'property_String' property. + /// </summary> + public new static readonly global::Godot.StringName property_String = "property_String"; + /// <summary> + /// Cached name for the 'property_Vector2' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector2 = "property_Vector2"; + /// <summary> + /// Cached name for the 'property_Vector2I' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector2I = "property_Vector2I"; + /// <summary> + /// Cached name for the 'property_Rect2' property. + /// </summary> + public new static readonly global::Godot.StringName property_Rect2 = "property_Rect2"; + /// <summary> + /// Cached name for the 'property_Rect2I' property. + /// </summary> + public new static readonly global::Godot.StringName property_Rect2I = "property_Rect2I"; + /// <summary> + /// Cached name for the 'property_Transform2D' property. + /// </summary> + public new static readonly global::Godot.StringName property_Transform2D = "property_Transform2D"; + /// <summary> + /// Cached name for the 'property_Vector3' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector3 = "property_Vector3"; + /// <summary> + /// Cached name for the 'property_Vector3I' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector3I = "property_Vector3I"; + /// <summary> + /// Cached name for the 'property_Basis' property. + /// </summary> + public new static readonly global::Godot.StringName property_Basis = "property_Basis"; + /// <summary> + /// Cached name for the 'property_Quaternion' property. + /// </summary> + public new static readonly global::Godot.StringName property_Quaternion = "property_Quaternion"; + /// <summary> + /// Cached name for the 'property_Transform3D' property. + /// </summary> + public new static readonly global::Godot.StringName property_Transform3D = "property_Transform3D"; + /// <summary> + /// Cached name for the 'property_Vector4' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector4 = "property_Vector4"; + /// <summary> + /// Cached name for the 'property_Vector4I' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector4I = "property_Vector4I"; + /// <summary> + /// Cached name for the 'property_Projection' property. + /// </summary> + public new static readonly global::Godot.StringName property_Projection = "property_Projection"; + /// <summary> + /// Cached name for the 'property_Aabb' property. + /// </summary> + public new static readonly global::Godot.StringName property_Aabb = "property_Aabb"; + /// <summary> + /// Cached name for the 'property_Color' property. + /// </summary> + public new static readonly global::Godot.StringName property_Color = "property_Color"; + /// <summary> + /// Cached name for the 'property_Plane' property. + /// </summary> + public new static readonly global::Godot.StringName property_Plane = "property_Plane"; + /// <summary> + /// Cached name for the 'property_Callable' property. + /// </summary> + public new static readonly global::Godot.StringName property_Callable = "property_Callable"; + /// <summary> + /// Cached name for the 'property_Signal' property. + /// </summary> + public new static readonly global::Godot.StringName property_Signal = "property_Signal"; + /// <summary> + /// Cached name for the 'property_Enum' property. + /// </summary> + public new static readonly global::Godot.StringName property_Enum = "property_Enum"; + /// <summary> + /// Cached name for the 'property_FlagsEnum' property. + /// </summary> + public new static readonly global::Godot.StringName property_FlagsEnum = "property_FlagsEnum"; + /// <summary> + /// Cached name for the 'property_ByteArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_ByteArray = "property_ByteArray"; + /// <summary> + /// Cached name for the 'property_Int32Array' property. + /// </summary> + public new static readonly global::Godot.StringName property_Int32Array = "property_Int32Array"; + /// <summary> + /// Cached name for the 'property_Int64Array' property. + /// </summary> + public new static readonly global::Godot.StringName property_Int64Array = "property_Int64Array"; + /// <summary> + /// Cached name for the 'property_SingleArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_SingleArray = "property_SingleArray"; + /// <summary> + /// Cached name for the 'property_DoubleArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_DoubleArray = "property_DoubleArray"; + /// <summary> + /// Cached name for the 'property_StringArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_StringArray = "property_StringArray"; + /// <summary> + /// Cached name for the 'property_StringArrayEnum' property. + /// </summary> + public new static readonly global::Godot.StringName property_StringArrayEnum = "property_StringArrayEnum"; + /// <summary> + /// Cached name for the 'property_Vector2Array' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector2Array = "property_Vector2Array"; + /// <summary> + /// Cached name for the 'property_Vector3Array' property. + /// </summary> + public new static readonly global::Godot.StringName property_Vector3Array = "property_Vector3Array"; + /// <summary> + /// Cached name for the 'property_ColorArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_ColorArray = "property_ColorArray"; + /// <summary> + /// Cached name for the 'property_GodotObjectOrDerivedArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotObjectOrDerivedArray = "property_GodotObjectOrDerivedArray"; + /// <summary> + /// Cached name for the 'field_StringNameArray' property. + /// </summary> + public new static readonly global::Godot.StringName field_StringNameArray = "field_StringNameArray"; + /// <summary> + /// Cached name for the 'field_NodePathArray' property. + /// </summary> + public new static readonly global::Godot.StringName field_NodePathArray = "field_NodePathArray"; + /// <summary> + /// Cached name for the 'field_RidArray' property. + /// </summary> + public new static readonly global::Godot.StringName field_RidArray = "field_RidArray"; + /// <summary> + /// Cached name for the 'property_Variant' property. + /// </summary> + public new static readonly global::Godot.StringName property_Variant = "property_Variant"; + /// <summary> + /// Cached name for the 'property_GodotObjectOrDerived' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotObjectOrDerived = "property_GodotObjectOrDerived"; + /// <summary> + /// Cached name for the 'property_GodotResourceTexture' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotResourceTexture = "property_GodotResourceTexture"; + /// <summary> + /// Cached name for the 'property_StringName' property. + /// </summary> + public new static readonly global::Godot.StringName property_StringName = "property_StringName"; + /// <summary> + /// Cached name for the 'property_NodePath' property. + /// </summary> + public new static readonly global::Godot.StringName property_NodePath = "property_NodePath"; + /// <summary> + /// Cached name for the 'property_Rid' property. + /// </summary> + public new static readonly global::Godot.StringName property_Rid = "property_Rid"; + /// <summary> + /// Cached name for the 'property_GodotDictionary' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotDictionary = "property_GodotDictionary"; + /// <summary> + /// Cached name for the 'property_GodotArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotArray = "property_GodotArray"; + /// <summary> + /// Cached name for the 'property_GodotGenericDictionary' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotGenericDictionary = "property_GodotGenericDictionary"; + /// <summary> + /// Cached name for the 'property_GodotGenericArray' property. + /// </summary> + public new static readonly global::Godot.StringName property_GodotGenericArray = "property_GodotGenericArray"; + /// <summary> + /// Cached name for the '_notGenerate_Property_String' field. + /// </summary> + public new static readonly global::Godot.StringName _notGenerate_Property_String = "_notGenerate_Property_String"; + /// <summary> + /// Cached name for the '_notGenerate_Property_Int' field. + /// </summary> + public new static readonly global::Godot.StringName _notGenerate_Property_Int = "_notGenerate_Property_Int"; + /// <summary> + /// Cached name for the '_fullProperty_String' field. + /// </summary> + public new static readonly global::Godot.StringName _fullProperty_String = "_fullProperty_String"; + /// <summary> + /// Cached name for the '_fullProperty_String_Complex' field. + /// </summary> + public new static readonly global::Godot.StringName _fullProperty_String_Complex = "_fullProperty_String_Complex"; + /// <summary> + /// Cached name for the '_lamdaProperty_String' field. + /// </summary> + public new static readonly global::Godot.StringName _lamdaProperty_String = "_lamdaProperty_String"; + } + /// <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.NotGenerate_Complex_Lamda_Property) { + this.NotGenerate_Complex_Lamda_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.NotGenerate_Lamda_NoField_Property) { + this.NotGenerate_Lamda_NoField_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.NotGenerate_Complex_Return_Property) { + this.NotGenerate_Complex_Return_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.NotGenerate_Returns_Property) { + this.NotGenerate_Returns_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.FullProperty_String) { + this.FullProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.FullProperty_String_Complex) { + this.FullProperty_String_Complex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.LamdaProperty_String) { + this.LamdaProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.property_Boolean) { + this.property_Boolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + return true; + } + else if (name == PropertyName.property_Char) { + this.property_Char = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); + return true; + } + else if (name == PropertyName.property_SByte) { + this.property_SByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); + return true; + } + else if (name == PropertyName.property_Int16) { + this.property_Int16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); + return true; + } + else if (name == PropertyName.property_Int32) { + this.property_Int32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); + return true; + } + else if (name == PropertyName.property_Int64) { + this.property_Int64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); + return true; + } + else if (name == PropertyName.property_Byte) { + this.property_Byte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); + return true; + } + else if (name == PropertyName.property_UInt16) { + this.property_UInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); + return true; + } + else if (name == PropertyName.property_UInt32) { + this.property_UInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); + return true; + } + else if (name == PropertyName.property_UInt64) { + this.property_UInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); + return true; + } + else if (name == PropertyName.property_Single) { + this.property_Single = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); + return true; + } + else if (name == PropertyName.property_Double) { + this.property_Double = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); + return true; + } + else if (name == PropertyName.property_String) { + this.property_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName.property_Vector2) { + this.property_Vector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); + return true; + } + else if (name == PropertyName.property_Vector2I) { + this.property_Vector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); + return true; + } + else if (name == PropertyName.property_Rect2) { + this.property_Rect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); + return true; + } + else if (name == PropertyName.property_Rect2I) { + this.property_Rect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); + return true; + } + else if (name == PropertyName.property_Transform2D) { + this.property_Transform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); + return true; + } + else if (name == PropertyName.property_Vector3) { + this.property_Vector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); + return true; + } + else if (name == PropertyName.property_Vector3I) { + this.property_Vector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); + return true; + } + else if (name == PropertyName.property_Basis) { + this.property_Basis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); + return true; + } + else if (name == PropertyName.property_Quaternion) { + this.property_Quaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); + return true; + } + else if (name == PropertyName.property_Transform3D) { + this.property_Transform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); + return true; + } + else if (name == PropertyName.property_Vector4) { + this.property_Vector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); + return true; + } + else if (name == PropertyName.property_Vector4I) { + this.property_Vector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); + return true; + } + else if (name == PropertyName.property_Projection) { + this.property_Projection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); + return true; + } + else if (name == PropertyName.property_Aabb) { + this.property_Aabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); + return true; + } + else if (name == PropertyName.property_Color) { + this.property_Color = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); + return true; + } + else if (name == PropertyName.property_Plane) { + this.property_Plane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); + return true; + } + else if (name == PropertyName.property_Callable) { + this.property_Callable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); + return true; + } + else if (name == PropertyName.property_Signal) { + this.property_Signal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); + return true; + } + else if (name == PropertyName.property_Enum) { + this.property_Enum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyEnum>(value); + return true; + } + else if (name == PropertyName.property_FlagsEnum) { + this.property_FlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyFlagsEnum>(value); + return true; + } + else if (name == PropertyName.property_ByteArray) { + this.property_ByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); + return true; + } + else if (name == PropertyName.property_Int32Array) { + this.property_Int32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + return true; + } + else if (name == PropertyName.property_Int64Array) { + this.property_Int64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); + return true; + } + else if (name == PropertyName.property_SingleArray) { + this.property_SingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); + return true; + } + else if (name == PropertyName.property_DoubleArray) { + this.property_DoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); + return true; + } + else if (name == PropertyName.property_StringArray) { + this.property_StringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + return true; + } + else if (name == PropertyName.property_StringArrayEnum) { + this.property_StringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + return true; + } + else if (name == PropertyName.property_Vector2Array) { + this.property_Vector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); + return true; + } + else if (name == PropertyName.property_Vector3Array) { + this.property_Vector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); + return true; + } + else if (name == PropertyName.property_ColorArray) { + this.property_ColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); + return true; + } + else if (name == PropertyName.property_GodotObjectOrDerivedArray) { + this.property_GodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); + return true; + } + else 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) { + this.field_NodePathArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath[]>(value); + return true; + } + else if (name == PropertyName.field_RidArray) { + this.field_RidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); + return true; + } + else if (name == PropertyName.property_Variant) { + this.property_Variant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); + return true; + } + else if (name == PropertyName.property_GodotObjectOrDerived) { + this.property_GodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); + return true; + } + else if (name == PropertyName.property_GodotResourceTexture) { + this.property_GodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); + return true; + } + else if (name == PropertyName.property_StringName) { + this.property_StringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); + return true; + } + else if (name == PropertyName.property_NodePath) { + this.property_NodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); + return true; + } + else if (name == PropertyName.property_Rid) { + this.property_Rid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); + return true; + } + else if (name == PropertyName.property_GodotDictionary) { + this.property_GodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); + return true; + } + else if (name == PropertyName.property_GodotArray) { + this.property_GodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); + return true; + } + else if (name == PropertyName.property_GodotGenericDictionary) { + this.property_GodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); + return true; + } + else if (name == PropertyName.property_GodotGenericArray) { + this.property_GodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); + return true; + } + else if (name == PropertyName._notGenerate_Property_String) { + this._notGenerate_Property_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName._notGenerate_Property_Int) { + this._notGenerate_Property_Int = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); + return true; + } + else if (name == PropertyName._fullProperty_String) { + this._fullProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName._fullProperty_String_Complex) { + this._fullProperty_String_Complex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + return true; + } + else if (name == PropertyName._lamdaProperty_String) { + this._lamdaProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(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.NotGenerate_Complex_Lamda_Property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Complex_Lamda_Property); + return true; + } + else if (name == PropertyName.NotGenerate_Lamda_NoField_Property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Lamda_NoField_Property); + return true; + } + else if (name == PropertyName.NotGenerate_Complex_Return_Property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Complex_Return_Property); + return true; + } + else if (name == PropertyName.NotGenerate_Returns_Property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Returns_Property); + return true; + } + else if (name == PropertyName.FullProperty_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullProperty_String); + return true; + } + else if (name == PropertyName.FullProperty_String_Complex) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullProperty_String_Complex); + return true; + } + else if (name == PropertyName.LamdaProperty_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.LamdaProperty_String); + return true; + } + else if (name == PropertyName.property_Boolean) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.property_Boolean); + return true; + } + else if (name == PropertyName.property_Char) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this.property_Char); + return true; + } + else if (name == PropertyName.property_SByte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this.property_SByte); + return true; + } + else if (name == PropertyName.property_Int16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this.property_Int16); + return true; + } + else if (name == PropertyName.property_Int32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this.property_Int32); + return true; + } + else if (name == PropertyName.property_Int64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this.property_Int64); + return true; + } + else if (name == PropertyName.property_Byte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this.property_Byte); + return true; + } + else if (name == PropertyName.property_UInt16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this.property_UInt16); + return true; + } + else if (name == PropertyName.property_UInt32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this.property_UInt32); + return true; + } + else if (name == PropertyName.property_UInt64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this.property_UInt64); + return true; + } + else if (name == PropertyName.property_Single) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this.property_Single); + return true; + } + else if (name == PropertyName.property_Double) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this.property_Double); + return true; + } + else if (name == PropertyName.property_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.property_String); + return true; + } + else if (name == PropertyName.property_Vector2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this.property_Vector2); + return true; + } + else if (name == PropertyName.property_Vector2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this.property_Vector2I); + return true; + } + else if (name == PropertyName.property_Rect2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this.property_Rect2); + return true; + } + else if (name == PropertyName.property_Rect2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this.property_Rect2I); + return true; + } + else if (name == PropertyName.property_Transform2D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this.property_Transform2D); + return true; + } + else if (name == PropertyName.property_Vector3) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this.property_Vector3); + return true; + } + else if (name == PropertyName.property_Vector3I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this.property_Vector3I); + return true; + } + else if (name == PropertyName.property_Basis) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this.property_Basis); + return true; + } + else if (name == PropertyName.property_Quaternion) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this.property_Quaternion); + return true; + } + else if (name == PropertyName.property_Transform3D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this.property_Transform3D); + return true; + } + else if (name == PropertyName.property_Vector4) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this.property_Vector4); + return true; + } + else if (name == PropertyName.property_Vector4I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this.property_Vector4I); + return true; + } + else if (name == PropertyName.property_Projection) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this.property_Projection); + return true; + } + else if (name == PropertyName.property_Aabb) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this.property_Aabb); + return true; + } + else if (name == PropertyName.property_Color) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this.property_Color); + return true; + } + else if (name == PropertyName.property_Plane) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this.property_Plane); + return true; + } + else if (name == PropertyName.property_Callable) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.property_Callable); + return true; + } + else if (name == PropertyName.property_Signal) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this.property_Signal); + return true; + } + else if (name == PropertyName.property_Enum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyEnum>(this.property_Enum); + return true; + } + else if (name == PropertyName.property_FlagsEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyFlagsEnum>(this.property_FlagsEnum); + return true; + } + else if (name == PropertyName.property_ByteArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this.property_ByteArray); + return true; + } + else if (name == PropertyName.property_Int32Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.property_Int32Array); + return true; + } + else if (name == PropertyName.property_Int64Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.property_Int64Array); + return true; + } + else if (name == PropertyName.property_SingleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this.property_SingleArray); + return true; + } + else if (name == PropertyName.property_DoubleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this.property_DoubleArray); + return true; + } + else if (name == PropertyName.property_StringArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.property_StringArray); + return true; + } + else if (name == PropertyName.property_StringArrayEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.property_StringArrayEnum); + return true; + } + else if (name == PropertyName.property_Vector2Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this.property_Vector2Array); + return true; + } + else if (name == PropertyName.property_Vector3Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this.property_Vector3Array); + return true; + } + else if (name == PropertyName.property_ColorArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this.property_ColorArray); + return true; + } + else if (name == PropertyName.property_GodotObjectOrDerivedArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this.property_GodotObjectOrDerivedArray); + return true; + } + else 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) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath[]>(this.field_NodePathArray); + return true; + } + else if (name == PropertyName.field_RidArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this.field_RidArray); + return true; + } + else if (name == PropertyName.property_Variant) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this.property_Variant); + return true; + } + else if (name == PropertyName.property_GodotObjectOrDerived) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this.property_GodotObjectOrDerived); + return true; + } + else if (name == PropertyName.property_GodotResourceTexture) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this.property_GodotResourceTexture); + return true; + } + else if (name == PropertyName.property_StringName) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this.property_StringName); + return true; + } + else if (name == PropertyName.property_NodePath) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this.property_NodePath); + return true; + } + else if (name == PropertyName.property_Rid) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this.property_Rid); + return true; + } + else if (name == PropertyName.property_GodotDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this.property_GodotDictionary); + return true; + } + else if (name == PropertyName.property_GodotArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this.property_GodotArray); + return true; + } + else if (name == PropertyName.property_GodotGenericDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this.property_GodotGenericDictionary); + return true; + } + else if (name == PropertyName.property_GodotGenericArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.property_GodotGenericArray); + return true; + } + else if (name == PropertyName._notGenerate_Property_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._notGenerate_Property_String); + return true; + } + else if (name == PropertyName._notGenerate_Property_Int) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._notGenerate_Property_Int); + return true; + } + else if (name == PropertyName._fullProperty_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullProperty_String); + return true; + } + else if (name == PropertyName._fullProperty_String_Complex) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullProperty_String_Complex); + return true; + } + else if (name == PropertyName._lamdaProperty_String) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._lamdaProperty_String); + 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)4, name: PropertyName._notGenerate_Property_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Complex_Lamda_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Lamda_NoField_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Complex_Return_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._notGenerate_Property_Int, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Returns_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fullProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.FullProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fullProperty_String_Complex, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.FullProperty_String_Complex, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._lamdaProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.LamdaProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.property_Boolean, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Char, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_SByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Int16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Int32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Int64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Byte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_UInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_UInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_UInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.property_Single, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.property_Double, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.property_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)5, name: PropertyName.property_Vector2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)6, name: PropertyName.property_Vector2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)7, name: PropertyName.property_Rect2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)8, name: PropertyName.property_Rect2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)11, name: PropertyName.property_Transform2D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)9, name: PropertyName.property_Vector3, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)10, name: PropertyName.property_Vector3I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)17, name: PropertyName.property_Basis, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)15, name: PropertyName.property_Quaternion, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)18, name: PropertyName.property_Transform3D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)12, name: PropertyName.property_Vector4, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)13, name: PropertyName.property_Vector4I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)19, name: PropertyName.property_Projection, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)16, name: PropertyName.property_Aabb, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)20, name: PropertyName.property_Color, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)14, name: PropertyName.property_Plane, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.property_Callable, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)26, name: PropertyName.property_Signal, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Enum, hint: (global::Godot.PropertyHint)2, hintString: "A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_FlagsEnum, hint: (global::Godot.PropertyHint)6, hintString: "A:0,B:1,C:2", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)29, name: PropertyName.property_ByteArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.property_Int32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.property_Int64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)32, name: PropertyName.property_SingleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)33, name: PropertyName.property_DoubleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.property_StringArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.property_StringArrayEnum, hint: (global::Godot.PropertyHint)23, hintString: "4/2:A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)35, name: PropertyName.property_Vector2Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)36, name: PropertyName.property_Vector3Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)37, name: PropertyName.property_ColorArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.property_GodotObjectOrDerivedArray, hint: (global::Godot.PropertyHint)23, hintString: "24/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_StringNameArray, hint: (global::Godot.PropertyHint)23, hintString: "21/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_NodePathArray, hint: (global::Godot.PropertyHint)23, hintString: "22/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_RidArray, hint: (global::Godot.PropertyHint)23, hintString: "23/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)0, name: PropertyName.property_Variant, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)135174, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.property_GodotObjectOrDerived, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.property_GodotResourceTexture, hint: (global::Godot.PropertyHint)17, hintString: "Texture", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)21, name: PropertyName.property_StringName, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)22, name: PropertyName.property_NodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.property_Rid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.property_GodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.property_GodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.property_GodotGenericDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.property_GodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", 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/ExportedProperties_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptPropertyDefVal.generated.cs new file mode 100644 index 0000000000..a4cd10d080 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,147 @@ +partial class ExportedProperties +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword +#if TOOLS + /// <summary> + /// Get the default values for all properties declared in this class. + /// This method is used by Godot to determine the value that will be + /// used by the inspector when resetting properties. + /// Do not call this method. + /// </summary> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues() + { + var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(64); + string __NotGenerate_Complex_Lamda_Property_default_value = default; + values.Add(PropertyName.NotGenerate_Complex_Lamda_Property, global::Godot.Variant.From<string>(__NotGenerate_Complex_Lamda_Property_default_value)); + string __NotGenerate_Lamda_NoField_Property_default_value = default; + values.Add(PropertyName.NotGenerate_Lamda_NoField_Property, global::Godot.Variant.From<string>(__NotGenerate_Lamda_NoField_Property_default_value)); + string __NotGenerate_Complex_Return_Property_default_value = default; + values.Add(PropertyName.NotGenerate_Complex_Return_Property, global::Godot.Variant.From<string>(__NotGenerate_Complex_Return_Property_default_value)); + string __NotGenerate_Returns_Property_default_value = default; + values.Add(PropertyName.NotGenerate_Returns_Property, global::Godot.Variant.From<string>(__NotGenerate_Returns_Property_default_value)); + string __FullProperty_String_default_value = "FullProperty_String"; + values.Add(PropertyName.FullProperty_String, global::Godot.Variant.From<string>(__FullProperty_String_default_value)); + string __FullProperty_String_Complex_default_value = new string("FullProperty_String_Complex") + global::System.Convert.ToInt32("1"); + values.Add(PropertyName.FullProperty_String_Complex, global::Godot.Variant.From<string>(__FullProperty_String_Complex_default_value)); + string __LamdaProperty_String_default_value = "LamdaProperty_String"; + values.Add(PropertyName.LamdaProperty_String, global::Godot.Variant.From<string>(__LamdaProperty_String_default_value)); + bool __property_Boolean_default_value = true; + values.Add(PropertyName.property_Boolean, global::Godot.Variant.From<bool>(__property_Boolean_default_value)); + char __property_Char_default_value = 'f'; + values.Add(PropertyName.property_Char, global::Godot.Variant.From<char>(__property_Char_default_value)); + sbyte __property_SByte_default_value = 10; + values.Add(PropertyName.property_SByte, global::Godot.Variant.From<sbyte>(__property_SByte_default_value)); + short __property_Int16_default_value = 10; + values.Add(PropertyName.property_Int16, global::Godot.Variant.From<short>(__property_Int16_default_value)); + int __property_Int32_default_value = 10; + values.Add(PropertyName.property_Int32, global::Godot.Variant.From<int>(__property_Int32_default_value)); + long __property_Int64_default_value = 10; + values.Add(PropertyName.property_Int64, global::Godot.Variant.From<long>(__property_Int64_default_value)); + byte __property_Byte_default_value = 10; + values.Add(PropertyName.property_Byte, global::Godot.Variant.From<byte>(__property_Byte_default_value)); + ushort __property_UInt16_default_value = 10; + values.Add(PropertyName.property_UInt16, global::Godot.Variant.From<ushort>(__property_UInt16_default_value)); + uint __property_UInt32_default_value = 10; + values.Add(PropertyName.property_UInt32, global::Godot.Variant.From<uint>(__property_UInt32_default_value)); + ulong __property_UInt64_default_value = 10; + values.Add(PropertyName.property_UInt64, global::Godot.Variant.From<ulong>(__property_UInt64_default_value)); + float __property_Single_default_value = 10; + values.Add(PropertyName.property_Single, global::Godot.Variant.From<float>(__property_Single_default_value)); + double __property_Double_default_value = 10; + values.Add(PropertyName.property_Double, global::Godot.Variant.From<double>(__property_Double_default_value)); + string __property_String_default_value = "foo"; + values.Add(PropertyName.property_String, global::Godot.Variant.From<string>(__property_String_default_value)); + global::Godot.Vector2 __property_Vector2_default_value = new(10f, 10f); + values.Add(PropertyName.property_Vector2, global::Godot.Variant.From<global::Godot.Vector2>(__property_Vector2_default_value)); + global::Godot.Vector2I __property_Vector2I_default_value = global::Godot.Vector2I.Up; + values.Add(PropertyName.property_Vector2I, global::Godot.Variant.From<global::Godot.Vector2I>(__property_Vector2I_default_value)); + global::Godot.Rect2 __property_Rect2_default_value = new(new global::Godot.Vector2(10f, 10f), new global::Godot.Vector2(10f, 10f)); + values.Add(PropertyName.property_Rect2, global::Godot.Variant.From<global::Godot.Rect2>(__property_Rect2_default_value)); + global::Godot.Rect2I __property_Rect2I_default_value = new(new global::Godot.Vector2I(10, 10), new global::Godot.Vector2I(10, 10)); + values.Add(PropertyName.property_Rect2I, global::Godot.Variant.From<global::Godot.Rect2I>(__property_Rect2I_default_value)); + global::Godot.Transform2D __property_Transform2D_default_value = global::Godot.Transform2D.Identity; + values.Add(PropertyName.property_Transform2D, global::Godot.Variant.From<global::Godot.Transform2D>(__property_Transform2D_default_value)); + global::Godot.Vector3 __property_Vector3_default_value = new(10f, 10f, 10f); + values.Add(PropertyName.property_Vector3, global::Godot.Variant.From<global::Godot.Vector3>(__property_Vector3_default_value)); + global::Godot.Vector3I __property_Vector3I_default_value = global::Godot.Vector3I.Back; + values.Add(PropertyName.property_Vector3I, global::Godot.Variant.From<global::Godot.Vector3I>(__property_Vector3I_default_value)); + global::Godot.Basis __property_Basis_default_value = new global::Godot.Basis(global::Godot.Quaternion.Identity); + values.Add(PropertyName.property_Basis, global::Godot.Variant.From<global::Godot.Basis>(__property_Basis_default_value)); + global::Godot.Quaternion __property_Quaternion_default_value = new global::Godot.Quaternion(global::Godot.Basis.Identity); + values.Add(PropertyName.property_Quaternion, global::Godot.Variant.From<global::Godot.Quaternion>(__property_Quaternion_default_value)); + global::Godot.Transform3D __property_Transform3D_default_value = global::Godot.Transform3D.Identity; + values.Add(PropertyName.property_Transform3D, global::Godot.Variant.From<global::Godot.Transform3D>(__property_Transform3D_default_value)); + global::Godot.Vector4 __property_Vector4_default_value = new(10f, 10f, 10f, 10f); + values.Add(PropertyName.property_Vector4, global::Godot.Variant.From<global::Godot.Vector4>(__property_Vector4_default_value)); + global::Godot.Vector4I __property_Vector4I_default_value = global::Godot.Vector4I.One; + values.Add(PropertyName.property_Vector4I, global::Godot.Variant.From<global::Godot.Vector4I>(__property_Vector4I_default_value)); + global::Godot.Projection __property_Projection_default_value = global::Godot.Projection.Identity; + values.Add(PropertyName.property_Projection, global::Godot.Variant.From<global::Godot.Projection>(__property_Projection_default_value)); + global::Godot.Aabb __property_Aabb_default_value = new global::Godot.Aabb(10f, 10f, 10f, new global::Godot.Vector3(1f, 1f, 1f)); + values.Add(PropertyName.property_Aabb, global::Godot.Variant.From<global::Godot.Aabb>(__property_Aabb_default_value)); + global::Godot.Color __property_Color_default_value = global::Godot.Colors.Aquamarine; + values.Add(PropertyName.property_Color, global::Godot.Variant.From<global::Godot.Color>(__property_Color_default_value)); + global::Godot.Plane __property_Plane_default_value = global::Godot.Plane.PlaneXZ; + values.Add(PropertyName.property_Plane, global::Godot.Variant.From<global::Godot.Plane>(__property_Plane_default_value)); + global::Godot.Callable __property_Callable_default_value = new global::Godot.Callable(global::Godot.Engine.GetMainLoop(), "_process"); + values.Add(PropertyName.property_Callable, global::Godot.Variant.From<global::Godot.Callable>(__property_Callable_default_value)); + global::Godot.Signal __property_Signal_default_value = new global::Godot.Signal(global::Godot.Engine.GetMainLoop(), "property_list_changed"); + values.Add(PropertyName.property_Signal, global::Godot.Variant.From<global::Godot.Signal>(__property_Signal_default_value)); + global::ExportedProperties.MyEnum __property_Enum_default_value = global::ExportedProperties.MyEnum.C; + values.Add(PropertyName.property_Enum, global::Godot.Variant.From<global::ExportedProperties.MyEnum>(__property_Enum_default_value)); + global::ExportedProperties.MyFlagsEnum __property_FlagsEnum_default_value = global::ExportedProperties.MyFlagsEnum.C; + values.Add(PropertyName.property_FlagsEnum, global::Godot.Variant.From<global::ExportedProperties.MyFlagsEnum>(__property_FlagsEnum_default_value)); + byte[] __property_ByteArray_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.property_ByteArray, global::Godot.Variant.From<byte[]>(__property_ByteArray_default_value)); + int[] __property_Int32Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.property_Int32Array, global::Godot.Variant.From<int[]>(__property_Int32Array_default_value)); + long[] __property_Int64Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.property_Int64Array, global::Godot.Variant.From<long[]>(__property_Int64Array_default_value)); + float[] __property_SingleArray_default_value = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + values.Add(PropertyName.property_SingleArray, global::Godot.Variant.From<float[]>(__property_SingleArray_default_value)); + double[] __property_DoubleArray_default_value = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + values.Add(PropertyName.property_DoubleArray, global::Godot.Variant.From<double[]>(__property_DoubleArray_default_value)); + string[] __property_StringArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.property_StringArray, global::Godot.Variant.From<string[]>(__property_StringArray_default_value)); + string[] __property_StringArrayEnum_default_value = { "foo", "bar" }; + values.Add(PropertyName.property_StringArrayEnum, global::Godot.Variant.From<string[]>(__property_StringArrayEnum_default_value)); + global::Godot.Vector2[] __property_Vector2Array_default_value = { global::Godot.Vector2.Up, global::Godot.Vector2.Down, global::Godot.Vector2.Left, global::Godot.Vector2.Right }; + values.Add(PropertyName.property_Vector2Array, global::Godot.Variant.From<global::Godot.Vector2[]>(__property_Vector2Array_default_value)); + global::Godot.Vector3[] __property_Vector3Array_default_value = { global::Godot.Vector3.Up, global::Godot.Vector3.Down, global::Godot.Vector3.Left, global::Godot.Vector3.Right }; + values.Add(PropertyName.property_Vector3Array, global::Godot.Variant.From<global::Godot.Vector3[]>(__property_Vector3Array_default_value)); + global::Godot.Color[] __property_ColorArray_default_value = { global::Godot.Colors.Aqua, global::Godot.Colors.Aquamarine, global::Godot.Colors.Azure, global::Godot.Colors.Beige }; + values.Add(PropertyName.property_ColorArray, global::Godot.Variant.From<global::Godot.Color[]>(__property_ColorArray_default_value)); + global::Godot.GodotObject[] __property_GodotObjectOrDerivedArray_default_value = { null }; + values.Add(PropertyName.property_GodotObjectOrDerivedArray, global::Godot.Variant.CreateFrom(__property_GodotObjectOrDerivedArray_default_value)); + global::Godot.StringName[] __field_StringNameArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.field_StringNameArray, global::Godot.Variant.From<global::Godot.StringName[]>(__field_StringNameArray_default_value)); + global::Godot.NodePath[] __field_NodePathArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.field_NodePathArray, global::Godot.Variant.From<global::Godot.NodePath[]>(__field_NodePathArray_default_value)); + global::Godot.Rid[] __field_RidArray_default_value = { default, default, default }; + values.Add(PropertyName.field_RidArray, global::Godot.Variant.From<global::Godot.Rid[]>(__field_RidArray_default_value)); + global::Godot.Variant __property_Variant_default_value = "foo"; + values.Add(PropertyName.property_Variant, global::Godot.Variant.From<global::Godot.Variant>(__property_Variant_default_value)); + global::Godot.GodotObject __property_GodotObjectOrDerived_default_value = default; + values.Add(PropertyName.property_GodotObjectOrDerived, global::Godot.Variant.From<global::Godot.GodotObject>(__property_GodotObjectOrDerived_default_value)); + global::Godot.Texture __property_GodotResourceTexture_default_value = default; + values.Add(PropertyName.property_GodotResourceTexture, global::Godot.Variant.From<global::Godot.Texture>(__property_GodotResourceTexture_default_value)); + global::Godot.StringName __property_StringName_default_value = new global::Godot.StringName("foo"); + values.Add(PropertyName.property_StringName, global::Godot.Variant.From<global::Godot.StringName>(__property_StringName_default_value)); + global::Godot.NodePath __property_NodePath_default_value = new global::Godot.NodePath("foo"); + values.Add(PropertyName.property_NodePath, global::Godot.Variant.From<global::Godot.NodePath>(__property_NodePath_default_value)); + global::Godot.Rid __property_Rid_default_value = default; + values.Add(PropertyName.property_Rid, global::Godot.Variant.From<global::Godot.Rid>(__property_Rid_default_value)); + global::Godot.Collections.Dictionary __property_GodotDictionary_default_value = new() { { "foo", 10 }, { global::Godot.Vector2.Up, global::Godot.Colors.Chocolate } }; + values.Add(PropertyName.property_GodotDictionary, global::Godot.Variant.From<global::Godot.Collections.Dictionary>(__property_GodotDictionary_default_value)); + global::Godot.Collections.Array __property_GodotArray_default_value = new() { "foo", 10, global::Godot.Vector2.Up, global::Godot.Colors.Chocolate }; + values.Add(PropertyName.property_GodotArray, global::Godot.Variant.From<global::Godot.Collections.Array>(__property_GodotArray_default_value)); + global::Godot.Collections.Dictionary<string, bool> __property_GodotGenericDictionary_default_value = new() { { "foo", true }, { "bar", false } }; + values.Add(PropertyName.property_GodotGenericDictionary, global::Godot.Variant.CreateFrom(__property_GodotGenericDictionary_default_value)); + global::Godot.Collections.Array<int> __property_GodotGenericArray_default_value = new() { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.property_GodotGenericArray, global::Godot.Variant.CreateFrom(__property_GodotGenericArray_default_value)); + return values; + } +#endif // TOOLS +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Foo_ScriptPath.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Foo_ScriptPath.generated.cs new file mode 100644 index 0000000000..9092ad9938 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Foo_ScriptPath.generated.cs @@ -0,0 +1,5 @@ +using Godot; +[ScriptPathAttribute("res://Foo.cs")] +partial class Foo +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic_ScriptPath.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic_ScriptPath.generated.cs new file mode 100644 index 0000000000..72c48595a2 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic_ScriptPath.generated.cs @@ -0,0 +1,5 @@ +using Godot; +[ScriptPathAttribute("res://Generic.cs")] +partial class Generic +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Methods_ScriptMethods.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Methods_ScriptMethods.generated.cs new file mode 100644 index 0000000000..f757497618 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Methods_ScriptMethods.generated.cs @@ -0,0 +1,61 @@ +using Godot; +using Godot.NativeInterop; + +partial class Methods +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword + /// <summary> + /// Cached StringNames for the methods contained in this class, for fast lookup. + /// </summary> + public new class MethodName : global::Godot.GodotObject.MethodName { + /// <summary> + /// Cached name for the 'MethodWithOverload' method. + /// </summary> + public new static readonly global::Godot.StringName MethodWithOverload = "MethodWithOverload"; + } + /// <summary> + /// Get the method information for all the methods declared in this class. + /// This method is used by Godot to register the available methods 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.MethodInfo> GetGodotMethodList() + { + var methods = new global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>(3); + methods.Add(new(name: MethodName.MethodWithOverload, returnVal: new(type: (global::Godot.Variant.Type)0, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), flags: (global::Godot.MethodFlags)1, arguments: null, defaultArguments: null)); + methods.Add(new(name: MethodName.MethodWithOverload, returnVal: new(type: (global::Godot.Variant.Type)0, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), flags: (global::Godot.MethodFlags)1, arguments: new() { new(type: (global::Godot.Variant.Type)2, name: "a", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), }, defaultArguments: null)); + methods.Add(new(name: MethodName.MethodWithOverload, returnVal: new(type: (global::Godot.Variant.Type)0, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), flags: (global::Godot.MethodFlags)1, arguments: new() { new(type: (global::Godot.Variant.Type)2, name: "a", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), new(type: (global::Godot.Variant.Type)2, name: "b", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), }, defaultArguments: null)); + return methods; + } +#pragma warning restore CS0109 + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret) + { + if (method == MethodName.MethodWithOverload && args.Count == 0) { + MethodWithOverload(); + ret = default; + return true; + } + if (method == MethodName.MethodWithOverload && args.Count == 1) { + MethodWithOverload(global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[0])); + ret = default; + return true; + } + if (method == MethodName.MethodWithOverload && args.Count == 2) { + MethodWithOverload(global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[0]), global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[1])); + ret = default; + return true; + } + return base.InvokeGodotClassMethod(method, args, out ret); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool HasGodotClassMethod(in godot_string_name method) + { + if (method == MethodName.MethodWithOverload) { + return true; + } + return base.HasGodotClassMethod(method); + } +} 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 new file mode 100644 index 0000000000..f812457aa5 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs @@ -0,0 +1,94 @@ +using Godot; +using Godot.NativeInterop; + +partial class MixedReadOnlyWriteOnly +{ +#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.GodotObject.PropertyName { + /// <summary> + /// Cached name for the 'readonly_auto_property' property. + /// </summary> + public new static readonly global::Godot.StringName readonly_auto_property = "readonly_auto_property"; + /// <summary> + /// Cached name for the 'readonly_property' property. + /// </summary> + public new static readonly global::Godot.StringName readonly_property = "readonly_property"; + /// <summary> + /// Cached name for the 'initonly_auto_property' property. + /// </summary> + public new static readonly global::Godot.StringName initonly_auto_property = "initonly_auto_property"; + /// <summary> + /// Cached name for the 'writeonly_property' property. + /// </summary> + public new static readonly global::Godot.StringName writeonly_property = "writeonly_property"; + /// <summary> + /// Cached name for the 'readonly_field' field. + /// </summary> + public new static readonly global::Godot.StringName readonly_field = "readonly_field"; + /// <summary> + /// Cached name for the 'writeonly_backing_field' field. + /// </summary> + public new static readonly global::Godot.StringName writeonly_backing_field = "writeonly_backing_field"; + } + /// <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.writeonly_property) { + this.writeonly_property = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + return true; + } + else if (name == PropertyName.writeonly_backing_field) { + this.writeonly_backing_field = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(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.readonly_auto_property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_auto_property); + return true; + } + else if (name == PropertyName.readonly_property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_property); + return true; + } + else if (name == PropertyName.initonly_auto_property) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.initonly_auto_property); + return true; + } + else if (name == PropertyName.readonly_field) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_field); + return true; + } + else if (name == PropertyName.writeonly_backing_field) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.writeonly_backing_field); + 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)4, name: PropertyName.readonly_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.initonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_backing_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + return properties; + } +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptMethods.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptMethods.generated.cs new file mode 100644 index 0000000000..328107a237 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptMethods.generated.cs @@ -0,0 +1,52 @@ +using Godot; +using Godot.NativeInterop; + +partial struct OuterClass +{ +partial class NestedClass +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword + /// <summary> + /// Cached StringNames for the methods contained in this class, for fast lookup. + /// </summary> + public new class MethodName : global::Godot.RefCounted.MethodName { + /// <summary> + /// Cached name for the '_Get' method. + /// </summary> + public new static readonly global::Godot.StringName _Get = "_Get"; + } + /// <summary> + /// Get the method information for all the methods declared in this class. + /// This method is used by Godot to register the available methods 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.MethodInfo> GetGodotMethodList() + { + var methods = new global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>(1); + methods.Add(new(name: MethodName._Get, returnVal: new(type: (global::Godot.Variant.Type)0, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)131078, exported: false), flags: (global::Godot.MethodFlags)1, arguments: new() { new(type: (global::Godot.Variant.Type)21, name: "property", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), }, defaultArguments: null)); + return methods; + } +#pragma warning restore CS0109 + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret) + { + if (method == MethodName._Get && args.Count == 1) { + var callRet = _Get(global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(args[0])); + ret = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(callRet); + return true; + } + return base.InvokeGodotClassMethod(method, args, out ret); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool HasGodotClassMethod(in godot_string_name method) + { + if (method == MethodName._Get) { + return true; + } + return base.HasGodotClassMethod(method); + } +} +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptProperties.generated.cs new file mode 100644 index 0000000000..79f014a41e --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptProperties.generated.cs @@ -0,0 +1,15 @@ +using Godot; +using Godot.NativeInterop; + +partial struct OuterClass +{ +partial class NestedClass +{ +#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.RefCounted.PropertyName { + } +} +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptSerialization.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptSerialization.generated.cs new file mode 100644 index 0000000000..4ecce50178 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/OuterClass.NestedClass_ScriptSerialization.generated.cs @@ -0,0 +1,21 @@ +using Godot; +using Godot.NativeInterop; + +partial struct OuterClass +{ +partial class NestedClass +{ + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void SaveGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info) + { + base.SaveGodotObjectData(info); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void RestoreGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info) + { + base.RestoreGodotObjectData(info); + } +} +} 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 new file mode 100644 index 0000000000..8656f4617e --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptMethods.generated.cs @@ -0,0 +1,62 @@ +using Godot; +using Godot.NativeInterop; + +partial class ScriptBoilerplate +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword + /// <summary> + /// Cached StringNames for the methods contained in this class, for fast lookup. + /// </summary> + public new class MethodName : global::Godot.Node.MethodName { + /// <summary> + /// Cached name for the '_Process' method. + /// </summary> + public new static readonly global::Godot.StringName _Process = "_Process"; + /// <summary> + /// Cached name for the 'Bazz' method. + /// </summary> + public new static readonly global::Godot.StringName Bazz = "Bazz"; + } + /// <summary> + /// Get the method information for all the methods declared in this class. + /// This method is used by Godot to register the available methods 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.MethodInfo> GetGodotMethodList() + { + var methods = new global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>(2); + methods.Add(new(name: MethodName._Process, returnVal: new(type: (global::Godot.Variant.Type)0, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), flags: (global::Godot.MethodFlags)1, arguments: new() { new(type: (global::Godot.Variant.Type)3, name: "delta", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), }, defaultArguments: null)); + methods.Add(new(name: MethodName.Bazz, returnVal: new(type: (global::Godot.Variant.Type)2, name: "", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), flags: (global::Godot.MethodFlags)1, arguments: new() { new(type: (global::Godot.Variant.Type)21, name: "name", hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)6, exported: false), }, defaultArguments: null)); + return methods; + } +#pragma warning restore CS0109 + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret) + { + if (method == MethodName._Process && args.Count == 1) { + _Process(global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(args[0])); + ret = default; + return true; + } + if (method == MethodName.Bazz && args.Count == 1) { + var callRet = Bazz(global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(args[0])); + ret = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(callRet); + return true; + } + return base.InvokeGodotClassMethod(method, args, out ret); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override bool HasGodotClassMethod(in godot_string_name method) + { + if (method == MethodName._Process) { + return true; + } + else 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_ScriptPath.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptPath.generated.cs new file mode 100644 index 0000000000..ffcd29f7cd --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptPath.generated.cs @@ -0,0 +1,5 @@ +using Godot; +[ScriptPathAttribute("res://ScriptBoilerplate.cs")] +partial class ScriptBoilerplate +{ +} 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 new file mode 100644 index 0000000000..09368b7ab6 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptProperties.generated.cs @@ -0,0 +1,62 @@ +using Godot; +using Godot.NativeInterop; + +partial class ScriptBoilerplate +{ +#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 '_nodePath' field. + /// </summary> + public new static readonly global::Godot.StringName _nodePath = "_nodePath"; + /// <summary> + /// Cached name for the '_velocity' field. + /// </summary> + public new static readonly global::Godot.StringName _velocity = "_velocity"; + } + /// <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._nodePath) { + this._nodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); + return true; + } + else if (name == PropertyName._velocity) { + this._velocity = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(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._nodePath) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this._nodePath); + return true; + } + else if (name == PropertyName._velocity) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._velocity); + 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)22, name: PropertyName._nodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._velocity, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + return properties; + } +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptSerialization.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptSerialization.generated.cs new file mode 100644 index 0000000000..28bc863b0a --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ScriptBoilerplate_ScriptSerialization.generated.cs @@ -0,0 +1,24 @@ +using Godot; +using Godot.NativeInterop; + +partial class ScriptBoilerplate +{ + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void SaveGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info) + { + base.SaveGodotObjectData(info); + info.AddProperty(PropertyName._nodePath, global::Godot.Variant.From<global::Godot.NodePath>(this._nodePath)); + info.AddProperty(PropertyName._velocity, global::Godot.Variant.From<int>(this._velocity)); + } + /// <inheritdoc/> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void RestoreGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info) + { + base.RestoreGodotObjectData(info); + if (info.TryGetProperty(PropertyName._nodePath, out var _value__nodePath)) + this._nodePath = _value__nodePath.As<global::Godot.NodePath>(); + if (info.TryGetProperty(PropertyName._velocity, out var _value__velocity)) + this._velocity = _value__velocity.As<int>(); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs new file mode 100644 index 0000000000..94c2bda363 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs @@ -0,0 +1,9 @@ +using Godot; + +public partial class AllReadOnly : GodotObject +{ + public readonly string readonly_field = "foo"; + public string readonly_auto_property { get; } = "foo"; + public string readonly_property { get => "foo"; } + public string initonly_auto_property { get; init; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs new file mode 100644 index 0000000000..156d6bb6a5 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs @@ -0,0 +1,7 @@ +using Godot; + +public partial class AllWriteOnly : GodotObject +{ + bool writeonly_backing_field = false; + public bool writeonly_property { set => writeonly_backing_field = value; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs new file mode 100644 index 0000000000..dfe2217c26 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs @@ -0,0 +1,14 @@ +using Godot; + +partial class Bar : GodotObject +{ +} + +// Foo in another file +partial class Foo +{ +} + +partial class NotSameNameAsFile : GodotObject +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/EventSignals.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/EventSignals.cs new file mode 100644 index 0000000000..160c5d193d --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/EventSignals.cs @@ -0,0 +1,7 @@ +using Godot; + +public partial class EventSignals : GodotObject +{ + [Signal] + public delegate void MySignalEventHandler(string str, int num); +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs new file mode 100644 index 0000000000..09d654ffcb --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs @@ -0,0 +1,102 @@ +using Godot; +using System; +using System.Collections.Generic; + +public partial class ExportedFields : GodotObject +{ + [Export] private Boolean field_Boolean = true; + [Export] private Char field_Char = 'f'; + [Export] private SByte field_SByte = 10; + [Export] private Int16 field_Int16 = 10; + [Export] private Int32 field_Int32 = 10; + [Export] private Int64 field_Int64 = 10; + [Export] private Byte field_Byte = 10; + [Export] private UInt16 field_UInt16 = 10; + [Export] private UInt32 field_UInt32 = 10; + [Export] private UInt64 field_UInt64 = 10; + [Export] private Single field_Single = 10; + [Export] private Double field_Double = 10; + [Export] private String field_String = "foo"; + + // Godot structs + [Export] private Vector2 field_Vector2 = new(10f, 10f); + [Export] private Vector2I field_Vector2I = Vector2I.Up; + [Export] private Rect2 field_Rect2 = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); + [Export] private Rect2I field_Rect2I = new(new Vector2I(10, 10), new Vector2I(10, 10)); + [Export] private Transform2D field_Transform2D = Transform2D.Identity; + [Export] private Vector3 field_Vector3 = new(10f, 10f, 10f); + [Export] private Vector3I field_Vector3I = Vector3I.Back; + [Export] private Basis field_Basis = new Basis(Quaternion.Identity); + [Export] private Quaternion field_Quaternion = new Quaternion(Basis.Identity); + [Export] private Transform3D field_Transform3D = Transform3D.Identity; + [Export] private Vector4 field_Vector4 = new(10f, 10f, 10f, 10f); + [Export] private Vector4I field_Vector4I = Vector4I.One; + [Export] private Projection field_Projection = Projection.Identity; + [Export] private Aabb field_Aabb = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); + [Export] private Color field_Color = Colors.Aquamarine; + [Export] private Plane field_Plane = Plane.PlaneXZ; + [Export] private Callable field_Callable = new Callable(Engine.GetMainLoop(), "_process"); + [Export] private Signal field_Signal = new Signal(Engine.GetMainLoop(), "property_list_changed"); + + // Enums + enum MyEnum + { + A, + B, + C + } + + [Export] private MyEnum field_Enum = MyEnum.C; + + [Flags] + enum MyFlagsEnum + { + A, + B, + C + } + + [Export] private MyFlagsEnum field_FlagsEnum = MyFlagsEnum.C; + + // Arrays + [Export] private Byte[] field_ByteArray = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int32[] field_Int32Array = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int64[] field_Int64Array = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Single[] field_SingleArray = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + [Export] private Double[] field_DoubleArray = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + [Export] private String[] field_StringArray = { "foo", "bar" }; + [Export(PropertyHint.Enum, "A,B,C")] private String[] field_StringArrayEnum = { "foo", "bar" }; + [Export] private Vector2[] field_Vector2Array = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; + [Export] private Vector3[] field_Vector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; + [Export] private Color[] field_ColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; + [Export] private GodotObject[] field_GodotObjectOrDerivedArray = { null }; + [Export] private StringName[] field_StringNameArray = { "foo", "bar" }; + [Export] private NodePath[] field_NodePathArray = { "foo", "bar" }; + [Export] private Rid[] field_RidArray = { default, default, default }; + // Note we use Array and not System.Array. This tests the generated namespace qualification. + [Export] private Int32[] field_empty_Int32Array = Array.Empty<Int32>(); + // Note we use List and not System.Collections.Generic. + [Export] private int[] field_array_from_list = new List<int>(Array.Empty<int>()).ToArray(); + + // Variant + [Export] private Variant field_Variant = "foo"; + + // Classes + [Export] private GodotObject field_GodotObjectOrDerived; + [Export] private Godot.Texture field_GodotResourceTexture; + [Export] private StringName field_StringName = new StringName("foo"); + [Export] private NodePath field_NodePath = new NodePath("foo"); + [Export] private Rid field_Rid; + + [Export] + private Godot.Collections.Dictionary field_GodotDictionary = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; + + [Export] + private Godot.Collections.Array field_GodotArray = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; + + [Export] + private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary = new() { { "foo", true }, { "bar", false } }; + + [Export] + private Godot.Collections.Array<int> field_GodotGenericArray = new() { 0, 1, 2, 3, 4, 5, 6 }; +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs new file mode 100644 index 0000000000..3783838dae --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs @@ -0,0 +1,186 @@ +using Godot; +using System; + +public partial class ExportedProperties : GodotObject +{ + // Do not generate default value + private String _notGenerate_Property_String = new string("not generate"); + [Export] + public String NotGenerate_Complex_Lamda_Property + { + get => _notGenerate_Property_String + Convert.ToInt32("1"); + set => _notGenerate_Property_String = value; + } + + [Export] + public String NotGenerate_Lamda_NoField_Property + { + get => new string("not generate"); + set => _notGenerate_Property_String = value; + } + + [Export] + public String NotGenerate_Complex_Return_Property + { + get + { + return _notGenerate_Property_String + Convert.ToInt32("1"); + } + set + { + _notGenerate_Property_String = value; + } + } + + private int _notGenerate_Property_Int = 1; + [Export] + public string NotGenerate_Returns_Property + { + get + { + if (_notGenerate_Property_Int == 1) + { + return "a"; + } + else + { + return "b"; + } + } + set + { + _notGenerate_Property_Int = value == "a" ? 1 : 2; + } + } + + // Full Property + private String _fullProperty_String = "FullProperty_String"; + [Export] + public String FullProperty_String + { + get + { + return _fullProperty_String; + } + set + { + _fullProperty_String = value; + } + } + + private String _fullProperty_String_Complex = new string("FullProperty_String_Complex") + Convert.ToInt32("1"); + [Export] + public String FullProperty_String_Complex + { + get + { + return _fullProperty_String_Complex; + } + set + { + _fullProperty_String_Complex = value; + } + } + + // Lambda Property + private String _lamdaProperty_String = "LamdaProperty_String"; + [Export] + public String LamdaProperty_String + { + get => _lamdaProperty_String; + set => _lamdaProperty_String = value; + } + + // Auto Property + [Export] private Boolean property_Boolean { get; set; } = true; + [Export] private Char property_Char { get; set; } = 'f'; + [Export] private SByte property_SByte { get; set; } = 10; + [Export] private Int16 property_Int16 { get; set; } = 10; + [Export] private Int32 property_Int32 { get; set; } = 10; + [Export] private Int64 property_Int64 { get; set; } = 10; + [Export] private Byte property_Byte { get; set; } = 10; + [Export] private UInt16 property_UInt16 { get; set; } = 10; + [Export] private UInt32 property_UInt32 { get; set; } = 10; + [Export] private UInt64 property_UInt64 { get; set; } = 10; + [Export] private Single property_Single { get; set; } = 10; + [Export] private Double property_Double { get; set; } = 10; + [Export] private String property_String { get; set; } = "foo"; + + // Godot structs + [Export] private Vector2 property_Vector2 { get; set; } = new(10f, 10f); + [Export] private Vector2I property_Vector2I { get; set; } = Vector2I.Up; + [Export] private Rect2 property_Rect2 { get; set; } = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); + [Export] private Rect2I property_Rect2I { get; set; } = new(new Vector2I(10, 10), new Vector2I(10, 10)); + [Export] private Transform2D property_Transform2D { get; set; } = Transform2D.Identity; + [Export] private Vector3 property_Vector3 { get; set; } = new(10f, 10f, 10f); + [Export] private Vector3I property_Vector3I { get; set; } = Vector3I.Back; + [Export] private Basis property_Basis { get; set; } = new Basis(Quaternion.Identity); + [Export] private Quaternion property_Quaternion { get; set; } = new Quaternion(Basis.Identity); + [Export] private Transform3D property_Transform3D { get; set; } = Transform3D.Identity; + [Export] private Vector4 property_Vector4 { get; set; } = new(10f, 10f, 10f, 10f); + [Export] private Vector4I property_Vector4I { get; set; } = Vector4I.One; + [Export] private Projection property_Projection { get; set; } = Projection.Identity; + [Export] private Aabb property_Aabb { get; set; } = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); + [Export] private Color property_Color { get; set; } = Colors.Aquamarine; + [Export] private Plane property_Plane { get; set; } = Plane.PlaneXZ; + [Export] private Callable property_Callable { get; set; } = new Callable(Engine.GetMainLoop(), "_process"); + [Export] private Signal property_Signal { get; set; } = new Signal(Engine.GetMainLoop(), "property_list_changed"); + + // Enums + enum MyEnum + { + A, + B, + C + } + + [Export] private MyEnum property_Enum { get; set; } = MyEnum.C; + + [Flags] + enum MyFlagsEnum + { + A, + B, + C + } + + [Export] private MyFlagsEnum property_FlagsEnum { get; set; } = MyFlagsEnum.C; + + // Arrays + [Export] private Byte[] property_ByteArray { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int32[] property_Int32Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int64[] property_Int64Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Single[] property_SingleArray { get; set; } = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + [Export] private Double[] property_DoubleArray { get; set; } = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + [Export] private String[] property_StringArray { get; set; } = { "foo", "bar" }; + [Export(PropertyHint.Enum, "A,B,C")] private String[] property_StringArrayEnum { get; set; } = { "foo", "bar" }; + [Export] private Vector2[] property_Vector2Array { get; set; } = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; + [Export] private Vector3[] property_Vector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; + [Export] private Color[] property_ColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; + [Export] private GodotObject[] property_GodotObjectOrDerivedArray { get; set; } = { null }; + [Export] private StringName[] field_StringNameArray { get; set; } = { "foo", "bar" }; + [Export] private NodePath[] field_NodePathArray { get; set; } = { "foo", "bar" }; + [Export] private Rid[] field_RidArray { get; set; } = { default, default, default }; + + // Variant + [Export] private Variant property_Variant { get; set; } = "foo"; + + // Classes + [Export] private GodotObject property_GodotObjectOrDerived { get; set; } + [Export] private Godot.Texture property_GodotResourceTexture { get; set; } + [Export] private StringName property_StringName { get; set; } = new StringName("foo"); + [Export] private NodePath property_NodePath { get; set; } = new NodePath("foo"); + [Export] private Rid property_Rid { get; set; } + + [Export] + private Godot.Collections.Dictionary property_GodotDictionary { get; set; } = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; + + [Export] + private Godot.Collections.Array property_GodotArray { get; set; } = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; + + [Export] + private Godot.Collections.Dictionary<string, bool> property_GodotGenericDictionary { get; set; } = new() { { "foo", true }, { "bar", false } }; + + [Export] + private Godot.Collections.Array<int> property_GodotGenericArray { get; set; } = new() { 0, 1, 2, 3, 4, 5, 6 }; +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs new file mode 100644 index 0000000000..26853553c7 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs @@ -0,0 +1,10 @@ +using Godot; + +partial class Foo : GodotObject +{ +} + +// Foo again in the same file +partial class Foo +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs new file mode 100644 index 0000000000..84d1ede065 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs @@ -0,0 +1,18 @@ +using Godot; + +partial class Generic<T> : GodotObject +{ + private int _field; +} + +// Generic again but different generic parameters +partial class Generic<T, R> : GodotObject +{ + private int _field; +} + +// Generic again but without generic parameters +partial class Generic : GodotObject +{ + private int _field; +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Methods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Methods.cs new file mode 100644 index 0000000000..1da9db8204 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Methods.cs @@ -0,0 +1,26 @@ +using Godot; + +public partial class Methods : GodotObject +{ + private void MethodWithOverload() + { + } + + private void MethodWithOverload(int a) + { + } + + private void MethodWithOverload(int a, int b) + { + } + + // Should be ignored. The previous one is picked. + private void MethodWithOverload(float a, float b) + { + } + + // Generic methods should be ignored. + private void GenericMethod<T>(T t) + { + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs new file mode 100644 index 0000000000..61a48cefc9 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs @@ -0,0 +1,12 @@ +using Godot; + +public partial class MixedReadOnlyWriteOnly : GodotObject +{ + public readonly string readonly_field = "foo"; + public string readonly_auto_property { get; } = "foo"; + public string readonly_property { get => "foo"; } + public string initonly_auto_property { get; init; } + + bool writeonly_backing_field = false; + public bool writeonly_property { set => writeonly_backing_field = value; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs new file mode 100644 index 0000000000..47063a9cdf --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs @@ -0,0 +1,8 @@ +using Godot; +using System; + +public partial class ExportedFields : GodotObject +{ + // Note we use Array and not System.Array. This tests the generated namespace qualification. + [Export] private Int64[] field_empty_Int64Array = Array.Empty<Int64>(); +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs new file mode 100644 index 0000000000..5506465b92 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs @@ -0,0 +1,33 @@ +using Godot; + +public partial class ScriptBoilerplate : Node +{ + private NodePath _nodePath; + private int _velocity; + + public override void _Process(double delta) + { + _ = delta; + + base._Process(delta); + } + + public int Bazz(StringName name) + { + _ = name; + return 1; + } + + public void IgnoreThisMethodWithByRefParams(ref int a) + { + _ = a; + } +} + +partial struct OuterClass +{ + public partial class NestedClass : RefCounted + { + public override Variant _Get(StringName property) => default; + } +} 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 23879e0e53..7d2395ba61 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 @@ -9,7 +9,7 @@ <Authors>Godot Engine contributors</Authors> <PackageId>Godot.SourceGenerators</PackageId> - <Version>4.2.0</Version> + <Version>4.3.0</Version> <PackageVersion>$(PackageVersion_Godot_SourceGenerators)</PackageVersion> <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index b16adb6f55..e516b4dd18 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -195,7 +195,7 @@ namespace GodotTools.Export bool isSim = arch == "i386" || arch == "x86_64"; // Shouldn't really happen as we don't do AOT for the simulator string versionMinName = isSim ? "iphonesimulator" : "iphoneos"; string iOSPlatformName = isSim ? "iPhoneSimulator" : "iPhoneOS"; - const string versionMin = "10.0"; // TODO: Turn this hard-coded version into an exporter setting + const string versionMin = "12.0"; // TODO: Turn this hard-coded version into an exporter setting string iOSSdkPath = Path.Combine(XcodeHelper.XcodePath, $"Contents/Developer/Platforms/{iOSPlatformName}.platform/Developer/SDKs/{iOSPlatformName}.sdk"); diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 91e5118990..c634d9c1ac 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -194,7 +194,7 @@ namespace GodotTools.Export BundleOutputs = false, IncludeDebugSymbols = publishConfig.IncludeDebugSymbols, RidOS = OS.DotNetOS.iOSSimulator, - UseTempDir = true, + UseTempDir = false, }); } @@ -361,7 +361,7 @@ namespace GodotTools.Export } var xcFrameworkPath = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig, - $"{GodotSharpDirs.ProjectAssemblyName}.xcframework"); + $"{GodotSharpDirs.ProjectAssemblyName}_aot.xcframework"); if (!BuildManager.GenerateXCFrameworkBlocking(outputPaths, Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig, xcFrameworkPath))) { diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 36fdda4625..25a5720bc4 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -69,6 +69,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) { #define OPEN_BLOCK_L1 INDENT1 OPEN_BLOCK #define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK +#define OPEN_BLOCK_L3 INDENT3 OPEN_BLOCK #define CLOSE_BLOCK_L1 INDENT1 CLOSE_BLOCK #define CLOSE_BLOCK_L2 INDENT2 CLOSE_BLOCK #define CLOSE_BLOCK_L3 INDENT3 CLOSE_BLOCK @@ -2591,7 +2592,11 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, // Generate icall function r_output << MEMBER_BEGIN "internal static unsafe " << (ret_void ? "void" : return_type->c_type_out) << " " - << icall_method << "(" << c_func_sig.as_string() << ") " OPEN_BLOCK; + << icall_method << "(" << c_func_sig.as_string() << ")\n" OPEN_BLOCK_L1; + + if (!p_icall.is_static) { + r_output << INDENT2 "ExceptionUtils.ThrowIfNullPtr(" CS_PARAM_INSTANCE ");\n"; + } if (!ret_void && (!p_icall.is_vararg || return_type->cname != name_cache.type_Variant)) { String ptrcall_return_type; @@ -2619,11 +2624,6 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, r_output << ptrcall_return_type << " " C_LOCAL_RET << initialization << ";\n"; } - if (!p_icall.is_static) { - r_output << INDENT2 "if (" CS_PARAM_INSTANCE " == IntPtr.Zero)\n" - << INDENT3 "throw new ArgumentNullException(nameof(" CS_PARAM_INSTANCE "));\n"; - } - String argc_str = itos(p_icall.get_arguments_count()); auto generate_call_and_return_stmts = [&](const char *base_indent) { @@ -2714,7 +2714,7 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, r_output << c_in_statements.as_string(); - r_output << INDENT3 "for (int i = 0; i < vararg_length; i++) " OPEN_BLOCK + r_output << INDENT3 "for (int i = 0; i < vararg_length; i++)\n" OPEN_BLOCK_L3 << INDENT4 "varargs[i] = " << vararg_arg << "[i].NativeVar;\n" << INDENT4 C_LOCAL_PTRCALL_ARGS "[" << real_argc_str << " + i] = new IntPtr(&varargs[i]);\n" << CLOSE_BLOCK_L3; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs index cc99225a33..57b5b09ebb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -689,7 +692,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the AABB and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Aabb other && Equals(other); } @@ -739,7 +742,7 @@ namespace Godot /// Converts this <see cref="Aabb"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this AABB.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"{_position.ToString(format)}, {_size.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 13c0cde1ef..c7420dcf7e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Runtime.CompilerServices; using Godot.NativeInterop; +#nullable enable + namespace Godot.Collections { /// <summary> @@ -22,7 +24,7 @@ namespace Godot.Collections { internal godot_array.movable NativeValue; - private WeakReference<IDisposable> _weakReferenceToSelf; + private WeakReference<IDisposable>? _weakReferenceToSelf; /// <summary> /// Constructs a new empty <see cref="Array"/>. @@ -1140,7 +1142,8 @@ namespace Godot.Collections /// </summary> /// <param name="from">The typed array to convert.</param> /// <returns>A new Godot Array, or <see langword="null"/> if <see paramref="from"/> was null.</returns> - public static explicit operator Array(Array<T> from) + [return: NotNullIfNotNull("from")] + public static explicit operator Array?(Array<T>? from) { return from?._underlyingArray; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index b4f7b82f60..589d6596f0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -1,7 +1,10 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.ComponentModel; +#nullable enable + namespace Godot { /// <summary> @@ -1090,7 +1093,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the basis matrix and the object are exactly equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Basis other && Equals(other); } @@ -1140,7 +1143,7 @@ namespace Godot /// Converts this <see cref="Basis"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this basis.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"[X: {X.ToString(format)}, Y: {Y.ToString(format)}, Z: {Z.ToString(format)}]"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 80c26e5708..a087b20308 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -194,7 +194,7 @@ namespace Godot.Bridge var native = GodotObject.InternalGetClassNativeBase(scriptType); - var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static | + var field = native.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) @@ -253,11 +253,15 @@ namespace Godot.Bridge { var editorAssembly = AppDomain.CurrentDomain.GetAssemblies() .FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor"); - wrapperType = editorAssembly?.GetType("Godot." + nativeTypeNameStr); - if (wrapperType == null) + if (editorAssembly != null) { - wrapperType = GetTypeByGodotClassAttr(editorAssembly, nativeTypeNameStr); + wrapperType = editorAssembly.GetType("Godot." + nativeTypeNameStr); + + if (wrapperType == null) + { + wrapperType = GetTypeByGodotClassAttr(editorAssembly, nativeTypeNameStr); + } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 293e680067..772209064c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -1,7 +1,10 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Godot.NativeInterop; +#nullable enable + namespace Godot { /// <summary> @@ -1274,7 +1277,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the color and the other object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Color other && Equals(other); } @@ -1324,7 +1327,7 @@ namespace Godot /// Converts this <see cref="Color"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this color.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({R.ToString(format)}, {G.ToString(format)}, {B.ToString(format)}, {A.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 6c2fb7374c..ab2e0a78b9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -414,7 +414,7 @@ namespace Godot { ulong objectId = reader.ReadUInt64(); // ReSharper disable once RedundantNameQualifier - GodotObject godotObject = GodotObject.InstanceFromId(objectId); + GodotObject? godotObject = GodotObject.InstanceFromId(objectId); if (godotObject == null) return false; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 2a72ebc32b..d08fad90db 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -5,6 +5,8 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Godot.NativeInterop; +#nullable enable + namespace Godot.Collections { /// <summary> @@ -19,7 +21,7 @@ namespace Godot.Collections { internal godot_dictionary.movable NativeValue; - private WeakReference<IDisposable> _weakReferenceToSelf; + private WeakReference<IDisposable>? _weakReferenceToSelf; /// <summary> /// Constructs a new empty <see cref="Dictionary"/>. @@ -559,7 +561,8 @@ namespace Godot.Collections /// </summary> /// <param name="from">The typed dictionary to convert.</param> /// <returns>A new Godot Dictionary, or <see langword="null"/> if <see paramref="from"/> was null.</returns> - public static explicit operator Dictionary(Dictionary<TKey, TValue> from) + [return: NotNullIfNotNull("from")] + public static explicit operator Dictionary?(Dictionary<TKey, TValue>? from) { return from?._underlyingDict; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs index 6c90c17078..563a6abe9b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs @@ -1,6 +1,8 @@ using System; using Godot.NativeInterop; +#nullable enable + namespace Godot { public partial class GodotObject @@ -26,7 +28,7 @@ namespace Godot /// </example> /// <param name="instanceId">Instance ID of the Object to retrieve.</param> /// <returns>The <see cref="GodotObject"/> instance.</returns> - public static GodotObject InstanceFromId(ulong instanceId) + public static GodotObject? InstanceFromId(ulong instanceId) { return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId)); } @@ -49,7 +51,7 @@ namespace Godot /// </summary> /// <param name="instance">The instance to check.</param> /// <returns>If the instance is a valid object.</returns> - public static bool IsInstanceValid(GodotObject instance) + public static bool IsInstanceValid(GodotObject? instance) { return instance != null && instance.NativeInstance != IntPtr.Zero; } @@ -66,9 +68,9 @@ namespace Godot /// </summary> /// <param name="obj">The object.</param> /// <returns> - /// The <see cref="WeakRef"/> reference to the object or <see langword="null"/>. + /// The <see cref="Godot.WeakRef"/> reference to the object or <see langword="null"/>. /// </returns> - public static WeakRef WeakRef(GodotObject obj) + public static WeakRef? WeakRef(GodotObject? obj) { if (!IsInstanceValid(obj)) return null; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs index 43598ca84d..8f8e884b8c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs @@ -1,8 +1,11 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; using Godot.Bridge; using Godot.NativeInterop; +#nullable enable + namespace Godot { public partial class GodotObject : IDisposable @@ -13,7 +16,7 @@ namespace Godot internal IntPtr NativePtr; private bool _memoryOwn; - private WeakReference<GodotObject> _weakReferenceToSelf; + private WeakReference<GodotObject>? _weakReferenceToSelf; /// <summary> /// Constructs a new <see cref="GodotObject"/>. @@ -59,7 +62,7 @@ namespace Godot /// </summary> public IntPtr NativeInstance => NativePtr; - internal static IntPtr GetPtr(GodotObject instance) + internal static IntPtr GetPtr(GodotObject? instance) { if (instance == null) return IntPtr.Zero; @@ -105,7 +108,7 @@ namespace Godot if (gcHandleToFree != IntPtr.Zero) { - object target = GCHandle.FromIntPtr(gcHandleToFree).Target; + object? target = GCHandle.FromIntPtr(gcHandleToFree).Target; // The GC handle may have been replaced in another thread. Release it only if // it's associated to this managed instance, or if the target is no longer alive. if (target != this && target != null) @@ -176,18 +179,14 @@ namespace Godot internal static Type InternalGetClassNativeBase(Type t) { - do - { - var assemblyName = t.Assembly.GetName(); + var name = t.Assembly.GetName().Name; - if (assemblyName.Name == "GodotSharp") - return t; + if (name == "GodotSharp" || name == "GodotSharpEditor") + return t; - if (assemblyName.Name == "GodotSharpEditor") - return t; - } while ((t = t.BaseType) != null); + Debug.Assert(t.BaseType is not null, "Script types must derive from a native Godot type."); - return null; + return InternalGetClassNativeBase(t.BaseType); } // ReSharper disable once VirtualMemberNeverOverridden.Global diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs index dc53e48bd0..04b6c2e743 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Text; #nullable enable @@ -239,5 +240,13 @@ namespace Godot.NativeInterop return variant->Type.ToString(); } + + internal static void ThrowIfNullPtr(IntPtr ptr, [CallerArgumentExpression("ptr")] string? paramName = null) + { + if (ptr == IntPtr.Zero) + { + throw new ArgumentNullException(paramName); + } + } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs index f216fb7ea3..0af640533d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using Godot.NativeInterop; +#nullable enable + namespace Godot { /// <summary> @@ -39,11 +42,11 @@ namespace Godot /// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene. /// </code> /// </example> - public sealed class NodePath : IDisposable, IEquatable<NodePath> + public sealed class NodePath : IDisposable, IEquatable<NodePath?> { internal godot_node_path.movable NativeValue; - private WeakReference<IDisposable> _weakReferenceToSelf; + private WeakReference<IDisposable>? _weakReferenceToSelf; ~NodePath() { @@ -135,7 +138,8 @@ namespace Godot /// Converts this <see cref="NodePath"/> to a string. /// </summary> /// <param name="from">The <see cref="NodePath"/> to convert.</param> - public static implicit operator string(NodePath from) => from?.ToString(); + [return: NotNullIfNotNull("from")] + public static implicit operator string?(NodePath? from) => from?.ToString(); /// <summary> /// Converts this <see cref="NodePath"/> to a string. @@ -289,19 +293,19 @@ namespace Godot /// <returns>If the <see cref="NodePath"/> is empty.</returns> public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty; - public static bool operator ==(NodePath left, NodePath right) + public static bool operator ==(NodePath? left, NodePath? right) { if (left is null) return right is null; return left.Equals(right); } - public static bool operator !=(NodePath left, NodePath right) + public static bool operator !=(NodePath? left, NodePath? right) { return !(left == right); } - public bool Equals(NodePath other) + public bool Equals([NotNullWhen(true)] NodePath? other) { if (other is null) return false; @@ -310,7 +314,7 @@ namespace Godot return NativeFuncs.godotsharp_node_path_equals(self, otherNative).ToBool(); } - public override bool Equals(object obj) + public override bool Equals([NotNullWhen(true)] object? obj) { return ReferenceEquals(this, obj) || (obj is NodePath other && Equals(other)); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 85b2b02c45..f5dc34d824 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -382,7 +385,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the plane and the other object are exactly equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Plane other && Equals(other); } @@ -430,7 +433,7 @@ namespace Godot /// Converts this <see cref="Plane"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this plane.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"{_normal.ToString(format)}, {_d.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index 155e90ff24..4c9e21fb79 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -586,7 +589,7 @@ namespace Godot public readonly Vector2 GetFarPlaneHalfExtents() { var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); - return new Vector2(res.Value.X, res.Value.Y); + return res is null ? default : new Vector2(res.Value.X, res.Value.Y); } /// <summary> @@ -597,7 +600,7 @@ namespace Godot public readonly Vector2 GetViewportHalfExtents() { var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); - return new Vector2(res.Value.X, res.Value.Y); + return res is null ? default : new Vector2(res.Value.X, res.Value.Y); } /// <summary> @@ -981,7 +984,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Projection other && Equals(other); } @@ -1018,7 +1021,7 @@ namespace Godot /// Converts this <see cref="Projection"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this projection.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"{X.X.ToString(format)}, {X.Y.ToString(format)}, {X.Z.ToString(format)}, {X.W.ToString(format)}\n" + $"{Y.X.ToString(format)}, {Y.Y.ToString(format)}, {Y.Z.ToString(format)}, {Y.W.ToString(format)}\n" + diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 3d45913586..2344e8c510 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -769,7 +772,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the quaternion and the other object are exactly equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Quaternion other && Equals(other); } @@ -817,7 +820,7 @@ namespace Godot /// Converts this <see cref="Quaternion"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this quaternion.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index babb26960b..71a35ab809 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -427,7 +430,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the rect and the other object are exactly equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Rect2 other && Equals(other); } @@ -475,7 +478,7 @@ namespace Godot /// Converts this <see cref="Rect2"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this rect.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"{_position.ToString(format)}, {_size.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs index 49fba02b54..ef7e9eacd8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -398,7 +401,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the rect and the other object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Rect2I other && Equals(other); } @@ -435,7 +438,7 @@ namespace Godot /// Converts this <see cref="Rect2I"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this rect.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"{_position.ToString(format)}, {_size.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs index 350626389b..fccae94eac 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs @@ -1,8 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Godot.NativeInterop; +#nullable enable + namespace Godot { /// <summary> @@ -71,7 +74,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the color and the other object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Rid other && Equals(other); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs index 97d28f9ee9..21d9ada127 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using Godot.NativeInterop; +#nullable enable + namespace Godot { /// <summary> @@ -10,11 +13,11 @@ namespace Godot /// Comparing them is much faster than with regular strings, because only the pointers are compared, /// not the whole strings. /// </summary> - public sealed class StringName : IDisposable, IEquatable<StringName> + public sealed class StringName : IDisposable, IEquatable<StringName?> { internal godot_string_name.movable NativeValue; - private WeakReference<IDisposable> _weakReferenceToSelf; + private WeakReference<IDisposable>? _weakReferenceToSelf; ~StringName() { @@ -81,7 +84,8 @@ namespace Godot /// Converts a <see cref="StringName"/> to a string. /// </summary> /// <param name="from">The <see cref="StringName"/> to convert.</param> - public static implicit operator string(StringName from) => from?.ToString(); + [return: NotNullIfNotNull("from")] + public static implicit operator string?(StringName? from) => from?.ToString(); /// <summary> /// Converts this <see cref="StringName"/> to a string. @@ -104,43 +108,43 @@ namespace Godot /// <returns>If the <see cref="StringName"/> is empty.</returns> public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty; - public static bool operator ==(StringName left, StringName right) + public static bool operator ==(StringName? left, StringName? right) { if (left is null) return right is null; return left.Equals(right); } - public static bool operator !=(StringName left, StringName right) + public static bool operator !=(StringName? left, StringName? right) { return !(left == right); } - public bool Equals(StringName other) + public bool Equals([NotNullWhen(true)] StringName? other) { if (other is null) return false; return NativeValue.DangerousSelfRef == other.NativeValue.DangerousSelfRef; } - public static bool operator ==(StringName left, in godot_string_name right) + public static bool operator ==(StringName? left, in godot_string_name right) { if (left is null) return right.IsEmpty; return left.Equals(right); } - public static bool operator !=(StringName left, in godot_string_name right) + public static bool operator !=(StringName? left, in godot_string_name right) { return !(left == right); } - public static bool operator ==(in godot_string_name left, StringName right) + public static bool operator ==(in godot_string_name left, StringName? right) { return right == left; } - public static bool operator !=(in godot_string_name left, StringName right) + public static bool operator !=(in godot_string_name left, StringName? right) { return !(right == left); } @@ -150,7 +154,7 @@ namespace Godot return NativeValue.DangerousSelfRef == other; } - public override bool Equals(object obj) + public override bool Equals([NotNullWhen(true)] object? obj) { return ReferenceEquals(this, obj) || (obj is StringName other && Equals(other)); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 386f587464..3443277fee 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -1,7 +1,10 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -606,7 +609,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the transform and the object are exactly equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Transform2D other && Equals(other); } @@ -656,7 +659,7 @@ namespace Godot /// Converts this <see cref="Transform2D"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this transform.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"[X: {X.ToString(format)}, Y: {Y.ToString(format)}, O: {Origin.ToString(format)}]"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 2d09259dcb..f80c0bd8dd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -1,7 +1,10 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.ComponentModel; +#nullable enable + namespace Godot { /// <summary> @@ -630,7 +633,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the transform and the object are exactly equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Transform3D other && Equals(other); } @@ -680,7 +683,7 @@ namespace Godot /// Converts this <see cref="Transform3D"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this transform.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"[X: {Basis.X.ToString(format)}, Y: {Basis.Y.ToString(format)}, Z: {Basis.Z.ToString(format)}, O: {Origin.ToString(format)}]"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 4842dbc9af..a27a1ab1cf 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -954,7 +957,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Vector2 other && Equals(other); } @@ -1016,7 +1019,7 @@ namespace Godot /// Converts this <see cref="Vector2"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs index 215bb4df8c..8960323754 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -121,6 +124,29 @@ namespace Godot } /// <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. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public readonly int DistanceSquaredTo(Vector2I to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector2I)"/> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public readonly real_t DistanceTo(Vector2I to) + { + return (to - this).Length(); + } + + /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> @@ -535,7 +561,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Vector2I other && Equals(other); } @@ -572,7 +598,7 @@ namespace Godot /// Converts this <see cref="Vector2I"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index d26d4662a0..54d698345f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -1056,7 +1059,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Vector3 other && Equals(other); } @@ -1118,7 +1121,7 @@ namespace Godot /// Converts this <see cref="Vector3"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs index fe74ec8884..2d7bbc926d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -129,6 +132,29 @@ namespace Godot } /// <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. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public readonly int DistanceSquaredTo(Vector3I to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector3I)"/> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public readonly real_t DistanceTo(Vector3I to) + { + return (to - this).Length(); + } + + /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> @@ -590,7 +616,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Vector3I other && Equals(other); } @@ -627,7 +653,7 @@ namespace Godot /// Converts this <see cref="Vector3I"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index eeaef5e46e..87c01ad5ea 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -838,7 +841,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Vector4 other && Equals(other); } @@ -900,7 +903,7 @@ namespace Godot /// Converts this <see cref="Vector4"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs index a0a4393523..9a85f359d7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +#nullable enable + namespace Godot { /// <summary> @@ -146,6 +149,29 @@ namespace Godot } /// <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. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public readonly int DistanceSquaredTo(Vector4I to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector4I)"/> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public readonly real_t DistanceTo(Vector4I to) + { + return (to - this).Length(); + } + + /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> @@ -611,7 +637,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) + public override readonly bool Equals([NotNullWhen(true)] object? obj) { return obj is Vector4I other && Equals(other); } @@ -648,7 +674,7 @@ namespace Godot /// Converts this <see cref="Vector4I"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public readonly string ToString(string format) + public readonly string ToString(string? format) { return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}), {W.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index a55b8d693b..db16b1fe1d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -17,7 +17,7 @@ <Authors>Godot Engine contributors</Authors> <PackageId>GodotSharp</PackageId> - <Version>4.2.0</Version> + <Version>4.3.0</Version> <PackageVersion>$(PackageVersion_GodotSharp)</PackageVersion> <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharp</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj index db9337d4eb..31e20e4ecd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj @@ -15,7 +15,7 @@ <Authors>Godot Engine contributors</Authors> <PackageId>GodotSharpEditor</PackageId> - <Version>4.2.0</Version> + <Version>4.3.0</Version> <PackageVersion>$(PackageVersion_GodotSharp)</PackageVersion> <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharpEditor</RepositoryUrl> <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 530936cfb4..1b46a619ca 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -68,7 +68,9 @@ class GDMono { String project_assembly_path; uint64_t project_assembly_modified_time = 0; +#ifdef GD_MONO_HOT_RELOAD int project_load_failure_count = 0; +#endif #ifdef TOOLS_ENABLED bool _load_project_assembly(); diff --git a/modules/multiplayer/scene_multiplayer.cpp b/modules/multiplayer/scene_multiplayer.cpp index 04de3dfb7f..665b246bc5 100644 --- a/modules/multiplayer/scene_multiplayer.cpp +++ b/modules/multiplayer/scene_multiplayer.cpp @@ -483,9 +483,14 @@ Error SceneMultiplayer::complete_auth(int p_peer) { ERR_FAIL_COND_V(!pending_peers.has(p_peer), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V_MSG(pending_peers[p_peer].local, ERR_FILE_CANT_WRITE, "The authentication session was already marked as completed."); pending_peers[p_peer].local = true; + // Notify the remote peer that the authentication has completed. uint8_t buf[2] = { NETWORK_COMMAND_SYS, SYS_COMMAND_AUTH }; + multiplayer_peer->set_target_peer(p_peer); + multiplayer_peer->set_transfer_channel(0); + multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); Error err = _send(buf, 2); + // The remote peer already reported the authentication as completed, so admit the peer. // May generate new packets, so it must happen after sending confirmation. if (pending_peers[p_peer].remote) { diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 6a3bf6793e..5a27f315b9 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -331,6 +331,13 @@ RID GodotNavigationServer::agent_get_map(RID p_agent) const { return RID(); } +Vector3 GodotNavigationServer::map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const { + const NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_NULL_V(map, Vector3()); + + return map->get_random_point(p_navigation_layers, p_uniformly); +} + RID GodotNavigationServer::region_create() { MutexLock lock(operations_mutex); @@ -384,6 +391,13 @@ COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) { region->set_transform(p_transform); } +Transform3D GodotNavigationServer::region_get_transform(RID p_region) const { + NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL_V(region, Transform3D()); + + return region->get_transform(); +} + COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) { NavRegion *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -498,6 +512,13 @@ Vector3 GodotNavigationServer::region_get_connection_pathway_end(RID p_region, i return region->get_connection_pathway_end(p_connection_id); } +Vector3 GodotNavigationServer::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const { + const NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL_V(region, Vector3()); + + return region->get_random_point(p_navigation_layers, p_uniformly); +} + RID GodotNavigationServer::link_create() { MutexLock lock(operations_mutex); @@ -705,6 +726,13 @@ COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) { agent->set_neighbor_distance(p_distance); } +real_t GodotNavigationServer::agent_get_neighbor_distance(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_neighbor_distance(); +} + COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) { NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -712,22 +740,43 @@ COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) { agent->set_max_neighbors(p_count); } +int GodotNavigationServer::agent_get_max_neighbors(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_max_neighbors(); +} + COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon) { - ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizion must be positive."); + ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive."); NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_time_horizon_agents(p_time_horizon); } +real_t GodotNavigationServer::agent_get_time_horizon_agents(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_time_horizon_agents(); +} + COMMAND_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon) { - ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizion must be positive."); + ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive."); NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_time_horizon_obstacles(p_time_horizon); } +real_t GodotNavigationServer::agent_get_time_horizon_obstacles(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_time_horizon_obstacles(); +} + COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) { ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive."); NavAgent *agent = agent_owner.get_or_null(p_agent); @@ -736,6 +785,13 @@ COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) { agent->set_radius(p_radius); } +real_t GodotNavigationServer::agent_get_radius(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_radius(); +} + COMMAND_2(agent_set_height, RID, p_agent, real_t, p_height) { ERR_FAIL_COND_MSG(p_height < 0.0, "Height must be positive."); NavAgent *agent = agent_owner.get_or_null(p_agent); @@ -744,6 +800,13 @@ COMMAND_2(agent_set_height, RID, p_agent, real_t, p_height) { agent->set_height(p_height); } +real_t GodotNavigationServer::agent_get_height(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_height(); +} + COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) { ERR_FAIL_COND_MSG(p_max_speed < 0.0, "Max speed must be positive."); NavAgent *agent = agent_owner.get_or_null(p_agent); @@ -752,6 +815,13 @@ COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) { agent->set_max_speed(p_max_speed); } +real_t GodotNavigationServer::agent_get_max_speed(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_max_speed(); +} + COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) { NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -759,6 +829,13 @@ COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) { agent->set_velocity(p_velocity); } +Vector3 GodotNavigationServer::agent_get_velocity(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, Vector3()); + + return agent->get_velocity(); +} + COMMAND_2(agent_set_velocity_forced, RID, p_agent, Vector3, p_velocity) { NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -773,6 +850,13 @@ COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position) { agent->set_position(p_position); } +Vector3 GodotNavigationServer::agent_get_position(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, Vector3()); + + return agent->get_position(); +} + bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const { NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL_V(agent, false); @@ -795,18 +879,39 @@ COMMAND_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback) { } } +bool GodotNavigationServer::agent_has_avoidance_callback(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, false); + + return agent->has_avoidance_callback(); +} + COMMAND_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers) { NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_avoidance_layers(p_layers); } +uint32_t GodotNavigationServer::agent_get_avoidance_layers(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_avoidance_layers(); +} + COMMAND_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask) { NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_avoidance_mask(p_mask); } +uint32_t GodotNavigationServer::agent_get_avoidance_mask(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_avoidance_mask(); +} + COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) { ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive."); ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive."); @@ -815,6 +920,13 @@ COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) { agent->set_avoidance_priority(p_priority); } +real_t GodotNavigationServer::agent_get_avoidance_priority(RID p_agent) const { + NavAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_NULL_V(agent, 0); + + return agent->get_avoidance_priority(); +} + RID GodotNavigationServer::obstacle_create() { MutexLock lock(operations_mutex); @@ -899,12 +1011,26 @@ COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius) { obstacle->set_radius(p_radius); } +real_t GodotNavigationServer::obstacle_get_radius(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_NULL_V(obstacle, 0); + + return obstacle->get_radius(); +} + COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_height(p_height); } +real_t GodotNavigationServer::obstacle_get_height(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_NULL_V(obstacle, 0); + + return obstacle->get_height(); +} + COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -912,24 +1038,52 @@ COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity) { obstacle->set_velocity(p_velocity); } +Vector3 GodotNavigationServer::obstacle_get_velocity(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_NULL_V(obstacle, Vector3()); + + return obstacle->get_velocity(); +} + COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_position(p_position); } +Vector3 GodotNavigationServer::obstacle_get_position(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_NULL_V(obstacle, Vector3()); + + return obstacle->get_position(); +} + void GodotNavigationServer::obstacle_set_vertices(RID p_obstacle, const Vector<Vector3> &p_vertices) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_vertices(p_vertices); } +Vector<Vector3> GodotNavigationServer::obstacle_get_vertices(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_NULL_V(obstacle, Vector<Vector3>()); + + return obstacle->get_vertices(); +} + COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_avoidance_layers(p_layers); } +uint32_t GodotNavigationServer::obstacle_get_avoidance_layers(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_NULL_V(obstacle, 0); + + return obstacle->get_avoidance_layers(); +} + void GodotNavigationServer::parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback) { #ifndef _3D_DISABLED ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "The SceneTree can only be parsed on the main thread. Call this function from the main thread or use call_deferred()."); diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 4ead4fc398..f19450db27 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -140,6 +140,8 @@ public: virtual void map_force_update(RID p_map) override; + virtual Vector3 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override; + virtual RID region_create() override; COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled); @@ -163,6 +165,7 @@ public: COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers); virtual uint32_t region_get_navigation_layers(RID p_region) const override; COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); + virtual Transform3D region_get_transform(RID p_region) const override; COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh); #ifndef DISABLE_DEPRECATED virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) override; @@ -170,6 +173,7 @@ public: virtual int region_get_connections_count(RID p_region) const override; virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; + virtual Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override; virtual RID link_create() override; COMMAND_2(link_set_map, RID, p_link, RID, p_map); @@ -201,20 +205,33 @@ public: COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused); virtual bool agent_get_paused(RID p_agent) const override; COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance); + virtual real_t agent_get_neighbor_distance(RID p_agent) const override; COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count); + virtual int agent_get_max_neighbors(RID p_agent) const override; COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon); + virtual real_t agent_get_time_horizon_agents(RID p_agent) const override; COMMAND_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon); + virtual real_t agent_get_time_horizon_obstacles(RID p_agent) const override; COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius); + virtual real_t agent_get_radius(RID p_agent) const override; COMMAND_2(agent_set_height, RID, p_agent, real_t, p_height); + virtual real_t agent_get_height(RID p_agent) const override; COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed); + virtual real_t agent_get_max_speed(RID p_agent) const override; COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity); + virtual Vector3 agent_get_velocity(RID p_agent) const override; COMMAND_2(agent_set_velocity_forced, RID, p_agent, Vector3, p_velocity); COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position); + virtual Vector3 agent_get_position(RID p_agent) const override; virtual bool agent_is_map_changed(RID p_agent) const override; COMMAND_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback); + virtual bool agent_has_avoidance_callback(RID p_agent) const override; COMMAND_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers); + virtual uint32_t agent_get_avoidance_layers(RID p_agent) const override; COMMAND_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask); + virtual uint32_t agent_get_avoidance_mask(RID p_agent) const override; COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority); + virtual real_t agent_get_avoidance_priority(RID p_agent) const override; virtual RID obstacle_create() override; COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled); @@ -226,11 +243,17 @@ public: COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused); virtual bool obstacle_get_paused(RID p_obstacle) const override; COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius); + virtual real_t obstacle_get_radius(RID p_obstacle) const override; COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity); + virtual Vector3 obstacle_get_velocity(RID p_obstacle) const override; COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position); + virtual Vector3 obstacle_get_position(RID p_obstacle) const override; COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height); + virtual real_t obstacle_get_height(RID p_obstacle) const override; virtual void obstacle_set_vertices(RID p_obstacle, const Vector<Vector3> &p_vertices) override; + virtual Vector<Vector3> obstacle_get_vertices(RID p_obstacle) const override; COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers); + virtual uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override; virtual void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override; virtual void bake_from_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override; diff --git a/modules/navigation/godot_navigation_server_2d.cpp b/modules/navigation/godot_navigation_server_2d.cpp index b54729e06f..76bfd3a101 100644 --- a/modules/navigation/godot_navigation_server_2d.cpp +++ b/modules/navigation/godot_navigation_server_2d.cpp @@ -141,6 +141,13 @@ static Transform3D trf2_to_trf3(const Transform2D &d) { return Transform3D(b, o); } +static Transform2D trf3_to_trf2(const Transform3D &d) { + Vector3 o = d.get_origin(); + Vector3 nx = d.xform(Vector3(1, 0, 0)) - o; + Vector3 nz = d.xform(Vector3(0, 0, 1)) - o; + return Transform2D(nx.x, nx.z, nz.x, nz.z, o.x, o.z); +} + static ObjectID id_to_id(const ObjectID &id) { return id; } @@ -259,8 +266,12 @@ Vector<Vector2> FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2 Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3); RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3); -RID FORWARD_0(region_create); +Vector2 GodotNavigationServer2D::map_get_random_point(RID p_map, uint32_t p_naviation_layers, bool p_uniformly) const { + Vector3 result = NavigationServer3D::get_singleton()->map_get_random_point(p_map, p_naviation_layers, p_uniformly); + return v3_to_v2(result); +} +RID FORWARD_0(region_create); void FORWARD_2(region_set_enabled, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool); bool FORWARD_1_C(region_get_enabled, RID, p_region, rid_to_rid); void FORWARD_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool); @@ -279,6 +290,10 @@ void FORWARD_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigati uint32_t FORWARD_1_C(region_get_navigation_layers, RID, p_region, rid_to_rid); void FORWARD_2(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3); +Transform2D GodotNavigationServer2D::region_get_transform(RID p_region) const { + return trf3_to_trf2(NavigationServer3D::get_singleton()->region_get_transform(p_region)); +} + void GodotNavigationServer2D::region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) { NavigationServer3D::get_singleton()->region_set_navigation_mesh(p_region, poly_to_mesh(p_navigation_polygon)); } @@ -287,6 +302,11 @@ int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid); Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int); Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int); +Vector2 GodotNavigationServer2D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const { + Vector3 result = NavigationServer3D::get_singleton()->region_get_random_point(p_region, p_navigation_layers, p_uniformly); + return v3_to_v2(result); +} + RID FORWARD_0(link_create); void FORWARD_2(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid); @@ -317,25 +337,60 @@ void FORWARD_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled, rid_t bool FORWARD_1_C(agent_get_avoidance_enabled, RID, p_agent, rid_to_rid); void FORWARD_2(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid); void FORWARD_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::agent_get_neighbor_distance(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_neighbor_distance(p_agent); +} void FORWARD_2(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int); +int GodotNavigationServer2D::agent_get_max_neighbors(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_max_neighbors(p_agent); +} void FORWARD_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::agent_get_time_horizon_agents(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_time_horizon_agents(p_agent); +} void FORWARD_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::agent_get_time_horizon_obstacles(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_time_horizon_obstacles(p_agent); +} void FORWARD_2(agent_set_radius, RID, p_agent, real_t, p_radius, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::agent_get_radius(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_radius(p_agent); +} void FORWARD_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::agent_get_max_speed(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_max_speed(p_agent); +} void FORWARD_2(agent_set_velocity_forced, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3); void FORWARD_2(agent_set_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3); +Vector2 GodotNavigationServer2D::agent_get_velocity(RID p_agent) const { + return v3_to_v2(NavigationServer3D::get_singleton()->agent_get_velocity(p_agent)); +} void FORWARD_2(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3); - +Vector2 GodotNavigationServer2D::agent_get_position(RID p_agent) const { + return v3_to_v2(NavigationServer3D::get_singleton()->agent_get_position(p_agent)); +} bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid); void FORWARD_2(agent_set_paused, RID, p_agent, bool, p_paused, rid_to_rid, bool_to_bool); bool FORWARD_1_C(agent_get_paused, RID, p_agent, rid_to_rid); void FORWARD_1(free, RID, p_object, rid_to_rid); void FORWARD_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable); +bool GodotNavigationServer2D::agent_has_avoidance_callback(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_has_avoidance_callback(p_agent); +} void FORWARD_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers, rid_to_rid, uint32_to_uint32); +uint32_t GodotNavigationServer2D::agent_get_avoidance_layers(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_avoidance_layers(p_agent); +} void FORWARD_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask, rid_to_rid, uint32_to_uint32); +uint32_t GodotNavigationServer2D::agent_get_avoidance_mask(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_avoidance_mask(p_agent); +} void FORWARD_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::agent_get_avoidance_priority(RID p_agent) const { + return NavigationServer3D::get_singleton()->agent_get_avoidance_priority(p_agent); +} RID GodotNavigationServer2D::obstacle_create() { RID obstacle = NavigationServer3D::get_singleton()->obstacle_create(); @@ -348,13 +403,28 @@ RID FORWARD_1_C(obstacle_get_map, RID, p_obstacle, rid_to_rid); void FORWARD_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused, rid_to_rid, bool_to_bool); bool FORWARD_1_C(obstacle_get_paused, RID, p_obstacle, rid_to_rid); void FORWARD_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius, rid_to_rid, real_to_real); +real_t GodotNavigationServer2D::obstacle_get_radius(RID p_obstacle) const { + return NavigationServer3D::get_singleton()->obstacle_get_radius(p_obstacle); +} void FORWARD_2(obstacle_set_velocity, RID, p_obstacle, Vector2, p_velocity, rid_to_rid, v2_to_v3); +Vector2 GodotNavigationServer2D::obstacle_get_velocity(RID p_obstacle) const { + return v3_to_v2(NavigationServer3D::get_singleton()->obstacle_get_velocity(p_obstacle)); +} void FORWARD_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position, rid_to_rid, v2_to_v3); +Vector2 GodotNavigationServer2D::obstacle_get_position(RID p_obstacle) const { + return v3_to_v2(NavigationServer3D::get_singleton()->obstacle_get_position(p_obstacle)); +} void FORWARD_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers, rid_to_rid, uint32_to_uint32); +uint32_t GodotNavigationServer2D::obstacle_get_avoidance_layers(RID p_obstacle) const { + return NavigationServer3D::get_singleton()->obstacle_get_avoidance_layers(p_obstacle); +} void GodotNavigationServer2D::obstacle_set_vertices(RID p_obstacle, const Vector<Vector2> &p_vertices) { NavigationServer3D::get_singleton()->obstacle_set_vertices(p_obstacle, vector_v2_to_v3(p_vertices)); } +Vector<Vector2> GodotNavigationServer2D::obstacle_get_vertices(RID p_obstacle) const { + return vector_v3_to_v2(NavigationServer3D::get_singleton()->obstacle_get_vertices(p_obstacle)); +} void GodotNavigationServer2D::query_path(const Ref<NavigationPathQueryParameters2D> &p_query_parameters, Ref<NavigationPathQueryResult2D> p_query_result) const { ERR_FAIL_COND(!p_query_parameters.is_valid()); diff --git a/modules/navigation/godot_navigation_server_2d.h b/modules/navigation/godot_navigation_server_2d.h index 337f5f40d8..2f473da1ab 100644 --- a/modules/navigation/godot_navigation_server_2d.h +++ b/modules/navigation/godot_navigation_server_2d.h @@ -76,6 +76,7 @@ public: virtual TypedArray<RID> map_get_agents(RID p_map) const override; virtual TypedArray<RID> map_get_obstacles(RID p_map) const override; virtual void map_force_update(RID p_map) override; + virtual Vector2 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override; virtual RID region_create() override; virtual void region_set_enabled(RID p_region, bool p_enabled) override; @@ -94,10 +95,12 @@ public: virtual void region_set_navigation_layers(RID p_region, uint32_t p_navigation_layers) override; virtual uint32_t region_get_navigation_layers(RID p_region) const override; virtual void region_set_transform(RID p_region, Transform2D p_transform) override; + virtual Transform2D region_get_transform(RID p_region) const override; virtual void region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) override; virtual int region_get_connections_count(RID p_region) const override; virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; + virtual Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override; virtual RID link_create() override; @@ -157,6 +160,7 @@ public: /// low, the simulation will not be safe. /// Must be non-negative. virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) override; + virtual real_t agent_get_neighbor_distance(RID p_agent) const override; /// The maximum number of other agents this /// agent takes into account in the navigation. @@ -165,6 +169,7 @@ public: /// number is too low, the simulation will not /// be safe. virtual void agent_set_max_neighbors(RID p_agent, int p_count) override; + virtual int agent_get_max_neighbors(RID p_agent) const override; /// The minimal amount of time for which this /// agent's velocities that are computed by the @@ -174,17 +179,20 @@ public: /// other agents, but the less freedom this /// agent has in choosing its velocities. /// Must be positive. - virtual void agent_set_time_horizon_agents(RID p_agent, real_t p_time_horizon) override; + virtual real_t agent_get_time_horizon_agents(RID p_agent) const override; virtual void agent_set_time_horizon_obstacles(RID p_agent, real_t p_time_horizon) override; + virtual real_t agent_get_time_horizon_obstacles(RID p_agent) const override; /// The radius of this agent. /// Must be non-negative. virtual void agent_set_radius(RID p_agent, real_t p_radius) override; + virtual real_t agent_get_radius(RID p_agent) const override; /// The maximum speed of this agent. /// Must be non-negative. virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) override; + virtual real_t agent_get_max_speed(RID p_agent) const override; /// forces and agent velocity change in the avoidance simulation, adds simulation instability if done recklessly virtual void agent_set_velocity_forced(RID p_agent, Vector2 p_velocity) override; @@ -192,19 +200,27 @@ public: /// The wanted velocity for the agent as a "suggestion" to the avoidance simulation. /// The simulation will try to fulfill this velocity wish if possible but may change the velocity depending on other agent's and obstacles'. virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity) override; + virtual Vector2 agent_get_velocity(RID p_agent) const override; /// Position of the agent in world space. virtual void agent_set_position(RID p_agent, Vector2 p_position) override; + virtual Vector2 agent_get_position(RID p_agent) const override; /// Returns true if the map got changed the previous frame. virtual bool agent_is_map_changed(RID p_agent) const override; /// Callback called at the end of the RVO process virtual void agent_set_avoidance_callback(RID p_agent, Callable p_callback) override; + virtual bool agent_has_avoidance_callback(RID p_agent) const override; virtual void agent_set_avoidance_layers(RID p_agent, uint32_t p_layers) override; + virtual uint32_t agent_get_avoidance_layers(RID p_agent) const override; + virtual void agent_set_avoidance_mask(RID p_agent, uint32_t p_mask) override; + virtual uint32_t agent_get_avoidance_mask(RID p_agent) const override; + virtual void agent_set_avoidance_priority(RID p_agent, real_t p_priority) override; + virtual real_t agent_get_avoidance_priority(RID p_agent) const override; virtual RID obstacle_create() override; virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) override; @@ -214,10 +230,15 @@ public: virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) override; virtual bool obstacle_get_paused(RID p_obstacle) const override; virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) override; + virtual real_t obstacle_get_radius(RID p_obstacle) const override; virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity) override; + virtual Vector2 obstacle_get_velocity(RID p_obstacle) const override; virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position) override; + virtual Vector2 obstacle_get_position(RID p_obstacle) const override; virtual void obstacle_set_vertices(RID p_obstacle, const Vector<Vector2> &p_vertices) override; + virtual Vector<Vector2> obstacle_get_vertices(RID p_obstacle) const override; virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override; + virtual uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override; virtual void query_path(const Ref<NavigationPathQueryParameters2D> &p_query_parameters, Ref<NavigationPathQueryResult2D> p_query_result) const override; diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 5ef0298eb4..6429513b53 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -372,7 +372,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p // Stores the further reachable end polygon, in case our goal is not reachable. if (is_reachable) { - real_t d = navigation_polys[least_cost_id].entry.distance_to(p_destination) * navigation_polys[least_cost_id].poly->owner->get_travel_cost(); + real_t d = navigation_polys[least_cost_id].entry.distance_to(p_destination); if (reachable_d > d) { reachable_d = d; reachable_end = navigation_polys[least_cost_id].poly; @@ -769,6 +769,70 @@ void NavMap::remove_agent_as_controlled(NavAgent *agent) { } } +Vector3 NavMap::get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const { + const LocalVector<NavRegion *> map_regions = get_regions(); + + if (map_regions.is_empty()) { + return Vector3(); + } + + LocalVector<const NavRegion *> accessible_regions; + + for (const NavRegion *region : map_regions) { + if (!region->get_enabled() || (p_navigation_layers & region->get_navigation_layers()) == 0) { + continue; + } + accessible_regions.push_back(region); + } + + if (accessible_regions.is_empty()) { + // All existing region polygons are disabled. + return Vector3(); + } + + if (p_uniformly) { + real_t accumulated_region_surface_area = 0; + RBMap<real_t, uint32_t> accessible_regions_area_map; + + for (uint32_t accessible_region_index = 0; accessible_region_index < accessible_regions.size(); accessible_region_index++) { + const NavRegion *region = accessible_regions[accessible_region_index]; + + real_t region_surface_area = region->get_surface_area(); + + if (region_surface_area == 0.0f) { + continue; + } + + accessible_regions_area_map[accumulated_region_surface_area] = accessible_region_index; + accumulated_region_surface_area += region_surface_area; + } + if (accessible_regions_area_map.is_empty() || accumulated_region_surface_area == 0) { + // All faces have no real surface / no area. + return Vector3(); + } + + real_t random_accessible_regions_area_map = Math::random(real_t(0), accumulated_region_surface_area); + + RBMap<real_t, uint32_t>::Iterator E = accessible_regions_area_map.find_closest(random_accessible_regions_area_map); + ERR_FAIL_COND_V(!E, Vector3()); + uint32_t random_region_index = E->value; + ERR_FAIL_UNSIGNED_INDEX_V(random_region_index, accessible_regions.size(), Vector3()); + + const NavRegion *random_region = accessible_regions[random_region_index]; + ERR_FAIL_NULL_V(random_region, Vector3()); + + return random_region->get_random_point(p_navigation_layers, p_uniformly); + + } else { + uint32_t random_region_index = Math::random(int(0), accessible_regions.size() - 1); + + const NavRegion *random_region = accessible_regions[random_region_index]; + ERR_FAIL_NULL_V(random_region, Vector3()); + + return random_region->get_random_point(p_navigation_layers, p_uniformly); + } +} + void NavMap::sync() { // Performance Monitor int _new_pm_region_count = regions.size(); @@ -1107,8 +1171,14 @@ void NavMap::_update_rvo_obstacles_tree_2d() { obstacle_vertex_count += obstacle->get_vertices().size(); } + // Cleaning old obstacles. + for (size_t i = 0; i < rvo_simulation_2d.obstacles_.size(); ++i) { + delete rvo_simulation_2d.obstacles_[i]; + } + rvo_simulation_2d.obstacles_.clear(); + // Cannot use LocalVector here as RVO library expects std::vector to build KdTree - std::vector<RVO2D::Obstacle2D *> raw_obstacles; + std::vector<RVO2D::Obstacle2D *> &raw_obstacles = rvo_simulation_2d.obstacles_; raw_obstacles.reserve(obstacle_vertex_count); // The following block is modified copy from RVO2D::AddObstacle() @@ -1125,8 +1195,14 @@ void NavMap::_update_rvo_obstacles_tree_2d() { rvo_2d_vertices.reserve(_obstacle_vertices.size()); uint32_t _obstacle_avoidance_layers = obstacle->get_avoidance_layers(); + real_t _obstacle_height = obstacle->get_height(); for (const Vector3 &_obstacle_vertex : _obstacle_vertices) { +#ifdef TOOLS_ENABLED + if (_obstacle_vertex.y != 0) { + WARN_PRINT_ONCE("Y coordinates of static obstacle vertices are ignored. Please use obstacle position Y to change elevation of obstacle."); + } +#endif rvo_2d_vertices.push_back(RVO2D::Vector2(_obstacle_vertex.x + _obstacle_position.x, _obstacle_vertex.z + _obstacle_position.z)); } @@ -1135,6 +1211,9 @@ void NavMap::_update_rvo_obstacles_tree_2d() { for (size_t i = 0; i < rvo_2d_vertices.size(); i++) { RVO2D::Obstacle2D *rvo_2d_obstacle = new RVO2D::Obstacle2D(); rvo_2d_obstacle->point_ = rvo_2d_vertices[i]; + rvo_2d_obstacle->height_ = _obstacle_height; + rvo_2d_obstacle->elevation_ = _obstacle_position.y; + rvo_2d_obstacle->avoidance_layers_ = _obstacle_avoidance_layers; if (i != 0) { diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index 5d78c14627..e8cbe7e247 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -190,6 +190,8 @@ public: return map_update_id; } + Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const; + void sync(); void step(real_t p_deltatime); void dispatch_callbacks(); diff --git a/modules/navigation/nav_mesh_generator_2d.cpp b/modules/navigation/nav_mesh_generator_2d.cpp index f8c12935b4..6dfafa4e91 100644 --- a/modules/navigation/nav_mesh_generator_2d.cpp +++ b/modules/navigation/nav_mesh_generator_2d.cpp @@ -591,13 +591,19 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo continue; } + // 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); + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_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); @@ -622,11 +628,15 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo 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)) { for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) { - const Vector<Vector2> &collision_polygon_points = tile_data->get_collision_polygon_points(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()); diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp index 09697c7be0..9cb235d79f 100644 --- a/modules/navigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -100,6 +100,88 @@ Vector3 NavRegion::get_connection_pathway_end(int p_connection_id) const { return connections[p_connection_id].pathway_end; } +Vector3 NavRegion::get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const { + if (!get_enabled()) { + return Vector3(); + } + + const LocalVector<gd::Polygon> ®ion_polygons = get_polygons(); + + if (region_polygons.is_empty()) { + return Vector3(); + } + + if (p_uniformly) { + real_t accumulated_area = 0; + RBMap<real_t, uint32_t> region_area_map; + + for (uint32_t rp_index = 0; rp_index < region_polygons.size(); rp_index++) { + const gd::Polygon ®ion_polygon = region_polygons[rp_index]; + real_t polyon_area = region_polygon.surface_area; + + if (polyon_area == 0.0) { + continue; + } + region_area_map[accumulated_area] = rp_index; + accumulated_area += polyon_area; + } + if (region_area_map.is_empty() || accumulated_area == 0) { + // All polygons have no real surface / no area. + return Vector3(); + } + + real_t region_area_map_pos = Math::random(real_t(0), accumulated_area); + + RBMap<real_t, uint32_t>::Iterator region_E = region_area_map.find_closest(region_area_map_pos); + ERR_FAIL_COND_V(!region_E, Vector3()); + uint32_t rrp_polygon_index = region_E->value; + ERR_FAIL_UNSIGNED_INDEX_V(rrp_polygon_index, region_polygons.size(), Vector3()); + + const gd::Polygon &rr_polygon = region_polygons[rrp_polygon_index]; + + real_t accumulated_polygon_area = 0; + RBMap<real_t, uint32_t> polygon_area_map; + + for (uint32_t rpp_index = 2; rpp_index < rr_polygon.points.size(); rpp_index++) { + real_t face_area = Face3(rr_polygon.points[0].pos, rr_polygon.points[rpp_index - 1].pos, rr_polygon.points[rpp_index].pos).get_area(); + + if (face_area == 0.0) { + continue; + } + polygon_area_map[accumulated_polygon_area] = rpp_index; + accumulated_polygon_area += face_area; + } + if (polygon_area_map.is_empty() || accumulated_polygon_area == 0) { + // All faces have no real surface / no area. + return Vector3(); + } + + real_t polygon_area_map_pos = Math::random(real_t(0), accumulated_polygon_area); + + RBMap<real_t, uint32_t>::Iterator polygon_E = polygon_area_map.find_closest(polygon_area_map_pos); + ERR_FAIL_COND_V(!polygon_E, Vector3()); + uint32_t rrp_face_index = polygon_E->value; + ERR_FAIL_UNSIGNED_INDEX_V(rrp_face_index, rr_polygon.points.size(), Vector3()); + + const Face3 face(rr_polygon.points[0].pos, rr_polygon.points[rrp_face_index - 1].pos, rr_polygon.points[rrp_face_index].pos); + + Vector3 face_random_position = face.get_random_point_inside(); + return face_random_position; + + } else { + uint32_t rrp_polygon_index = Math::random(int(0), region_polygons.size() - 1); + + const gd::Polygon &rr_polygon = region_polygons[rrp_polygon_index]; + + uint32_t rrp_face_index = Math::random(int(2), rr_polygon.points.size() - 1); + + const Face3 face(rr_polygon.points[0].pos, rr_polygon.points[rrp_face_index - 1].pos, rr_polygon.points[rrp_face_index].pos); + + Vector3 face_random_position = face.get_random_point_inside(); + return face_random_position; + } +} + bool NavRegion::sync() { bool something_changed = polygons_dirty /* || something_dirty? */; @@ -113,6 +195,7 @@ void NavRegion::update_polygons() { return; } polygons.clear(); + surface_area = 0.0; polygons_dirty = false; if (map == nullptr) { @@ -147,21 +230,46 @@ void NavRegion::update_polygons() { polygons.resize(mesh->get_polygon_count()); + real_t _new_region_surface_area = 0.0; + // Build - for (size_t i(0); i < polygons.size(); i++) { - gd::Polygon &p = polygons[i]; - p.owner = this; + int navigation_mesh_polygon_index = 0; + for (gd::Polygon &polygon : polygons) { + polygon.owner = this; + polygon.surface_area = 0.0; - Vector<int> mesh_poly = mesh->get_polygon(i); - const int *indices = mesh_poly.ptr(); + Vector<int> navigation_mesh_polygon = mesh->get_polygon(navigation_mesh_polygon_index); + navigation_mesh_polygon_index += 1; + + int navigation_mesh_polygon_size = navigation_mesh_polygon.size(); + if (navigation_mesh_polygon_size < 3) { + continue; + } + + const int *indices = navigation_mesh_polygon.ptr(); bool valid(true); - p.points.resize(mesh_poly.size()); - p.edges.resize(mesh_poly.size()); - Vector3 center; + polygon.points.resize(navigation_mesh_polygon_size); + polygon.edges.resize(navigation_mesh_polygon_size); + + real_t _new_polygon_surface_area = 0.0; + + for (int j(2); j < navigation_mesh_polygon_size; j++) { + const Face3 face = Face3( + transform.xform(vertices_r[indices[0]]), + transform.xform(vertices_r[indices[j - 1]]), + transform.xform(vertices_r[indices[j]])); + + _new_polygon_surface_area += face.get_area(); + } + + polygon.surface_area = _new_polygon_surface_area; + _new_region_surface_area += _new_polygon_surface_area; + + Vector3 polygon_center; real_t sum(0); - for (int j(0); j < mesh_poly.size(); j++) { + for (int j(0); j < navigation_mesh_polygon_size; j++) { int idx = indices[j]; if (idx < 0 || idx >= len) { valid = false; @@ -169,10 +277,10 @@ void NavRegion::update_polygons() { } Vector3 point_position = transform.xform(vertices_r[idx]); - p.points[j].pos = point_position; - p.points[j].key = map->get_point_key(point_position); + polygon.points[j].pos = point_position; + polygon.points[j].key = map->get_point_key(point_position); - center += point_position; // Composing the center of the polygon + polygon_center += point_position; // Composing the center of the polygon if (j >= 2) { Vector3 epa = transform.xform(vertices_r[indices[j - 2]]); @@ -186,9 +294,11 @@ void NavRegion::update_polygons() { ERR_BREAK_MSG(!valid, "The navigation mesh set in this region is not valid!"); } - p.clockwise = sum > 0; - if (mesh_poly.size() != 0) { - p.center = center / real_t(mesh_poly.size()); + polygon.clockwise = sum > 0; + if (!navigation_mesh_polygon.is_empty()) { + polygon.center = polygon_center / real_t(navigation_mesh_polygon.size()); } } + + surface_area = _new_region_surface_area; } diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index 6a8ebe5336..a9cfc53c7e 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -50,6 +50,8 @@ class NavRegion : public NavBase { /// Cache LocalVector<gd::Polygon> polygons; + real_t surface_area = 0.0; + public: NavRegion() { type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION; @@ -93,6 +95,10 @@ public: return polygons; } + Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const; + + real_t get_surface_area() const { return surface_area; }; + bool sync(); private: diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index 6ddd8b9078..aa5ccc96dc 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -112,6 +112,8 @@ struct Polygon { /// The center of this `Polygon` Vector3 center; + + real_t surface_area = 0.0; }; struct NavigationPoly { diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp index 1100367f03..1e6a9bbb6a 100644 --- a/modules/ogg/ogg_packet_sequence.cpp +++ b/modules/ogg/ogg_packet_sequence.cpp @@ -159,9 +159,7 @@ bool OggPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const { *p_packet = packet; - if (!packet->e_o_s) { // Added this so it doesn't try to go to the next packet if it's the last packet of the file. - packet_cursor++; - } + packet_cursor++; return true; } diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index 72866f1cf7..bbcb63a7e6 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -177,7 +177,6 @@ void OpenXRActionMap::create_default_action_sets() { Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); - Ref<OpenXRAction> grip_touch = action_set->add_new_action("grip_touch", "Grip touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> grip_force = action_set->add_new_action("grip_force", "Grip force", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 6d1c215ffc..666d20d7e7 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -129,9 +129,11 @@ </member> <member name="foveation_dynamic" type="bool" setter="set_foveation_dynamic" getter="get_foveation_dynamic" default="false"> Enable dynamic foveation adjustment, the interface must be initialized before this is accessible. If enabled foveation will automatically adjusted between low and [member foveation_level]. + [b]Note:[/b] Only works on compatibility renderer. </member> <member name="foveation_level" type="int" setter="set_foveation_level" getter="get_foveation_level" default="0"> Set foveation level from 0 (off) to 3 (high), the interface must be initialized before this is accessible. + [b]Note:[/b] Only works on compatibility renderer. </member> <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. diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 3c606de670..da6fd2e9b2 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -87,7 +87,7 @@ String OpenXRAPI::get_default_action_map_resource_name() { return name; } -String OpenXRAPI::get_error_string(XrResult result) { +String OpenXRAPI::get_error_string(XrResult result) const { if (XR_SUCCEEDED(result)) { return String("Succeeded"); } @@ -1261,6 +1261,7 @@ bool OpenXRAPI::resolve_instance_openxr_symbols() { OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat); OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f); OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile); + OPENXR_API_INIT_XR_FUNC_V(xrGetReferenceSpaceBoundsRect); OPENXR_API_INIT_XR_FUNC_V(xrGetSystem); OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties); OPENXR_API_INIT_XR_FUNC_V(xrLocateViews); @@ -2072,6 +2073,25 @@ void OpenXRAPI::set_foveation_dynamic(bool p_foveation_dynamic) { } } +Size2 OpenXRAPI::get_play_space_bounds() const { + Size2 ret; + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Size2()); + + XrExtent2Df extents; + + XrResult result = xrGetReferenceSpaceBoundsRect(session, reference_space, &extents); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get play space bounds! [", get_error_string(result), "]"); + return ret; + } + + ret.width = extents.width; + ret.height = extents.height; + + return ret; +} + OpenXRAPI::OpenXRAPI() { // OpenXRAPI is only constructed if OpenXR is enabled. singleton = this; diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 64769b244c..efa32b7544 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -199,6 +199,7 @@ private: EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateVector2f, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateVector2f *), state) EXT_PROTO_XRRESULT_FUNC3(xrGetCurrentInteractionProfile, (XrSession), session, (XrPath), topLevelUserPath, (XrInteractionProfileState *), interactionProfile) EXT_PROTO_XRRESULT_FUNC2(xrGetInstanceProperties, (XrInstance), instance, (XrInstanceProperties *), instanceProperties) + EXT_PROTO_XRRESULT_FUNC3(xrGetReferenceSpaceBoundsRect, (XrSession), session, (XrReferenceSpaceType), referenceSpaceType, (XrExtent2Df *), bounds) EXT_PROTO_XRRESULT_FUNC3(xrGetSystem, (XrInstance), instance, (const XrSystemGetInfo *), getInfo, (XrSystemId *), systemId) EXT_PROTO_XRRESULT_FUNC3(xrGetSystemProperties, (XrInstance), instance, (XrSystemId), systemId, (XrSystemProperties *), properties) EXT_PROTO_XRRESULT_FUNC4(xrLocateSpace, (XrSpace), space, (XrSpace), baseSpace, (XrTime), time, (XrSpaceLocation *), location) @@ -317,7 +318,7 @@ public: XrResult try_get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr); XrResult get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr); - String get_error_string(XrResult result); + String get_error_string(XrResult result) const; String get_swapchain_format_name(int64_t p_swapchain_format) const; void set_xr_interface(OpenXRInterface *p_xr_interface); @@ -380,6 +381,9 @@ public: bool get_foveation_dynamic() const; void set_foveation_dynamic(bool p_foveation_dynamic); + // Play space. + Size2 get_play_space_bounds() const; + // action map String get_default_action_map_resource_name(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 8ce76a5fad..66f8192c9e 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -690,6 +690,42 @@ bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) { return false; } +PackedVector3Array OpenXRInterface::get_play_area() const { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, PackedVector3Array()); + PackedVector3Array arr; + + Vector3 sides[4] = { + Vector3(-0.5f, 0.0f, -0.5f), + Vector3(0.5f, 0.0f, -0.5f), + Vector3(0.5f, 0.0f, 0.5f), + Vector3(-0.5f, 0.0f, 0.5f), + }; + + if (openxr_api != nullptr && openxr_api->is_initialized()) { + Size2 extents = openxr_api->get_play_space_bounds(); + if (extents.width != 0.0 && extents.height != 0.0) { + Transform3D reference_frame = xr_server->get_reference_frame(); + + for (int i = 0; i < 4; i++) { + Vector3 coord = sides[i]; + + // Scale it up. + coord.x *= extents.width; + coord.z *= extents.height; + + // Now apply our reference. + Vector3 out = reference_frame.xform(coord); + arr.push_back(out); + } + } else { + WARN_PRINT_ONCE("OpenXR: No extents available."); + } + } + + return arr; +} + float OpenXRInterface::get_display_refresh_rate() const { if (openxr_api == nullptr) { return 0.0; diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 51ef4ea228..489d0845ba 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -125,6 +125,7 @@ public: virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override; virtual XRInterface::PlayAreaMode get_play_area_mode() const override; virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override; + virtual PackedVector3Array get_play_area() const override; float get_display_refresh_rate() const; void set_display_refresh_rate(float p_refresh_rate); diff --git a/modules/squish/image_decompress_squish.cpp b/modules/squish/image_decompress_squish.cpp index 5b35a2643a..fba76621d6 100644 --- a/modules/squish/image_decompress_squish.cpp +++ b/modules/squish/image_decompress_squish.cpp @@ -36,7 +36,9 @@ void image_decompress_squish(Image *p_image) { int w = p_image->get_width(); int h = p_image->get_height(); + Image::Format source_format = p_image->get_format(); Image::Format target_format = Image::FORMAT_RGBA8; + Vector<uint8_t> data; int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); int mm_count = p_image->get_mipmap_count(); @@ -45,33 +47,49 @@ void image_decompress_squish(Image *p_image) { const uint8_t *rb = p_image->get_data().ptr(); uint8_t *wb = data.ptrw(); - int squish_flags = Image::FORMAT_MAX; - if (p_image->get_format() == Image::FORMAT_DXT1) { - squish_flags = squish::kDxt1; - } else if (p_image->get_format() == Image::FORMAT_DXT3) { - squish_flags = squish::kDxt3; - } else if (p_image->get_format() == Image::FORMAT_DXT5 || p_image->get_format() == Image::FORMAT_DXT5_RA_AS_RG) { - squish_flags = squish::kDxt5; - } else if (p_image->get_format() == Image::FORMAT_RGTC_R) { - squish_flags = squish::kBc4; - } else if (p_image->get_format() == Image::FORMAT_RGTC_RG) { - squish_flags = squish::kBc5; - } else { - ERR_FAIL_MSG("Squish: Can't decompress unknown format: " + itos(p_image->get_format()) + "."); + int squish_flags = 0; + + switch (source_format) { + case Image::FORMAT_DXT1: + squish_flags = squish::kDxt1; + break; + + case Image::FORMAT_DXT3: + squish_flags = squish::kDxt3; + break; + + case Image::FORMAT_DXT5: + case Image::FORMAT_DXT5_RA_AS_RG: + squish_flags = squish::kDxt5; + break; + + case Image::FORMAT_RGTC_R: + squish_flags = squish::kBc4; + break; + + case Image::FORMAT_RGTC_RG: + squish_flags = squish::kBc5; + break; + + default: + ERR_FAIL_MSG("Squish: Can't decompress unknown format: " + itos(p_image->get_format()) + "."); + break; } for (int i = 0; i <= mm_count; i++) { int src_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0; p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h); + int dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i); squish::DecompressImage(&wb[dst_ofs], w, h, &rb[src_ofs], squish_flags); + w >>= 1; h >>= 1; } p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); - if (p_image->get_format() == Image::FORMAT_DXT5_RA_AS_RG) { + if (source_format == Image::FORMAT_DXT5_RA_AS_RG) { p_image->convert_ra_rgba8_to_rg(); } } diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 6d0a398218..bcc7bff909 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -3504,6 +3504,9 @@ void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2 } void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; // Non visual character, skip. + } FontAdvanced *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -3541,6 +3544,9 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { + if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) { + return; // Nothing to draw. + } ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); if (gl.texture_idx != -1) { @@ -3608,6 +3614,9 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; // Non visual character, skip. + } FontAdvanced *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -3645,6 +3654,9 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { + if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) { + return; // Nothing to draw. + } ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); if (gl.texture_idx != -1) { @@ -4048,6 +4060,20 @@ String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shap return sd->custom_punct; } +void TextServerAdvanced::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) { + _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_NULL(sd); + sd->el_char = p_char; +} + +int64_t TextServerAdvanced::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_NULL_V(sd, 0); + return sd->el_char; +} + void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_NULL(sd); @@ -4800,6 +4826,166 @@ double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const Pac return 0.0; } +RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) { + RID f; + // Try system fallback. + String font_name = _font_get_name(p_fdef); + BitField<FontStyle> font_style = _font_get_style(p_fdef); + int font_weight = _font_get_weight(p_fdef); + int font_stretch = _font_get_stretch(p_fdef); + Dictionary dvar = _font_get_variation_coordinates(p_fdef); + static int64_t wgth_tag = _name_to_tag("weight"); + static int64_t wdth_tag = _name_to_tag("width"); + static int64_t ital_tag = _name_to_tag("italic"); + if (dvar.has(wgth_tag)) { + font_weight = dvar[wgth_tag].operator int(); + } + if (dvar.has(wdth_tag)) { + font_stretch = dvar[wdth_tag].operator int(); + } + if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { + font_style.set_flag(TextServer::FONT_ITALIC); + } + + String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, p_text, locale, p_script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); +#ifdef GDEXTENSION + for (int fb = 0; fb < fallback_font_name.size(); fb++) { + const String &E = fallback_font_name[fb]; +#else + for (const String &E : fallback_font_name) { +#endif + SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this); + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { + const SystemFontCacheRec &F = sysf_cache.var[face_idx]; + if (unlikely(!_font_has_char(F.rid, p_text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(F.rid); + int weight = _font_get_weight(F.rid); + int stretch = _font_get_stretch(F.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match != -1) { + f = sysf_cache.var[best_match].rid; + } + } + if (!f.is_valid()) { + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + if (sysf_cache.max_var == sysf_cache.var.size()) { + // All subfonts already tested, skip. + continue; + } + } + + if (!system_font_data.has(E)) { + system_font_data[E] = FileAccess::get_file_as_bytes(E); + } + + const PackedByteArray &font_data = system_font_data[E]; + + SystemFontCacheRec sysf; + sysf.rid = _create_font(); + _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); + + Dictionary var = dvar; + // Select matching style from collection. + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { + _font_set_face_index(sysf.rid, face_idx); + if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(sysf.rid); + int weight = _font_get_weight(sysf.rid); + int stretch = _font_get_stretch(sysf.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match == -1) { + _free_rid(sysf.rid); + continue; + } else { + _font_set_face_index(sysf.rid, best_match); + } + sysf.index = best_match; + + // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. + if (best_score != 70) { + Dictionary ftr = _font_supported_variation_list(sysf.rid); + if (ftr.has(wdth_tag)) { + var[wdth_tag] = font_stretch; + _font_set_stretch(sysf.rid, font_stretch); + } + if (ftr.has(wgth_tag)) { + var[wgth_tag] = font_weight; + _font_set_weight(sysf.rid, font_weight); + } + if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { + var[ital_tag] = 1; + _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); + } + } + + _font_set_antialiasing(sysf.rid, key.antialiasing); + _font_set_generate_mipmaps(sysf.rid, key.mipmaps); + _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); + _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); + _font_set_msdf_size(sysf.rid, key.msdf_source_size); + _font_set_fixed_size(sysf.rid, key.fixed_size); + _font_set_force_autohinter(sysf.rid, key.force_autohinter); + _font_set_hinting(sysf.rid, key.hinting); + _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); + _font_set_variation_coordinates(sysf.rid, var); + _font_set_oversampling(sysf.rid, key.oversampling); + _font_set_embolden(sysf.rid, key.embolden); + _font_set_transform(sysf.rid, key.transform); + _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]); + _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]); + _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]); + _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]); + + if (system_fonts.has(key)) { + system_fonts[key].var.push_back(sysf); + } else { + SystemFontCache &sysf_cache = system_fonts[key]; + sysf_cache.max_var = _font_get_face_count(sysf.rid); + sysf_cache.var.push_back(sysf); + } + f = sysf.rid; + } + break; + } + return f; +} + void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid."); @@ -4842,20 +5028,52 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ int sd_size = sd->glyphs.size(); int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; + bool found_el_char = false; // Find usable fonts, if fonts from the last glyph do not have required chars. RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!_font_has_char(dot_gl_font_rid, '.')) { + if (!_font_has_char(dot_gl_font_rid, sd->el_char)) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (_font_has_char(fonts[i], '.')) { + if (_font_has_char(fonts[i], sd->el_char)) { dot_gl_font_rid = fonts[i]; + found_el_char = true; break; } } + if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) { + const char32_t u32str[] = { sd->el_char, 0 }; + RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, u32str); + if (rid.is_valid()) { + dot_gl_font_rid = rid; + found_el_char = true; + } + } + } else { + found_el_char = true; + } + if (!found_el_char) { + bool found_dot_char = false; + dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!_font_has_char(dot_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (_font_has_char(fonts[i], '.')) { + dot_gl_font_rid = fonts[i]; + found_dot_char = true; + break; + } + } + if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) { + RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, "."); + if (rid.is_valid()) { + dot_gl_font_rid = rid; + } + } + } } RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!_font_has_char(whitespace_gl_font_rid, '.')) { + if (!_font_has_char(whitespace_gl_font_rid, ' ')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { if (_font_has_char(fonts[i], ' ')) { @@ -4865,14 +5083,14 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ } } - int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10; + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, (found_el_char ? sd->el_char : '.'), 0) : -1; Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); - int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10; + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1; Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { - ellipsis_width = 3 * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + ellipsis_width = (found_el_char ? 1 : 3) * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; @@ -4951,7 +5169,7 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ if (dot_gl_idx != 0) { Glyph gl; gl.count = 1; - gl.repeat = 3; + gl.repeat = (found_el_char ? 1 : 3); gl.advance = dot_adv.x; gl.index = dot_gl_idx; gl.font_rid = dot_gl_font_rid; @@ -5580,166 +5798,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star break; } } - String text = p_sd->text.substr(p_start, next - p_start); - - String font_name = _font_get_name(fdef); - BitField<FontStyle> font_style = _font_get_style(fdef); - int font_weight = _font_get_weight(fdef); - int font_stretch = _font_get_stretch(fdef); - Dictionary dvar = _font_get_variation_coordinates(fdef); - static int64_t wgth_tag = _name_to_tag("weight"); - static int64_t wdth_tag = _name_to_tag("width"); - static int64_t ital_tag = _name_to_tag("italic"); - if (dvar.has(wgth_tag)) { - font_weight = dvar[wgth_tag].operator int(); - } - if (dvar.has(wdth_tag)) { - font_stretch = dvar[wdth_tag].operator int(); - } - if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { - font_style.set_flag(TextServer::FONT_ITALIC); - } - char scr_buffer[5] = { 0, 0, 0, 0, 0 }; hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer); String script_code = String(scr_buffer); - String locale = (p_sd->spans[p_span].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_sd->spans[p_span].language; - - PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); -#ifdef GDEXTENSION - for (int fb = 0; fb < fallback_font_name.size(); fb++) { - const String &E = fallback_font_name[fb]; -#else - for (const String &E : fallback_font_name) { -#endif - SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this); - if (system_fonts.has(key)) { - const SystemFontCache &sysf_cache = system_fonts[key]; - int best_score = 0; - int best_match = -1; - for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { - const SystemFontCacheRec &F = sysf_cache.var[face_idx]; - if (unlikely(!_font_has_char(F.rid, text[0]))) { - continue; - } - BitField<FontStyle> style = _font_get_style(F.rid); - int weight = _font_get_weight(F.rid); - int stretch = _font_get_stretch(F.rid); - int score = (20 - Math::abs(weight - font_weight) / 50); - score += (20 - Math::abs(stretch - font_stretch) / 10); - if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { - score += 30; - } - if (score >= best_score) { - best_score = score; - best_match = face_idx; - } - if (best_score == 70) { - break; - } - } - if (best_match != -1) { - f = sysf_cache.var[best_match].rid; - } - } - if (!f.is_valid()) { - if (system_fonts.has(key)) { - const SystemFontCache &sysf_cache = system_fonts[key]; - if (sysf_cache.max_var == sysf_cache.var.size()) { - // All subfonts already tested, skip. - continue; - } - } - if (!system_font_data.has(E)) { - system_font_data[E] = FileAccess::get_file_as_bytes(E); - } - - const PackedByteArray &font_data = system_font_data[E]; - - SystemFontCacheRec sysf; - sysf.rid = _create_font(); - _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); - - Dictionary var = dvar; - // Select matching style from collection. - int best_score = 0; - int best_match = -1; - for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { - _font_set_face_index(sysf.rid, face_idx); - if (unlikely(!_font_has_char(sysf.rid, text[0]))) { - continue; - } - BitField<FontStyle> style = _font_get_style(sysf.rid); - int weight = _font_get_weight(sysf.rid); - int stretch = _font_get_stretch(sysf.rid); - int score = (20 - Math::abs(weight - font_weight) / 50); - score += (20 - Math::abs(stretch - font_stretch) / 10); - if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { - score += 30; - } - if (score >= best_score) { - best_score = score; - best_match = face_idx; - } - if (best_score == 70) { - break; - } - } - if (best_match == -1) { - _free_rid(sysf.rid); - continue; - } else { - _font_set_face_index(sysf.rid, best_match); - } - sysf.index = best_match; - - // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. - if (best_score != 70) { - Dictionary ftr = _font_supported_variation_list(sysf.rid); - if (ftr.has(wdth_tag)) { - var[wdth_tag] = font_stretch; - _font_set_stretch(sysf.rid, font_stretch); - } - if (ftr.has(wgth_tag)) { - var[wgth_tag] = font_weight; - _font_set_weight(sysf.rid, font_weight); - } - if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { - var[ital_tag] = 1; - _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); - } - } - - _font_set_antialiasing(sysf.rid, key.antialiasing); - _font_set_generate_mipmaps(sysf.rid, key.mipmaps); - _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); - _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); - _font_set_msdf_size(sysf.rid, key.msdf_source_size); - _font_set_fixed_size(sysf.rid, key.fixed_size); - _font_set_force_autohinter(sysf.rid, key.force_autohinter); - _font_set_hinting(sysf.rid, key.hinting); - _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); - _font_set_variation_coordinates(sysf.rid, var); - _font_set_oversampling(sysf.rid, key.oversampling); - _font_set_embolden(sysf.rid, key.embolden); - _font_set_transform(sysf.rid, key.transform); - _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]); - _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]); - _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]); - _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]); - - if (system_fonts.has(key)) { - system_fonts[key].var.push_back(sysf); - } else { - SystemFontCache &sysf_cache = system_fonts[key]; - sysf_cache.max_var = _font_get_face_count(sysf.rid); - sysf_cache.var.push_back(sysf); - } - f = sysf.rid; - } - break; - } + String text = p_sd->text.substr(p_start, next - p_start); + f = _find_sys_font_for_text(fdef, script_code, p_sd->spans[p_span].language, text); } } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index cbd2911aaf..e5d0ab3105 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -502,6 +502,7 @@ class TextServerAdvanced : public TextServerExtension { double upos = 0.0; double uthk = 0.0; + char32_t el_char = 0x2026; TrimData overrun_trim_data; bool fit_width_minimum_reached = false; @@ -647,6 +648,7 @@ class TextServerAdvanced : public TextServerExtension { bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const; void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end); Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size); + _FORCE_INLINE_ RID _find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text); _FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs); @@ -899,6 +901,9 @@ public: MODBIND2(shaped_text_set_custom_punctuation, const RID &, const String &); MODBIND1RC(String, shaped_text_get_custom_punctuation, const RID &); + MODBIND2(shaped_text_set_custom_ellipsis, const RID &, int64_t); + MODBIND1RC(int64_t, shaped_text_get_custom_ellipsis, const RID &); + MODBIND2(shaped_text_set_orientation, const RID &, Orientation); MODBIND1RC(Orientation, shaped_text_get_orientation, const RID &); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index f12275d10c..8fc7694aa4 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -2439,6 +2439,9 @@ void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2 } void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; // Non visual character, skip. + } FontFallback *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -2476,6 +2479,9 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { + if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) { + return; // Nothing to draw. + } ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); if (gl.texture_idx != -1) { @@ -2543,6 +2549,9 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; // Non visual character, skip. + } FontFallback *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -2580,6 +2589,9 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { + if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) { + return; // Nothing to draw. + } ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); if (gl.texture_idx != -1) { @@ -2905,6 +2917,20 @@ String TextServerFallback::_shaped_text_get_custom_punctuation(const RID &p_shap return sd->custom_punct; } +void TextServerFallback::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) { + _THREAD_SAFE_METHOD_ + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_NULL(sd); + sd->el_char = p_char; +} + +int64_t TextServerFallback::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_NULL_V(sd, 0); + return sd->el_char; +} + void TextServerFallback::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_NULL(sd); @@ -3601,6 +3627,168 @@ bool TextServerFallback::_shaped_text_update_justification_ops(const RID &p_shap return true; } +RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) { + RID f; + // Try system fallback. + if (_font_is_allow_system_fallback(p_fdef)) { + String font_name = _font_get_name(p_fdef); + BitField<FontStyle> font_style = _font_get_style(p_fdef); + int font_weight = _font_get_weight(p_fdef); + int font_stretch = _font_get_stretch(p_fdef); + Dictionary dvar = _font_get_variation_coordinates(p_fdef); + static int64_t wgth_tag = _name_to_tag("weight"); + static int64_t wdth_tag = _name_to_tag("width"); + static int64_t ital_tag = _name_to_tag("italic"); + if (dvar.has(wgth_tag)) { + font_weight = dvar[wgth_tag].operator int(); + } + if (dvar.has(wdth_tag)) { + font_stretch = dvar[wdth_tag].operator int(); + } + if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { + font_style.set_flag(TextServer::FONT_ITALIC); + } + + String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, p_text, locale, p_script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); +#ifdef GDEXTENSION + for (int fb = 0; fb < fallback_font_name.size(); fb++) { + const String &E = fallback_font_name[fb]; +#else + for (const String &E : fallback_font_name) { +#endif + SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this); + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { + const SystemFontCacheRec &F = sysf_cache.var[face_idx]; + if (unlikely(!_font_has_char(F.rid, p_text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(F.rid); + int weight = _font_get_weight(F.rid); + int stretch = _font_get_stretch(F.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match != -1) { + f = sysf_cache.var[best_match].rid; + } + } + if (!f.is_valid()) { + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + if (sysf_cache.max_var == sysf_cache.var.size()) { + // All subfonts already tested, skip. + continue; + } + } + + if (!system_font_data.has(E)) { + system_font_data[E] = FileAccess::get_file_as_bytes(E); + } + + const PackedByteArray &font_data = system_font_data[E]; + + SystemFontCacheRec sysf; + sysf.rid = _create_font(); + _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); + + Dictionary var = dvar; + // Select matching style from collection. + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { + _font_set_face_index(sysf.rid, face_idx); + if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(sysf.rid); + int weight = _font_get_weight(sysf.rid); + int stretch = _font_get_stretch(sysf.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match == -1) { + _free_rid(sysf.rid); + continue; + } else { + _font_set_face_index(sysf.rid, best_match); + } + sysf.index = best_match; + + // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. + if (best_score != 70) { + Dictionary ftr = _font_supported_variation_list(sysf.rid); + if (ftr.has(wdth_tag)) { + var[wdth_tag] = font_stretch; + _font_set_stretch(sysf.rid, font_stretch); + } + if (ftr.has(wgth_tag)) { + var[wgth_tag] = font_weight; + _font_set_weight(sysf.rid, font_weight); + } + if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { + var[ital_tag] = 1; + _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); + } + } + + _font_set_antialiasing(sysf.rid, key.antialiasing); + _font_set_generate_mipmaps(sysf.rid, key.mipmaps); + _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); + _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); + _font_set_msdf_size(sysf.rid, key.msdf_source_size); + _font_set_fixed_size(sysf.rid, key.fixed_size); + _font_set_force_autohinter(sysf.rid, key.force_autohinter); + _font_set_hinting(sysf.rid, key.hinting); + _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); + _font_set_variation_coordinates(sysf.rid, var); + _font_set_oversampling(sysf.rid, key.oversampling); + _font_set_embolden(sysf.rid, key.embolden); + _font_set_transform(sysf.rid, key.transform); + _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]); + _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]); + _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]); + _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]); + + if (system_fonts.has(key)) { + system_fonts[key].var.push_back(sysf); + } else { + SystemFontCache &sysf_cache = system_fonts[key]; + sysf_cache.max_var = _font_get_face_count(sysf.rid); + sysf_cache.var.push_back(sysf); + } + f = sysf.rid; + } + break; + } + } + return f; +} + void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_NULL_MSG(sd, "ShapedTextDataFallback invalid."); @@ -3643,20 +3831,52 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ int sd_size = sd->glyphs.size(); int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; + bool found_el_char = false; // Find usable fonts, if fonts from the last glyph do not have required chars. RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!_font_has_char(dot_gl_font_rid, '.')) { + if (!_font_has_char(dot_gl_font_rid, sd->el_char)) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (_font_has_char(fonts[i], '.')) { + if (_font_has_char(fonts[i], sd->el_char)) { dot_gl_font_rid = fonts[i]; + found_el_char = true; break; } } + if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) { + const char32_t u32str[] = { sd->el_char, 0 }; + RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, u32str); + if (rid.is_valid()) { + dot_gl_font_rid = rid; + found_el_char = true; + } + } + } else { + found_el_char = true; + } + if (!found_el_char) { + bool found_dot_char = false; + dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!_font_has_char(dot_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (_font_has_char(fonts[i], '.')) { + dot_gl_font_rid = fonts[i]; + found_dot_char = true; + break; + } + } + if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) { + RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, "."); + if (rid.is_valid()) { + dot_gl_font_rid = rid; + } + } + } } RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!_font_has_char(whitespace_gl_font_rid, '.')) { + if (!_font_has_char(whitespace_gl_font_rid, ' ')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { if (_font_has_char(fonts[i], ' ')) { @@ -3666,14 +3886,14 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ } } - int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10; + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, (found_el_char ? sd->el_char : '.'), 0) : -1; Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); - int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10; + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1; Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { - ellipsis_width = 3 * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + ellipsis_width = (found_el_char ? 1 : 3) * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; @@ -3742,7 +3962,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ if (dot_gl_idx != 0) { Glyph gl; gl.count = 1; - gl.repeat = 3; + gl.repeat = (found_el_char ? 1 : 3); gl.advance = dot_adv.x; gl.index = dot_gl_idx; gl.font_rid = dot_gl_font_rid; @@ -3873,161 +4093,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { RID fdef = span.fonts[0]; if (_font_is_allow_system_fallback(fdef)) { String text = sd->text.substr(j, 1); - String font_name = _font_get_name(fdef); - BitField<FontStyle> font_style = _font_get_style(fdef); - int font_weight = _font_get_weight(fdef); - int font_stretch = _font_get_stretch(fdef); - Dictionary dvar = _font_get_variation_coordinates(fdef); - static int64_t wgth_tag = _name_to_tag("weight"); - static int64_t wdth_tag = _name_to_tag("width"); - static int64_t ital_tag = _name_to_tag("italic"); - if (dvar.has(wgth_tag)) { - font_weight = dvar[wgth_tag].operator int(); - } - if (dvar.has(wdth_tag)) { - font_stretch = dvar[wdth_tag].operator int(); - } - if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { - font_style.set_flag(TextServer::FONT_ITALIC); - } - - String locale = (span.language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : span.language; - - PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, String(), font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); -#ifdef GDEXTENSION - for (int fb = 0; fb < fallback_font_name.size(); fb++) { - const String &E = fallback_font_name[fb]; -#else - for (const String &E : fallback_font_name) { -#endif - SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this); - if (system_fonts.has(key)) { - const SystemFontCache &sysf_cache = system_fonts[key]; - int best_score = 0; - int best_match = -1; - for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { - const SystemFontCacheRec &F = sysf_cache.var[face_idx]; - if (unlikely(!_font_has_char(F.rid, text[0]))) { - continue; - } - BitField<FontStyle> style = _font_get_style(F.rid); - int weight = _font_get_weight(F.rid); - int stretch = _font_get_stretch(F.rid); - int score = (20 - Math::abs(weight - font_weight) / 50); - score += (20 - Math::abs(stretch - font_stretch) / 10); - if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { - score += 30; - } - if (score >= best_score) { - best_score = score; - best_match = face_idx; - } - if (best_score == 70) { - break; - } - } - if (best_match != -1) { - gl.font_rid = sysf_cache.var[best_match].rid; - } - } - if (!gl.font_rid.is_valid()) { - if (system_fonts.has(key)) { - const SystemFontCache &sysf_cache = system_fonts[key]; - if (sysf_cache.max_var == sysf_cache.var.size()) { - // All subfonts already tested, skip. - continue; - } - } - - if (!system_font_data.has(E)) { - system_font_data[E] = FileAccess::get_file_as_bytes(E); - } - - const PackedByteArray &font_data = system_font_data[E]; - - SystemFontCacheRec sysf; - sysf.rid = _create_font(); - _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); - - Dictionary var = dvar; - // Select matching style from collection. - int best_score = 0; - int best_match = -1; - for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { - _font_set_face_index(sysf.rid, face_idx); - if (unlikely(!_font_has_char(sysf.rid, text[0]))) { - continue; - } - BitField<FontStyle> style = _font_get_style(sysf.rid); - int weight = _font_get_weight(sysf.rid); - int stretch = _font_get_stretch(sysf.rid); - int score = (20 - Math::abs(weight - font_weight) / 50); - score += (20 - Math::abs(stretch - font_stretch) / 10); - if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { - score += 30; - } - if (score >= best_score) { - best_score = score; - best_match = face_idx; - } - if (best_score == 70) { - break; - } - } - if (best_match == -1) { - _free_rid(sysf.rid); - continue; - } else { - _font_set_face_index(sysf.rid, best_match); - } - sysf.index = best_match; - - // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. - if (best_score != 70) { - Dictionary ftr = _font_supported_variation_list(sysf.rid); - if (ftr.has(wdth_tag)) { - var[wdth_tag] = font_stretch; - _font_set_stretch(sysf.rid, font_stretch); - } - if (ftr.has(wgth_tag)) { - var[wgth_tag] = font_weight; - _font_set_weight(sysf.rid, font_weight); - } - if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { - var[ital_tag] = 1; - _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); - } - } - - _font_set_antialiasing(sysf.rid, key.antialiasing); - _font_set_generate_mipmaps(sysf.rid, key.mipmaps); - _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); - _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); - _font_set_msdf_size(sysf.rid, key.msdf_source_size); - _font_set_fixed_size(sysf.rid, key.fixed_size); - _font_set_force_autohinter(sysf.rid, key.force_autohinter); - _font_set_hinting(sysf.rid, key.hinting); - _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); - _font_set_variation_coordinates(sysf.rid, var); - _font_set_oversampling(sysf.rid, key.oversampling); - _font_set_embolden(sysf.rid, key.embolden); - _font_set_transform(sysf.rid, key.transform); - _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]); - _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]); - _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]); - _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]); - - if (system_fonts.has(key)) { - system_fonts[key].var.push_back(sysf); - } else { - SystemFontCache &sysf_cache = system_fonts[key]; - sysf_cache.max_var = _font_get_face_count(sysf.rid); - sysf_cache.var.push_back(sysf); - } - gl.font_rid = sysf.rid; - } - break; - } + gl.font_rid = _find_sys_font_for_text(fdef, String(), span.language, text); } } prev_font = gl.font_rid; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 5c30ea0c05..68e0cbff6c 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -447,6 +447,7 @@ class TextServerFallback : public TextServerExtension { double upos = 0.0; double uthk = 0.0; + char32_t el_char = 0x2026; TrimData overrun_trim_data; bool fit_width_minimum_reached = false; @@ -555,6 +556,7 @@ class TextServerFallback : public TextServerExtension { mutable HashMap<String, PackedByteArray> system_font_data; void _realign(ShapedTextDataFallback *p_sd) const; + _FORCE_INLINE_ RID _find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text); Mutex ft_mutex; @@ -766,6 +768,9 @@ public: MODBIND2(shaped_text_set_custom_punctuation, const RID &, const String &); MODBIND1RC(String, shaped_text_get_custom_punctuation, const RID &); + MODBIND2(shaped_text_set_custom_ellipsis, const RID &, int64_t); + MODBIND1RC(int64_t, shaped_text_get_custom_ellipsis, const RID &); + MODBIND2(shaped_text_set_orientation, const RID &, Orientation); MODBIND1RC(Orientation, shaped_text_get_orientation, const RID &); diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index f64bb14e4a..8720ca56f6 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -68,6 +68,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitF if (ret != TINYEXR_SUCCESS) { if (err) { ERR_PRINT(String(err)); + FreeEXRErrorMessage(err); } return ERR_FILE_CORRUPT; } @@ -86,6 +87,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitF if (ret != TINYEXR_SUCCESS) { if (err) { ERR_PRINT(String(err)); + FreeEXRErrorMessage(err); } return ERR_FILE_CORRUPT; } diff --git a/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml index 7e3af6688a..d2f6745e2f 100644 --- a/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml @@ -7,6 +7,7 @@ The AudioStreamOggVorbis class is a specialized [AudioStream] for handling Ogg Vorbis file formats. It offers functionality for loading and playing back Ogg Vorbis files, as well as managing looping and other playback properties. This class is part of the audio stream system, which also supports WAV files through the [AudioStreamWAV] class. </description> <tutorials> + <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <methods> <method name="load_from_buffer" qualifiers="static"> diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp index 26af912999..def34220ea 100644 --- a/modules/vorbis/register_types.cpp +++ b/modules/vorbis/register_types.cpp @@ -48,8 +48,13 @@ void initialize_vorbis_module(ModuleInitializationLevel p_level) { ResourceFormatImporter::get_singleton()->add_importer(ogg_vorbis_importer); } + ClassDB::APIType prev_api = ClassDB::get_current_api(); + ClassDB::set_current_api(ClassDB::API_EDITOR); + // Required to document import options in the class reference. GDREGISTER_CLASS(ResourceImporterOggVorbis); + + ClassDB::set_current_api(prev_api); #endif GDREGISTER_CLASS(AudioStreamOggVorbis); diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index a8c92f06f6..bf5d964d39 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -90,7 +90,7 @@ bool ResourceImporterOggVorbis::has_advanced_options() const { void ResourceImporterOggVorbis::show_advanced_options(const String &p_path) { Ref<AudioStreamOggVorbis> ogg_stream = load_from_file(p_path); if (ogg_stream.is_valid()) { - AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream); + AudioStreamImportSettingsDialog::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream); } } #endif diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index 454f8f2ed4..8698c5755a 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml @@ -76,7 +76,7 @@ <method name="get_signaling_state" qualifiers="const"> <return type="int" enum="WebRTCPeerConnection.SignalingState" /> <description> - Returns the [enum SignalingState] on the local end of the connection while connecting or reconnecting to another peer. + Returns the signaling state on the local end of the connection while connecting or reconnecting to another peer. </description> </method> <method name="initialize"> diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 47f20ce1a3..828476edfb 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -309,7 +309,7 @@ void WebXRInterfaceJS::uninitialize() { godot_webxr_uninitialize(); - GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage); + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); if (texture_storage != nullptr) { for (KeyValue<unsigned int, RID> &E : texture_cache) { // Forcibly mark as not part of a render target so we can free it. @@ -438,16 +438,11 @@ Projection WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p_a } bool WebXRInterfaceJS::pre_draw_viewport(RID p_render_target) { - GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage); + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); if (texture_storage == nullptr) { return false; } - GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target); - if (rt == nullptr) { - return false; - } - // Cache the resources so we don't have to get them from JS twice. color_texture = _get_color_texture(); depth_texture = _get_depth_texture(); @@ -460,23 +455,9 @@ bool WebXRInterfaceJS::pre_draw_viewport(RID p_render_target) { // // See: https://immersive-web.github.io/layers/#xropaquetextures // - // This is why we're doing this sort of silly check: if the color and depth - // textures are the same this frame as last frame, we need to attach them - // again, despite the fact that the GLuint for them hasn't changed. - if (rt->overridden.is_overridden && rt->overridden.color == color_texture && rt->overridden.depth == depth_texture) { - GLES3::Config *config = GLES3::Config::get_singleton(); - bool use_multiview = rt->view_count > 1 && config->multiview_supported; - - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - if (use_multiview) { - glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count); - glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count); - } else { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } - glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo); - } + // So, even if the color and depth textures have the same GLuint as the last + // frame, we need to re-attach them again. + texture_storage->render_target_set_reattach_textures(p_render_target, true); return true; } @@ -484,7 +465,12 @@ bool WebXRInterfaceJS::pre_draw_viewport(RID p_render_target) { Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { Vector<BlitToScreen> blit_to_screen; - // We don't need to do anything here. + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + if (texture_storage == nullptr) { + return blit_to_screen; + } + + texture_storage->render_target_set_reattach_textures(p_render_target, false); return blit_to_screen; }; @@ -513,7 +499,7 @@ RID WebXRInterfaceJS::_get_texture(unsigned int p_texture_id) { return cache->get(); } - GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage); + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); if (texture_storage == nullptr) { return RID(); } diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp index 5f623476fc..e67c65d4d1 100644 --- a/modules/zip/zip_packer.cpp +++ b/modules/zip/zip_packer.cpp @@ -72,7 +72,24 @@ Error ZIPPacker::start_file(const String &p_path) { zipfi.internal_fa = 0; zipfi.external_fa = 0; - int err = zipOpenNewFileInZip(zf, p_path.utf8().get_data(), &zipfi, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION); + int err = zipOpenNewFileInZip4(zf, + p_path.utf8().get_data(), + &zipfi, + nullptr, + 0, + nullptr, + 0, + nullptr, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION, + 0, + -MAX_WBITS, + DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, + nullptr, + 0, + 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions. + 1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8. return err == ZIP_OK ? OK : FAILED; } |