summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/arkit/arkit_interface.mm4
-rw-r--r--modules/assimp/SCsub30
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp19
-rw-r--r--modules/basis_universal/SCsub17
-rw-r--r--modules/bullet/SCsub14
-rw-r--r--modules/bullet/bullet_physics_server.cpp16
-rw-r--r--modules/bullet/bullet_physics_server.h3
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp8
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h3
-rw-r--r--modules/bullet/rigid_body_bullet.cpp13
-rw-r--r--modules/bullet/rigid_body_bullet.h2
-rw-r--r--modules/bullet/space_bullet.cpp14
-rw-r--r--modules/csg/csg_gizmos.cpp2
-rw-r--r--modules/csg/csg_gizmos.h2
-rw-r--r--modules/cvtt/SCsub15
-rw-r--r--modules/denoise/SCsub17
-rw-r--r--modules/enet/SCsub16
-rw-r--r--modules/etc/SCsub15
-rw-r--r--modules/etc/image_compress_etc.cpp (renamed from modules/etc/image_etc.cpp)10
-rw-r--r--modules/etc/image_compress_etc.h (renamed from modules/etc/image_etc.h)8
-rw-r--r--modules/etc/register_types.cpp2
-rw-r--r--modules/freetype/SCsub14
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp12
-rw-r--r--modules/gdnative/include/gdnative/variant.h2
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h2
-rw-r--r--modules/gdnative/include/text/godot_text.h3
-rw-r--r--modules/gdnative/nativescript/nativescript.h8
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp30
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h7
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h18
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp18
-rw-r--r--modules/gdnative/text/text_server_gdnative.h4
-rw-r--r--modules/gdnavigation/SCsub31
-rw-r--r--modules/gdnavigation/nav_map.cpp2
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.cpp8
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml86
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h2
-rw-r--r--modules/gdscript/gdscript.cpp262
-rw-r--r--modules/gdscript/gdscript.h37
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp126
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp85
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h33
-rw-r--r--modules/gdscript/gdscript_codegen.h6
-rw-r--r--modules/gdscript/gdscript_compiler.cpp115
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp48
-rw-r--r--modules/gdscript/gdscript_editor.cpp76
-rw-r--r--modules/gdscript/gdscript_function.h17
-rw-r--r--modules/gdscript/gdscript_functions.cpp1942
-rw-r--r--modules/gdscript/gdscript_parser.cpp282
-rw-r--r--modules/gdscript/gdscript_parser.h40
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp20
-rw-r--r--modules/gdscript/gdscript_tokenizer.h20
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp718
-rw-r--r--modules/gdscript/gdscript_utility_functions.h (renamed from modules/gdscript/gdscript_functions.h)123
-rw-r--r--modules/gdscript/gdscript_vm.cpp91
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp3
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp3
-rw-r--r--modules/gdscript/language_server/lsp.hpp2
-rw-r--r--modules/gdscript/register_types.cpp4
-rw-r--r--modules/glslang/SCsub18
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp4
-rw-r--r--modules/jpg/SCsub17
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp75
-rwxr-xr-xmodules/mbedtls/SCsub25
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp71
-rw-r--r--modules/mbedtls/crypto_mbedtls.h22
-rw-r--r--modules/mbedtls/register_types.cpp4
-rw-r--r--modules/mbedtls/tests/test_crypto_mbedtls.cpp62
-rw-r--r--modules/mbedtls/tests/test_crypto_mbedtls.h61
-rw-r--r--modules/meshoptimizer/SCsub45
-rw-r--r--modules/meshoptimizer/config.py7
-rw-r--r--modules/meshoptimizer/register_types.cpp43
-rw-r--r--modules/meshoptimizer/register_types.h37
-rw-r--r--modules/minimp3/SCsub17
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp228
-rw-r--r--modules/minimp3/audio_stream_mp3.h110
-rw-r--r--modules/minimp3/config.py16
-rw-r--r--modules/minimp3/doc_classes/AudioStreamMP3.xml26
-rw-r--r--modules/minimp3/register_types.cpp52
-rw-r--r--modules/minimp3/register_types.h37
-rw-r--r--modules/minimp3/resource_importer_mp3.cpp104
-rw-r--r--modules/minimp3/resource_importer_mp3.h58
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py4
-rw-r--r--modules/mono/build_scripts/mono_configure.py10
-rw-r--r--modules/mono/config.py8
-rw-r--r--modules/mono/csharp_script.cpp2
-rw-r--r--modules/mono/csharp_script.h9
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs36
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs45
-rw-r--r--modules/mono/editor/bindings_generator.cpp73
-rw-r--r--modules/mono/editor/bindings_generator.h9
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp139
-rw-r--r--modules/mono/editor/godotsharp_export.cpp8
-rw-r--r--modules/mono/editor/script_class_parser.h10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs5
-rw-r--r--modules/mono/glue/base_object_glue.cpp28
-rw-r--r--modules/mono/glue/collections_glue.cpp106
-rw-r--r--modules/mono/glue/gd_glue.cpp50
-rw-r--r--modules/mono/glue/nodepath_glue.cpp22
-rw-r--r--modules/mono/glue/rid_glue.cpp6
-rw-r--r--modules/mono/glue/scene_tree_glue.cpp2
-rw-r--r--modules/mono/glue/string_glue.cpp12
-rw-r--r--modules/mono/glue/string_name_glue.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h11
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp319
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp6
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp952
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h43
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp25
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h11
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp5
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h20
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.cpp79
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h263
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp4
-rw-r--r--modules/mono/signal_awaiter_utils.cpp24
-rw-r--r--modules/ogg/SCsub16
-rw-r--r--modules/opensimplex/SCsub17
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml16
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp14
-rw-r--r--modules/opensimplex/open_simplex_noise.h24
-rw-r--r--modules/opus/SCsub19
-rw-r--r--modules/pvr/SCsub15
-rw-r--r--modules/pvr/image_compress_pvrtc.cpp84
-rw-r--r--modules/pvr/image_compress_pvrtc.h36
-rw-r--r--modules/pvr/register_types.cpp3
-rw-r--r--modules/pvr/texture_loader_pvr.cpp58
-rw-r--r--modules/regex/SCsub18
-rw-r--r--modules/squish/SCsub16
-rw-r--r--modules/stb_vorbis/SCsub17
-rw-r--r--modules/svg/SCsub17
-rw-r--r--modules/text_server_adv/SCsub62
-rw-r--r--modules/text_server_adv/bitmap_font_adv.cpp15
-rw-r--r--modules/text_server_adv/bitmap_font_adv.h3
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp126
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h11
-rw-r--r--modules/text_server_adv/font_adv.h4
-rw-r--r--modules/text_server_adv/script_iterator.cpp3
-rw-r--r--modules/text_server_adv/text_server_adv.cpp225
-rw-r--r--modules/text_server_adv/text_server_adv.h4
-rw-r--r--modules/text_server_fb/SCsub1
-rw-r--r--modules/text_server_fb/bitmap_font_fb.cpp1
-rw-r--r--modules/text_server_fb/dynamic_font_fb.cpp62
-rw-r--r--modules/text_server_fb/dynamic_font_fb.h5
-rw-r--r--modules/text_server_fb/text_server_fb.cpp113
-rw-r--r--modules/theora/SCsub16
-rw-r--r--modules/tinyexr/SCsub17
-rw-r--r--modules/upnp/SCsub15
-rw-r--r--modules/vhacd/SCsub17
-rw-r--r--modules/visual_script/visual_script.cpp2
-rw-r--r--modules/visual_script/visual_script.h8
-rw-r--r--modules/visual_script/visual_script_editor.cpp12
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp9
-rw-r--r--modules/vorbis/SCsub20
-rw-r--r--modules/webm/SCsub15
-rw-r--r--modules/webm/libvpx/SCsub2
-rw-r--r--modules/webp/SCsub16
-rw-r--r--modules/webrtc/SCsub2
-rw-r--r--modules/webrtc/library_godot_webrtc.js22
-rw-r--r--modules/websocket/SCsub32
-rw-r--r--modules/websocket/library_godot_websocket.js4
-rw-r--r--modules/xatlas_unwrap/SCsub16
-rw-r--r--modules/xatlas_unwrap/register_types.cpp6
169 files changed, 5506 insertions, 3785 deletions
diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm
index e8fa023ac7..6d69f4a2f4 100644
--- a/modules/arkit/arkit_interface.mm
+++ b/modules/arkit/arkit_interface.mm
@@ -712,8 +712,8 @@ void ARKitInterface::_add_or_update_anchor(GodotARAnchor *p_anchor) {
int16_t index = planeAnchor.geometry.triangleIndices[j];
simd_float3 vrtx = planeAnchor.geometry.vertices[index];
simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index];
- surftool->add_uv(Vector2(textcoord[0], textcoord[1]));
- surftool->add_color(Color(0.8, 0.8, 0.8));
+ surftool->set_uv(Vector2(textcoord[0], textcoord[1]));
+ surftool->set_color(Color(0.8, 0.8, 0.8));
surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2]));
}
diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub
index f1d0c742b4..7213efb74d 100644
--- a/modules/assimp/SCsub
+++ b/modules/assimp/SCsub
@@ -5,8 +5,13 @@ Import("env_modules")
env_assimp = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
# Force bundled version for now, there's no released version of Assimp with
# support for ArmaturePopulate which we use from their master branch.
+
if True: # env['builtin_assimp']:
thirdparty_dir = "#thirdparty/assimp"
@@ -84,11 +89,20 @@ if True: # env['builtin_assimp']:
env_thirdparty = env_assimp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Common/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Material/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
-
-# Godot's own source files
-env_assimp.add_source_files(env.modules_sources, "*.cpp")
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Common/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Material/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_assimp.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
index e5becfd559..796ee27a7d 100644
--- a/modules/assimp/editor_scene_importer_assimp.cpp
+++ b/modules/assimp/editor_scene_importer_assimp.cpp
@@ -827,8 +827,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
Ref<ArrayMesh> mesh;
mesh.instance();
bool has_uvs = false;
- bool compress_vert_data = state.import_flags & IMPORT_USE_COMPRESSION;
- uint32_t mesh_flags = compress_vert_data ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
+ uint32_t mesh_flags = 0;
Map<String, uint32_t> morph_mesh_string_lookup;
@@ -839,7 +838,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName);
if (!morph_mesh_string_lookup.has(ai_anim_mesh_name)) {
morph_mesh_string_lookup.insert(ai_anim_mesh_name, j);
- mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
+ mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED);
if (ai_anim_mesh_name.empty()) {
ai_anim_mesh_name = String("morph_") + itos(j);
}
@@ -904,33 +903,33 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
// Get the texture coordinates if they exist
if (ai_mesh->HasTextureCoords(0)) {
has_uvs = true;
- st->add_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y));
+ st->set_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y));
}
if (ai_mesh->HasTextureCoords(1)) {
has_uvs = true;
- st->add_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y));
+ st->set_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y));
}
// Assign vertex colors
if (ai_mesh->HasVertexColors(0)) {
Color color = Color(ai_mesh->mColors[0]->r, ai_mesh->mColors[0]->g, ai_mesh->mColors[0]->b,
ai_mesh->mColors[0]->a);
- st->add_color(color);
+ st->set_color(color);
}
// Work out normal calculations? - this needs work it doesn't work properly on huestos
if (ai_mesh->mNormals != nullptr) {
const aiVector3D normals = ai_mesh->mNormals[j];
const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
- st->add_normal(godot_normal);
+ st->set_normal(godot_normal);
if (ai_mesh->HasTangentsAndBitangents()) {
const aiVector3D tangents = ai_mesh->mTangents[j];
const Vector3 godot_tangent = Vector3(tangents.x, tangents.y, tangents.z);
const aiVector3D bitangent = ai_mesh->mBitangents[j];
const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
- st->add_tangent(Plane(tangents.x, tangents.y, tangents.z, d));
+ st->set_tangent(Plane(tangents.x, tangents.y, tangents.z, d));
}
}
@@ -948,8 +947,8 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
weights.write[k] = bone_info[k].weight;
}
- st->add_bones(bones);
- st->add_weights(weights);
+ st->set_bones(bones);
+ st->set_weights(weights);
}
// Assign vertex
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub
index dc7b176d24..351628a0e3 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_basisu = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/basis_universal/"
tool_sources = [
@@ -41,8 +44,16 @@ if env["target"] == "debug":
env_thirdparty = env_basisu.Clone()
env_thirdparty.disable_warnings()
if env["tools"]:
- env_thirdparty.add_source_files(env.modules_sources, tool_sources)
-env_thirdparty.add_source_files(env.modules_sources, transcoder_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, tool_sources)
+env_thirdparty.add_source_files(thirdparty_obj, transcoder_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_basisu.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_basisu.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index 21bdcca18e..bfac0df5b0 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -7,6 +7,8 @@ env_bullet = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_bullet"]:
# Build only version 2 for now (as of 2.89)
# Sync file list with relevant upstream CMakeLists.txt for each folder.
@@ -208,8 +210,16 @@ if env["builtin_bullet"]:
env_thirdparty = env_bullet.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
# Godot source files
-env_bullet.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_bullet.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 663ad6e3e1..3b548b7faa 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -1463,22 +1463,6 @@ bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Ax
return generic_6dof_joint->get_flag(p_axis, p_flag);
}
-void BulletPhysicsServer3D::generic_6dof_joint_set_precision(RID p_joint, int p_precision) {
- JointBullet *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
- Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
- generic_6dof_joint->set_precision(p_precision);
-}
-
-int BulletPhysicsServer3D::generic_6dof_joint_get_precision(RID p_joint) {
- JointBullet *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
- Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
- return generic_6dof_joint->get_precision();
-}
-
void BulletPhysicsServer3D::free(RID p_rid) {
if (shape_owner.owns(p_rid)) {
ShapeBullet *shape = shape_owner.getornull(p_rid);
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index dca9339c44..07a32e510c 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -376,9 +376,6 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) override;
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) override;
- virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) override;
- virtual int generic_6dof_joint_get_precision(RID p_joint) override;
-
/* MISC */
virtual void free(RID p_rid) override;
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index 56a66dba45..d75bf1fb98 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -273,11 +273,3 @@ bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6D
ERR_FAIL_INDEX_V(p_axis, 3, false);
return flags[p_axis][p_flag];
}
-
-void Generic6DOFJointBullet::set_precision(int p_precision) {
- sixDOFConstraint->setOverrideNumSolverIterations(MAX(1, p_precision));
-}
-
-int Generic6DOFJointBullet::get_precision() const {
- return sixDOFConstraint->getOverrideNumSolverIterations();
-}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index 316708bb11..ed25337745 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -68,9 +68,6 @@ public:
void set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value);
bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const;
-
- void set_precision(int p_precision);
- int get_precision() const;
};
#endif
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index eb599df74c..284a22717b 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -323,9 +323,6 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) {
can_integrate_forces = false;
isScratchedSpaceOverrideModificator = false;
- // Remove all eventual constraints
- assert_no_constraints();
-
// Remove this object form the physics world
space->remove_rigid_body(this);
}
@@ -443,12 +440,6 @@ bool RigidBodyBullet::was_colliding(RigidBodyBullet *p_other_object) {
return false;
}
-void RigidBodyBullet::assert_no_constraints() {
- if (btBody->getNumConstraintRefs()) {
- WARN_PRINT("A body with a joints is destroyed. Please check the implementation in order to destroy the joint before the body.");
- }
-}
-
void RigidBodyBullet::set_activation_state(bool p_active) {
if (p_active) {
btBody->activate();
@@ -744,7 +735,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
}
btBody->setCcdSweptSphereRadius(radius * 0.2);
} else {
- btBody->setCcdMotionThreshold(10000.0);
+ btBody->setCcdMotionThreshold(0.);
btBody->setCcdSweptSphereRadius(0.);
}
}
@@ -824,7 +815,7 @@ void RigidBodyBullet::reload_shapes() {
btBody->updateInertiaTensor();
reload_kinematic_shapes();
- set_continuous_collision_detection(btBody->getCcdMotionThreshold() < 9998.0);
+ set_continuous_collision_detection(is_continuous_collision_detection_enabled());
reload_body();
}
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index c643611397..8ff96577b6 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -267,8 +267,6 @@ public:
bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index);
bool was_colliding(RigidBodyBullet *p_other_object);
- void assert_no_constraints();
-
void set_activation_state(bool p_active);
bool is_active() const;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index abad1beacb..3bfcd83606 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -478,10 +478,20 @@ void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) {
}
void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) {
+ btRigidBody *btBody = p_body->get_bt_rigid_body();
+
+ int constraints = btBody->getNumConstraintRefs();
+ if (constraints > 0) {
+ WARN_PRINT("A body connected to joints was removed. Ensure bodies are disconnected from joints before removing them.");
+ for (int i = 0; i < constraints; i++) {
+ dynamicsWorld->removeConstraint(btBody->getConstraintRef(i));
+ }
+ }
+
if (p_body->is_static()) {
- dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
+ dynamicsWorld->removeCollisionObject(btBody);
} else {
- dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body());
+ dynamicsWorld->removeRigidBody(btBody);
}
}
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index cce72770f5..f8c05761bb 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -319,7 +319,7 @@ bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial);
}
-String CSGShape3DGizmoPlugin::get_name() const {
+String CSGShape3DGizmoPlugin::get_gizmo_name() const {
return "CSGShape3D";
}
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 83ee847caf..cf44f76f37 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -40,7 +40,7 @@ class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
public:
bool has_gizmo(Node3D *p_spatial) override;
- String get_name() const override;
+ String get_gizmo_name() const override;
int get_priority() const override;
bool is_selectable_when_hidden() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
diff --git a/modules/cvtt/SCsub b/modules/cvtt/SCsub
index 5438f7ebac..e56177d6e9 100644
--- a/modules/cvtt/SCsub
+++ b/modules/cvtt/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_cvtt = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/cvtt/"
thirdparty_sources = [
"ConvectionKernels.cpp",
@@ -17,7 +20,15 @@ env_cvtt.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_cvtt.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_cvtt.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_cvtt.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub
index bf3bd7d073..97feea2b44 100644
--- a/modules/denoise/SCsub
+++ b/modules/denoise/SCsub
@@ -8,6 +8,9 @@ Import("env_modules")
env_oidn = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/oidn/"
thirdparty_sources = [
"core/api.cpp",
@@ -106,7 +109,8 @@ env_oidn.Append(
env_thirdparty = env_oidn.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
@@ -114,5 +118,12 @@ weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
env_thirdparty.Depends(weights_out_path, weights_in_path)
env_thirdparty.CommandNoCache(weights_out_path, weights_in_path, resource_to_cpp.tza_to_cpp)
-env_oidn.add_source_files(env.modules_sources, "denoise_wrapper.cpp")
-env_modules.add_source_files(env.modules_sources, ["register_types.cpp", "lightmap_denoiser.cpp"])
+# Godot source files
+
+module_obj = []
+
+env_oidn.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/enet/SCsub b/modules/enet/SCsub
index c8f4b3885e..580e5a3eb0 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -7,6 +7,8 @@ env_enet = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_enet"]:
thirdparty_dir = "#thirdparty/enet/"
thirdparty_sources = [
@@ -26,6 +28,16 @@ if env["builtin_enet"]:
env_thirdparty = env_enet.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_enet.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_enet.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
index 383bbf83c3..9b46f17916 100644
--- a/modules/etc/SCsub
+++ b/modules/etc/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_etc = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/etc2comp/"
thirdparty_sources = [
@@ -31,7 +34,15 @@ env_etc.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_etc.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_etc.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_etc.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_compress_etc.cpp
index 4e9e64c6a7..bcdea41b43 100644
--- a/modules/etc/image_etc.cpp
+++ b/modules/etc/image_compress_etc.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_etc.cpp */
+/* image_compress_etc.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "image_etc.h"
-#include "Etc.h"
-#include "EtcFilter.h"
+#include "image_compress_etc.h"
+
#include "core/io/image.h"
#include "core/os/copymem.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
+#include <Etc.h>
+#include <EtcFilter.h>
+
static Image::Format _get_etc2_mode(Image::UsedChannels format) {
switch (format) {
case Image::USED_CHANNELS_R:
diff --git a/modules/etc/image_etc.h b/modules/etc/image_compress_etc.h
index 7b4f26e127..016e64e4fc 100644
--- a/modules/etc/image_etc.h
+++ b/modules/etc/image_compress_etc.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_etc.h */
+/* image_compress_etc.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_ETC1_H
-#define IMAGE_ETC1_H
+#ifndef IMAGE_COMPRESS_ETC_H
+#define IMAGE_COMPRESS_ETC_H
void _register_etc_compress_func();
-#endif // IMAGE_ETC_H
+#endif // IMAGE_COMPRESS_ETC_H
diff --git a/modules/etc/register_types.cpp b/modules/etc/register_types.cpp
index 0972857808..225ba6b954 100644
--- a/modules/etc/register_types.cpp
+++ b/modules/etc/register_types.cpp
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "image_etc.h"
+#include "image_compress_etc.h"
#include "texture_loader_pkm.h"
static Ref<ResourceFormatPKM> resource_loader_pkm;
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index bfc1658bb4..fc2535a6ca 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_freetype = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_freetype"]:
thirdparty_dir = "#thirdparty/freetype/"
thirdparty_sources = [
@@ -84,6 +87,7 @@ if env["builtin_freetype"]:
env_thirdparty = env_freetype.Clone()
env_thirdparty.disable_warnings()
lib = env_thirdparty.add_library("freetype_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -98,5 +102,13 @@ if env["builtin_freetype"]:
if not inserted:
env.Append(LIBS=[lib])
+
# Godot source files
-env_freetype.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_freetype.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index f0f095ddf5..52f8c837c4 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -308,11 +308,11 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
platform_android.library_extension = "*.so";
platforms["Android"] = platform_android;
- // TODO: Javascript platform is not supported yet
- // NativePlatformConfig platform_html5;
- // platform_html5.name = "HTML5";
- // platform_html5.library_extension = "*.wasm";
- // platforms["Javascript"] = platform_html5;
+ NativePlatformConfig platform_html5;
+ platform_html5.name = "HTML5";
+ platform_html5.entries.push_back("wasm32");
+ platform_html5.library_extension = "*.wasm";
+ platforms["HTML5"] = platform_html5;
NativePlatformConfig platform_ios;
platform_ios.name = "iOS";
@@ -382,7 +382,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
new_architecture_dialog->add_child(new_architecture_input);
// new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE);
new_architecture_input->set_anchors_and_margins_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE);
- new_architecture_dialog->get_ok()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
+ new_architecture_dialog->get_ok_button()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
}
void GDNativeLibraryEditorPlugin::edit(Object *p_node) {
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 0a611b76e9..2e803d602b 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -52,7 +52,7 @@ typedef enum godot_variant_type {
// atomic types
GODOT_VARIANT_TYPE_BOOL,
GODOT_VARIANT_TYPE_INT,
- GODOT_VARIANT_TYPE_REAL,
+ GODOT_VARIANT_TYPE_FLOAT,
GODOT_VARIANT_TYPE_STRING,
// math types
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index 406c3ba663..e4b1fd5eb0 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -72,6 +72,7 @@ typedef struct {
godot_string_name name;
godot_bool is_tool;
godot_string_name base;
+ godot_string icon_path;
// Member lines format: {<string>: <int>}
godot_dictionary member_lines;
@@ -127,6 +128,7 @@ typedef struct {
const char **string_delimiters; // nullptr terminated array
godot_bool has_named_classes;
godot_bool supports_builtin_mode;
+ godot_bool can_inherit_from_file;
godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name);
godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions);
diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h
index 2eac6adfb5..6885f2463d 100644
--- a/modules/gdnative/include/text/godot_text.h
+++ b/modules/gdnative/include/text/godot_text.h
@@ -82,6 +82,9 @@ typedef struct {
void (*font_set_antialiased)(void *, godot_rid *, bool);
bool (*font_get_antialiased)(void *, godot_rid *);
godot_dictionary (*font_get_feature_list)(void *, godot_rid *);
+ godot_dictionary (*font_get_variation_list)(void *, godot_rid *);
+ void (*font_set_variation)(void *, godot_rid *, const godot_string *, double);
+ double (*font_get_variation)(void *, godot_rid *, const godot_string *);
void (*font_set_distance_field_hint)(void *, godot_rid *, bool);
bool (*font_get_distance_field_hint)(void *, godot_rid *);
void (*font_set_hinting)(void *, godot_rid *, godot_int);
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 2aaa4be325..e91d9b7bfb 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -31,6 +31,7 @@
#ifndef NATIVE_SCRIPT_H
#define NATIVE_SCRIPT_H
+#include "core/doc_data.h"
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
@@ -152,6 +153,13 @@ public:
virtual void set_source_code(const String &p_code) override;
virtual Error reload(bool p_keep_state = false) override;
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ static Vector<DocData::ClassDoc> docs;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual bool has_method(const StringName &p_method) const override;
virtual MethodInfo get_method_info(const StringName &p_method) const override;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index fc9c4ebd77..df685e716f 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -142,6 +142,10 @@ bool PluginScriptLanguage::supports_builtin_mode() const {
return _desc.supports_builtin_mode;
}
+bool PluginScriptLanguage::can_inherit_from_file() const {
+ return _desc.can_inherit_from_file;
+}
+
int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const {
if (_desc.find_function) {
return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code);
@@ -398,6 +402,32 @@ void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool
#endif
}
+bool PluginScriptLanguage::handles_global_class_type(const String &p_type) const {
+ return p_type == "PluginScript";
+}
+
+String PluginScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
+ if (!p_path.empty()) {
+ Ref<PluginScript> script = ResourceLoader::load(p_path, "PluginScript");
+ if (script.is_valid()) {
+ if (r_base_type) {
+ *r_base_type = script->get_instance_base_type();
+ }
+ if (r_icon_path) {
+ *r_icon_path = script->get_script_class_icon_path();
+ }
+ return script->get_script_class_name();
+ }
+ if (r_base_type) {
+ *r_base_type = String();
+ }
+ if (r_icon_path) {
+ *r_icon_path = String();
+ }
+ }
+ return String();
+}
+
void PluginScriptLanguage::lock() {
_lock.lock();
}
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index 53e1e3ae9b..7548eba4a0 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -78,7 +78,7 @@ public:
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
- virtual bool can_inherit_from_file() { return true; }
+ virtual bool can_inherit_from_file() const;
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const;
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint);
@@ -122,6 +122,11 @@ public:
virtual void frame();
+ /* GLOBAL CLASSES */
+
+ virtual bool handles_global_class_type(const String &p_type) const;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const;
+
void lock();
void unlock();
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 87c6288806..d69ab2fcb7 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -302,6 +302,7 @@ Error PluginScript::reload(bool p_keep_state) {
_data = manifest.data;
_name = *(StringName *)&manifest.name;
_tool = manifest.is_tool;
+ _icon_path = *(String *)&manifest.icon_path;
Dictionary *members = (Dictionary *)&manifest.member_lines;
for (const Variant *key = members->next(); key != nullptr; key = members->next(key)) {
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index 150de05e74..12d93cc407 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -32,6 +32,8 @@
#define PLUGINSCRIPT_SCRIPT_H
// Godot imports
+
+#include "core/doc_data.h"
#include "core/object/script_language.h"
// PluginScript imports
#include "pluginscript_language.h"
@@ -67,6 +69,7 @@ private:
String _source;
String _path;
StringName _name;
+ String _icon_path;
protected:
static void _bind_methods();
@@ -82,6 +85,14 @@ protected:
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
public:
+ String get_script_class_name() const {
+ return _name;
+ }
+
+ String get_script_class_icon_path() const {
+ return _icon_path;
+ }
+
virtual bool can_instance() const override;
virtual Ref<Script> get_base_script() const override; //for script inheritance
@@ -97,6 +108,13 @@ public:
// TODO: load_source_code only allow utf-8 file, should handle bytecode as well ?
virtual Error load_source_code(const String &p_path);
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ static Vector<DocData::ClassDoc> docs;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual bool has_method(const StringName &p_method) const override;
virtual MethodInfo get_method_info(const StringName &p_method) const override;
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index 68624260a6..cb87adafe8 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -148,6 +148,24 @@ bool TextServerGDNative::font_get_antialiased(RID p_font) const {
return interface->font_get_antialiased(data, (godot_rid *)&p_font);
}
+Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, Dictionary());
+ godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font);
+ Dictionary info = *(Dictionary *)&result;
+ godot_dictionary_destroy(&result);
+
+ return info;
+}
+
+void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value);
+}
+
+double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const {
+ return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name);
+}
+
void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
ERR_FAIL_COND(interface == nullptr);
interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting);
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
index 0196120c00..959302aaf4 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -76,6 +76,10 @@ public:
virtual bool font_get_antialiased(RID p_font) const override;
virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;
diff --git a/modules/gdnavigation/SCsub b/modules/gdnavigation/SCsub
index 877d601c6a..22b5509b32 100644
--- a/modules/gdnavigation/SCsub
+++ b/modules/gdnavigation/SCsub
@@ -5,6 +5,10 @@ Import("env_modules")
env_navigation = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
# Recast Thirdparty source files
if env["builtin_recast"]:
thirdparty_dir = "#thirdparty/recastnavigation/Recast/"
@@ -23,28 +27,37 @@ if env["builtin_recast"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_navigation.Prepend(CPPPATH=[thirdparty_dir + "/Include"])
+ env_navigation.Prepend(CPPPATH=[thirdparty_dir + "Include"])
env_thirdparty = env_navigation.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
-
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
# RVO Thirdparty source files
if env["builtin_rvo2"]:
- thirdparty_dir = "#thirdparty/rvo2"
+ thirdparty_dir = "#thirdparty/rvo2/"
thirdparty_sources = [
- "/src/Agent.cpp",
- "/src/KdTree.cpp",
+ "Agent.cpp",
+ "KdTree.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_navigation.Prepend(CPPPATH=[thirdparty_dir + "/src"])
+ env_navigation.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_navigation.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+
+
+env.modules_sources += thirdparty_obj
# Godot source files
-env_navigation.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_navigation.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 7919e6a01f..c8c1b422e8 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -707,7 +707,7 @@ void NavMap::sync() {
}
if (regenerate_links) {
- map_update_id = map_update_id + 1 % 9999999;
+ map_update_id = (map_update_id + 1) % 9999999;
}
if (agents_dirty) {
diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/gdnavigation/navigation_mesh_generator.cpp
index 5329600e39..3310123ca9 100644
--- a/modules/gdnavigation/navigation_mesh_generator.cpp
+++ b/modules/gdnavigation/navigation_mesh_generator.cpp
@@ -176,10 +176,10 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
BoxShape3D *box = Object::cast_to<BoxShape3D>(*s);
if (box) {
- Ref<CubeMesh> cube_mesh;
- cube_mesh.instance();
- cube_mesh->set_size(box->get_extents() * 2.0);
- mesh = cube_mesh;
+ Ref<BoxMesh> box_mesh;
+ box_mesh.instance();
+ box_mesh->set_size(box->get_extents() * 2.0);
+ mesh = box_mesh;
}
CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s);
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index d90b3e52d0..4ed129b3ff 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -55,8 +55,7 @@
<description>
Returns the absolute value of parameter [code]s[/code] (i.e. positive value).
[codeblock]
- # a is 1
- a = abs(-1)
+ a = abs(-1) # a is 1
[/codeblock]
</description>
</method>
@@ -166,10 +165,10 @@
<description>
Rounds [code]s[/code] upward (towards positive infinity), returning the smallest whole number that is not less than [code]s[/code].
[codeblock]
- i = ceil(1.45) # i is 2
- i = ceil(1.001) # i is 2
+ a = ceil(1.45) # a is 2.0
+ a = ceil(1.001) # a is 2.0
[/codeblock]
- See also [method floor], [method round], and [method stepify].
+ See also [method floor], [method round], [method stepify], and [int].
</description>
</method>
<method name="char">
@@ -199,13 +198,9 @@
<description>
Clamps [code]value[/code] and returns a value not less than [code]min[/code] and not more than [code]max[/code].
[codeblock]
- speed = 1000
- # a is 20
- a = clamp(speed, 1, 20)
-
- speed = -10
- # a is 1
- a = clamp(speed, 1, 20)
+ a = clamp(1000, 1, 20) # a is 20
+ a = clamp(-10, 1, 20) # a is 1
+ a = clamp(15, 1, 20) # a is 15
[/codeblock]
</description>
</method>
@@ -236,9 +231,8 @@
<description>
Returns the cosine of angle [code]s[/code] in radians.
[codeblock]
- # Prints 1 then -1
- print(cos(PI * 2))
- print(cos(PI))
+ a = cos(TAU) # a is 1.0
+ a = cos(PI) # a is -1.0
[/codeblock]
</description>
</method>
@@ -250,8 +244,7 @@
<description>
Returns the hyperbolic cosine of [code]s[/code] in radians.
[codeblock]
- # Prints 1.543081
- print(cosh(1))
+ print(cosh(1)) # Prints 1.543081
[/codeblock]
</description>
</method>
@@ -276,8 +269,7 @@
<description>
Returns the result of [code]value[/code] decreased by [code]step[/code] * [code]amount[/code].
[codeblock]
- # a = 59
- a = dectime(60, 10, 0.1))
+ a = dectime(60, 10, 0.1)) # a is 59.0
[/codeblock]
</description>
</method>
@@ -289,8 +281,7 @@
<description>
Converts an angle expressed in degrees to radians.
[codeblock]
- # r is 3.141593
- r = deg2rad(180)
+ r = deg2rad(180) # r is 3.141593
[/codeblock]
</description>
</method>
@@ -300,7 +291,7 @@
<argument index="0" name="dict" type="Dictionary">
</argument>
<description>
- Converts a previously converted instance to a dictionary, back into an instance. Useful for deserializing.
+ Converts a dictionary (previously created with [method inst2dict]) back to an instance. Useful for deserializing.
</description>
</method>
<method name="ease">
@@ -336,13 +327,12 @@
<description>
Rounds [code]s[/code] downward (towards negative infinity), returning the largest whole number that is not more than [code]s[/code].
[codeblock]
- # a is 2.0
- a = floor(2.99)
- # a is -3.0
- a = floor(-2.99)
+ a = floor(2.45) # a is 2.0
+ a = floor(2.99) # a is 2.0
+ a = floor(-2.99) # a is -3.0
[/codeblock]
- See also [method ceil], [method round], and [method stepify].
- [b]Note:[/b] This method returns a float. If you need an integer, you can use [code]int(s)[/code] directly.
+ See also [method ceil], [method round], [method stepify], and [int].
+ [b]Note:[/b] This method returns a float. If you need an integer and [code]s[/code] is a non-negative number, you can use [code]int(s)[/code] directly.
</description>
</method>
<method name="fmod">
@@ -355,8 +345,7 @@
<description>
Returns the floating-point remainder of [code]a/b[/code], keeping the sign of [code]a[/code].
[codeblock]
- # Remainder is 1.5
- var remainder = fmod(7, 5.5)
+ r = fmod(7, 5.5) # r is 1.5
[/codeblock]
For the integer remainder operation, use the % operator.
</description>
@@ -774,9 +763,9 @@
<argument index="1" name="exp" type="float">
</argument>
<description>
- Returns the result of [code]x[/code] raised to the power of [code]y[/code].
+ Returns the result of [code]base[/code] raised to the power of [code]exp[/code].
[codeblock]
- pow(2, 5) # Returns 32
+ pow(2, 5) # Returns 32.0
[/codeblock]
</description>
</method>
@@ -801,7 +790,7 @@
Converts one or more arguments to strings in the best way possible and prints them to the console.
[codeblock]
a = [1, 2, 3]
- print("a", "b", a) # Prints ab[1, 2, 3]
+ print("a", "=", a) # Prints a=[1, 2, 3]
[/codeblock]
[b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
</description>
@@ -900,7 +889,7 @@
<description>
Converts an angle expressed in radians to degrees.
[codeblock]
- rad2deg(0.523599) # Returns 30
+ rad2deg(0.523599) # Returns 30.0
[/codeblock]
</description>
</method>
@@ -1022,9 +1011,11 @@
<description>
Rounds [code]s[/code] to the nearest whole number, with halfway cases rounded away from zero.
[codeblock]
- round(2.6) # Returns 3
+ a = round(2.49) # a is 2.0
+ a = round(2.5) # a is 3.0
+ a = round(2.51) # a is 3.0
[/codeblock]
- See also [method floor], [method ceil], and [method stepify].
+ See also [method floor], [method ceil], [method stepify], and [int].
</description>
</method>
<method name="seed">
@@ -1094,9 +1085,9 @@
This S-shaped curve is the cubic Hermite interpolator, given by [code]f(s) = 3*s^2 - 2*s^3[/code].
[codeblock]
smoothstep(0, 2, -5.0) # Returns 0.0
- smoothstep(0, 2, 0.5) # Returns 0.15625
- smoothstep(0, 2, 1.0) # Returns 0.5
- smoothstep(0, 2, 2.0) # Returns 1.0
+ smoothstep(0, 2, 0.5) # Returns 0.15625
+ smoothstep(0, 2, 1.0) # Returns 0.5
+ smoothstep(0, 2, 2.0) # Returns 1.0
[/codeblock]
</description>
</method>
@@ -1121,12 +1112,9 @@
<description>
Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation.
[codeblock]
- # n is 0
- n = step_decimals(5)
- # n is 4
- n = step_decimals(1.0005)
- # n is 9
- n = step_decimals(0.000000005)
+ n = step_decimals(5) # n is 0
+ n = step_decimals(1.0005) # n is 4
+ n = step_decimals(0.000000005) # n is 9
[/codeblock]
</description>
</method>
@@ -1140,10 +1128,10 @@
<description>
Snaps float value [code]s[/code] to a given [code]step[/code]. This can also be used to round a floating point number to an arbitrary number of decimals.
[codeblock]
- stepify(100, 32) # Returns 96
+ stepify(100, 32) # Returns 96.0
stepify(3.14159, 0.01) # Returns 3.14
[/codeblock]
- See also [method ceil], [method floor], and [method round].
+ See also [method ceil], [method floor], [method round], and [int].
</description>
</method>
<method name="str" qualifiers="vararg">
@@ -1193,8 +1181,8 @@
<description>
Returns the hyperbolic tangent of [code]s[/code].
[codeblock]
- a = log(2.0) # Returns 0.693147
- tanh(a) # Returns 0.6
+ a = log(2.0) # a is 0.693147
+ b = tanh(a) # b is 0.6
[/codeblock]
</description>
</method>
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 49357f3d2e..e38647eaab 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -42,7 +42,7 @@ private:
Color color;
String start_key;
String end_key;
- bool line_only;
+ bool line_only = false;
};
Vector<ColorRegion> color_regions;
Map<int, int> color_region_cache;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 53602f7a9b..8fa2de7063 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -231,7 +231,7 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
}
#endif
-void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
+void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const {
const GDScript *current = this;
while (current) {
for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) {
@@ -239,18 +239,29 @@ void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
MethodInfo mi;
mi.name = E->key();
for (int i = 0; i < func->get_argument_count(); i++) {
- mi.arguments.push_back(func->get_argument_type(i));
+ PropertyInfo arginfo = func->get_argument_type(i);
+#ifdef TOOLS_ENABLED
+ arginfo.name = func->get_argument_name(i);
+#endif
+ mi.arguments.push_back(arginfo);
}
mi.return_val = func->get_return_type();
- p_list->push_back(mi);
+ r_list->push_back(mi);
+ }
+ if (!p_include_base) {
+ return;
}
current = current->_base;
}
}
-void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
+void GDScript::get_script_method_list(List<MethodInfo> *r_list) const {
+ _get_script_method_list(r_list, true);
+}
+
+void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_include_base) const {
const GDScript *sptr = this;
List<PropertyInfo> props;
@@ -269,15 +280,22 @@ void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
+ if (!p_include_base) {
+ break;
+ }
sptr = sptr->_base;
}
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
- p_list->push_back(E->get());
+ r_list->push_back(E->get());
}
}
+void GDScript::get_script_property_list(List<PropertyInfo> *r_list) const {
+ _get_script_property_list(r_list, true);
+}
+
bool GDScript::has_method(const StringName &p_method) const {
return member_functions.has(p_method);
}
@@ -383,6 +401,183 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro
propnames.push_back(E->get());
}
}
+
+void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {
+ if (_owner) {
+ _owner->_add_doc(p_inner_class);
+ } else {
+ for (int i = 0; i < docs.size(); i++) {
+ if (docs[i].name == p_inner_class.name) {
+ docs.remove(i);
+ break;
+ }
+ }
+ docs.append(p_inner_class);
+ }
+}
+
+void GDScript::_clear_doc() {
+ docs.clear();
+ doc = DocData::ClassDoc();
+}
+
+void GDScript::_update_doc() {
+ _clear_doc();
+
+ doc.script_path = "\"" + get_path().get_slice("://", 1) + "\"";
+ if (!name.empty()) {
+ doc.name = name;
+ } else {
+ doc.name = doc.script_path;
+ }
+
+ if (_owner) {
+ doc.name = _owner->doc.name + "." + doc.name;
+ doc.script_path = doc.script_path + "." + doc.name;
+ }
+
+ doc.is_script_doc = true;
+
+ if (base.is_valid() && base->is_valid()) {
+ if (base->doc.name != String()) {
+ doc.inherits = base->doc.name;
+ } else {
+ doc.inherits = base->get_instance_base_type();
+ }
+ } else if (native.is_valid()) {
+ doc.inherits = native->get_name();
+ }
+
+ doc.brief_description = doc_brief_description;
+ doc.description = doc_description;
+ doc.tutorials = doc_tutorials;
+
+ for (Map<String, DocData::EnumDoc>::Element *E = doc_enums.front(); E; E = E->next()) {
+ if (E->value().description != "") {
+ doc.enums[E->key()] = E->value().description;
+ }
+ }
+
+ List<MethodInfo> methods;
+ _get_script_method_list(&methods, false);
+ for (int i = 0; i < methods.size(); i++) {
+ // Ignore internal methods.
+ if (methods[i].name[0] == '@') {
+ continue;
+ }
+
+ DocData::MethodDoc method_doc;
+ const String &class_name = methods[i].name;
+ if (member_functions.has(class_name)) {
+ GDScriptFunction *fn = member_functions[class_name];
+
+ // Change class name if return type is script reference.
+ GDScriptDataType return_type = fn->get_return_type();
+ if (return_type.kind == GDScriptDataType::GDSCRIPT) {
+ methods[i].return_val.class_name = _get_gdscript_reference_class_name(Object::cast_to<GDScript>(return_type.script_type));
+ }
+
+ // Change class name if argumetn is script reference.
+ for (int j = 0; j < fn->get_argument_count(); j++) {
+ GDScriptDataType arg_type = fn->get_argument_type(j);
+ if (arg_type.kind == GDScriptDataType::GDSCRIPT) {
+ methods[i].arguments[j].class_name = _get_gdscript_reference_class_name(Object::cast_to<GDScript>(arg_type.script_type));
+ }
+ }
+ }
+ if (doc_functions.has(methods[i].name)) {
+ DocData::method_doc_from_methodinfo(method_doc, methods[i], doc_functions[methods[i].name]);
+ } else {
+ DocData::method_doc_from_methodinfo(method_doc, methods[i], String());
+ }
+ doc.methods.push_back(method_doc);
+ }
+
+ List<PropertyInfo> props;
+ _get_script_property_list(&props, false);
+ for (int i = 0; i < props.size(); i++) {
+ ScriptMemberInfo scr_member_info;
+ scr_member_info.propinfo = props[i];
+ scr_member_info.propinfo.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ if (member_indices.has(props[i].name)) {
+ const MemberInfo &mi = member_indices[props[i].name];
+ scr_member_info.setter = mi.setter;
+ scr_member_info.getter = mi.getter;
+ if (mi.data_type.kind == GDScriptDataType::GDSCRIPT) {
+ scr_member_info.propinfo.class_name = _get_gdscript_reference_class_name(
+ Object::cast_to<GDScript>(mi.data_type.script_type));
+ }
+ }
+ if (member_default_values.has(props[i].name)) {
+ scr_member_info.has_default_value = true;
+ scr_member_info.default_value = member_default_values[props[i].name];
+ }
+ if (doc_variables.has(props[i].name)) {
+ scr_member_info.doc_string = doc_variables[props[i].name];
+ }
+
+ DocData::PropertyDoc prop_doc;
+ DocData::property_doc_from_scriptmemberinfo(prop_doc, scr_member_info);
+ doc.properties.push_back(prop_doc);
+ }
+
+ List<MethodInfo> signals;
+ _get_script_signal_list(&signals, false);
+ for (int i = 0; i < signals.size(); i++) {
+ DocData::MethodDoc signal_doc;
+ if (doc_signals.has(signals[i].name)) {
+ DocData::signal_doc_from_methodinfo(signal_doc, signals[i], signals[i].name);
+ } else {
+ DocData::signal_doc_from_methodinfo(signal_doc, signals[i], String());
+ }
+ doc.signals.push_back(signal_doc);
+ }
+
+ for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
+ if (subclasses.has(E->key())) {
+ continue;
+ }
+
+ // Enums.
+ bool is_enum = false;
+ if (E->value().get_type() == Variant::DICTIONARY) {
+ if (doc_enums.has(E->key())) {
+ is_enum = true;
+ for (int i = 0; i < doc_enums[E->key()].values.size(); i++) {
+ doc_enums[E->key()].values.write[i].enumeration = E->key();
+ doc.constants.push_back(doc_enums[E->key()].values[i]);
+ }
+ }
+ }
+ if (!is_enum && doc_enums.has("@unnamed_enums")) {
+ for (int i = 0; i < doc_enums["@unnamed_enums"].values.size(); i++) {
+ if (E->key() == doc_enums["@unnamed_enums"].values[i].name) {
+ is_enum = true;
+ DocData::ConstantDoc constant_doc;
+ constant_doc.enumeration = "@unnamed_enums";
+ DocData::constant_doc_from_variant(constant_doc, E->key(), E->value(), doc_enums["@unnamed_enums"].values[i].description);
+ doc.constants.push_back(constant_doc);
+ break;
+ }
+ }
+ }
+ if (!is_enum) {
+ DocData::ConstantDoc constant_doc;
+ String doc_description;
+ if (doc_constants.has(E->key())) {
+ doc_description = doc_constants[E->key()];
+ }
+ DocData::constant_doc_from_variant(constant_doc, E->key(), E->value(), doc_description);
+ doc.constants.push_back(constant_doc);
+ }
+ }
+
+ for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
+ E->get()->_update_doc();
+ }
+
+ _add_doc(doc);
+}
#endif
bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {
@@ -628,8 +823,12 @@ Error GDScript::reload(bool p_keep_state) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
- // TODO: Show all error messages.
- _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+
+ const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front();
+ while (e != nullptr) {
+ _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ e = e->next();
+ }
ERR_FAIL_V(ERR_PARSE_ERROR);
}
@@ -638,6 +837,10 @@ Error GDScript::reload(bool p_keep_state) {
GDScriptCompiler compiler;
err = compiler.compile(&parser, this, p_keep_state);
+#ifdef TOOLS_ENABLED
+ _update_doc();
+#endif
+
if (err) {
if (can_run) {
if (EngineDebugger::is_active()) {
@@ -911,7 +1114,7 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
return false;
}
-void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const {
for (const Map<StringName, Vector<StringName>>::Element *E = _signals.front(); E; E = E->next()) {
MethodInfo mi;
mi.name = E->key();
@@ -920,20 +1123,43 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
arg.name = E->get()[i];
mi.arguments.push_back(arg);
}
- r_signals->push_back(mi);
+ r_list->push_back(mi);
+ }
+
+ if (!p_include_base) {
+ return;
}
if (base.is_valid()) {
- base->get_script_signal_list(r_signals);
+ base->get_script_signal_list(r_list);
}
#ifdef TOOLS_ENABLED
else if (base_cache.is_valid()) {
- base_cache->get_script_signal_list(r_signals);
+ base_cache->get_script_signal_list(r_list);
}
#endif
}
+void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ _get_script_signal_list(r_signals, true);
+}
+
+String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript) {
+ ERR_FAIL_NULL_V(p_gdscript, String());
+
+ String class_name;
+ while (p_gdscript) {
+ if (class_name == "") {
+ class_name = p_gdscript->get_script_class_name();
+ } else {
+ class_name = p_gdscript->get_script_class_name() + "." + class_name;
+ }
+ p_gdscript = p_gdscript->_owner;
+ }
+ return class_name;
+}
+
GDScript::GDScript() :
script_list(this) {
valid = false;
@@ -1061,6 +1287,13 @@ GDScript::~GDScript() {
_save_orphaned_subclasses();
+#ifdef TOOLS_ENABLED
+ // Clearing inner class doc, script doc only cleared when the script source deleted.
+ if (_owner) {
+ _clear_doc();
+ }
+#endif
+
#ifdef DEBUG_ENABLED
{
MutexLock lock(GDScriptLanguage::get_singleton()->lock);
@@ -1889,8 +2122,11 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
w++;
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- p_words->push_back(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)));
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ p_words->push_back(String(E->get()));
}
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index b69a6e39c0..11c449c5f2 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -33,6 +33,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/doc_data.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/script_language.h"
@@ -71,8 +72,8 @@ class GDScript : public Script {
friend class GDScriptFunction;
friend class GDScriptAnalyzer;
friend class GDScriptCompiler;
- friend class GDScriptFunctions;
friend class GDScriptLanguage;
+ friend struct GDScriptUtilityFunctionsDefinitions;
Ref<GDScriptNativeClass> native;
Ref<GDScript> base;
@@ -91,9 +92,7 @@ class GDScript : public Script {
#ifdef TOOLS_ENABLED
Map<StringName, int> member_lines;
-
Map<StringName, Variant> member_default_values;
-
List<PropertyInfo> members_cache;
Map<StringName, Variant> member_default_values_cache;
Ref<GDScript> base_cache;
@@ -102,6 +101,20 @@ class GDScript : public Script {
bool placeholder_fallback_enabled;
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
+ DocData::ClassDoc doc;
+ Vector<DocData::ClassDoc> docs;
+ String doc_brief_description;
+ String doc_description;
+ Vector<DocData::TutorialDoc> doc_tutorials;
+ Map<String, String> doc_functions;
+ Map<String, String> doc_variables;
+ Map<String, String> doc_constants;
+ Map<String, String> doc_signals;
+ Map<String, DocData::EnumDoc> doc_enums;
+ void _clear_doc();
+ void _update_doc();
+ void _add_doc(const DocData::ClassDoc &p_inner_class);
+
#endif
Map<StringName, PropertyInfo> member_info;
@@ -141,6 +154,13 @@ class GDScript : public Script {
void _save_orphaned_subclasses();
void _init_rpc_methods_properties();
+ void _get_script_property_list(List<PropertyInfo> *r_list, bool p_include_base) const;
+ void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const;
+ void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const;
+
+ // This method will map the class name from "Reference" to "MyClass.InnerClass".
+ static String _get_gdscript_reference_class_name(const GDScript *p_gdscript);
+
protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
@@ -191,6 +211,12 @@ public:
virtual void set_source_code(const String &p_code) override;
virtual void update_exports() override;
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual Error reload(bool p_keep_state = false) override;
void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too...
@@ -244,8 +270,8 @@ public:
class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
- friend class GDScriptFunctions;
friend class GDScriptCompiler;
+ friend struct GDScriptUtilityFunctionsDefinitions;
ObjectID owner_id;
Object *owner;
@@ -444,7 +470,8 @@ public:
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
- virtual bool can_inherit_from_file() { return true; }
+ virtual bool supports_documentation() const;
+ virtual bool can_inherit_from_file() const { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const;
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint);
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 3f2fdc04a5..19951ff17d 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -37,6 +37,7 @@
#include "core/os/file_access.h"
#include "core/templates/hash_map.h"
#include "gdscript.h"
+#include "gdscript_utility_functions.h"
// TODO: Move this to a central location (maybe core?).
static HashMap<StringName, StringName> underscore_map;
@@ -72,6 +73,39 @@ static StringName get_real_class_name(const StringName &p_source) {
return p_source;
}
+static MethodInfo info_from_utility_func(const StringName &p_function) {
+ ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo());
+
+ MethodInfo info(p_function);
+
+ if (Variant::has_utility_function_return_value(p_function)) {
+ info.return_val.type = Variant::get_utility_function_return_type(p_function);
+ if (info.return_val.type == Variant::NIL) {
+ info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ }
+
+ if (Variant::is_utility_function_vararg(p_function)) {
+ info.flags |= METHOD_FLAG_VARARG;
+ } else {
+ for (int i = 0; i < Variant::get_utility_function_argument_count(p_function); i++) {
+ PropertyInfo pi;
+#ifdef DEBUG_METHODS_ENABLED
+ pi.name = Variant::get_utility_function_argument_name(p_function, i);
+#else
+ pi.name = "arg" + itos(i + 1);
+#endif
+ pi.type = Variant::get_utility_function_argument_type(p_function, i);
+ if (pi.type == Variant::NIL) {
+ pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ info.arguments.push_back(pi);
+ }
+ }
+
+ return info;
+}
+
void GDScriptAnalyzer::cleanup() {
underscore_map.clear();
}
@@ -860,7 +894,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, p_function->identifier->name, p_function->parameters[i]->identifier->name);
}
is_shadowing(p_function->parameters[i]->identifier, "function parameter");
-#endif
+#endif // DEBUG_ENABLED
+#ifdef TOOLS_ENABLED
+ if (p_function->parameters[i]->default_value && p_function->parameters[i]->default_value->is_constant) {
+ p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value);
+ }
+#endif // TOOLS_ENABLED
}
if (p_function->identifier->name == "_init") {
@@ -1611,7 +1650,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
if (p_binary_op->reduced_value.get_type() == Variant::STRING) {
push_error(vformat(R"(%s in operator %s.)", p_binary_op->reduced_value, Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op);
} else {
- push_error(vformat(R"(Invalid operands to operator %s, %s and %s.".)",
+ push_error(vformat(R"(Invalid operands to operator %s, %s and %s.)",
Variant::get_operator_name(p_binary_op->variant_op),
Variant::get_type_name(p_binary_op->left_operand->reduced_value.get_type()),
Variant::get_type_name(p_binary_op->right_operand->reduced_value.get_type())),
@@ -1696,7 +1735,6 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
// Call to name directly.
StringName function_name = p_call->function_name;
Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
- GDScriptFunctions::Function builtin_function = GDScriptParser::get_builtin_function(function_name);
if (builtin_type < Variant::VARIANT_MAX) {
// Is a builtin constructor.
@@ -1709,7 +1747,27 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
call_type.native_type = function_name; // "Object".
}
- if (all_is_constant) {
+ bool safe_to_fold = true;
+ switch (builtin_type) {
+ // Those are stored by reference so not suited for compile-time construction.
+ // Because in this case they would be the same reference in all constructed values.
+ case Variant::OBJECT:
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_STRING_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY:
+ safe_to_fold = false;
+ break;
+ default:
+ break;
+ }
+
+ if (all_is_constant && safe_to_fold) {
// Construct here.
Vector<const Variant *> args;
for (int i = 0; i < p_call->arguments.size(); i++) {
@@ -1818,10 +1876,52 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
}
p_call->set_datatype(call_type);
return;
- } else if (builtin_function < GDScriptFunctions::FUNC_MAX) {
- MethodInfo function_info = GDScriptFunctions::get_info(builtin_function);
+ } else if (GDScriptUtilityFunctions::function_exists(function_name)) {
+ MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
+
+ if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
+ // Can call on compilation.
+ Vector<const Variant *> args;
+ for (int i = 0; i < p_call->arguments.size(); i++) {
+ args.push_back(&(p_call->arguments[i]->reduced_value));
+ }
+
+ Variant value;
+ Callable::CallError err;
+ GDScriptUtilityFunctions::get_function(function_name)(&value, (const Variant **)args.ptr(), args.size(), err);
+
+ switch (err.error) {
+ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
+ PropertyInfo wrong_arg = function_info.arguments[err.argument];
+ push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
+ type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
+ p_call->arguments[err.argument]);
+ } break;
+ case Callable::CallError::CALL_ERROR_INVALID_METHOD:
+ push_error(vformat(R"(Invalid call for function "%s".)", function_name), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
+ push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
+ break; // Can't happen in a builtin constructor.
+ case Callable::CallError::CALL_OK:
+ p_call->is_constant = true;
+ p_call->reduced_value = value;
+ break;
+ }
+ } else {
+ validate_call_arg(function_info, p_call);
+ }
+ p_call->set_datatype(type_from_property(function_info.return_val));
+ return;
+ } else if (Variant::has_utility_function(function_name)) {
+ MethodInfo function_info = info_from_utility_func(function_name);
- if (all_is_constant && GDScriptFunctions::is_deterministic(builtin_function)) {
+ if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
// Can call on compilation.
Vector<const Variant *> args;
for (int i = 0; i < p_call->arguments.size(); i++) {
@@ -1830,23 +1930,23 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
Variant value;
Callable::CallError err;
- GDScriptFunctions::call(builtin_function, (const Variant **)args.ptr(), args.size(), value, err);
+ Variant::call_utility_function(function_name, &value, (const Variant **)args.ptr(), args.size(), err);
switch (err.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
PropertyInfo wrong_arg = function_info.arguments[err.argument];
- push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", GDScriptFunctions::get_func_name(builtin_function), err.argument + 1,
+ push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
p_call->arguments[err.argument]);
} break;
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
- push_error(vformat(R"(Invalid call for function "%s".)", GDScriptFunctions::get_func_name(builtin_function)), p_call);
+ push_error(vformat(R"(Invalid call for function "%s".)", function_name), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
- push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", GDScriptFunctions::get_func_name(builtin_function), err.expected, p_call->arguments.size()), p_call);
+ push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
- push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", GDScriptFunctions::get_func_name(builtin_function), err.expected, p_call->arguments.size()), p_call);
+ push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
break;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
break; // Can't happen in a builtin constructor.
@@ -2360,7 +2460,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
// Not found.
// Check if it's a builtin function.
- if (parser->get_builtin_function(name) < GDScriptFunctions::FUNC_MAX) {
+ if (GDScriptUtilityFunctions::function_exists(name)) {
push_error(vformat(R"(Built-in function "%s" cannot be used as an identifier.)", name), p_identifier);
} else {
push_error(vformat(R"(Identifier "%s" not declared in the current scope.)", name), p_identifier);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 7c20cda39c..a5d96077d9 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -40,10 +40,6 @@ uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool
function->_argument_count++;
function->argument_types.push_back(p_type);
if (p_is_optional) {
- if (function->_default_arg_count == 0) {
- append(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
- }
- function->default_arguments.push_back(opcodes.size());
function->_default_arg_count++;
}
@@ -96,7 +92,12 @@ void GDScriptByteCodeGenerator::pop_temporary() {
current_temporaries--;
}
-void GDScriptByteCodeGenerator::start_parameters() {}
+void GDScriptByteCodeGenerator::start_parameters() {
+ if (function->_default_arg_count > 0) {
+ append(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
+ function->default_arguments.push_back(opcodes.size());
+ }
+}
void GDScriptByteCodeGenerator::end_parameters() {
function->default_arguments.invert();
@@ -167,7 +168,7 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
}
if (function->default_arguments.size()) {
- function->_default_arg_count = function->default_arguments.size();
+ function->_default_arg_count = function->default_arguments.size() - 1;
function->_default_arg_ptr = &function->default_arguments[0];
} else {
function->_default_arg_count = 0;
@@ -282,6 +283,30 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_constructors_count = 0;
}
+ if (utilities_map.size()) {
+ function->utilities.resize(utilities_map.size());
+ function->_utilities_ptr = function->utilities.ptr();
+ function->_utilities_count = utilities_map.size();
+ for (const Map<Variant::ValidatedUtilityFunction, int>::Element *E = utilities_map.front(); E; E = E->next()) {
+ function->utilities.write[E->get()] = E->key();
+ }
+ } else {
+ function->_utilities_ptr = nullptr;
+ function->_utilities_count = 0;
+ }
+
+ if (gds_utilities_map.size()) {
+ function->gds_utilities.resize(gds_utilities_map.size());
+ function->_gds_utilities_ptr = function->gds_utilities.ptr();
+ function->_gds_utilities_count = gds_utilities_map.size();
+ for (const Map<GDScriptUtilityFunctions::FunctionPtr, int>::Element *E = gds_utilities_map.front(); E; E = E->next()) {
+ function->gds_utilities.write[E->get()] = E->key();
+ }
+ } else {
+ function->_gds_utilities_ptr = nullptr;
+ function->_gds_utilities_count = 0;
+ }
+
if (method_bind_map.size()) {
function->methods.resize(method_bind_map.size());
function->_methods_ptr = function->methods.ptrw();
@@ -403,7 +428,7 @@ void GDScriptByteCodeGenerator::write_end_and(const Address &p_target) {
patch_jump(logic_op_jump_pos2.back()->get());
logic_op_jump_pos1.pop_back();
logic_op_jump_pos2.pop_back();
- append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 0);
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 1);
append(p_target);
}
@@ -428,7 +453,7 @@ void GDScriptByteCodeGenerator::write_end_or(const Address &p_target) {
// Jump away from the success condition.
append(GDScriptFunction::OPCODE_JUMP, 0);
append(opcodes.size() + 3);
- // Here it means one of operands is false.
+ // Here it means one of operands is true.
patch_jump(logic_op_jump_pos1.back()->get());
patch_jump(logic_op_jump_pos2.back()->get());
logic_op_jump_pos1.pop_back();
@@ -633,6 +658,11 @@ void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) {
append(p_target);
}
+void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src) {
+ write_assign(p_dst, p_src);
+ function->default_arguments.push_back(opcodes.size());
+}
+
void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
int index = 0;
@@ -698,8 +728,8 @@ void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const
append(p_function_name);
}
-void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CALL_BUILT_IN, 1 + p_arguments.size());
+void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
@@ -708,6 +738,41 @@ void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDSc
append(p_function);
}
+void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {
+ bool is_validated = true;
+ if (Variant::is_utility_function_vararg(p_function)) {
+ is_validated = true; // Vararg works fine with any argument, since they can be any type.
+ } else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) {
+ bool all_types_exact = true;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_utility_function_argument_type(p_function, i))) {
+ all_types_exact = false;
+ break;
+ }
+ }
+
+ is_validated = all_types_exact;
+ }
+
+ if (is_validated) {
+ append(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(Variant::get_validated_utility_function(p_function));
+ } else {
+ append(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(p_function);
+ }
+}
+
void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {
bool is_validated = false;
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 34d2bb6098..21576b08a4 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -34,6 +34,7 @@
#include "gdscript_codegen.h"
#include "gdscript_function.h"
+#include "gdscript_utility_functions.h"
class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
bool ended = false;
@@ -76,6 +77,8 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
Map<Variant::ValidatedConstructor, int> constructors_map;
+ Map<Variant::ValidatedUtilityFunction, int> utilities_map;
+ Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
Map<MethodBind *, int> method_bind_map;
// Lists since these can be nested.
@@ -241,6 +244,24 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
+ int get_utility_pos(const Variant::ValidatedUtilityFunction p_utility) {
+ if (utilities_map.has(p_utility)) {
+ return utilities_map[p_utility];
+ }
+ int pos = utilities_map.size();
+ utilities_map[p_utility] = pos;
+ return pos;
+ }
+
+ int get_gds_utility_pos(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
+ if (gds_utilities_map.has(p_gds_utility)) {
+ return gds_utilities_map[p_gds_utility];
+ }
+ int pos = gds_utilities_map.size();
+ gds_utilities_map[p_gds_utility] = pos;
+ return pos;
+ }
+
int get_method_bind_pos(MethodBind *p_method) {
if (method_bind_map.has(p_method)) {
return method_bind_map[p_method];
@@ -346,6 +367,14 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
opcodes.push_back(get_constructor_pos(p_constructor));
}
+ void append(const Variant::ValidatedUtilityFunction p_utility) {
+ opcodes.push_back(get_utility_pos(p_utility));
+ }
+
+ void append(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
+ opcodes.push_back(get_gds_utility_pos(p_gds_utility));
+ }
+
void append(MethodBind *p_method) {
opcodes.push_back(get_method_bind_pos(p_method));
}
@@ -401,11 +430,13 @@ public:
virtual void write_assign(const Address &p_target, const Address &p_source) override;
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
+ virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
- virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) override;
+ virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
+ virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 35e326c61f..e776007bd7 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -35,7 +35,7 @@
#include "core/string/string_name.h"
#include "core/variant/variant.h"
#include "gdscript_function.h"
-#include "gdscript_functions.h"
+#include "gdscript_utility_functions.h"
class GDScriptCodeGenerator {
public:
@@ -122,11 +122,13 @@ public:
virtual void write_assign(const Address &p_target, const Address &p_source) = 0;
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
+ virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index b41dc15324..af6991041e 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -33,6 +33,7 @@
#include "gdscript.h"
#include "gdscript_byte_codegen.h"
#include "gdscript_cache.h"
+#include "gdscript_utility_functions.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
if (codegen.function_node && codegen.function_node->is_static) {
@@ -98,7 +99,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
} break;
case GDScriptParser::DataType::SCRIPT: {
result.kind = GDScriptDataType::SCRIPT;
- result.script_type = Ref<Script>(p_datatype.script_type).ptr();
+ result.script_type_ref = Ref<Script>(p_datatype.script_type);
+ result.script_type = result.script_type_ref.ptr();
result.native_type = result.script_type->get_instance_base_type();
} break;
case GDScriptParser::DataType::CLASS: {
@@ -124,11 +126,13 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
names.pop_back();
}
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type = script.ptr();
+ result.script_type_ref = script;
+ result.script_type = result.script_type_ref.ptr();
result.native_type = script->get_instance_base_type();
} else {
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path).ptr();
+ result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path);
+ result.script_type = result.script_type_ref.ptr();
result.native_type = p_datatype.native_type;
}
}
@@ -151,8 +155,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Only hold strong reference to the script if it's not the owner of the
// element qualified with this type, to avoid cyclic references (leaks).
- if (result.script_type && result.script_type != p_owner) {
- result.script_type_ref = Ref<Script>(result.script_type);
+ if (result.script_type && result.script_type == p_owner) {
+ result.script_type_ref = Ref<Script>();
}
return result;
@@ -453,15 +457,17 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
arguments.push_back(arg);
}
- if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != Variant::VARIANT_MAX) {
+ if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) != Variant::VARIANT_MAX) {
// Construct a built-in type.
Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
gen->write_construct(result, vtype, arguments);
- } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != GDScriptFunctions::FUNC_MAX) {
- // Built-in function.
- GDScriptFunctions::Function func = GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- gen->write_call_builtin(result, func, arguments);
+ } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
+ // Variant utility function.
+ gen->write_call_utility(result, call->function_name, arguments);
+ } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ // GDScript utility function.
+ gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
} else {
// Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
@@ -1132,7 +1138,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Evaluate expression type.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(expr_addr);
- codegen.generator->write_call_builtin(result_addr, GDScriptFunctions::TYPE_OF, typeof_args);
+ codegen.generator->write_call_utility(result_addr, "typeof", typeof_args);
// Check type equality.
codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
@@ -1196,7 +1202,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> len_args;
len_args.push_back(p_value_addr);
- codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, len_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), len_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
@@ -1250,7 +1256,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Also get type of element.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(element_addr);
- codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, typeof_args);
+ codegen.generator->write_call_utility(element_type_addr, "typeof", typeof_args);
// Try the pattern inside the element.
test_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, p_previous_test, false, true);
@@ -1295,7 +1301,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> func_args;
func_args.push_back(p_value_addr);
- codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, func_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), func_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
@@ -1364,7 +1370,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Also get type of value.
func_args.clear();
func_args.push_back(element_addr);
- codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, func_args);
+ codegen.generator->write_call_utility(element_type_addr, "typeof", func_args);
// Try the pattern inside the value.
test_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, test_addr, false, true);
@@ -1497,7 +1503,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(value);
- gen->write_call_builtin(type, GDScriptFunctions::TYPE_OF, typeof_args);
+ gen->write_call_utility(type, "typeof", typeof_args);
// Now we can actually start testing.
// For each branch.
@@ -1838,7 +1844,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return error;
}
GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
- codegen.generator->write_assign(dst_addr, src_addr);
+ codegen.generator->write_assign_default_parameter(dst_addr, src_addr);
if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
@@ -1883,6 +1889,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->set_initial_line(p_func->start_line);
#ifdef TOOLS_ENABLED
p_script->member_lines[func_name] = p_func->start_line;
+ p_script->doc_functions[func_name] = p_func->doc_description;
#endif
} else {
codegen.generator->set_initial_line(0);
@@ -1896,6 +1903,21 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
p_script->implicit_initializer = gd_function;
}
+ if (p_func) {
+ // if no return statement -> return type is void not unresolved Variant
+ if (p_func->body->has_return) {
+ gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype());
+ } else {
+ gd_function->return_type = GDScriptDataType();
+ gd_function->return_type.has_type = true;
+ gd_function->return_type.kind = GDScriptDataType::BUILTIN;
+ gd_function->return_type.builtin_type = Variant::NIL;
+ }
+#ifdef TOOLS_ENABLED
+ gd_function->default_arg_values = p_func->default_arg_values;
+#endif
+ }
+
p_script->member_functions[func_name] = gd_function;
memdelete(codegen.generator);
@@ -1993,6 +2015,24 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
}
+#ifdef TOOLS_ENABLED
+ p_script->doc_functions.clear();
+ p_script->doc_variables.clear();
+ p_script->doc_constants.clear();
+ p_script->doc_enums.clear();
+ p_script->doc_signals.clear();
+ p_script->doc_tutorials.clear();
+
+ p_script->doc_brief_description = p_class->doc_brief_description;
+ p_script->doc_description = p_class->doc_description;
+ for (int i = 0; i < p_class->doc_tutorials.size(); i++) {
+ DocData::TutorialDoc td;
+ td.title = p_class->doc_tutorials[i].first;
+ td.link = p_class->doc_tutorials[i].second;
+ p_script->doc_tutorials.append(td);
+ }
+#endif
+
p_script->native = Ref<GDScriptNativeClass>();
p_script->base = Ref<GDScript>();
p_script->_base = nullptr;
@@ -2105,20 +2145,23 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
prop_info.usage = export_info.usage;
-#ifdef TOOLS_ENABLED
- if (variable->initializer != nullptr && variable->initializer->type == GDScriptParser::Node::LITERAL) {
- p_script->member_default_values[name] = static_cast<const GDScriptParser::LiteralNode *>(variable->initializer)->value;
- }
-#endif
} else {
prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
}
+#ifdef TOOLS_ENABLED
+ p_script->doc_variables[name] = variable->doc_description;
+#endif
p_script->member_info[name] = prop_info;
p_script->member_indices[name] = minfo;
p_script->members.insert(name);
#ifdef TOOLS_ENABLED
+ if (variable->initializer != nullptr && variable->initializer->is_constant) {
+ p_script->member_default_values[name] = variable->initializer->reduced_value;
+ } else {
+ p_script->member_default_values.erase(name);
+ }
p_script->member_lines[name] = variable->start_line;
#endif
} break;
@@ -2129,8 +2172,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(name, constant->initializer->reduced_value);
#ifdef TOOLS_ENABLED
-
p_script->member_lines[name] = constant->start_line;
+ if (constant->doc_description != String()) {
+ p_script->doc_constants[name] = constant->doc_description;
+ }
#endif
} break;
@@ -2141,6 +2186,15 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(name, enum_value.value);
#ifdef TOOLS_ENABLED
p_script->member_lines[name] = enum_value.identifier->start_line;
+ if (!p_script->doc_enums.has("@unnamed_enums")) {
+ p_script->doc_enums["@unnamed_enums"] = DocData::EnumDoc();
+ p_script->doc_enums["@unnamed_enums"].name = "@unnamed_enums";
+ }
+ DocData::ConstantDoc const_doc;
+ const_doc.name = enum_value.identifier->name;
+ const_doc.value = Variant(enum_value.value).operator String(); // TODO-DOC: enum value currently is int.
+ const_doc.description = enum_value.doc_description;
+ p_script->doc_enums["@unnamed_enums"].values.push_back(const_doc);
#endif
} break;
@@ -2176,6 +2230,11 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
parameters_names.write[j] = signal->parameters[j]->identifier->name;
}
p_script->_signals[name] = parameters_names;
+#ifdef TOOLS_ENABLED
+ if (!signal->doc_description.empty()) {
+ p_script->doc_signals[name] = signal->doc_description;
+ }
+#endif
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
@@ -2192,6 +2251,16 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(enum_n->identifier->name, new_enum);
#ifdef TOOLS_ENABLED
p_script->member_lines[enum_n->identifier->name] = enum_n->start_line;
+ p_script->doc_enums[enum_n->identifier->name] = DocData::EnumDoc();
+ p_script->doc_enums[enum_n->identifier->name].name = enum_n->identifier->name;
+ p_script->doc_enums[enum_n->identifier->name].description = enum_n->doc_description;
+ for (int j = 0; j < enum_n->values.size(); j++) {
+ DocData::ConstantDoc const_doc;
+ const_doc.name = enum_n->values[j].identifier->name;
+ const_doc.value = Variant(enum_n->values[j].value).operator String();
+ const_doc.description = enum_n->values[j].doc_description;
+ p_script->doc_enums[enum_n->identifier->name].values.push_back(const_doc);
+ }
#endif
} break;
default:
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 92a44c57f8..5938cfd7b2 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -34,7 +34,6 @@
#include "core/string/string_builder.h"
#include "gdscript.h"
-#include "gdscript_functions.h"
static String _get_variant_string(const Variant &p_variant) {
String txt;
@@ -324,11 +323,8 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 4;
} break;
case OPCODE_ASSIGN_TYPED_NATIVE: {
- Variant class_name = _constants_ptr[_code_ptr[ip + 3]];
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
-
text += "assign typed native (";
- text += nc->get_name().operator String();
+ text += DADDR(3);
text += ") ";
text += DADDR(1);
text += " = ";
@@ -607,13 +603,49 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 5 + argc;
} break;
- case OPCODE_CALL_BUILT_IN: {
- text += "call-built-in ";
+ case OPCODE_CALL_UTILITY: {
+ text += "call-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_UTILITY_VALIDATED: {
+ text += "call-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += "<unkown function>";
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_GDSCRIPT_UTILITY: {
+ text += "call-gscript-utility ";
int argc = _code_ptr[ip + 1 + instr_var_args];
text += DADDR(1 + argc) + " = ";
- text += GDScriptFunctions::get_func_name(GDScriptFunctions::Function(_code_ptr[ip + 2 + instr_var_args]));
+ text += "<unknown function>";
text += "(";
for (int i = 0; i < argc; i++) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index a426046797..2181d17cf0 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -37,6 +37,7 @@
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
#include "gdscript_tokenizer.h"
+#include "gdscript_utility_functions.h"
#ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
@@ -193,6 +194,10 @@ bool GDScriptLanguage::supports_builtin_mode() const {
return true;
}
+bool GDScriptLanguage::supports_documentation() const {
+ return true;
+}
+
int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const {
GDScriptTokenizer tokenizer;
tokenizer.set_source_code(p_code);
@@ -407,11 +412,14 @@ void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) con
}
void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- p_functions->push_back(GDScriptFunctions::get_info(GDScriptFunctions::Function(i)));
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E->get()));
}
- //not really "functions", but..
+ // Not really "functions", but show in documentation.
{
MethodInfo mi;
mi.name = "preload";
@@ -1026,9 +1034,12 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
_find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth + 1);
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- MethodInfo function = GDScriptFunctions::get_info(GDScriptFunctions::Function(i));
- ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION);
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ MethodInfo function = GDScriptUtilityFunctions::get_function_info(E->get());
+ ScriptCodeCompletionOption option(String(E->get()), ScriptCodeCompletionOption::KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
} else {
@@ -1054,10 +1065,8 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
}
static const char *_keywords[] = {
- "and", "in", "not", "or", "false", "PI", "TAU", "INF", "NAN", "self", "true", "as", "assert",
- "breakpoint", "class", "extends", "is", "func", "preload", "signal", "tool", "await",
- "const", "enum", "static", "super", "var", "break", "continue", "if", "elif",
- "else", "for", "pass", "return", "match", "while",
+ "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
+ "break", "continue", "pass", "return",
0
};
@@ -1068,6 +1077,33 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
kw++;
}
+ static const char *_keywords_with_space[] = {
+ "and", "in", "not", "or", "as", "class", "extends", "is", "func", "signal", "await",
+ "const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
+ 0
+ };
+
+ const char **kws = _keywords_with_space;
+ while (*kws) {
+ ScriptCodeCompletionOption option(*kws, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ option.insert_text += " ";
+ r_result.insert(option.display, option);
+ kws++;
+ }
+
+ static const char *_keywords_with_args[] = {
+ "assert", "preload",
+ 0
+ };
+
+ const char **kwa = _keywords_with_args;
+ while (*kwa) {
+ ScriptCodeCompletionOption option(*kwa, ScriptCodeCompletionOption::KIND_FUNCTION);
+ option.insert_text += "(";
+ r_result.insert(option.display, option);
+ kwa++;
+ }
+
Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
for (const Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E != nullptr; E = E->next()) {
if (!E->value().is_singleton) {
@@ -1259,8 +1295,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
r_type.type.builtin_type = GDScriptParser::get_builtin_type(call->function_name);
found = true;
break;
- } else if (GDScriptParser::get_builtin_function(call->function_name) < GDScriptFunctions::FUNC_MAX) {
- MethodInfo mi = GDScriptFunctions::get_info(GDScriptParser::get_builtin_function(call->function_name));
+ } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo mi = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_type = _type_from_property(mi.return_val);
found = true;
break;
@@ -2313,8 +2349,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptCompletionIdentifier connect_base;
- if (GDScriptParser::get_builtin_function(call->function_name) < GDScriptFunctions::FUNC_MAX) {
- MethodInfo info = GDScriptFunctions::get_info(GDScriptParser::get_builtin_function(call->function_name));
+ if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_arghint = _make_arguments_hint(info, p_argidx);
return;
} else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
@@ -2942,13 +2978,11 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
}
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- if (GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)) == p_symbol) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
- r_result.class_name = "@GDScript";
- r_result.class_member = p_symbol;
- return OK;
- }
+ if (GDScriptUtilityFunctions::function_exists(p_symbol)) {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name = "@GDScript";
+ r_result.class_member = p_symbol;
+ return OK;
}
if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) {
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index bb5cc1284d..b669870b51 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -38,6 +38,7 @@
#include "core/templates/pair.h"
#include "core/templates/self_list.h"
#include "core/variant/variant.h"
+#include "gdscript_utility_functions.h"
class GDScriptInstance;
class GDScript;
@@ -190,7 +191,9 @@ public:
OPCODE_CALL,
OPCODE_CALL_RETURN,
OPCODE_CALL_ASYNC,
- OPCODE_CALL_BUILT_IN,
+ OPCODE_CALL_UTILITY,
+ OPCODE_CALL_UTILITY_VALIDATED,
+ OPCODE_CALL_GDSCRIPT_UTILITY,
OPCODE_CALL_BUILTIN_TYPE_VALIDATED,
OPCODE_CALL_SELF_BASE,
OPCODE_CALL_METHOD_BIND,
@@ -344,6 +347,10 @@ private:
const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
int _constructors_count = 0;
const Variant::ValidatedConstructor *_constructors_ptr = nullptr;
+ int _utilities_count = 0;
+ const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr;
+ int _gds_utilities_count = 0;
+ const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
int _methods_count = 0;
MethodBind **_methods_ptr = nullptr;
const int *_code_ptr = nullptr;
@@ -372,6 +379,8 @@ private:
Vector<Variant::ValidatedIndexedGetter> indexed_getters;
Vector<Variant::ValidatedBuiltInMethod> builtin_methods;
Vector<Variant::ValidatedConstructor> constructors;
+ Vector<Variant::ValidatedUtilityFunction> utilities;
+ Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities;
Vector<MethodBind *> methods;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
@@ -379,6 +388,7 @@ private:
#ifdef TOOLS_ENABLED
Vector<StringName> arg_names;
+ Vector<Variant> default_arg_values;
#endif
List<StackDebug> stack_debug;
@@ -458,6 +468,11 @@ public:
ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), Variant());
return default_arguments[p_idx];
}
+#ifdef TOOLS_ENABLED
+ const Vector<Variant> &get_default_arg_values() const {
+ return default_arg_values;
+ }
+#endif // TOOLS_ENABLED
Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr);
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
deleted file mode 100644
index 3a7c1a8676..0000000000
--- a/modules/gdscript/gdscript_functions.cpp
+++ /dev/null
@@ -1,1942 +0,0 @@
-/*************************************************************************/
-/* gdscript_functions.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "gdscript_functions.h"
-
-#include "core/io/json.h"
-#include "core/io/marshalls.h"
-#include "core/math/math_funcs.h"
-#include "core/object/class_db.h"
-#include "core/object/reference.h"
-#include "core/os/os.h"
-#include "core/variant/variant_parser.h"
-#include "gdscript.h"
-
-const char *GDScriptFunctions::get_func_name(Function p_func) {
- ERR_FAIL_INDEX_V(p_func, FUNC_MAX, "");
-
- static const char *_names[FUNC_MAX] = {
- "sin",
- "cos",
- "tan",
- "sinh",
- "cosh",
- "tanh",
- "asin",
- "acos",
- "atan",
- "atan2",
- "sqrt",
- "fmod",
- "fposmod",
- "posmod",
- "floor",
- "ceil",
- "round",
- "abs",
- "sign",
- "pow",
- "log",
- "exp",
- "is_nan",
- "is_inf",
- "is_equal_approx",
- "is_zero_approx",
- "ease",
- "step_decimals",
- "stepify",
- "lerp",
- "lerp_angle",
- "inverse_lerp",
- "range_lerp",
- "smoothstep",
- "move_toward",
- "dectime",
- "randomize",
- "randi",
- "randf",
- "randf_range",
- "randi_range",
- "seed",
- "rand_seed",
- "deg2rad",
- "rad2deg",
- "linear2db",
- "db2linear",
- "polar2cartesian",
- "cartesian2polar",
- "wrapi",
- "wrapf",
- "max",
- "min",
- "clamp",
- "nearest_po2",
- "weakref",
- "convert",
- "typeof",
- "type_exists",
- "char",
- "ord",
- "str",
- "print",
- "printt",
- "prints",
- "printerr",
- "printraw",
- "print_debug",
- "push_error",
- "push_warning",
- "var2str",
- "str2var",
- "var2bytes",
- "bytes2var",
- "range",
- "load",
- "inst2dict",
- "dict2inst",
- "validate_json",
- "parse_json",
- "to_json",
- "hash",
- "Color8",
- "ColorN",
- "print_stack",
- "get_stack",
- "instance_from_id",
- "len",
- "is_instance_valid",
- };
-
- return _names[p_func];
-}
-
-void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
-#ifdef DEBUG_ENABLED
-
-#define VALIDATE_ARG_COUNT(m_count) \
- if (p_arg_count < m_count) { \
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
- r_error.argument = m_count; \
- r_error.expected = m_count; \
- r_ret = Variant(); \
- return; \
- } \
- if (p_arg_count > m_count) { \
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
- r_error.argument = m_count; \
- r_error.expected = m_count; \
- r_ret = Variant(); \
- return; \
- }
-
-#define VALIDATE_ARG_NUM(m_arg) \
- if (!p_args[m_arg]->is_num()) { \
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
- r_error.argument = m_arg; \
- r_error.expected = Variant::FLOAT; \
- r_ret = Variant(); \
- return; \
- }
-
-#else
-
-#define VALIDATE_ARG_COUNT(m_count)
-#define VALIDATE_ARG_NUM(m_arg)
-#endif
-
- //using a switch, so the compiler generates a jumptable
-
- switch (p_func) {
- case MATH_SIN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sin((double)*p_args[0]);
- } break;
- case MATH_COS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::cos((double)*p_args[0]);
- } break;
- case MATH_TAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::tan((double)*p_args[0]);
- } break;
- case MATH_SINH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sinh((double)*p_args[0]);
- } break;
- case MATH_COSH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::cosh((double)*p_args[0]);
- } break;
- case MATH_TANH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::tanh((double)*p_args[0]);
- } break;
- case MATH_ASIN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::asin((double)*p_args[0]);
- } break;
- case MATH_ACOS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::acos((double)*p_args[0]);
- } break;
- case MATH_ATAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::atan((double)*p_args[0]);
- } break;
- case MATH_ATAN2: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::atan2((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_SQRT: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sqrt((double)*p_args[0]);
- } break;
- case MATH_FMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::fmod((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_FPOSMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::fposmod((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_POSMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::posmod((int)*p_args[0], (int)*p_args[1]);
- } break;
- case MATH_FLOOR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::floor((double)*p_args[0]);
- } break;
- case MATH_CEIL: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::ceil((double)*p_args[0]);
- } break;
- case MATH_ROUND: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::round((double)*p_args[0]);
- } break;
- case MATH_ABS: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::INT) {
- int64_t i = *p_args[0];
- r_ret = ABS(i);
- } else if (p_args[0]->get_type() == Variant::FLOAT) {
- double r = *p_args[0];
- r_ret = Math::abs(r);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- r_ret = Variant();
- }
- } break;
- case MATH_SIGN: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::INT) {
- int64_t i = *p_args[0];
- r_ret = i < 0 ? -1 : (i > 0 ? +1 : 0);
- } else if (p_args[0]->get_type() == Variant::FLOAT) {
- double r = *p_args[0];
- r_ret = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- r_ret = Variant();
- }
- } break;
- case MATH_POW: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::pow((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_LOG: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::log((double)*p_args[0]);
- } break;
- case MATH_EXP: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::exp((double)*p_args[0]);
- } break;
- case MATH_ISNAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_nan((double)*p_args[0]);
- } break;
- case MATH_ISINF: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_inf((double)*p_args[0]);
- } break;
- case MATH_ISEQUALAPPROX: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]);
- } break;
- case MATH_ISZEROAPPROX: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_zero_approx((real_t)*p_args[0]);
- } break;
- case MATH_EASE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::ease((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_STEP_DECIMALS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::step_decimals((double)*p_args[0]);
- } break;
- case MATH_STEPIFY: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::stepify((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_LERP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(2);
- const double t = (double)*p_args[2];
- switch (p_args[0]->get_type() == p_args[1]->get_type() ? p_args[0]->get_type() : Variant::FLOAT) {
- case Variant::VECTOR2: {
- r_ret = ((Vector2)*p_args[0]).lerp((Vector2)*p_args[1], t);
- } break;
- case Variant::VECTOR3: {
- r_ret = (p_args[0]->operator Vector3()).lerp(p_args[1]->operator Vector3(), t);
- } break;
- case Variant::COLOR: {
- r_ret = ((Color)*p_args[0]).lerp((Color)*p_args[1], t);
- } break;
- default: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::lerp((double)*p_args[0], (double)*p_args[1], t);
- } break;
- }
- } break;
- case MATH_LERP_ANGLE: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::lerp_angle((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_INVERSE_LERP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::inverse_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_RANGE_LERP: {
- VALIDATE_ARG_COUNT(5);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- VALIDATE_ARG_NUM(3);
- VALIDATE_ARG_NUM(4);
- r_ret = Math::range_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2], (double)*p_args[3], (double)*p_args[4]);
- } break;
- case MATH_SMOOTHSTEP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::smoothstep((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_MOVE_TOWARD: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::move_toward((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_DECTIME: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::dectime((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_RANDOMIZE: {
- VALIDATE_ARG_COUNT(0);
- Math::randomize();
- r_ret = Variant();
- } break;
- case MATH_RANDI: {
- VALIDATE_ARG_COUNT(0);
- r_ret = Math::rand();
- } break;
- case MATH_RANDF: {
- VALIDATE_ARG_COUNT(0);
- r_ret = Math::randf();
- } break;
- case MATH_RANDF_RANGE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::random((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_RANDI_RANGE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::random((int)*p_args[0], (int)*p_args[1]);
- } break;
- case MATH_SEED: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_args[0];
- Math::seed(seed);
- r_ret = Variant();
- } break;
- case MATH_RANDSEED: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_args[0];
- int ret = Math::rand_from_seed(&seed);
- Array reta;
- reta.push_back(ret);
- reta.push_back(seed);
- r_ret = reta;
-
- } break;
- case MATH_DEG2RAD: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::deg2rad((double)*p_args[0]);
- } break;
- case MATH_RAD2DEG: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::rad2deg((double)*p_args[0]);
- } break;
- case MATH_LINEAR2DB: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::linear2db((double)*p_args[0]);
- } break;
- case MATH_DB2LINEAR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::db2linear((double)*p_args[0]);
- } break;
- case MATH_POLAR2CARTESIAN: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double r = *p_args[0];
- double th = *p_args[1];
- r_ret = Vector2(r * Math::cos(th), r * Math::sin(th));
- } break;
- case MATH_CARTESIAN2POLAR: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double x = *p_args[0];
- double y = *p_args[1];
- r_ret = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
- } break;
- case MATH_WRAP: {
- VALIDATE_ARG_COUNT(3);
- r_ret = Math::wrapi((int64_t)*p_args[0], (int64_t)*p_args[1], (int64_t)*p_args[2]);
- } break;
- case MATH_WRAPF: {
- VALIDATE_ARG_COUNT(3);
- r_ret = Math::wrapf((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case LOGIC_MAX: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- r_ret = MAX(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- double a = *p_args[0];
- double b = *p_args[1];
-
- r_ret = MAX(a, b);
- }
-
- } break;
- case LOGIC_MIN: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- r_ret = MIN(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- double a = *p_args[0];
- double b = *p_args[1];
-
- r_ret = MIN(a, b);
- }
- } break;
- case LOGIC_CLAMP: {
- VALIDATE_ARG_COUNT(3);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT && p_args[2]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- int64_t c = *p_args[2];
- r_ret = CLAMP(a, b, c);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- double a = *p_args[0];
- double b = *p_args[1];
- double c = *p_args[2];
-
- r_ret = CLAMP(a, b, c);
- }
- } break;
- case LOGIC_NEAREST_PO2: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- int64_t num = *p_args[0];
- r_ret = next_power_of_2(num);
- } break;
- case OBJ_WEAKREF: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::OBJECT) {
- if (p_args[0]->is_ref()) {
- Ref<WeakRef> wref = memnew(WeakRef);
- REF r = *p_args[0];
- if (r.is_valid()) {
- wref->set_ref(r);
- }
- r_ret = wref;
- } else {
- Ref<WeakRef> wref = memnew(WeakRef);
- Object *obj = *p_args[0];
- if (obj) {
- wref->set_obj(obj);
- }
- r_ret = wref;
- }
- } else if (p_args[0]->get_type() == Variant::NIL) {
- Ref<WeakRef> wref = memnew(WeakRef);
- r_ret = wref;
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- return;
- }
- } break;
- case TYPE_CONVERT: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(1);
- int type = *p_args[1];
- if (type < 0 || type >= Variant::VARIANT_MAX) {
- r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return;
-
- } else {
- Variant::construct(Variant::Type(type), r_ret, p_args, 1, r_error);
- }
- } break;
- case TYPE_OF: {
- VALIDATE_ARG_COUNT(1);
- r_ret = p_args[0]->get_type();
-
- } break;
- case TYPE_EXISTS: {
- VALIDATE_ARG_COUNT(1);
- r_ret = ClassDB::class_exists(*p_args[0]);
-
- } break;
- case TEXT_CHAR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- char32_t result[2] = { *p_args[0], 0 };
- r_ret = String(result);
- } break;
- case TEXT_ORD: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- String str = p_args[0]->operator String();
-
- if (str.length() != 1) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = RTR("Expected a string of length 1 (a character).");
- return;
- }
-
- r_ret = str.get(0);
-
- } break;
- case TEXT_STR: {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
-
- return;
- }
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
-
- if (i == 0) {
- str = os;
- } else {
- str += os;
- }
- }
-
- r_ret = str;
-
- } break;
- case TEXT_PRINT: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_TABBED: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- str += "\t";
- }
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_SPACED: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- str += " ";
- }
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
-
- case TEXT_PRINTERR: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- print_error(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINTRAW: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- OS::get_singleton()->print("%s", str.utf8().get_data());
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_DEBUG: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- if (script->debug_get_stack_level_count() > 0) {
- str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
- }
-
- print_line(str);
- r_ret = Variant();
- } break;
- case PUSH_ERROR: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- break;
- }
-
- String message = *p_args[0];
- ERR_PRINT(message);
- r_ret = Variant();
- } break;
- case PUSH_WARNING: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- break;
- }
-
- String message = *p_args[0];
- WARN_PRINT(message);
- r_ret = Variant();
- } break;
- case VAR_TO_STR: {
- VALIDATE_ARG_COUNT(1);
- String vars;
- VariantWriter::write_to_string(*p_args[0], vars);
- r_ret = vars;
- } break;
- case STR_TO_VAR: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
- r_ret = *p_args[0];
-
- VariantParser::StreamString ss;
- ss.s = *p_args[0];
-
- String errs;
- int line;
- (void)VariantParser::parse(&ss, r_ret, errs, line);
- } break;
- case VAR_TO_BYTES: {
- bool full_objects = false;
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- } else if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- } else if (p_arg_count == 2) {
- if (p_args[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- r_ret = Variant();
- return;
- }
- full_objects = *p_args[1];
- }
-
- PackedByteArray barr;
- int len;
- Error err = encode_variant(*p_args[0], nullptr, len, full_objects);
- if (err) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::NIL;
- r_ret = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
- return;
- }
-
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- encode_variant(*p_args[0], w, len, full_objects);
- }
- r_ret = barr;
- } break;
- case BYTES_TO_VAR: {
- bool allow_objects = false;
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- } else if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- } else if (p_arg_count == 2) {
- if (p_args[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- r_ret = Variant();
- return;
- }
- allow_objects = *p_args[1];
- }
-
- if (p_args[0]->get_type() != Variant::PACKED_BYTE_ARRAY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- r_ret = Variant();
- return;
- }
-
- PackedByteArray varr = *p_args[0];
- Variant ret;
- {
- const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
- if (err != OK) {
- r_ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- return;
- }
- }
-
- r_ret = ret;
-
- } break;
- case GEN_RANGE: {
- switch (p_arg_count) {
- case 0: {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_error.expected = 1;
- r_ret = Variant();
-
- } break;
- case 1: {
- VALIDATE_ARG_NUM(0);
- int count = *p_args[0];
- Array arr;
- if (count <= 0) {
- r_ret = arr;
- return;
- }
- Error err = arr.resize(count);
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
-
- for (int i = 0; i < count; i++) {
- arr[i] = i;
- }
-
- r_ret = arr;
- } break;
- case 2: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- int from = *p_args[0];
- int to = *p_args[1];
-
- Array arr;
- if (from >= to) {
- r_ret = arr;
- return;
- }
- Error err = arr.resize(to - from);
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
- for (int i = from; i < to; i++) {
- arr[i - from] = i;
- }
- r_ret = arr;
- } break;
- case 3: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- int from = *p_args[0];
- int to = *p_args[1];
- int incr = *p_args[2];
- if (incr == 0) {
- r_ret = RTR("Step argument is zero!");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return;
- }
-
- Array arr;
- if (from >= to && incr > 0) {
- r_ret = arr;
- return;
- }
- if (from <= to && incr < 0) {
- r_ret = arr;
- return;
- }
-
- //calculate how many
- int count = 0;
- if (incr > 0) {
- count = ((to - from - 1) / incr) + 1;
- } else {
- count = ((from - to - 1) / -incr) + 1;
- }
-
- Error err = arr.resize(count);
-
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
-
- if (incr > 0) {
- int idx = 0;
- for (int i = from; i < to; i += incr) {
- arr[idx++] = i;
- }
- } else {
- int idx = 0;
- for (int i = from; i > to; i += incr) {
- arr[idx++] = i;
- }
- }
-
- r_ret = arr;
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 3;
- r_error.expected = 3;
- r_ret = Variant();
-
- } break;
- }
-
- } break;
- case RESOURCE_LOAD: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- } else {
- r_ret = ResourceLoader::load(*p_args[0]);
- }
-
- } break;
- case INST2DICT: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() == Variant::NIL) {
- r_ret = Variant();
- } else if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_ret = Variant();
- } else {
- Object *obj = *p_args[0];
- if (!obj) {
- r_ret = Variant();
-
- } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = RTR("Not a script with an instance");
- return;
- } else {
- GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance());
- Ref<GDScript> base = ins->get_script();
- if (base.is_null()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = RTR("Not based on a script");
- return;
- }
-
- GDScript *p = base.ptr();
- Vector<StringName> sname;
-
- while (p->_owner) {
- sname.push_back(p->name);
- p = p->_owner;
- }
- sname.invert();
-
- if (!p->path.is_resource_file()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = Variant();
-
- r_ret = RTR("Not based on a resource file");
-
- return;
- }
-
- NodePath cp(sname, Vector<StringName>(), false);
-
- Dictionary d;
- d["@subpath"] = cp;
- d["@path"] = p->get_path();
-
- for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
- if (!d.has(E->key())) {
- d[E->key()] = ins->members[E->get().index];
- }
- }
- r_ret = d;
- }
- }
-
- } break;
- case DICT2INST: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::DICTIONARY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = Variant();
-
- return;
- }
-
- Dictionary d = *p_args[0];
-
- if (!d.has("@path")) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = RTR("Invalid instance dictionary format (missing @path)");
-
- return;
- }
-
- Ref<Script> scr = ResourceLoader::load(d["@path"]);
- if (!scr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = RTR("Invalid instance dictionary format (can't load script at @path)");
- return;
- }
-
- Ref<GDScript> gdscr = scr;
-
- if (!gdscr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Invalid instance dictionary format (invalid script at @path)");
- return;
- }
-
- NodePath sub;
- if (d.has("@subpath")) {
- sub = d["@subpath"];
- }
-
- for (int i = 0; i < sub.get_name_count(); i++) {
- gdscr = gdscr->subclasses[sub.get_name(i)];
- if (!gdscr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Invalid instance dictionary (invalid subclasses)");
- return;
- }
- }
- r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error);
-
- if (r_error.error != Callable::CallError::CALL_OK) {
- r_ret = Variant();
- return;
- }
-
- GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(r_ret)->get_script_instance());
- Ref<GDScript> gd_ref = ins->get_script();
-
- for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
- if (d.has(E->key())) {
- ins->members.write[E->get().index] = d[E->key()];
- }
- }
-
- } break;
- case VALIDATE_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- String errs;
- int errl;
-
- Error err = JSON::parse(*p_args[0], r_ret, errs, errl);
-
- if (err != OK) {
- r_ret = itos(errl) + ":" + errs;
- } else {
- r_ret = "";
- }
-
- } break;
- case PARSE_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- String errs;
- int errl;
-
- Error err = JSON::parse(*p_args[0], r_ret, errs, errl);
-
- if (err != OK) {
- r_ret = Variant();
- ERR_PRINT(vformat("Error parsing JSON at line %s: %s", errl, errs));
- }
-
- } break;
- case TO_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- r_ret = JSON::print(*p_args[0]);
- } break;
- case HASH: {
- VALIDATE_ARG_COUNT(1);
- r_ret = p_args[0]->hash();
-
- } break;
- case COLOR8: {
- if (p_arg_count < 3) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 3;
- r_ret = Variant();
-
- return;
- }
- if (p_arg_count > 4) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 4;
- r_ret = Variant();
-
- return;
- }
-
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- Color color((float)*p_args[0] / 255.0f, (float)*p_args[1] / 255.0f, (float)*p_args[2] / 255.0f);
-
- if (p_arg_count == 4) {
- VALIDATE_ARG_NUM(3);
- color.a = (float)*p_args[3] / 255.0f;
- }
-
- r_ret = color;
-
- } break;
- case COLORN: {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- }
-
- if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- return;
- }
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_ret = Variant();
- } else {
- Color color = Color::named(*p_args[0]);
- if (p_arg_count == 2) {
- VALIDATE_ARG_NUM(1);
- color.a = *p_args[1];
- }
- r_ret = color;
- }
-
- } break;
-
- case PRINT_STACK: {
- VALIDATE_ARG_COUNT(0);
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
- print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
- };
- } break;
-
- case GET_STACK: {
- VALIDATE_ARG_COUNT(0);
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- Array ret;
- for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
- Dictionary frame;
- frame["source"] = script->debug_get_stack_level_source(i);
- frame["function"] = script->debug_get_stack_level_function(i);
- frame["line"] = script->debug_get_stack_level_line(i);
- ret.push_back(frame);
- };
- r_ret = ret;
- } break;
-
- case INSTANCE_FROM_ID: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::INT && p_args[0]->get_type() != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- r_ret = Variant();
- break;
- }
-
- ObjectID id = *p_args[0];
- r_ret = ObjectDB::get_instance(id);
-
- } break;
- case LEN: {
- VALIDATE_ARG_COUNT(1);
- switch (p_args[0]->get_type()) {
- case Variant::STRING: {
- String d = *p_args[0];
- r_ret = d.length();
- } break;
- case Variant::DICTIONARY: {
- Dictionary d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::ARRAY: {
- Array d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- Vector<uint8_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- Vector<int32_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- Vector<int64_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- Vector<float> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- Vector<double> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- Vector<String> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_VECTOR2_ARRAY: {
- Vector<Vector2> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- Vector<Vector3> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- Vector<Color> d = *p_args[0];
- r_ret = d.size();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Object can't provide a length.");
- }
- }
-
- } break;
- case IS_INSTANCE_VALID: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_ret = false;
- } else {
- Object *obj = p_args[0]->get_validated_object();
- r_ret = obj != nullptr;
- }
-
- } break;
- case FUNC_MAX: {
- ERR_FAIL();
- } break;
- }
-}
-
-bool GDScriptFunctions::is_deterministic(Function p_func) {
- //man i couldn't have chosen a worse function name,
- //way too controversial..
-
- switch (p_func) {
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_ATAN2:
- case MATH_SQRT:
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case MATH_POSMOD:
- case MATH_FLOOR:
- case MATH_CEIL:
- case MATH_ROUND:
- case MATH_ABS:
- case MATH_SIGN:
- case MATH_POW:
- case MATH_LOG:
- case MATH_EXP:
- case MATH_ISNAN:
- case MATH_ISINF:
- case MATH_EASE:
- case MATH_STEP_DECIMALS:
- case MATH_STEPIFY:
- case MATH_LERP:
- case MATH_INVERSE_LERP:
- case MATH_RANGE_LERP:
- case MATH_SMOOTHSTEP:
- case MATH_MOVE_TOWARD:
- case MATH_DECTIME:
- case MATH_DEG2RAD:
- case MATH_RAD2DEG:
- case MATH_LINEAR2DB:
- case MATH_DB2LINEAR:
- case MATH_POLAR2CARTESIAN:
- case MATH_CARTESIAN2POLAR:
- case MATH_WRAP:
- case MATH_WRAPF:
- case LOGIC_MAX:
- case LOGIC_MIN:
- case LOGIC_CLAMP:
- case LOGIC_NEAREST_PO2:
- case TYPE_CONVERT:
- case TYPE_OF:
- case TYPE_EXISTS:
- case TEXT_CHAR:
- case TEXT_ORD:
- case TEXT_STR:
- case COLOR8:
- case LEN:
- // enable for debug only, otherwise not desirable - case GEN_RANGE:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-MethodInfo GDScriptFunctions::get_info(Function p_func) {
-#ifdef DEBUG_ENABLED
- //using a switch, so the compiler generates a jumptable
-
- switch (p_func) {
- case MATH_SIN: {
- MethodInfo mi("sin", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
-
- } break;
- case MATH_COS: {
- MethodInfo mi("cos", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_TAN: {
- MethodInfo mi("tan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SINH: {
- MethodInfo mi("sinh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_COSH: {
- MethodInfo mi("cosh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_TANH: {
- MethodInfo mi("tanh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ASIN: {
- MethodInfo mi("asin", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ACOS: {
- MethodInfo mi("acos", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ATAN: {
- MethodInfo mi("atan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ATAN2: {
- MethodInfo mi("atan2", PropertyInfo(Variant::FLOAT, "y"), PropertyInfo(Variant::FLOAT, "x"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SQRT: {
- MethodInfo mi("sqrt", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_FMOD: {
- MethodInfo mi("fmod", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_FPOSMOD: {
- MethodInfo mi("fposmod", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POSMOD: {
- MethodInfo mi("posmod", PropertyInfo(Variant::INT, "a"), PropertyInfo(Variant::INT, "b"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_FLOOR: {
- MethodInfo mi("floor", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_CEIL: {
- MethodInfo mi("ceil", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ROUND: {
- MethodInfo mi("round", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ABS: {
- MethodInfo mi("abs", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SIGN: {
- MethodInfo mi("sign", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POW: {
- MethodInfo mi("pow", PropertyInfo(Variant::FLOAT, "base"), PropertyInfo(Variant::FLOAT, "exp"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LOG: {
- MethodInfo mi("log", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_EXP: {
- MethodInfo mi("exp", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ISNAN: {
- MethodInfo mi("is_nan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISINF: {
- MethodInfo mi("is_inf", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISEQUALAPPROX: {
- MethodInfo mi("is_equal_approx", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISZEROAPPROX: {
- MethodInfo mi("is_zero_approx", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_EASE: {
- MethodInfo mi("ease", PropertyInfo(Variant::FLOAT, "s"), PropertyInfo(Variant::FLOAT, "curve"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_STEP_DECIMALS: {
- MethodInfo mi("step_decimals", PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_STEPIFY: {
- MethodInfo mi("stepify", PropertyInfo(Variant::FLOAT, "s"), PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LERP: {
- MethodInfo mi("lerp", PropertyInfo(Variant::NIL, "from"), PropertyInfo(Variant::NIL, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case MATH_LERP_ANGLE: {
- MethodInfo mi("lerp_angle", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_INVERSE_LERP: {
- MethodInfo mi("inverse_lerp", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANGE_LERP: {
- MethodInfo mi("range_lerp", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "istart"), PropertyInfo(Variant::FLOAT, "istop"), PropertyInfo(Variant::FLOAT, "ostart"), PropertyInfo(Variant::FLOAT, "ostop"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SMOOTHSTEP: {
- MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_MOVE_TOWARD: {
- MethodInfo mi("move_toward", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "delta"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_DECTIME: {
- MethodInfo mi("dectime", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "amount"), PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDOMIZE: {
- MethodInfo mi("randomize");
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case MATH_RANDI: {
- MethodInfo mi("randi");
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_RANDF: {
- MethodInfo mi("randf");
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDF_RANGE: {
- MethodInfo mi("randf_range", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDI_RANGE: {
- MethodInfo mi("randi_range", PropertyInfo(Variant::INT, "from"), PropertyInfo(Variant::INT, "to"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_SEED: {
- MethodInfo mi("seed", PropertyInfo(Variant::INT, "seed"));
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case MATH_RANDSEED: {
- MethodInfo mi("rand_seed", PropertyInfo(Variant::INT, "seed"));
- mi.return_val.type = Variant::ARRAY;
- return mi;
- } break;
- case MATH_DEG2RAD: {
- MethodInfo mi("deg2rad", PropertyInfo(Variant::FLOAT, "deg"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RAD2DEG: {
- MethodInfo mi("rad2deg", PropertyInfo(Variant::FLOAT, "rad"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LINEAR2DB: {
- MethodInfo mi("linear2db", PropertyInfo(Variant::FLOAT, "nrg"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_DB2LINEAR: {
- MethodInfo mi("db2linear", PropertyInfo(Variant::FLOAT, "db"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POLAR2CARTESIAN: {
- MethodInfo mi("polar2cartesian", PropertyInfo(Variant::FLOAT, "r"), PropertyInfo(Variant::FLOAT, "th"));
- mi.return_val.type = Variant::VECTOR2;
- return mi;
- } break;
- case MATH_CARTESIAN2POLAR: {
- MethodInfo mi("cartesian2polar", PropertyInfo(Variant::FLOAT, "x"), PropertyInfo(Variant::FLOAT, "y"));
- mi.return_val.type = Variant::VECTOR2;
- return mi;
- } break;
- case MATH_WRAP: {
- MethodInfo mi("wrapi", PropertyInfo(Variant::INT, "value"), PropertyInfo(Variant::INT, "min"), PropertyInfo(Variant::INT, "max"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_WRAPF: {
- MethodInfo mi("wrapf", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_MAX: {
- MethodInfo mi("max", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
-
- } break;
- case LOGIC_MIN: {
- MethodInfo mi("min", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_CLAMP: {
- MethodInfo mi("clamp", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_NEAREST_PO2: {
- MethodInfo mi("nearest_po2", PropertyInfo(Variant::INT, "value"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case OBJ_WEAKREF: {
- MethodInfo mi("weakref", PropertyInfo(Variant::OBJECT, "obj"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "WeakRef";
-
- return mi;
-
- } break;
- case TYPE_CONVERT: {
- MethodInfo mi("convert", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::INT, "type"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case TYPE_OF: {
- MethodInfo mi("typeof", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
-
- } break;
- case TYPE_EXISTS: {
- MethodInfo mi("type_exists", PropertyInfo(Variant::STRING, "type"));
- mi.return_val.type = Variant::BOOL;
- return mi;
-
- } break;
- case TEXT_CHAR: {
- MethodInfo mi("char", PropertyInfo(Variant::INT, "code"));
- mi.return_val.type = Variant::STRING;
- return mi;
-
- } break;
- case TEXT_ORD: {
- MethodInfo mi("ord", PropertyInfo(Variant::STRING, "char"));
- mi.return_val.type = Variant::INT;
- return mi;
-
- } break;
- case TEXT_STR: {
- MethodInfo mi("str");
- mi.return_val.type = Variant::STRING;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT: {
- MethodInfo mi("print");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_TABBED: {
- MethodInfo mi("printt");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_SPACED: {
- MethodInfo mi("prints");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINTERR: {
- MethodInfo mi("printerr");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINTRAW: {
- MethodInfo mi("printraw");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_DEBUG: {
- MethodInfo mi("print_debug");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case PUSH_ERROR: {
- MethodInfo mi(Variant::NIL, "push_error", PropertyInfo(Variant::STRING, "message"));
- mi.return_val.type = Variant::NIL;
- return mi;
-
- } break;
- case PUSH_WARNING: {
- MethodInfo mi(Variant::NIL, "push_warning", PropertyInfo(Variant::STRING, "message"));
- mi.return_val.type = Variant::NIL;
- return mi;
-
- } break;
- case VAR_TO_STR: {
- MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case STR_TO_VAR: {
- MethodInfo mi(Variant::NIL, "str2var", PropertyInfo(Variant::STRING, "string"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case VAR_TO_BYTES: {
- MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "full_objects"));
- mi.default_arguments.push_back(false);
- mi.return_val.type = Variant::PACKED_BYTE_ARRAY;
- return mi;
- } break;
- case BYTES_TO_VAR: {
- MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytes"), PropertyInfo(Variant::BOOL, "allow_objects"));
- mi.default_arguments.push_back(false);
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case GEN_RANGE: {
- MethodInfo mi("range");
- mi.return_val.type = Variant::ARRAY;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
- } break;
- case RESOURCE_LOAD: {
- MethodInfo mi("load", PropertyInfo(Variant::STRING, "path"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "Resource";
- return mi;
- } break;
- case INST2DICT: {
- MethodInfo mi("inst2dict", PropertyInfo(Variant::OBJECT, "inst"));
- mi.return_val.type = Variant::DICTIONARY;
- return mi;
- } break;
- case DICT2INST: {
- MethodInfo mi("dict2inst", PropertyInfo(Variant::DICTIONARY, "dict"));
- mi.return_val.type = Variant::OBJECT;
- return mi;
- } break;
- case VALIDATE_JSON: {
- MethodInfo mi("validate_json", PropertyInfo(Variant::STRING, "json"));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case PARSE_JSON: {
- MethodInfo mi(Variant::NIL, "parse_json", PropertyInfo(Variant::STRING, "json"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case TO_JSON: {
- MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case HASH: {
- MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case COLOR8: {
- MethodInfo mi("Color8", PropertyInfo(Variant::INT, "r8"), PropertyInfo(Variant::INT, "g8"), PropertyInfo(Variant::INT, "b8"), PropertyInfo(Variant::INT, "a8"));
- mi.default_arguments.push_back(255);
- mi.return_val.type = Variant::COLOR;
- return mi;
- } break;
- case COLORN: {
- MethodInfo mi("ColorN", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "alpha"));
- mi.default_arguments.push_back(1.0f);
- mi.return_val.type = Variant::COLOR;
- return mi;
- } break;
-
- case PRINT_STACK: {
- MethodInfo mi("print_stack");
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case GET_STACK: {
- MethodInfo mi("get_stack");
- mi.return_val.type = Variant::ARRAY;
- return mi;
- } break;
-
- case INSTANCE_FROM_ID: {
- MethodInfo mi("instance_from_id", PropertyInfo(Variant::INT, "instance_id"));
- mi.return_val.type = Variant::OBJECT;
- return mi;
- } break;
- case LEN: {
- MethodInfo mi("len", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case IS_INSTANCE_VALID: {
- MethodInfo mi("is_instance_valid", PropertyInfo(Variant::OBJECT, "instance"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- default: {
- ERR_FAIL_V(MethodInfo());
- } break;
- }
-#endif
- MethodInfo mi;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
-}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 372af204f5..2c735049b6 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -98,15 +98,6 @@ void GDScriptParser::cleanup() {
builtin_types.clear();
}
-GDScriptFunctions::Function GDScriptParser::get_builtin_function(const StringName &p_name) {
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- if (p_name == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) {
- return GDScriptFunctions::Function(i);
- }
- }
- return GDScriptFunctions::FUNC_MAX;
-}
-
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
List<StringName> keys;
valid_annotations.get_key_list(&keys);
@@ -558,6 +549,17 @@ void GDScriptParser::parse_program() {
parse_class_body();
+#ifdef TOOLS_ENABLED
+ for (Map<int, GDScriptTokenizer::CommentData>::Element *E = tokenizer.get_comments().front(); E; E = E->next()) {
+ if (E->get().new_line && E->get().comment.begins_with("##")) {
+ class_doc_line = MIN(class_doc_line, E->key());
+ }
+ }
+ if (has_comment(class_doc_line)) {
+ get_class_doc_comment(class_doc_line, head->doc_brief_description, head->doc_description, head->doc_tutorials, false);
+ }
+#endif // TOOLS_ENABLED
+
if (!check(GDScriptTokenizer::Token::TK_EOF)) {
push_error("Expected end of file.");
}
@@ -668,6 +670,10 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
if (member == nullptr) {
return;
}
+#ifdef TOOLS_ENABLED
+ int doc_comment_line = member->start_line - 1;
+#endif // TOOLS_ENABLED
+
// Consume annotations.
while (!annotation_stack.empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
@@ -680,7 +686,25 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
clear_unused_annotations();
return;
}
+#ifdef TOOLS_ENABLED
+ if (last_annotation->start_line == doc_comment_line) {
+ doc_comment_line--;
+ }
+#endif // TOOLS_ENABLED
}
+
+#ifdef TOOLS_ENABLED
+ // Consume doc comments.
+ class_doc_line = MIN(class_doc_line, doc_comment_line - 1);
+ if (has_comment(doc_comment_line)) {
+ if constexpr (std::is_same_v<T, ClassNode>) {
+ get_class_doc_comment(doc_comment_line, member->doc_brief_description, member->doc_description, member->doc_tutorials, true);
+ } else {
+ member->doc_description = get_doc_comment(doc_comment_line);
+ }
+ }
+#endif // TOOLS_ENABLED
+
if (member->identifier != nullptr) {
// Enums may be unnamed.
// TODO: Consider names in outer scope too, for constants and classes (and static functions?)
@@ -1050,6 +1074,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
item.parent_enum = enum_node;
item.line = previous.start_line;
item.leftmost_column = previous.leftmost_column;
+ item.rightmost_column = previous.rightmost_column;
if (elements.has(item.identifier->name)) {
push_error(vformat(R"(Name "%s" was already in this enum (at line %d).)", item.identifier->name, elements[item.identifier->name]), item.identifier);
@@ -1088,6 +1113,31 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
pop_multiline();
consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" for enum.)");
+#ifdef TOOLS_ENABLED
+ // Enum values documentaion.
+ for (int i = 0; i < enum_node->values.size(); i++) {
+ if (i == enum_node->values.size() - 1) {
+ // If close bracket is same line as last value.
+ if (enum_node->values[i].line != previous.start_line && has_comment(enum_node->values[i].line)) {
+ if (named) {
+ enum_node->values.write[i].doc_description = get_doc_comment(enum_node->values[i].line, true);
+ } else {
+ current_class->set_enum_value_doc(enum_node->values[i].identifier->name, get_doc_comment(enum_node->values[i].line, true));
+ }
+ }
+ } else {
+ // If two values are same line.
+ if (enum_node->values[i].line != enum_node->values[i + 1].line && has_comment(enum_node->values[i].line)) {
+ if (named) {
+ enum_node->values.write[i].doc_description = get_doc_comment(enum_node->values[i].line, true);
+ } else {
+ current_class->set_enum_value_doc(enum_node->values[i].identifier->name, get_doc_comment(enum_node->values[i].line, true));
+ }
+ }
+ }
+ }
+#endif // TOOLS_ENABLED
+
end_statement("enum");
return enum_node;
@@ -2494,7 +2544,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
// Arguments.
CompletionType ct = COMPLETION_CALL_ARGUMENTS;
- if (get_builtin_function(call->function_name) == GDScriptFunctions::RESOURCE_LOAD) {
+ if (call->function_name == "load") {
ct = COMPLETION_RESOURCE_PATH;
}
push_completion_call(call);
@@ -2624,6 +2674,218 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) {
return type;
}
+#ifdef TOOLS_ENABLED
+static bool _in_codeblock(String p_line, bool p_already_in, int *r_block_begins = nullptr) {
+ int start_block = p_line.rfind("[codeblock]");
+ int end_block = p_line.rfind("[/codeblock]");
+
+ if (start_block != -1 && r_block_begins) {
+ *r_block_begins = start_block;
+ }
+
+ if (p_already_in) {
+ if (end_block == -1) {
+ return true;
+ } else if (start_block == -1) {
+ return false;
+ } else {
+ return start_block > end_block;
+ }
+ } else {
+ if (start_block == -1) {
+ return false;
+ } else if (end_block == -1) {
+ return true;
+ } else {
+ return start_block > end_block;
+ }
+ }
+}
+
+bool GDScriptParser::has_comment(int p_line) {
+ return tokenizer.get_comments().has(p_line);
+}
+
+String GDScriptParser::get_doc_comment(int p_line, bool p_single_line) {
+ const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ ERR_FAIL_COND_V(!comments.has(p_line), String());
+
+ if (p_single_line) {
+ if (comments[p_line].comment.begins_with("##")) {
+ return comments[p_line].comment.trim_prefix("##").strip_edges();
+ }
+ return "";
+ }
+
+ String doc;
+
+ int line = p_line;
+ bool in_codeblock = false;
+
+ while (comments.has(line - 1)) {
+ if (!comments[line - 1].new_line || !comments[line - 1].comment.begins_with("##")) {
+ break;
+ }
+ line--;
+ }
+
+ int codeblock_begins = 0;
+ while (comments.has(line)) {
+ if (!comments[line].new_line || !comments[line].comment.begins_with("##")) {
+ break;
+ }
+ String doc_line = comments[line].comment.trim_prefix("##");
+
+ in_codeblock = _in_codeblock(doc_line, in_codeblock, &codeblock_begins);
+
+ if (in_codeblock) {
+ int i = 0;
+ for (; i < codeblock_begins; i++) {
+ if (doc_line[i] != ' ') {
+ break;
+ }
+ }
+ doc_line = doc_line.substr(i);
+ } else {
+ doc_line = doc_line.strip_edges();
+ }
+ String line_join = (in_codeblock) ? "\n" : " ";
+
+ doc = (doc.empty()) ? doc_line : doc + line_join + doc_line;
+ line++;
+ }
+
+ return doc;
+}
+
+void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &p_desc, Vector<Pair<String, String>> &p_tutorials, bool p_inner_class) {
+ const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ if (!comments.has(p_line)) {
+ return;
+ }
+ ERR_FAIL_COND(p_brief != "" || p_desc != "" || p_tutorials.size() != 0);
+
+ int line = p_line;
+ bool in_codeblock = false;
+ enum Mode {
+ BRIEF,
+ DESC,
+ TUTORIALS,
+ DONE,
+ };
+ Mode mode = BRIEF;
+
+ if (p_inner_class) {
+ while (comments.has(line - 1)) {
+ if (!comments[line - 1].new_line || !comments[line - 1].comment.begins_with("##")) {
+ break;
+ }
+ line--;
+ }
+ }
+
+ int codeblock_begins = 0;
+ while (comments.has(line)) {
+ if (!comments[line].new_line || !comments[line].comment.begins_with("##")) {
+ break;
+ }
+
+ String title, link; // For tutorials.
+ String doc_line = comments[line++].comment.trim_prefix("##");
+ String striped_line = doc_line.strip_edges();
+
+ // Set the read mode.
+ if (striped_line.begins_with("@desc:") && p_desc == "") {
+ mode = DESC;
+ striped_line = striped_line.trim_prefix("@desc:");
+ in_codeblock = _in_codeblock(doc_line, in_codeblock);
+
+ } else if (striped_line.begins_with("@tutorial")) {
+ int begin_scan = String("@tutorial").length();
+ if (begin_scan >= striped_line.length()) {
+ continue; // invalid syntax.
+ }
+
+ if (striped_line[begin_scan] == ':') { // No title.
+ // Syntax: ## @tutorial: https://godotengine.org/ // The title argument is optional.
+ title = "";
+ link = striped_line.trim_prefix("@tutorial:").strip_edges();
+
+ } else {
+ /* Syntax:
+ @tutorial ( The Title Here ) : http://the.url/
+ ^ open ^ close ^ colon ^ url
+ */
+ int open_bracket_pos = begin_scan, close_bracket_pos = 0;
+ while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) {
+ open_bracket_pos++;
+ }
+ if (open_bracket_pos == striped_line.length() || striped_line[open_bracket_pos++] != '(') {
+ continue; // invalid syntax.
+ }
+ close_bracket_pos = open_bracket_pos;
+ while (close_bracket_pos < striped_line.length() && striped_line[close_bracket_pos] != ')') {
+ close_bracket_pos++;
+ }
+ if (close_bracket_pos == striped_line.length()) {
+ continue; // invalid syntax.
+ }
+
+ int colon_pos = close_bracket_pos + 1;
+ while (colon_pos < striped_line.length() && (striped_line[colon_pos] == ' ' || striped_line[colon_pos] == '\t')) {
+ colon_pos++;
+ }
+ if (colon_pos == striped_line.length() || striped_line[colon_pos++] != ':') {
+ continue; // invalid syntax.
+ }
+
+ title = striped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges();
+ link = striped_line.substr(colon_pos).strip_edges();
+ }
+
+ mode = TUTORIALS;
+ in_codeblock = false;
+ } else if (striped_line.empty()) {
+ continue;
+ } else {
+ // Tutorial docs are single line, we need a @tag after it.
+ if (mode == TUTORIALS) {
+ mode = DONE;
+ }
+
+ in_codeblock = _in_codeblock(doc_line, in_codeblock, &codeblock_begins);
+ }
+
+ if (in_codeblock) {
+ int i = 0;
+ for (; i < codeblock_begins; i++) {
+ if (doc_line[i] != ' ') {
+ break;
+ }
+ }
+ doc_line = doc_line.substr(i);
+ } else {
+ doc_line = striped_line;
+ }
+ String line_join = (in_codeblock) ? "\n" : " ";
+
+ switch (mode) {
+ case BRIEF:
+ p_brief = (p_brief.length() == 0) ? doc_line : p_brief + line_join + doc_line;
+ break;
+ case DESC:
+ p_desc = (p_desc.length() == 0) ? doc_line : p_desc + line_join + doc_line;
+ break;
+ case TUTORIALS:
+ p_tutorials.append(Pair<String, String>(title, link));
+ break;
+ case DONE:
+ return;
+ }
+ }
+}
+#endif // TOOLS_ENABLED
+
GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Type p_token_type) {
// Function table for expression parsing.
// clang-format destroys the alignment here, so turn off for the table.
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index b24acc4778..4cecdc6970 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -43,7 +43,6 @@
#include "core/templates/vector.h"
#include "core/variant/variant.h"
#include "gdscript_cache.h"
-#include "gdscript_functions.h"
#include "gdscript_tokenizer.h"
#ifdef DEBUG_ENABLED
@@ -413,9 +412,16 @@ public:
int line = 0;
int leftmost_column = 0;
int rightmost_column = 0;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
};
+
IdentifierNode *identifier = nullptr;
Vector<Value> values;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
EnumNode() {
type = ENUM;
@@ -568,6 +574,17 @@ public:
Vector<StringName> extends; // List for indexing: extends A.B.C
DataType base_type;
String fqcn; // Fully-qualified class name. Identifies uniquely any class in the project.
+#ifdef TOOLS_ENABLED
+ String doc_description;
+ String doc_brief_description;
+ Vector<Pair<String, String>> doc_tutorials;
+
+ // EnumValue docs are parsed after itself, so we need a method to add/modify the doc property later.
+ void set_enum_value_doc(const StringName &p_name, const String &p_doc_description) {
+ ERR_FAIL_INDEX(members_indices[p_name], members.size());
+ members.write[members_indices[p_name]].enum_value.doc_description = p_doc_description;
+ }
+#endif // TOOLS_ENABLED
bool resolved_interface = false;
bool resolved_body = false;
@@ -602,6 +619,9 @@ public:
TypeNode *datatype_specifier = nullptr;
bool infer_datatype = false;
int usages = 0;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
ConstantNode() {
type = CONSTANT;
@@ -653,6 +673,10 @@ public:
bool is_coroutine = false;
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
MethodInfo info;
+#ifdef TOOLS_ENABLED
+ Vector<Variant> default_arg_values;
+ String doc_description;
+#endif // TOOLS_ENABLED
bool resolved_signature = false;
bool resolved_body = false;
@@ -820,6 +844,9 @@ public:
IdentifierNode *identifier = nullptr;
Vector<ParameterNode *> parameters;
HashMap<StringName, int> parameters_indices;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
SignalNode() {
type = SIGNAL;
@@ -1012,6 +1039,9 @@ public:
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
int assignments = 0;
int usages = 0;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
VariableNode() {
type = VARIABLE;
@@ -1270,13 +1300,19 @@ private:
ExpressionNode *parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign);
TypeNode *parse_type(bool p_allow_void = false);
+#ifdef TOOLS_ENABLED
+ // Doc comments.
+ int class_doc_line = 0x7FFFFFFF;
+ bool has_comment(int p_line);
+ String get_doc_comment(int p_line, bool p_single_line = false);
+ void get_class_doc_comment(int p_line, String &p_brief, String &p_desc, Vector<Pair<String, String>> &p_tutorials, bool p_inner_class);
+#endif // TOOLS_ENABLED
public:
Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion);
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
- static GDScriptFunctions::Function get_builtin_function(const StringName &p_name);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index b91777ede1..ac43105254 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -1014,9 +1014,17 @@ void GDScriptTokenizer::check_indent() {
}
if (_peek() == '#') {
// Comment. Advance to the next line.
+#ifdef TOOLS_ENABLED
+ String comment;
+ while (_peek() != '\n' && !_is_at_end()) {
+ comment += _advance();
+ }
+ comments[line] = CommentData(comment, true);
+#else
while (_peek() != '\n' && !_is_at_end()) {
_advance();
}
+#endif // TOOLS_ENABLED
if (_is_at_end()) {
// Reached the end with an empty line, so just dedent as much as needed.
pending_indents -= indent_level();
@@ -1125,18 +1133,26 @@ void GDScriptTokenizer::_skip_whitespace() {
newline(!is_bol); // Don't create new line token if line is empty.
check_indent();
break;
- case '#':
+ case '#': {
// Comment.
+#ifdef TOOLS_ENABLED
+ String comment;
+ while (_peek() != '\n' && !_is_at_end()) {
+ comment += _advance();
+ }
+ comments[line] = CommentData(comment, is_bol);
+#else
while (_peek() != '\n' && !_is_at_end()) {
_advance();
}
+#endif // TOOLS_ENABLED
if (_is_at_end()) {
return;
}
_advance(); // Consume '\n'
newline(!is_bol);
check_indent();
- break;
+ } break;
default:
return;
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index d51f1f250f..f236c86f9f 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -32,6 +32,7 @@
#define GDSCRIPT_TOKENIZER_H
#include "core/templates/list.h"
+#include "core/templates/map.h"
#include "core/templates/set.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h"
@@ -181,6 +182,21 @@ public:
}
};
+#ifdef TOOLS_ENABLED
+ struct CommentData {
+ String comment;
+ bool new_line = false;
+ CommentData() {}
+ CommentData(const String &p_comment, bool p_new_line) {
+ comment = p_comment;
+ new_line = p_new_line;
+ }
+ };
+ const Map<int, CommentData> &get_comments() const {
+ return comments;
+ }
+#endif // TOOLS_ENABLED
+
private:
String source;
const char32_t *_source = nullptr;
@@ -207,6 +223,10 @@ private:
int position = 0;
int length = 0;
+#ifdef TOOLS_ENABLED
+ Map<int, CommentData> comments;
+#endif // TOOLS_ENABLED
+
_FORCE_INLINE_ bool _is_at_end() { return position >= length; }
_FORCE_INLINE_ char32_t _peek(int p_offset = 0) { return position + p_offset >= 0 && position + p_offset < length ? _current[p_offset] : '\0'; }
int indent_level() const { return indent_stack.size(); }
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
new file mode 100644
index 0000000000..b1780446d0
--- /dev/null
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -0,0 +1,718 @@
+/*************************************************************************/
+/* gdscript_utility_functions.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "gdscript_utility_functions.h"
+
+#include "core/io/resource_loader.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/object/object.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/vector.h"
+#include "gdscript.h"
+
+#ifdef DEBUG_ENABLED
+
+#define VALIDATE_ARG_COUNT(m_count) \
+ if (p_arg_count < m_count) { \
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
+ r_error.argument = m_count; \
+ r_error.expected = m_count; \
+ *r_ret = Variant(); \
+ return; \
+ } \
+ if (p_arg_count > m_count) { \
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
+ r_error.argument = m_count; \
+ r_error.expected = m_count; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#define VALIDATE_ARG_INT(m_arg) \
+ if (p_args[m_arg]->get_type() != Variant::INT) { \
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::INT; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#define VALIDATE_ARG_NUM(m_arg) \
+ if (!p_args[m_arg]->is_num()) { \
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::FLOAT; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#else
+
+#define VALIDATE_ARG_COUNT(m_count)
+#define VALIDATE_ARG_INT(m_arg)
+#define VALIDATE_ARG_NUM(m_arg)
+
+#endif
+
+struct GDScriptUtilityFunctionsDefinitions {
+ static inline void convert(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_INT(1);
+ int type = *p_args[1];
+ if (type < 0 || type >= Variant::VARIANT_MAX) {
+ *r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants.");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ return;
+
+ } else {
+ Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error);
+ }
+ }
+
+ static inline void type_exists(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ *r_ret = ClassDB::class_exists(*p_args[0]);
+ }
+
+ static inline void _char(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_INT(0);
+ char32_t result[2] = { *p_args[0], 0 };
+ *r_ret = String(result);
+ }
+
+ static inline void str(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ *r_ret = Variant();
+ return;
+ }
+
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+ *r_ret = str;
+ }
+
+ static inline void range(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ switch (p_arg_count) {
+ case 0: {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ r_error.expected = 1;
+ *r_ret = Variant();
+ } break;
+ case 1: {
+ VALIDATE_ARG_NUM(0);
+ int count = *p_args[0];
+ Array arr;
+ if (count <= 0) {
+ *r_ret = arr;
+ return;
+ }
+ Error err = arr.resize(count);
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+
+ for (int i = 0; i < count; i++) {
+ arr[i] = i;
+ }
+
+ *r_ret = arr;
+ } break;
+ case 2: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ int from = *p_args[0];
+ int to = *p_args[1];
+
+ Array arr;
+ if (from >= to) {
+ *r_ret = arr;
+ return;
+ }
+ Error err = arr.resize(to - from);
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+ for (int i = from; i < to; i++) {
+ arr[i - from] = i;
+ }
+ *r_ret = arr;
+ } break;
+ case 3: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+
+ int from = *p_args[0];
+ int to = *p_args[1];
+ int incr = *p_args[2];
+ if (incr == 0) {
+ *r_ret = RTR("Step argument is zero!");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ Array arr;
+ if (from >= to && incr > 0) {
+ *r_ret = arr;
+ return;
+ }
+ if (from <= to && incr < 0) {
+ *r_ret = arr;
+ return;
+ }
+
+ // Calculate how many.
+ int count = 0;
+ if (incr > 0) {
+ count = ((to - from - 1) / incr) + 1;
+ } else {
+ count = ((from - to - 1) / -incr) + 1;
+ }
+
+ Error err = arr.resize(count);
+
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+
+ if (incr > 0) {
+ int idx = 0;
+ for (int i = from; i < to; i += incr) {
+ arr[idx++] = i;
+ }
+ } else {
+ int idx = 0;
+ for (int i = from; i > to; i += incr) {
+ arr[idx++] = i;
+ }
+ }
+
+ *r_ret = arr;
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 3;
+ r_error.expected = 3;
+ *r_ret = Variant();
+
+ } break;
+ }
+ }
+
+ static inline void load(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ *r_ret = Variant();
+ } else {
+ *r_ret = ResourceLoader::load(*p_args[0]);
+ }
+ }
+
+ static inline void inst2dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() == Variant::NIL) {
+ *r_ret = Variant();
+ } else if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ *r_ret = Variant();
+ } else {
+ Object *obj = *p_args[0];
+ if (!obj) {
+ *r_ret = Variant();
+
+ } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = RTR("Not a script with an instance");
+ return;
+ } else {
+ GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance());
+ Ref<GDScript> base = ins->get_script();
+ if (base.is_null()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = RTR("Not based on a script");
+ return;
+ }
+
+ GDScript *p = base.ptr();
+ Vector<StringName> sname;
+
+ while (p->_owner) {
+ sname.push_back(p->name);
+ p = p->_owner;
+ }
+ sname.invert();
+
+ if (!p->path.is_resource_file()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = Variant();
+
+ *r_ret = RTR("Not based on a resource file");
+
+ return;
+ }
+
+ NodePath cp(sname, Vector<StringName>(), false);
+
+ Dictionary d;
+ d["@subpath"] = cp;
+ d["@path"] = p->get_path();
+
+ for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
+ if (!d.has(E->key())) {
+ d[E->key()] = ins->members[E->get().index];
+ }
+ }
+ *r_ret = d;
+ }
+ }
+ }
+
+ static inline void dict2inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() != Variant::DICTIONARY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = Variant();
+
+ return;
+ }
+
+ Dictionary d = *p_args[0];
+
+ if (!d.has("@path")) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = RTR("Invalid instance dictionary format (missing @path)");
+
+ return;
+ }
+
+ Ref<Script> scr = ResourceLoader::load(d["@path"]);
+ if (!scr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = RTR("Invalid instance dictionary format (can't load script at @path)");
+ return;
+ }
+
+ Ref<GDScript> gdscr = scr;
+
+ if (!gdscr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = Variant();
+ *r_ret = RTR("Invalid instance dictionary format (invalid script at @path)");
+ return;
+ }
+
+ NodePath sub;
+ if (d.has("@subpath")) {
+ sub = d["@subpath"];
+ }
+
+ for (int i = 0; i < sub.get_name_count(); i++) {
+ gdscr = gdscr->subclasses[sub.get_name(i)];
+ if (!gdscr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = Variant();
+ *r_ret = RTR("Invalid instance dictionary (invalid subclasses)");
+ return;
+ }
+ }
+ *r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error);
+
+ if (r_error.error != Callable::CallError::CALL_OK) {
+ *r_ret = Variant();
+ return;
+ }
+
+ GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(*r_ret)->get_script_instance());
+ Ref<GDScript> gd_ref = ins->get_script();
+
+ for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
+ if (d.has(E->key())) {
+ ins->members.write[E->get().index] = d[E->key()];
+ }
+ }
+ }
+
+ static inline void Color8(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 3) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 3;
+ *r_ret = Variant();
+ return;
+ }
+ if (p_arg_count > 4) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 4;
+ *r_ret = Variant();
+ return;
+ }
+
+ VALIDATE_ARG_INT(0);
+ VALIDATE_ARG_INT(1);
+ VALIDATE_ARG_INT(2);
+
+ Color color((int64_t)*p_args[0] / 255.0f, (int64_t)*p_args[1] / 255.0f, (int64_t)*p_args[2] / 255.0f);
+
+ if (p_arg_count == 4) {
+ VALIDATE_ARG_INT(3);
+ color.a = (int64_t)*p_args[3] / 255.0f;
+ }
+
+ *r_ret = color;
+ }
+
+ static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ str += p_args[i]->operator String();
+ }
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ if (script->debug_get_stack_level_count() > 0) {
+ str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
+ }
+
+ print_line(str);
+ *r_ret = Variant();
+ }
+
+ static inline void print_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(0);
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
+ print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
+ };
+ }
+
+ static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(0);
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ Array ret;
+ for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
+ Dictionary frame;
+ frame["source"] = script->debug_get_stack_level_source(i);
+ frame["function"] = script->debug_get_stack_level_function(i);
+ frame["line"] = script->debug_get_stack_level_line(i);
+ ret.push_back(frame);
+ };
+ *r_ret = ret;
+ }
+
+ 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: {
+ String d = *p_args[0];
+ *r_ret = d.length();
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::ARRAY: {
+ Array d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_BYTE_ARRAY: {
+ Vector<uint8_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+ Vector<int32_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_INT64_ARRAY: {
+ Vector<int64_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ Vector<float> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ Vector<double> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+ Vector<String> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ Vector<Vector2> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ Vector<Vector3> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_COLOR_ARRAY: {
+ Vector<Color> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ *r_ret = vformat(RTR("Value of type '%s' can't provide a length."), Variant::get_type_name(p_args[0]->get_type()));
+ }
+ }
+ }
+};
+
+struct GDScriptUtilityFunctionInfo {
+ GDScriptUtilityFunctions::FunctionPtr function;
+ MethodInfo info;
+ bool is_constant = false;
+};
+
+static OAHashMap<StringName, GDScriptUtilityFunctionInfo> utility_function_table;
+static List<StringName> utility_function_name_table;
+
+static void _register_function(const String &p_name, const MethodInfo &p_method_info, GDScriptUtilityFunctions::FunctionPtr p_function, bool p_is_const) {
+ StringName sname(p_name);
+
+ ERR_FAIL_COND(utility_function_table.has(sname));
+
+ GDScriptUtilityFunctionInfo function;
+ function.function = p_function;
+ function.info = p_method_info;
+ function.is_constant = p_is_const;
+
+ utility_function_table.insert(sname, function);
+ utility_function_name_table.push_back(sname);
+}
+
+#define REGISTER_FUNC(m_func, m_is_const, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_FUNC_NO_ARGS(m_func, m_is_const, m_return_type) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name); \
+ info.return_val.type = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_VARARG_FUNC(m_func, m_is_const, m_return_type) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name); \
+ info.return_val.type = m_return_type; \
+ info.flags |= METHOD_FLAG_VARARG; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_VARIANT_FUNC(m_func, m_is_const, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = Variant::NIL; \
+ info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_CLASS_FUNC(m_func, m_is_const, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = Variant::OBJECT; \
+ info.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE; \
+ info.return_val.class_name = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_FUNC_DEF(m_func, m_is_const, m_default, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = m_return_type; \
+ info.default_arguments.push_back(m_default); \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define ARG(m_name, m_type) \
+ PropertyInfo(m_type, m_name)
+
+#define VARARG(m_name) \
+ PropertyInfo(Variant::NIL, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)
+
+void GDScriptUtilityFunctions::register_functions() {
+ REGISTER_VARIANT_FUNC(convert, true, VARARG("what"), ARG("type", Variant::INT));
+ REGISTER_FUNC(type_exists, true, Variant::BOOL, ARG("type", Variant::STRING_NAME));
+ REGISTER_FUNC(_char, true, Variant::STRING, ARG("char", Variant::INT));
+ REGISTER_VARARG_FUNC(str, true, Variant::STRING);
+ REGISTER_VARARG_FUNC(range, false, Variant::ARRAY);
+ REGISTER_CLASS_FUNC(load, false, "Resource", ARG("path", Variant::STRING));
+ REGISTER_FUNC(inst2dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT));
+ REGISTER_FUNC(dict2inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY));
+ REGISTER_FUNC_DEF(Color8, true, 255, Variant::COLOR, ARG("r8", Variant::INT), ARG("g8", Variant::INT), ARG("b8", Variant::INT), ARG("a8", Variant::INT));
+ REGISTER_VARARG_FUNC(print_debug, false, Variant::NIL);
+ REGISTER_FUNC_NO_ARGS(print_stack, false, Variant::NIL);
+ REGISTER_FUNC_NO_ARGS(get_stack, false, Variant::ARRAY);
+ REGISTER_FUNC(len, true, Variant::INT, VARARG("var"));
+}
+
+void GDScriptUtilityFunctions::unregister_functions() {
+ utility_function_name_table.clear();
+ utility_function_table.clear();
+}
+
+GDScriptUtilityFunctions::FunctionPtr GDScriptUtilityFunctions::get_function(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, nullptr);
+ return info->function;
+}
+
+bool GDScriptUtilityFunctions::has_function_return_value(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return info->info.return_val.type != Variant::NIL || bool(info->info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
+}
+
+Variant::Type GDScriptUtilityFunctions::get_function_return_type(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, Variant::NIL);
+ return info->info.return_val.type;
+}
+
+StringName GDScriptUtilityFunctions::get_function_return_class(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, StringName());
+ return info->info.return_val.class_name;
+}
+
+Variant::Type GDScriptUtilityFunctions::get_function_argument_type(const StringName &p_function, int p_arg) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, Variant::NIL);
+ ERR_FAIL_COND_V(p_arg >= info->info.arguments.size(), Variant::NIL);
+ return info->info.arguments[p_arg].type;
+}
+
+int GDScriptUtilityFunctions::get_function_argument_count(const StringName &p_function, int p_arg) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, 0);
+ return info->info.arguments.size();
+}
+
+bool GDScriptUtilityFunctions::is_function_vararg(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return (bool)(info->info.flags & METHOD_FLAG_VARARG);
+}
+
+bool GDScriptUtilityFunctions::is_function_constant(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return info->is_constant;
+}
+
+bool GDScriptUtilityFunctions::function_exists(const StringName &p_function) {
+ return utility_function_table.has(p_function);
+}
+
+void GDScriptUtilityFunctions::get_function_list(List<StringName> *r_functions) {
+ for (const List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) {
+ r_functions->push_back(E->get());
+ }
+}
+
+MethodInfo GDScriptUtilityFunctions::get_function_info(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, MethodInfo());
+ return info->info;
+}
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_utility_functions.h
index 005b49c5da..50867438d9 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_utility_functions.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gdscript_functions.h */
+/* gdscript_utility_functions.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,110 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GDSCRIPT_FUNCTIONS_H
-#define GDSCRIPT_FUNCTIONS_H
+#ifndef GDSCRIPT_UTILITY_FUNCTIONS_H
+#define GDSCRIPT_UTILITY_FUNCTIONS_H
+#include "core/string/string_name.h"
#include "core/variant/variant.h"
-class GDScriptFunctions {
+class GDScriptUtilityFunctions {
public:
- enum Function {
- MATH_SIN,
- MATH_COS,
- MATH_TAN,
- MATH_SINH,
- MATH_COSH,
- MATH_TANH,
- MATH_ASIN,
- MATH_ACOS,
- MATH_ATAN,
- MATH_ATAN2,
- MATH_SQRT,
- MATH_FMOD,
- MATH_FPOSMOD,
- MATH_POSMOD,
- MATH_FLOOR,
- MATH_CEIL,
- MATH_ROUND,
- MATH_ABS,
- MATH_SIGN,
- MATH_POW,
- MATH_LOG,
- MATH_EXP,
- MATH_ISNAN,
- MATH_ISINF,
- MATH_ISEQUALAPPROX,
- MATH_ISZEROAPPROX,
- MATH_EASE,
- MATH_STEP_DECIMALS,
- MATH_STEPIFY,
- MATH_LERP,
- MATH_LERP_ANGLE,
- MATH_INVERSE_LERP,
- MATH_RANGE_LERP,
- MATH_SMOOTHSTEP,
- MATH_MOVE_TOWARD,
- MATH_DECTIME,
- MATH_RANDOMIZE,
- MATH_RANDI,
- MATH_RANDF,
- MATH_RANDF_RANGE,
- MATH_RANDI_RANGE,
- MATH_SEED,
- MATH_RANDSEED,
- MATH_DEG2RAD,
- MATH_RAD2DEG,
- MATH_LINEAR2DB,
- MATH_DB2LINEAR,
- MATH_POLAR2CARTESIAN,
- MATH_CARTESIAN2POLAR,
- MATH_WRAP,
- MATH_WRAPF,
- LOGIC_MAX,
- LOGIC_MIN,
- LOGIC_CLAMP,
- LOGIC_NEAREST_PO2,
- OBJ_WEAKREF,
- TYPE_CONVERT,
- TYPE_OF,
- TYPE_EXISTS,
- TEXT_CHAR,
- TEXT_ORD,
- TEXT_STR,
- TEXT_PRINT,
- TEXT_PRINT_TABBED,
- TEXT_PRINT_SPACED,
- TEXT_PRINTERR,
- TEXT_PRINTRAW,
- TEXT_PRINT_DEBUG,
- PUSH_ERROR,
- PUSH_WARNING,
- VAR_TO_STR,
- STR_TO_VAR,
- VAR_TO_BYTES,
- BYTES_TO_VAR,
- GEN_RANGE,
- RESOURCE_LOAD,
- INST2DICT,
- DICT2INST,
- VALIDATE_JSON,
- PARSE_JSON,
- TO_JSON,
- HASH,
- COLOR8,
- COLORN,
- PRINT_STACK,
- GET_STACK,
- INSTANCE_FROM_ID,
- LEN,
- IS_INSTANCE_VALID,
- FUNC_MAX
- };
+ typedef void (*FunctionPtr)(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
- static const char *get_func_name(Function p_func);
- static void call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error);
- static bool is_deterministic(Function p_func);
- static MethodInfo get_info(Function p_func);
+ static FunctionPtr get_function(const StringName &p_function);
+ static bool has_function_return_value(const StringName &p_function);
+ static Variant::Type get_function_return_type(const StringName &p_function);
+ static StringName get_function_return_class(const StringName &p_function);
+ static Variant::Type get_function_argument_type(const StringName &p_function, int p_arg);
+ static int get_function_argument_count(const StringName &p_function, int p_arg);
+ static bool is_function_vararg(const StringName &p_function);
+ static bool is_function_constant(const StringName &p_function);
+
+ static bool function_exists(const StringName &p_function);
+ static void get_function_list(List<StringName> *r_functions);
+ static MethodInfo get_function_info(const StringName &p_function);
+
+ static void register_functions();
+ static void unregister_functions();
};
-#endif // GDSCRIPT_FUNCTIONS_H
+#endif // GDSCRIPT_UTILITY_FUNCTIONS_H
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 7c8bfcd944..b8e1791467 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -33,7 +33,6 @@
#include "core/core_string_names.h"
#include "core/os/os.h"
#include "gdscript.h"
-#include "gdscript_functions.h"
Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
int address = p_address & ADDR_MASK;
@@ -220,7 +219,9 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
- &&OPCODE_CALL_BUILT_IN, \
+ &&OPCODE_CALL_UTILITY, \
+ &&OPCODE_CALL_UTILITY_VALIDATED, \
+ &&OPCODE_CALL_GDSCRIPT_UTILITY, \
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
@@ -738,7 +739,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
const Variant::ValidatedKeyedSetter setter = _keyed_setters_ptr[index_setter];
bool valid;
- setter(dst, index, value, valid);
+ setter(dst, index, value, &valid);
#ifdef DEBUG_ENABLED
if (!valid) {
@@ -770,7 +771,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
int64_t int_index = *VariantInternal::get_int(index);
bool oob;
- setter(dst, int_index, value, oob);
+ setter(dst, int_index, value, &oob);
#ifdef DEBUG_ENABLED
if (oob) {
@@ -835,9 +836,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
// Allow better error message in cases where src and dst are the same stack position.
Variant ret;
- getter(src, key, &ret, valid);
+ getter(src, key, &ret, &valid);
#else
- getter(src, key, dst, valid);
+ getter(src, key, dst, &valid);
#endif
#ifdef DEBUG_ENABLED
if (!valid) {
@@ -870,7 +871,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
int64_t int_index = *VariantInternal::get_int(index);
bool oob;
- getter(src, int_index, dst, oob);
+ getter(src, int_index, dst, &oob);
#ifdef DEBUG_ENABLED
if (oob) {
@@ -1292,7 +1293,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_INSTRUCTION_ARG(dst, argc);
- constructor(*dst, (const Variant **)argptrs);
+ constructor(dst, (const Variant **)argptrs);
ip += 3;
}
@@ -1653,7 +1654,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
VariantInternal::initialize(ret, Variant::OBJECT);
Object **ret_opaque = VariantInternal::get_object(ret);
method->ptrcall(base_obj, argptrs, ret_opaque);
- VariantInternal::set_object(ret, *ret_opaque);
+ VariantInternal::object_assign(ret, *ret_opaque); // Set so ID is correct too.
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
@@ -1749,7 +1750,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
- OPCODE(OPCODE_CALL_BUILT_IN) {
+ OPCODE(OPCODE_CALL_UTILITY) {
CHECK_SPACE(3 + instr_arg_count);
ip += instr_arg_count;
@@ -1757,22 +1758,80 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
int argc = _code_ptr[ip + 1];
GD_ERR_BREAK(argc < 0);
- GDScriptFunctions::Function func = GDScriptFunctions::Function(_code_ptr[ip + 2]);
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _global_names_count);
+ StringName function = _global_names_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ Callable::CallError err;
+ Variant::call_utility_function(function, dst, (const Variant **)argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (err.error != Callable::CallError::CALL_OK) {
+ String methodstr = function;
+ if (dst->get_type() == Variant::STRING) {
+ // Call provided error string.
+ err_text = "Error calling utility function '" + methodstr + "': " + String(*dst);
+ } else {
+ err_text = _get_call_error(err, "utility function '" + methodstr + "'", (const Variant **)argptrs);
+ }
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_UTILITY_VALIDATED) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _utilities_count);
+ Variant::ValidatedUtilityFunction function = _utilities_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ function(dst, (const Variant **)argptrs, argc);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_GDSCRIPT_UTILITY) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _gds_utilities_count);
+ GDScriptUtilityFunctions::FunctionPtr function = _gds_utilities_ptr[_code_ptr[ip + 2]];
+
Variant **argptrs = instruction_args;
GET_INSTRUCTION_ARG(dst, argc);
Callable::CallError err;
- GDScriptFunctions::call(func, (const Variant **)argptrs, argc, *dst, err);
+ function(dst, (const Variant **)argptrs, argc, err);
#ifdef DEBUG_ENABLED
if (err.error != Callable::CallError::CALL_OK) {
- String methodstr = GDScriptFunctions::get_func_name(func);
+ // TODO: Add this information in debug.
+ String methodstr = "<unkown function>";
if (dst->get_type() == Variant::STRING) {
- //call provided error string
- err_text = "Error calling built-in function '" + methodstr + "': " + String(*dst);
+ // Call provided error string.
+ err_text = "Error calling GDScript utility function '" + methodstr + "': " + String(*dst);
} else {
- err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
+ err_text = _get_call_error(err, "GDScript utility function '" + methodstr + "'", (const Variant **)argptrs);
}
OPCODE_BREAK;
}
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 668dfd4835..bd2d170e52 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -723,8 +723,8 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
} break;
case ClassNode::Member::ENUM: {
Dictionary enum_dict;
- for (int j = 0; j < m.m_enum->values.size(); i++) {
- enum_dict[m.m_enum->values[i].identifier->name] = m.m_enum->values[i].value;
+ for (int j = 0; j < m.m_enum->values.size(); j++) {
+ enum_dict[m.m_enum->values[j].identifier->name] = m.m_enum->values[j].value;
}
Dictionary api;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 6ddb0d149e..729be237ec 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/io/json.h"
#include "core/os/copymem.h"
+#include "editor/doc_tools.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
@@ -212,7 +213,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
void GDScriptLanguageProtocol::initialized(const Variant &p_params) {
lsp::GodotCapabilities capabilities;
- DocData *doc = EditorHelp::get_doc_data();
+ DocTools *doc = EditorHelp::get_doc_data();
for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
lsp::GodotNativeClassInfo gdclass;
gdclass.name = E->get().name;
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index f6643d07f9..60668e7b31 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -34,6 +34,7 @@
#include "../gdscript_parser.h"
#include "core/config/project_settings.h"
#include "core/object/script_language.h"
+#include "editor/doc_tools.h"
#include "editor/editor_file_system.h"
#include "editor/editor_help.h"
#include "editor/editor_node.h"
@@ -189,7 +190,7 @@ Error GDScriptWorkspace::initialize() {
return OK;
}
- DocData *doc = EditorHelp::get_doc_data();
+ DocTools *doc = EditorHelp::get_doc_data();
for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
const DocData::ClassDoc &class_data = E->value();
lsp::DocumentSymbol class_symbol;
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 288fd41c87..1029c53bbf 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -31,9 +31,9 @@
#ifndef GODOT_LSP_H
#define GODOT_LSP_H
+#include "core/doc_data.h"
#include "core/object/class_db.h"
#include "core/templates/list.h"
-#include "editor/doc_data.h"
namespace lsp {
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 6c2af66c65..0c4996e9bb 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -38,6 +38,7 @@
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_tokenizer.h"
+#include "gdscript_utility_functions.h"
#ifdef TESTS_ENABLED
#include "tests/test_gdscript.h"
@@ -130,6 +131,8 @@ void register_gdscript_types() {
gdscript_translation_parser_plugin.instance();
EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
#endif // TOOLS_ENABLED
+
+ GDScriptUtilityFunctions::register_functions();
}
void unregister_gdscript_types() {
@@ -156,6 +159,7 @@ void unregister_gdscript_types() {
GDScriptParser::cleanup();
GDScriptAnalyzer::cleanup();
+ GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub
index 58c033c75d..182272ffc7 100644
--- a/modules/glslang/SCsub
+++ b/modules/glslang/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_glslang = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_glslang"]:
thirdparty_dir = "#thirdparty/glslang/"
thirdparty_sources = [
@@ -70,7 +73,16 @@ if env["builtin_glslang"]:
env_thirdparty = env_glslang.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_glslang.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_glslang.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 0e6ec7f520..cda217acf0 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -1030,11 +1030,15 @@ void GridMapEditor::_notification(int p_what) {
for (int i = 0; i < 3; i++) {
grid[i] = RS::get_singleton()->mesh_create();
grid_instance[i] = RS::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
selection_level_instance[i] = RenderingServer::get_singleton()->instance_create2(selection_level_mesh[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(selection_level_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
}
selection_instance = RenderingServer::get_singleton()->instance_create2(selection_mesh, get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(selection_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
paste_instance = RenderingServer::get_singleton()->instance_create2(paste_mesh, get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(paste_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
_update_selection_transform();
_update_paste_indicator();
diff --git a/modules/jpg/SCsub b/modules/jpg/SCsub
index 8ee8e6dd6e..7c6ceeea29 100644
--- a/modules/jpg/SCsub
+++ b/modules/jpg/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_jpg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled for now as they are not commonly available as shared library
thirdparty_dir = "#thirdparty/jpeg-compressor/"
thirdparty_sources = [
@@ -17,7 +20,15 @@ env_jpg.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_jpg.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_jpg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_jpg.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 1ef991841b..66995382e7 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -447,7 +447,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
if (cell != last_cell) {
//cell changed, update pointer to indices
giw[cell * 2 + 1] = i;
- last_cell = cell;
solidw[cell] = true;
}
tiw[i] = triangle_sort[i].triangle_index;
@@ -543,7 +542,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
tf.width = grid_size;
tf.height = grid_size;
tf.depth = grid_size;
- tf.type = RD::TEXTURE_TYPE_3D;
+ tf.texture_type = RD::TEXTURE_TYPE_3D;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
Vector<Vector<uint8_t>> texdata;
@@ -695,7 +694,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
tf.width = atlas_size.width;
tf.height = atlas_size.height;
tf.array_layers = atlas_slices;
- tf.type = RD::TEXTURE_TYPE_2D_ARRAY;
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
@@ -826,84 +825,84 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
u.ids.push_back(vertex_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
u.ids.push_back(triangle_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 3;
u.ids.push_back(box_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 4;
u.ids.push_back(triangle_cell_indices_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 5;
u.ids.push_back(lights_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 6;
u.ids.push_back(seams_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 7;
u.ids.push_back(probe_positions_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 8;
u.ids.push_back(grid_texture);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
u.ids.push_back(grid_texture_sdf);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 10;
u.ids.push_back(albedo_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 11;
u.ids.push_back(emission_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 12;
u.ids.push_back(sampler);
base_uniforms.push_back(u);
@@ -917,7 +916,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
tf.width = atlas_size.width;
tf.height = atlas_size.height;
tf.depth = 1;
- tf.type = RD::TEXTURE_TYPE_2D;
+ tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
tf.format = RD::DATA_FORMAT_D32_SFLOAT;
@@ -1049,14 +1048,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(position_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 1;
u.ids.push_back(unocclude_tex); //will be unused
uniforms.push_back(u);
@@ -1089,42 +1088,42 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(light_source_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_dest_tex); //will be unused
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
u.ids.push_back(position_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.ids.push_back(normal_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 4;
u.ids.push_back(light_accum_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 5;
u.ids.push_back(light_primary_dynamic_tex);
uniforms.push_back(u);
@@ -1169,49 +1168,49 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(light_dest_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_source_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
u.ids.push_back(position_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.ids.push_back(normal_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 4;
u.ids.push_back(light_accum_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 5;
u.ids.push_back(unocclude_tex); //reuse unocclude tex
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 6;
u.ids.push_back(light_environment_tex); //reuse unocclude tex
uniforms.push_back(u);
@@ -1317,28 +1316,28 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 0;
u.ids.push_back(light_probe_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_dest_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
u.ids.push_back(light_primary_dynamic_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.ids.push_back(light_environment_tex);
uniforms.push_back(u);
@@ -1463,14 +1462,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(light_accum_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_accum_tex2);
uniforms.push_back(u);
@@ -1554,7 +1553,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
u.ids.push_back(light_accum_tex2);
uniforms.push_back(u);
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
index 5f5d25a3ee..4fcbe8fb43 100755
--- a/modules/mbedtls/SCsub
+++ b/modules/mbedtls/SCsub
@@ -5,8 +5,11 @@ Import("env_modules")
env_mbed_tls = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_mbedtls"]:
- # Thirdparty source files
thirdparty_sources = [
"aes.c",
"aesni.c",
@@ -96,7 +99,21 @@ if env["builtin_mbedtls"]:
env_thirdparty = env_mbed_tls.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_mbed_tls.add_source_files(module_obj, "*.cpp")
+
+if env["tests"]:
+ env_mbed_tls.Append(CPPDEFINES=["TESTS_ENABLED"])
+ env_mbed_tls.add_source_files(module_obj, "./tests/*.cpp")
+
+env.modules_sources += module_obj
-# Module sources
-env_mbed_tls.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index bec792450a..4ea38ebd60 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -44,6 +44,7 @@
#define PEM_END_CRT "-----END CERTIFICATE-----\n"
#include <mbedtls/debug.h>
+#include <mbedtls/md.h>
#include <mbedtls/pem.h>
CryptoKey *CryptoKeyMbedTLS::create() {
@@ -186,6 +187,68 @@ Error X509CertificateMbedTLS::save(String p_path) {
return OK;
}
+bool HMACContextMbedTLS::is_md_type_allowed(mbedtls_md_type_t p_md_type) {
+ switch (p_md_type) {
+ case MBEDTLS_MD_SHA1:
+ case MBEDTLS_MD_SHA256:
+ return true;
+ default:
+ return false;
+ }
+}
+
+HMACContext *HMACContextMbedTLS::create() {
+ return memnew(HMACContextMbedTLS);
+}
+
+Error HMACContextMbedTLS::start(HashingContext::HashType p_hash_type, PackedByteArray p_key) {
+ ERR_FAIL_COND_V_MSG(ctx != nullptr, ERR_FILE_ALREADY_IN_USE, "HMACContext already started.");
+
+ // HMAC keys can be any size.
+ ERR_FAIL_COND_V_MSG(p_key.empty(), ERR_INVALID_PARAMETER, "Key must not be empty.");
+
+ hash_type = p_hash_type;
+ mbedtls_md_type_t ht = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, hash_len);
+
+ bool allowed = HMACContextMbedTLS::is_md_type_allowed(ht);
+ ERR_FAIL_COND_V_MSG(!allowed, ERR_INVALID_PARAMETER, "Unsupported hash type.");
+
+ ctx = memalloc(sizeof(mbedtls_md_context_t));
+ mbedtls_md_init((mbedtls_md_context_t *)ctx);
+
+ mbedtls_md_setup((mbedtls_md_context_t *)ctx, mbedtls_md_info_from_type((mbedtls_md_type_t)ht), 1);
+ int ret = mbedtls_md_hmac_starts((mbedtls_md_context_t *)ctx, (const uint8_t *)p_key.ptr(), (size_t)p_key.size());
+ return ret ? FAILED : OK;
+}
+
+Error HMACContextMbedTLS::update(PackedByteArray p_data) {
+ ERR_FAIL_COND_V_MSG(ctx == nullptr, ERR_INVALID_DATA, "Start must be called before update.");
+
+ ERR_FAIL_COND_V_MSG(p_data.empty(), ERR_INVALID_PARAMETER, "Src must not be empty.");
+
+ int ret = mbedtls_md_hmac_update((mbedtls_md_context_t *)ctx, (const uint8_t *)p_data.ptr(), (size_t)p_data.size());
+ return ret ? FAILED : OK;
+}
+
+PackedByteArray HMACContextMbedTLS::finish() {
+ ERR_FAIL_COND_V_MSG(ctx == nullptr, PackedByteArray(), "Start must be called before finish.");
+ ERR_FAIL_COND_V_MSG(hash_len == 0, PackedByteArray(), "Unsupported hash type.");
+
+ PackedByteArray out;
+ out.resize(hash_len);
+
+ unsigned char *out_ptr = (unsigned char *)out.ptrw();
+ int ret = mbedtls_md_hmac_finish((mbedtls_md_context_t *)ctx, out_ptr);
+
+ mbedtls_md_free((mbedtls_md_context_t *)ctx);
+ memfree((mbedtls_md_context_t *)ctx);
+ ctx = nullptr;
+ hash_len = 0;
+
+ ERR_FAIL_COND_V_MSG(ret, PackedByteArray(), "Error received while finishing HMAC");
+ return out;
+}
+
Crypto *CryptoMbedTLS::create() {
return memnew(CryptoMbedTLS);
}
@@ -199,6 +262,7 @@ void CryptoMbedTLS::initialize_crypto() {
Crypto::_load_default_certificates = load_default_certificates;
X509CertificateMbedTLS::make_default();
CryptoKeyMbedTLS::make_default();
+ HMACContextMbedTLS::make_default();
}
void CryptoMbedTLS::finalize_crypto() {
@@ -210,6 +274,7 @@ void CryptoMbedTLS::finalize_crypto() {
}
X509CertificateMbedTLS::finalize();
CryptoKeyMbedTLS::finalize();
+ HMACContextMbedTLS::finalize();
}
CryptoMbedTLS::CryptoMbedTLS() {
@@ -313,7 +378,7 @@ PackedByteArray CryptoMbedTLS::generate_random_bytes(int p_bytes) {
return out;
}
-mbedtls_md_type_t CryptoMbedTLS::_md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
+mbedtls_md_type_t CryptoMbedTLS::md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
switch (p_hash_type) {
case HashingContext::HASH_MD5:
r_size = 16;
@@ -332,7 +397,7 @@ mbedtls_md_type_t CryptoMbedTLS::_md_type_from_hashtype(HashingContext::HashType
Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Ref<CryptoKey> p_key) {
int size;
- mbedtls_md_type_t type = _md_type_from_hashtype(p_hash_type, size);
+ mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, Vector<uint8_t>(), "Invalid hash type.");
ERR_FAIL_COND_V_MSG(p_hash.size() != size, Vector<uint8_t>(), "Invalid hash provided. Size must be " + itos(size));
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
@@ -350,7 +415,7 @@ Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector
bool CryptoMbedTLS::verify(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Vector<uint8_t> p_signature, Ref<CryptoKey> p_key) {
int size;
- mbedtls_md_type_t type = _md_type_from_hashtype(p_hash_type, size);
+ mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, false, "Invalid hash type.");
ERR_FAIL_COND_V_MSG(p_hash.size() != size, false, "Invalid hash provided. Size must be " + itos(size));
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h
index e40ca08643..990f8ae578 100644
--- a/modules/mbedtls/crypto_mbedtls.h
+++ b/modules/mbedtls/crypto_mbedtls.h
@@ -101,12 +101,31 @@ public:
friend class SSLContextMbedTLS;
};
+class HMACContextMbedTLS : public HMACContext {
+private:
+ HashingContext::HashType hash_type;
+ int hash_len = 0;
+ void *ctx = nullptr;
+
+public:
+ static HMACContext *create();
+ static void make_default() { HMACContext::_create = create; }
+ static void finalize() { HMACContext::_create = nullptr; }
+
+ static bool is_md_type_allowed(mbedtls_md_type_t p_md_type);
+
+ virtual Error start(HashingContext::HashType p_hash_type, PackedByteArray p_key);
+ virtual Error update(PackedByteArray p_data);
+ virtual PackedByteArray finish();
+
+ HMACContextMbedTLS() {}
+};
+
class CryptoMbedTLS : public Crypto {
private:
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
static X509CertificateMbedTLS *default_certs;
- mbedtls_md_type_t _md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
public:
static Crypto *create();
@@ -114,6 +133,7 @@ public:
static void finalize_crypto();
static X509CertificateMbedTLS *get_default_certificates();
static void load_default_certificates(String p_path);
+ static mbedtls_md_type_t md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
virtual PackedByteArray generate_random_bytes(int p_bytes);
virtual Ref<CryptoKey> generate_rsa(int p_bytes);
diff --git a/modules/mbedtls/register_types.cpp b/modules/mbedtls/register_types.cpp
index 84a27c29bd..59abbac8ec 100644
--- a/modules/mbedtls/register_types.cpp
+++ b/modules/mbedtls/register_types.cpp
@@ -35,6 +35,10 @@
#include "packet_peer_mbed_dtls.h"
#include "stream_peer_mbedtls.h"
+#ifdef TESTS_ENABLED
+#include "tests/test_crypto_mbedtls.h"
+#endif
+
void register_mbedtls_types() {
CryptoMbedTLS::initialize_crypto();
StreamPeerMbedTLS::initialize_ssl();
diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.cpp b/modules/mbedtls/tests/test_crypto_mbedtls.cpp
new file mode 100644
index 0000000000..c5a27aa794
--- /dev/null
+++ b/modules/mbedtls/tests/test_crypto_mbedtls.cpp
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* test_crypto_mbedtls.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "modules/mbedtls/tests/test_crypto_mbedtls.h"
+
+#include "modules/mbedtls/crypto_mbedtls.h"
+#include "tests/test_macros.h"
+
+namespace TestCryptoMbedTLS {
+
+void hmac_digest_test(HashingContext::HashType ht, String expected_hex) {
+ CryptoMbedTLS crypto;
+ PackedByteArray key = String("supersecretkey").to_utf8_buffer();
+ PackedByteArray msg = String("Return of the MAC!").to_utf8_buffer();
+ PackedByteArray digest = crypto.hmac_digest(ht, key, msg);
+ String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
+ CHECK(hex == expected_hex);
+}
+
+void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex) {
+ HMACContextMbedTLS ctx;
+ PackedByteArray key = String("supersecretkey").to_utf8_buffer();
+ PackedByteArray msg1 = String("Return of ").to_utf8_buffer();
+ PackedByteArray msg2 = String("the MAC!").to_utf8_buffer();
+ Error err = ctx.start(ht, key);
+ CHECK(err == OK);
+ err = ctx.update(msg1);
+ CHECK(err == OK);
+ err = ctx.update(msg2);
+ CHECK(err == OK);
+ PackedByteArray digest = ctx.finish();
+ String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
+ CHECK(hex == expected_hex);
+}
+} // namespace TestCryptoMbedTLS
diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.h b/modules/mbedtls/tests/test_crypto_mbedtls.h
new file mode 100644
index 0000000000..7b1e062239
--- /dev/null
+++ b/modules/mbedtls/tests/test_crypto_mbedtls.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* test_crypto_mbedtls.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 TEST_CRYPTO_MBEDTLS_H
+#define TEST_CRYPTO_MBEDTLS_H
+
+#include "core/crypto/hashing_context.h"
+
+#include "tests/test_macros.h"
+
+namespace TestCryptoMbedTLS {
+
+void hmac_digest_test(HashingContext::HashType ht, String expected_hex);
+
+TEST_CASE("[CryptoMbedTLS] HMAC digest") {
+ // SHA-256
+ hmac_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
+
+ // SHA-1
+ hmac_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
+}
+
+void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex);
+
+TEST_CASE("[HMACContext] HMAC digest") {
+ // SHA-256
+ hmac_context_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
+
+ // SHA-1
+ hmac_context_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
+}
+} // namespace TestCryptoMbedTLS
+
+#endif // TEST_CRYPTO_MBEDTLS_H
diff --git a/modules/meshoptimizer/SCsub b/modules/meshoptimizer/SCsub
new file mode 100644
index 0000000000..3f86bb4f00
--- /dev/null
+++ b/modules/meshoptimizer/SCsub
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_meshoptimizer = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/meshoptimizer/"
+thirdparty_sources = [
+ "allocator.cpp",
+ "clusterizer.cpp",
+ "indexcodec.cpp",
+ "indexgenerator.cpp",
+ "overdrawanalyzer.cpp",
+ "overdrawoptimizer.cpp",
+ "simplifier.cpp",
+ "spatialorder.cpp",
+ "stripifier.cpp",
+ "vcacheanalyzer.cpp",
+ "vcacheoptimizer.cpp",
+ "vertexcodec.cpp",
+ "vertexfilter.cpp",
+ "vfetchanalyzer.cpp",
+ "vfetchoptimizer.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_thirdparty = env_meshoptimizer.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_meshoptimizer.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py
new file mode 100644
index 0000000000..82e4e43397
--- /dev/null
+++ b/modules/meshoptimizer/config.py
@@ -0,0 +1,7 @@
+def can_build(env, platform):
+ # Having this on release by default, it's small and a lot of users like to do procedural stuff
+ return True
+
+
+def configure(env):
+ pass
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
new file mode 100644
index 0000000000..26c8c6ab72
--- /dev/null
+++ b/modules/meshoptimizer/register_types.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "register_types.h"
+#include "scene/resources/surface_tool.h"
+#include "thirdparty/meshoptimizer/meshoptimizer.h"
+
+void register_meshoptimizer_types() {
+ SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
+ SurfaceTool::simplify_func = meshopt_simplify;
+}
+
+void unregister_meshoptimizer_types() {
+ SurfaceTool::optimize_vertex_cache_func = nullptr;
+ SurfaceTool::simplify_func = nullptr;
+}
diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h
new file mode 100644
index 0000000000..42b3a76a85
--- /dev/null
+++ b/modules/meshoptimizer/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 MESHOPTIMIZER_REGISTER_TYPES_H
+#define MESHOPTIMIZER_REGISTER_TYPES_H
+
+void register_meshoptimizer_types();
+void unregister_meshoptimizer_types();
+
+#endif // PVR_REGISTER_TYPES_H
diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub
new file mode 100644
index 0000000000..f4d1605d55
--- /dev/null
+++ b/modules/minimp3/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_minimp3 = env_modules.Clone()
+
+thirdparty_dir = "#thirdparty/minimp3/"
+
+# Treat minimp3 headers as system headers to avoid raising warnings. Not supported on MSVC.
+if not env.msvc:
+ env_minimp3.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
+else:
+ env_minimp3.Prepend(CPPPATH=[thirdparty_dir])
+
+# Godot's own source files
+env_minimp3.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
new file mode 100644
index 0000000000..b20c043e0c
--- /dev/null
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -0,0 +1,228 @@
+/*************************************************************************/
+/* audio_stream_mp3.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#define MINIMP3_ONLY_MP3
+#define MINIMP3_FLOAT_OUTPUT
+#define MINIMP3_IMPLEMENTATION
+#define MINIMP3_NO_STDIO
+
+#include "audio_stream_mp3.h"
+
+#include "core/os/file_access.h"
+
+void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+ ERR_FAIL_COND(!active);
+
+ int todo = p_frames;
+
+ while (todo && active) {
+ mp3dec_frame_info_t frame_info;
+ mp3d_sample_t *buf_frame = nullptr;
+
+ int samples_mixed = mp3dec_ex_read_frame(mp3d, &buf_frame, &frame_info, mp3_stream->channels);
+
+ if (samples_mixed) {
+ p_buffer[p_frames - todo] = AudioFrame(buf_frame[0], buf_frame[samples_mixed - 1]);
+ --todo;
+ ++frames_mixed;
+ }
+
+ else {
+ //EOF
+ if (mp3_stream->loop) {
+ seek(mp3_stream->loop_offset);
+ loops++;
+ } else {
+ //fill remainder with silence
+ for (int i = p_frames - todo; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0, 0);
+ }
+ active = false;
+ todo = 0;
+ }
+ }
+ }
+}
+
+float AudioStreamPlaybackMP3::get_stream_sampling_rate() {
+ return mp3_stream->sample_rate;
+}
+
+void AudioStreamPlaybackMP3::start(float p_from_pos) {
+ active = true;
+ seek(p_from_pos);
+ loops = 0;
+ _begin_resample();
+}
+
+void AudioStreamPlaybackMP3::stop() {
+ active = false;
+}
+
+bool AudioStreamPlaybackMP3::is_playing() const {
+ return active;
+}
+
+int AudioStreamPlaybackMP3::get_loop_count() const {
+ return loops;
+}
+
+float AudioStreamPlaybackMP3::get_playback_position() const {
+ return float(frames_mixed) / mp3_stream->sample_rate;
+}
+
+void AudioStreamPlaybackMP3::seek(float p_time) {
+ if (!active)
+ return;
+
+ if (p_time >= mp3_stream->get_length()) {
+ p_time = 0;
+ }
+
+ frames_mixed = uint32_t(mp3_stream->sample_rate * p_time);
+ mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels);
+}
+
+AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() {
+ if (mp3d) {
+ mp3dec_ex_close(mp3d);
+ memfree(mp3d);
+ }
+}
+
+Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() {
+ Ref<AudioStreamPlaybackMP3> mp3s;
+
+ ERR_FAIL_COND_V(data == nullptr, mp3s);
+
+ mp3s.instance();
+ mp3s->mp3_stream = Ref<AudioStreamMP3>(this);
+ mp3s->mp3d = (mp3dec_ex_t *)memalloc(sizeof(mp3dec_ex_t));
+
+ int errorcode = mp3dec_ex_open_buf(mp3s->mp3d, (const uint8_t *)data, data_len, MP3D_SEEK_TO_SAMPLE);
+
+ mp3s->frames_mixed = 0;
+ mp3s->active = false;
+ mp3s->loops = 0;
+
+ if (errorcode) {
+ ERR_FAIL_COND_V(errorcode, Ref<AudioStreamPlaybackMP3>());
+ }
+
+ return mp3s;
+}
+
+String AudioStreamMP3::get_stream_name() const {
+ return ""; //return stream_name;
+}
+
+void AudioStreamMP3::clear_data() {
+ if (data) {
+ memfree(data);
+ data = nullptr;
+ data_len = 0;
+ }
+}
+
+void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) {
+ int src_data_len = p_data.size();
+ const uint8_t *src_datar = p_data.ptr();
+
+ mp3dec_ex_t mp3d;
+ mp3dec_ex_open_buf(&mp3d, src_datar, src_data_len, MP3D_SEEK_TO_SAMPLE);
+
+ channels = mp3d.info.channels;
+ sample_rate = mp3d.info.hz;
+ length = float(mp3d.samples) / (sample_rate * float(channels));
+
+ mp3dec_ex_close(&mp3d);
+
+ clear_data();
+
+ data = memalloc(src_data_len);
+ copymem(data, src_datar, src_data_len);
+ data_len = src_data_len;
+}
+
+Vector<uint8_t> AudioStreamMP3::get_data() const {
+ Vector<uint8_t> vdata;
+
+ if (data_len && data) {
+ vdata.resize(data_len);
+ {
+ uint8_t *w = vdata.ptrw();
+ copymem(w, data, data_len);
+ }
+ }
+
+ return vdata;
+}
+
+void AudioStreamMP3::set_loop(bool p_enable) {
+ loop = p_enable;
+}
+
+bool AudioStreamMP3::has_loop() const {
+ return loop;
+}
+
+void AudioStreamMP3::set_loop_offset(float p_seconds) {
+ loop_offset = p_seconds;
+}
+
+float AudioStreamMP3::get_loop_offset() const {
+ return loop_offset;
+}
+
+float AudioStreamMP3::get_length() const {
+ return length;
+}
+
+void AudioStreamMP3::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamMP3::set_data);
+ ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamMP3::get_data);
+
+ ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamMP3::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamMP3::has_loop);
+
+ ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamMP3::set_loop_offset);
+ ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamMP3::get_loop_offset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop", "has_loop");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop_offset", "get_loop_offset");
+}
+
+AudioStreamMP3::AudioStreamMP3() {
+}
+
+AudioStreamMP3::~AudioStreamMP3() {
+ clear_data();
+}
diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h
new file mode 100644
index 0000000000..8d67190ac5
--- /dev/null
+++ b/modules/minimp3/audio_stream_mp3.h
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* audio_stream_mp3.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 AUDIO_STREAM_MP3_H
+#define AUDIO_STREAM_MP3_H
+
+#include "core/io/resource_loader.h"
+#include "servers/audio/audio_stream.h"
+
+#include "minimp3_ex.h"
+
+class AudioStreamMP3;
+
+class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled {
+ GDCLASS(AudioStreamPlaybackMP3, AudioStreamPlaybackResampled);
+
+ mp3dec_ex_t *mp3d = nullptr;
+ uint32_t frames_mixed = 0;
+ bool active = false;
+ int loops = 0;
+
+ friend class AudioStreamMP3;
+
+ Ref<AudioStreamMP3> mp3_stream;
+
+protected:
+ virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override;
+ virtual float get_stream_sampling_rate() override;
+
+public:
+ virtual void start(float p_from_pos = 0.0) override;
+ virtual void stop() override;
+ virtual bool is_playing() const override;
+
+ virtual int get_loop_count() const override; //times it looped
+
+ virtual float get_playback_position() const override;
+ virtual void seek(float p_time) override;
+
+ AudioStreamPlaybackMP3() {}
+ ~AudioStreamPlaybackMP3();
+};
+
+class AudioStreamMP3 : public AudioStream {
+ GDCLASS(AudioStreamMP3, AudioStream);
+ OBJ_SAVE_TYPE(AudioStream) //children are all saved as AudioStream, so they can be exchanged
+ RES_BASE_EXTENSION("mp3str");
+
+ friend class AudioStreamPlaybackMP3;
+
+ void *data = nullptr;
+ uint32_t data_len = 0;
+
+ float sample_rate = 1;
+ int channels = 1;
+ float length = 0;
+ bool loop = false;
+ float loop_offset = 0;
+ void clear_data();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_loop(bool p_enable);
+ bool has_loop() const;
+
+ void set_loop_offset(float p_seconds);
+ float get_loop_offset() const;
+
+ virtual Ref<AudioStreamPlayback> instance_playback() override;
+ virtual String get_stream_name() const override;
+
+ void set_data(const Vector<uint8_t> &p_data);
+ Vector<uint8_t> get_data() const;
+
+ virtual float get_length() const override;
+
+ AudioStreamMP3();
+ virtual ~AudioStreamMP3();
+};
+
+#endif // AUDIO_STREAM_MP3_H
diff --git a/modules/minimp3/config.py b/modules/minimp3/config.py
new file mode 100644
index 0000000000..bd35d099b9
--- /dev/null
+++ b/modules/minimp3/config.py
@@ -0,0 +1,16 @@
+def can_build(env, platform):
+ return True
+
+
+def configure(env):
+ pass
+
+
+def get_doc_classes():
+ return [
+ "AudioStreamMP3",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml
new file mode 100644
index 0000000000..92e777ca0f
--- /dev/null
+++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamMP3" inherits="AudioStream" version="4.0">
+ <brief_description>
+ MP3 audio stream driver.
+ </brief_description>
+ <description>
+ MP3 audio stream driver.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )">
+ Contains the audio data in bytes.
+ </member>
+ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
+ If [code]true[/code], the stream will automatically loop when it reaches the end.
+ </member>
+ <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0">
+ Time in seconds at which the stream starts after being looped.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp
new file mode 100644
index 0000000000..2c648b8efe
--- /dev/null
+++ b/modules/minimp3/register_types.cpp
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "register_types.h"
+
+#include "audio_stream_mp3.h"
+
+#ifdef TOOLS_ENABLED
+#include "core/config/engine.h"
+#include "resource_importer_mp3.h"
+#endif
+
+void register_minimp3_types() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ Ref<ResourceImporterMP3> mp3_import;
+ mp3_import.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(mp3_import);
+ }
+#endif
+ ClassDB::register_class<AudioStreamMP3>();
+}
+
+void unregister_minimp3_types() {
+}
diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h
new file mode 100644
index 0000000000..0d841e4987
--- /dev/null
+++ b/modules/minimp3/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 MINIMP3_REGISTER_TYPES_H
+#define MINIMP3_REGISTER_TYPES_H
+
+void register_minimp3_types();
+void unregister_minimp3_types();
+
+#endif // MINIMP3_REGISTER_TYPES_H
diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp
new file mode 100644
index 0000000000..82e536a755
--- /dev/null
+++ b/modules/minimp3/resource_importer_mp3.cpp
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* resource_importer_mp3.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "resource_importer_mp3.h"
+
+#include "core/io/resource_saver.h"
+#include "core/os/file_access.h"
+#include "scene/resources/texture.h"
+
+String ResourceImporterMP3::get_importer_name() const {
+ return "mp3";
+}
+
+String ResourceImporterMP3::get_visible_name() const {
+ return "MP3";
+}
+
+void ResourceImporterMP3::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("mp3");
+}
+
+String ResourceImporterMP3::get_save_extension() const {
+ return "mp3str";
+}
+
+String ResourceImporterMP3::get_resource_type() const {
+ return "AudioStreamMP3";
+}
+
+bool ResourceImporterMP3::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+ return true;
+}
+
+int ResourceImporterMP3::get_preset_count() const {
+ return 0;
+}
+
+String ResourceImporterMP3::get_preset_name(int p_idx) const {
+ return String();
+}
+
+void ResourceImporterMP3::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0));
+}
+
+Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+ bool loop = p_options["loop"];
+ float loop_offset = p_options["loop_offset"];
+
+ FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
+
+ ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+
+ size_t len = f->get_len();
+
+ Vector<uint8_t> data;
+ data.resize(len);
+ uint8_t *w = data.ptrw();
+
+ f->get_buffer(w, len);
+
+ memdelete(f);
+
+ Ref<AudioStreamMP3> mp3_stream;
+ mp3_stream.instance();
+
+ mp3_stream->set_data(data);
+ ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT);
+ mp3_stream->set_loop(loop);
+ mp3_stream->set_loop_offset(loop_offset);
+
+ return ResourceSaver::save(p_save_path + ".mp3str", mp3_stream);
+}
+
+ResourceImporterMP3::ResourceImporterMP3() {
+}
diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h
new file mode 100644
index 0000000000..c1e8315e21
--- /dev/null
+++ b/modules/minimp3/resource_importer_mp3.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* resource_importer_mp3.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 RESOURCE_IMPORTER_MP3_H
+#define RESOURCE_IMPORTER_MP3_H
+
+#include "audio_stream_mp3.h"
+#include "core/io/resource_importer.h"
+
+class ResourceImporterMP3 : public ResourceImporter {
+ GDCLASS(ResourceImporterMP3, ResourceImporter);
+
+public:
+ virtual String get_importer_name() const override;
+ virtual String get_visible_name() const override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual String get_save_extension() const override;
+ virtual String get_resource_type() const override;
+
+ virtual int get_preset_count() const override;
+ virtual String get_preset_name(int p_idx) const override;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
+
+ virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
+
+ ResourceImporterMP3();
+};
+
+#endif // RESOURCE_IMPORTER_MP3_H
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
index 04f8c80243..28494bff6e 100644
--- a/modules/mono/build_scripts/make_android_mono_config.py
+++ b/modules/mono/build_scripts/make_android_mono_config.py
@@ -38,10 +38,10 @@ String get_godot_android_mono_config() {
Vector<uint8_t> data;
data.resize(config_uncompressed_size);
uint8_t* w = data.ptrw();
- Compression::decompress(w.ptr(), config_uncompressed_size, config_compressed_data,
+ Compression::decompress(w, config_uncompressed_size, config_compressed_data,
config_compressed_size, Compression::MODE_DEFLATE);
String s;
- if (s.parse_utf8((const char *)w.ptr(), data.size())) {
+ if (s.parse_utf8((const char *)w, data.size())) {
ERR_FAIL_V(String());
}
return s;
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index 6057004166..309abfbff7 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -97,6 +97,7 @@ def configure(env, env_mono):
copy_mono_root = env["copy_mono_root"]
mono_prefix = env["mono_prefix"]
+ mono_bcl = env["mono_bcl"]
mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"]
@@ -262,7 +263,8 @@ def configure(env, env_mono):
env_mono.Append(CPPDEFINES=["_REENTRANT"])
if mono_static:
- env.Append(LINKFLAGS=["-rdynamic"])
+ if not is_javascript:
+ env.Append(LINKFLAGS=["-rdynamic"])
mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a")
@@ -397,7 +399,7 @@ def configure(env, env_mono):
if tools_enabled:
# Only supported for editor builds.
- copy_mono_root_files(env, mono_root)
+ copy_mono_root_files(env, mono_root, mono_bcl)
def make_template_dir(env, mono_root):
@@ -430,7 +432,7 @@ def make_template_dir(env, mono_root):
copy_mono_shared_libs(env, mono_root, template_mono_root_dir)
-def copy_mono_root_files(env, mono_root):
+def copy_mono_root_files(env, mono_root, mono_bcl):
from glob import glob
from shutil import copy
from shutil import rmtree
@@ -455,7 +457,7 @@ def copy_mono_root_files(env, mono_root):
# Copy framework assemblies
- mono_framework_dir = os.path.join(mono_root, "lib", "mono", "4.5")
+ mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5")
mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades")
editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5")
diff --git a/modules/mono/config.py b/modules/mono/config.py
index c4a6b408e6..4c851a2989 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -27,6 +27,14 @@ def configure(env):
PathVariable.PathAccept,
)
)
+ envvars.Add(
+ PathVariable(
+ "mono_bcl",
+ "Path to a custom Mono BCL (Base Class Library) directory for the target platform",
+ "",
+ PathVariable.PathAccept,
+ )
+ )
envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static))
envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True))
envvars.Add(BoolVariable("build_cil", "Build C# solutions", True))
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index b4537f531d..63ac0956f4 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2984,7 +2984,7 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
}
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
if (!p_script->tool) {
p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 3e4e6c3f86..f482cc21f0 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -31,6 +31,7 @@
#ifndef CSHARP_SCRIPT_H
#define CSHARP_SCRIPT_H
+#include "core/doc_data.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/script_language.h"
@@ -189,6 +190,14 @@ public:
String get_source_code() const override;
void set_source_code(const String &p_code) override;
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ // TODO
+ static Vector<DocData::ClassDoc> docs;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
Error reload(bool p_keep_state = false) override;
bool has_script_signal(const StringName &p_signal) const override;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index 9514cc9622..1a1639aac7 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -2,6 +2,7 @@ using Godot;
using System;
using Godot.Collections;
using GodotTools.Internals;
+using JetBrains.Annotations;
using File = GodotTools.Utils.File;
using Path = System.IO.Path;
@@ -26,6 +27,9 @@ namespace GodotTools.Build
private TextEdit buildLog;
private PopupMenu issuesListContextMenu;
+ private readonly object pendingBuildLogTextLock = new object();
+ [NotNull] private string pendingBuildLogText = string.Empty;
+
[Signal] public event Action BuildStateChanged;
public bool HasBuildExited { get; private set; } = false;
@@ -240,16 +244,34 @@ namespace GodotTools.Build
EmitSignal(nameof(BuildStateChanged));
}
+ private void UpdateBuildLogText()
+ {
+ lock (pendingBuildLogTextLock)
+ {
+ buildLog.Text += pendingBuildLogText;
+ pendingBuildLogText = string.Empty;
+ ScrollToLastNonEmptyLogLine();
+ }
+ }
+
private void StdOutputReceived(string text)
{
- buildLog.Text += text + "\n";
- ScrollToLastNonEmptyLogLine();
+ lock (pendingBuildLogTextLock)
+ {
+ if (pendingBuildLogText.Length == 0)
+ CallDeferred(nameof(UpdateBuildLogText));
+ pendingBuildLogText += text + "\n";
+ }
}
private void StdErrorReceived(string text)
{
- buildLog.Text += text + "\n";
- ScrollToLastNonEmptyLogLine();
+ lock (pendingBuildLogTextLock)
+ {
+ if (pendingBuildLogText.Length == 0)
+ CallDeferred(nameof(UpdateBuildLogText));
+ pendingBuildLogText += text + "\n";
+ }
}
private void ScrollToLastNonEmptyLogLine()
@@ -377,12 +399,14 @@ namespace GodotTools.Build
BuildManager.BuildStarted += BuildStarted;
BuildManager.BuildFinished += BuildFinished;
// StdOutput/Error can be received from different threads, so we need to use CallDeferred
- BuildManager.StdOutputReceived += line => CallDeferred(nameof(StdOutputReceived), line);
- BuildManager.StdErrorReceived += line => CallDeferred(nameof(StdErrorReceived), line);
+ BuildManager.StdOutputReceived += StdOutputReceived;
+ BuildManager.StdErrorReceived += StdErrorReceived;
}
public void OnBeforeSerialize()
{
+ // In case it didn't update yet. We don't want to have to serialize any pending output.
+ UpdateBuildLogText();
}
public void OnAfterDeserialize()
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index e18ed7f107..e9bb701562 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -173,6 +173,8 @@ namespace GodotTools.Export
assemblies[projectDllName] = projectDllSrcPath;
+ string bclDir = DeterminePlatformBclDir(platform);
+
if (platform == OS.Platforms.Android)
{
string godotAndroidExtProfileDir = GetBclProfileDir("godot_android_ext");
@@ -183,8 +185,49 @@ namespace GodotTools.Export
assemblies["Mono.Android"] = monoAndroidAssemblyPath;
}
+ else if (platform == OS.Platforms.HTML5)
+ {
+ // Ideally these would be added automatically since they're referenced by the wasm BCL assemblies.
+ // However, at least in the case of 'WebAssembly.Net.Http' for some reason the BCL assemblies
+ // reference a different version even though the assembly is the same, for some weird reason.
- string bclDir = DeterminePlatformBclDir(platform);
+ var wasmFrameworkAssemblies = new[] {"WebAssembly.Bindings", "WebAssembly.Net.WebSockets"};
+
+ foreach (string thisWasmFrameworkAssemblyName in wasmFrameworkAssemblies)
+ {
+ string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName + ".dll");
+ if (!File.Exists(thisWasmFrameworkAssemblyPath))
+ throw new FileNotFoundException($"Assembly not found: '{thisWasmFrameworkAssemblyName}'", thisWasmFrameworkAssemblyPath);
+ assemblies[thisWasmFrameworkAssemblyName] = thisWasmFrameworkAssemblyPath;
+ }
+
+ // Assemblies that can have a different name in a newer version. Newer version must come first and it has priority.
+ (string newName, string oldName)[] wasmFrameworkAssembliesOneOf = new[]
+ {
+ ("System.Net.Http.WebAssemblyHttpHandler", "WebAssembly.Net.Http")
+ };
+
+ foreach (var thisWasmFrameworkAssemblyName in wasmFrameworkAssembliesOneOf)
+ {
+ string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.newName + ".dll");
+ if (File.Exists(thisWasmFrameworkAssemblyPath))
+ {
+ assemblies[thisWasmFrameworkAssemblyName.newName] = thisWasmFrameworkAssemblyPath;
+ }
+ else
+ {
+ thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.oldName + ".dll");
+ if (!File.Exists(thisWasmFrameworkAssemblyPath))
+ {
+ throw new FileNotFoundException("Expected one of the following assemblies but none were found: " +
+ $"'{thisWasmFrameworkAssemblyName.newName}' / '{thisWasmFrameworkAssemblyName.oldName}'",
+ thisWasmFrameworkAssemblyPath);
+ }
+
+ assemblies[thisWasmFrameworkAssemblyName.oldName] = thisWasmFrameworkAssemblyPath;
+ }
+ }
+ }
var initialAssemblies = assemblies.Duplicate();
internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies);
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index ff3122a77f..ad7e5d4200 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -97,7 +97,7 @@
#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(12)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
@@ -185,7 +185,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
return String();
}
- DocData *doc = EditorHelp::get_doc_data();
+ DocTools *doc = EditorHelp::get_doc_data();
String bbcode = p_bbcode;
@@ -1999,12 +1999,12 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
{ \
- output.append("\tmono_add_internal_call("); \
+ output.append("\tGDMonoUtils::add_internal_call("); \
output.append("\"" BINDINGS_NAMESPACE "."); \
output.append(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
output.append("::"); \
output.append(m_icall.name); \
- output.append("\", (void*)"); \
+ output.append("\", "); \
output.append(m_icall.name); \
output.append(");\n"); \
}
@@ -3100,44 +3100,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
INSERT_INT_TYPE("sbyte", int8_t, int64_t);
INSERT_INT_TYPE("short", int16_t, int64_t);
INSERT_INT_TYPE("int", int32_t, int64_t);
+ INSERT_INT_TYPE("long", int64_t, int64_t);
INSERT_INT_TYPE("byte", uint8_t, int64_t);
INSERT_INT_TYPE("ushort", uint16_t, int64_t);
INSERT_INT_TYPE("uint", uint32_t, int64_t);
-
- itype = TypeInterface::create_value_type(String("long"));
- {
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
- itype.c_type = "int64_t";
- itype.c_arg_in = "&%s_in";
- }
- itype.c_type_in = "int64_t*";
- itype.c_type_out = "int64_t";
- itype.im_type_in = "ref " + itype.name;
- itype.im_type_out = "out " + itype.name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
- builtin_types.insert(itype.cname, itype);
-
- itype = TypeInterface::create_value_type(String("ulong"));
- {
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
- itype.c_type = "int64_t";
- itype.c_arg_in = "&%s_in";
- }
- itype.c_type_in = "uint64_t*";
- itype.c_type_out = "uint64_t";
- itype.im_type_in = "ref " + itype.name;
- itype.im_type_out = "out " + itype.name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
- builtin_types.insert(itype.cname, itype);
+ INSERT_INT_TYPE("ulong", uint64_t, int64_t);
}
// Floating point types
@@ -3149,20 +3116,16 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = "float";
{
// The expected type for 'float' in ptrcall is 'double'
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "float*";
+ itype.c_type_in = "float";
itype.c_type_out = "float";
itype.c_arg_in = "&%s_in";
}
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = "out " + itype.proxy_name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
// double
@@ -3171,20 +3134,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "double";
{
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "double*";
+ itype.c_type_in = "double";
itype.c_type_out = "double";
- itype.c_arg_in = "&%s_in";
+ itype.c_arg_in = "&%s";
}
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = "out " + itype.proxy_name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index eeab518954..0cc1bb5f46 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -31,9 +31,10 @@
#ifndef BINDINGS_GENERATOR_H
#define BINDINGS_GENERATOR_H
+#include "core/doc_data.h"
#include "core/object/class_db.h"
#include "core/string/string_builder.h"
-#include "editor/doc_data.h"
+#include "editor/doc_tools.h"
#include "editor/editor_help.h"
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
@@ -44,7 +45,7 @@ class BindingsGenerator {
struct ConstantInterface {
String name;
String proxy_name;
- int value;
+ int value = 0;
const DocData::ConstantDoc *const_doc;
ConstantInterface() {}
@@ -74,7 +75,7 @@ class BindingsGenerator {
struct PropertyInterface {
StringName cname;
String proxy_name;
- int index;
+ int index = 0;
StringName setter;
StringName getter;
@@ -479,7 +480,7 @@ class BindingsGenerator {
String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq]
String im_sig; // Signature for the C# method declaration
String unique_sig; // Unique signature to avoid duplicates in containers
- bool editor_only;
+ bool editor_only = false;
InternalCall() {}
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 68fc372959..f9be19bbe2 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -47,7 +47,6 @@
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/osx_utils.h"
-#include "bindings_generator.h"
#include "code_completion.h"
#include "godotsharp_export.h"
#include "script_class_parser.h"
@@ -173,35 +172,6 @@ MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_st
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-BindingsGenerator *godot_icall_BindingsGenerator_Ctor() {
- return memnew(BindingsGenerator);
-}
-
-void godot_icall_BindingsGenerator_Dtor(BindingsGenerator *p_handle) {
- memdelete(p_handle);
-}
-
-MonoBoolean godot_icall_BindingsGenerator_LogPrintEnabled(BindingsGenerator *p_handle) {
- return p_handle->is_log_print_enabled();
-}
-
-void godot_icall_BindingsGenerator_SetLogPrintEnabled(BindingsGenerator p_handle, MonoBoolean p_enabled) {
- p_handle.set_log_print_enabled(p_enabled);
-}
-
-int32_t godot_icall_BindingsGenerator_GenerateCsApi(BindingsGenerator *p_handle, MonoString *p_output_dir) {
- String output_dir = GDMonoMarshal::mono_string_to_godot(p_output_dir);
- return p_handle->generate_cs_api(output_dir);
-}
-
-uint32_t godot_icall_BindingsGenerator_Version() {
- return BindingsGenerator::get_version();
-}
-
-uint32_t godot_icall_BindingsGenerator_CsGlueVersion() {
- return CS_GLUE_VERSION;
-}
-
int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObject *p_classes, MonoString **r_error_str) {
*r_error_str = nullptr;
@@ -400,75 +370,66 @@ MonoBoolean godot_icall_Utils_OS_UnixFileHasExecutableAccess(MonoString *p_file_
void register_editor_internal_calls() {
// GodotSharpDirs
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", (void *)godot_icall_GodotSharpDirs_ResDataDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", (void *)godot_icall_GodotSharpDirs_ResMetadataDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", (void *)godot_icall_GodotSharpDirs_ResConfigDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", (void *)godot_icall_GodotSharpDirs_ResTempDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", (void *)godot_icall_GodotSharpDirs_MonoUserDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", (void *)godot_icall_GodotSharpDirs_MonoLogsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", (void *)godot_icall_GodotSharpDirs_MonoSolutionsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", (void *)godot_icall_GodotSharpDirs_BuildLogsDirs);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", (void *)godot_icall_GodotSharpDirs_ProjectSlnPath);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", (void *)godot_icall_GodotSharpDirs_ProjectCsProjPath);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", (void *)godot_icall_GodotSharpDirs_DataEditorToolsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", (void *)godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", (void *)godot_icall_GodotSharpDirs_DataMonoEtcDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", (void *)godot_icall_GodotSharpDirs_DataMonoLibDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", (void *)godot_icall_GodotSharpDirs_DataMonoBinDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", godot_icall_GodotSharpDirs_ResDataDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", godot_icall_GodotSharpDirs_ResMetadataDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", godot_icall_GodotSharpDirs_ResAssembliesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", godot_icall_GodotSharpDirs_ResConfigDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", godot_icall_GodotSharpDirs_ResTempDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", godot_icall_GodotSharpDirs_ResTempAssembliesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", godot_icall_GodotSharpDirs_MonoUserDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", godot_icall_GodotSharpDirs_MonoLogsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", godot_icall_GodotSharpDirs_MonoSolutionsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", godot_icall_GodotSharpDirs_DataMonoEtcDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", godot_icall_GodotSharpDirs_DataMonoLibDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", godot_icall_GodotSharpDirs_DataMonoBinDir);
// EditorProgress
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", (void *)godot_icall_EditorProgress_Create);
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", (void *)godot_icall_EditorProgress_Dispose);
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", (void *)godot_icall_EditorProgress_Step);
-
- // BiningsGenerator
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Ctor", (void *)godot_icall_BindingsGenerator_Ctor);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Dtor", (void *)godot_icall_BindingsGenerator_Dtor);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_LogPrintEnabled", (void *)godot_icall_BindingsGenerator_LogPrintEnabled);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_SetLogPrintEnabled", (void *)godot_icall_BindingsGenerator_SetLogPrintEnabled);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_GenerateCsApi", (void *)godot_icall_BindingsGenerator_GenerateCsApi);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Version", (void *)godot_icall_BindingsGenerator_Version);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_CsGlueVersion", (void *)godot_icall_BindingsGenerator_CsGlueVersion);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", godot_icall_EditorProgress_Create);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", godot_icall_EditorProgress_Dispose);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", godot_icall_EditorProgress_Step);
// ScriptClassParser
- mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", godot_icall_ScriptClassParser_ParseFile);
// ExportPlugin
- mono_add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", (void *)godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
+ GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
// Internals
- mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", (void *)godot_icall_Internal_FullTemplatesDir);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", (void *)godot_icall_Internal_SimplifyGodotPath);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", (void *)godot_icall_Internal_IsOsxAppBundleInstalled);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", (void *)godot_icall_Internal_GodotIs32Bits);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", (void *)godot_icall_Internal_GodotIsRealTDouble);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", (void *)godot_icall_Internal_GodotMainIteration);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", (void *)godot_icall_Internal_GetCoreApiHash);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", (void *)godot_icall_Internal_GetEditorApiHash);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", (void *)godot_icall_Internal_IsAssembliesReloadingNeeded);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", (void *)godot_icall_Internal_ReloadAssemblies);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", (void *)godot_icall_Internal_EditorDebuggerNodeReloadScripts);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", (void *)godot_icall_Internal_ScriptEditorEdit);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", (void *)godot_icall_Internal_EditorNodeShowScriptScreen);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", (void *)godot_icall_Internal_GetScriptsMetadataOrNothing);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", (void *)godot_icall_Internal_MonoWindowsInstallRoot);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", (void *)godot_icall_Internal_EditorRunPlay);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", (void *)godot_icall_Internal_EditorRunStop);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", (void *)godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", (void *)godot_icall_Internal_CodeCompletionRequest);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", godot_icall_Internal_FullTemplatesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", godot_icall_Internal_IsOsxAppBundleInstalled);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", godot_icall_Internal_GetCoreApiHash);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", godot_icall_Internal_GetEditorApiHash);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", godot_icall_Internal_IsAssembliesReloadingNeeded);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", godot_icall_Internal_ReloadAssemblies);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", godot_icall_Internal_ScriptEditorEdit);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", godot_icall_Internal_EditorNodeShowScriptScreen);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", godot_icall_Internal_GetScriptsMetadataOrNothing);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", godot_icall_Internal_MonoWindowsInstallRoot);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", godot_icall_Internal_EditorRunPlay);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", godot_icall_Internal_EditorRunStop);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", godot_icall_Internal_CodeCompletionRequest);
// Globals
- mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", (void *)godot_icall_Globals_EditorScale);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", (void *)godot_icall_Globals_GlobalDef);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", (void *)godot_icall_Globals_EditorDef);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_TTR", (void *)godot_icall_Globals_TTR);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", godot_icall_Globals_EditorScale);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", godot_icall_Globals_GlobalDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", godot_icall_Globals_EditorDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_TTR", godot_icall_Globals_TTR);
// Utils.OS
- mono_add_internal_call("GodotTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
- mono_add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", (void *)godot_icall_Utils_OS_UnixFileHasExecutableAccess);
+ GDMonoUtils::add_internal_call("GodotTools.Utils.OS::GetPlatformName", godot_icall_Utils_OS_GetPlatformName);
+ GDMonoUtils::add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", godot_icall_Utils_OS_UnixFileHasExecutableAccess);
}
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 1a0d5743ae..b006eed69f 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -55,10 +55,10 @@ MonoAssemblyName *new_mono_assembly_name() {
struct AssemblyRefInfo {
String name;
- uint16_t major;
- uint16_t minor;
- uint16_t build;
- uint16_t revision;
+ uint16_t major = 0;
+ uint16_t minor = 0;
+ uint16_t build = 0;
+ uint16_t revision = 0;
};
AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) {
diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h
index 3c55fa07a7..deb6061191 100644
--- a/modules/mono/editor/script_class_parser.h
+++ b/modules/mono/editor/script_class_parser.h
@@ -45,22 +45,22 @@ public:
};
String name;
- Type type;
+ Type type = NAMESPACE_DECL;
};
struct ClassDecl {
String name;
String namespace_;
Vector<String> base;
- bool nested;
+ bool nested = false;
};
private:
String code;
- int idx;
- int line;
+ int idx = 0;
+ int line = 0;
String error_str;
- bool error;
+ bool error = false;
Variant value;
Vector<ClassDecl> classes;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
index b33490f9cb..bd3bcb0c58 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
@@ -120,13 +120,13 @@ namespace Godot
/// <param name="b">The destination quaternion.</param>
/// <param name="preA">A quaternion before this quaternion.</param>
/// <param name="postB">A quaternion after `b`.</param>
- /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated quaternion.</returns>
- public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t)
+ public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight)
{
- real_t t2 = (1.0f - t) * t * 2f;
- Quat sp = Slerp(b, t);
- Quat sq = preA.Slerpni(postB, t);
+ real_t t2 = (1.0f - weight) * weight * 2f;
+ Quat sp = Slerp(b, weight);
+ Quat sq = preA.Slerpni(postB, weight);
return sp.Slerpni(sq, t2);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index d536b14eac..b74dd6f4f4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -194,15 +194,16 @@ namespace Godot
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after `b`.</param>
- /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t)
+ public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight)
{
Vector2 p0 = preA;
Vector2 p1 = this;
Vector2 p2 = b;
Vector2 p3 = postB;
+ real_t t = weight;
real_t t2 = t * t;
real_t t3 = t2 * t;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 4a4a2a43cd..07f5b3c38e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -161,15 +161,16 @@ namespace Godot
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after `b`.</param>
- /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t)
+ public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight)
{
Vector3 p0 = preA;
Vector3 p1 = this;
Vector3 p2 = b;
Vector3 p3 = postB;
+ real_t t = weight;
real_t t2 = t * t;
real_t t3 = t2 * t;
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 544f414cba..afcc75395b 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -163,9 +163,9 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
return GDMonoUtils::unmanaged_get_managed(wref.ptr());
}
-Error godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
+int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
StringName signal = p_signal ? *p_signal : StringName();
- return gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
+ return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
}
MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
@@ -240,18 +240,18 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) {
}
void godot_register_object_icalls() {
- mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor);
- mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed);
- mono_add_internal_call("Godot.Object::godot_icall_Reference_Disposed", (void *)godot_icall_Reference_Disposed);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", (void *)godot_icall_Object_ConnectEventSignals);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ToString", (void *)godot_icall_Object_ToString);
- mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref);
- mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", (void *)godot_icall_DynamicGodotObject_SetMemberList);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", (void *)godot_icall_DynamicGodotObject_InvokeMember);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", (void *)godot_icall_DynamicGodotObject_GetMember);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", (void *)godot_icall_DynamicGodotObject_SetMember);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref);
+ GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", godot_icall_DynamicGodotObject_SetMemberList);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", godot_icall_DynamicGodotObject_InvokeMember);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index bb3ea0f730..dedb5b9f75 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -47,7 +47,7 @@ void godot_icall_Array_Dtor(Array *ptr) {
memdelete(ptr);
}
-MonoObject *godot_icall_Array_At(Array *ptr, int index) {
+MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return nullptr;
@@ -55,7 +55,7 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) {
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
}
-MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) {
+MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return nullptr;
@@ -63,7 +63,7 @@ MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_en
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
}
-void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
+void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -71,11 +71,11 @@ void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
}
-int godot_icall_Array_Count(Array *ptr) {
+int32_t godot_icall_Array_Count(Array *ptr) {
return ptr->size();
}
-int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
+int32_t godot_icall_Array_Add(Array *ptr, MonoObject *item) {
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
return ptr->size();
}
@@ -88,7 +88,7 @@ MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
}
-void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
+void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index) {
unsigned int count = ptr->size();
if (mono_array_length(array) < (array_index + count)) {
@@ -129,11 +129,11 @@ Array *godot_icall_Array_Concatenate(Array *left, Array *right) {
return new_array;
}
-int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
+int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
}
-void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
+void godot_icall_Array_Insert(Array *ptr, int32_t index, MonoObject *item) {
if (index < 0 || index > ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -150,7 +150,7 @@ MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
return false;
}
-void godot_icall_Array_RemoveAt(Array *ptr, int index) {
+void godot_icall_Array_RemoveAt(Array *ptr, int32_t index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -158,8 +158,8 @@ void godot_icall_Array_RemoveAt(Array *ptr, int index) {
ptr->remove(index);
}
-Error godot_icall_Array_Resize(Array *ptr, int new_size) {
- return ptr->resize(new_size);
+int32_t godot_icall_Array_Resize(Array *ptr, int32_t new_size) {
+ return (int32_t)ptr->resize(new_size);
}
void godot_icall_Array_Shuffle(Array *ptr) {
@@ -226,7 +226,7 @@ Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
return memnew(Array(ptr->values()));
}
-int godot_icall_Dictionary_Count(Dictionary *ptr) {
+int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
return ptr->size();
}
@@ -308,47 +308,47 @@ MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
}
void godot_register_collections_icalls() {
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", (void *)godot_icall_Array_Ctor_MonoArray);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", (void *)godot_icall_Array_Concatenate);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", (void *)godot_icall_Array_Duplicate);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", (void *)godot_icall_Array_Resize);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", (void *)godot_icall_Array_Shuffle);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", (void *)godot_icall_Array_ToString);
-
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", (void *)godot_icall_Dictionary_GetValue_Generic);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", (void *)godot_icall_Dictionary_Duplicate);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", (void *)godot_icall_Dictionary_ToString);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", godot_icall_Array_Clear);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", godot_icall_Array_Concatenate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", godot_icall_Array_Contains);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", godot_icall_Array_CopyTo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", godot_icall_Array_Duplicate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", godot_icall_Array_IndexOf);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", godot_icall_Array_Insert);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", godot_icall_Array_Remove);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString);
+
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", godot_icall_Dictionary_ContainsKey);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", godot_icall_Dictionary_Duplicate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 58d8dceb25..a4566b82fb 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -289,33 +289,33 @@ MonoObject *godot_icall_DefaultGodotTaskScheduler() {
}
void godot_register_gd_icalls() {
- mono_add_internal_call("Godot.GD::godot_icall_GD_bytes2var", (void *)godot_icall_GD_bytes2var);
- mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
- mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
- mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
- mono_add_internal_call("Godot.GD::godot_icall_GD_pusherror", (void *)godot_icall_GD_pusherror);
- mono_add_internal_call("Godot.GD::godot_icall_GD_pushwarning", (void *)godot_icall_GD_pushwarning);
- mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
- mono_add_internal_call("Godot.GD::godot_icall_GD_prints", (void *)godot_icall_GD_prints);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printt", (void *)godot_icall_GD_printt);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randf", (void *)godot_icall_GD_randf);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randi", (void *)godot_icall_GD_randi);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randomize", (void *)godot_icall_GD_randomize);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randf_range", (void *)godot_icall_GD_randf_range);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randi_range", (void *)godot_icall_GD_randi_range);
- mono_add_internal_call("Godot.GD::godot_icall_GD_rand_seed", (void *)godot_icall_GD_rand_seed);
- mono_add_internal_call("Godot.GD::godot_icall_GD_seed", (void *)godot_icall_GD_seed);
- mono_add_internal_call("Godot.GD::godot_icall_GD_str", (void *)godot_icall_GD_str);
- mono_add_internal_call("Godot.GD::godot_icall_GD_str2var", (void *)godot_icall_GD_str2var);
- mono_add_internal_call("Godot.GD::godot_icall_GD_type_exists", (void *)godot_icall_GD_type_exists);
- mono_add_internal_call("Godot.GD::godot_icall_GD_var2bytes", (void *)godot_icall_GD_var2bytes);
- mono_add_internal_call("Godot.GD::godot_icall_GD_var2str", (void *)godot_icall_GD_var2str);
- mono_add_internal_call("Godot.GD::godot_icall_TypeToVariantType", (void *)godot_icall_TypeToVariantType);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_bytes2var", godot_icall_GD_bytes2var);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_convert", godot_icall_GD_convert);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_hash", godot_icall_GD_hash);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", godot_icall_GD_instance_from_id);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pusherror", godot_icall_GD_pusherror);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pushwarning", godot_icall_GD_pushwarning);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print", godot_icall_GD_print);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printerr", godot_icall_GD_printerr);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printraw", godot_icall_GD_printraw);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_prints", godot_icall_GD_prints);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printt", godot_icall_GD_printt);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf", godot_icall_GD_randf);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi", godot_icall_GD_randi);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randomize", godot_icall_GD_randomize);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf_range", godot_icall_GD_randf_range);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi_range", godot_icall_GD_randi_range);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_rand_seed", godot_icall_GD_rand_seed);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_seed", godot_icall_GD_seed);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str", godot_icall_GD_str);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str2var", godot_icall_GD_str2var);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_type_exists", godot_icall_GD_type_exists);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2bytes", godot_icall_GD_var2bytes);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2str", godot_icall_GD_var2str);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_TypeToVariantType", godot_icall_TypeToVariantType);
// Dispatcher
- mono_add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", (void *)godot_icall_DefaultGodotTaskScheduler);
+ GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
index 09c6d8f482..9405360c6c 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/nodepath_glue.cpp
@@ -81,17 +81,17 @@ MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
}
void godot_register_nodepath_icalls() {
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", (void *)godot_icall_NodePath_Ctor);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", (void *)godot_icall_NodePath_Dtor);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", (void *)godot_icall_NodePath_operator_String);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", godot_icall_NodePath_Ctor);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", godot_icall_NodePath_get_name_count);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", godot_icall_NodePath_get_subname);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", godot_icall_NodePath_get_subname_count);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", godot_icall_NodePath_is_absolute);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", godot_icall_NodePath_is_empty);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp
index cb4f26511f..410a98aa84 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/modules/mono/glue/rid_glue.cpp
@@ -56,9 +56,9 @@ uint32_t godot_icall_RID_get_id(RID *p_ptr) {
}
void godot_register_rid_icalls() {
- mono_add_internal_call("Godot.RID::godot_icall_RID_Ctor", (void *)godot_icall_RID_Ctor);
- mono_add_internal_call("Godot.RID::godot_icall_RID_Dtor", (void *)godot_icall_RID_Dtor);
- mono_add_internal_call("Godot.RID::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Ctor", godot_icall_RID_Ctor);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Dtor", godot_icall_RID_Dtor);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_get_id", godot_icall_RID_get_id);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp
index 53d6c1436d..88695201a3 100644
--- a/modules/mono/glue/scene_tree_glue.cpp
+++ b/modules/mono/glue/scene_tree_glue.cpp
@@ -80,7 +80,7 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa
}
void godot_register_scene_tree_icalls() {
- mono_add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", (void *)godot_icall_SceneTree_get_nodes_in_group_Generic);
+ GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp
index 9271731573..d71d175418 100644
--- a/modules/mono/glue/string_glue.cpp
+++ b/modules/mono/glue/string_glue.cpp
@@ -68,12 +68,12 @@ MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
}
void godot_register_string_icalls() {
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", (void *)godot_icall_String_md5_buffer);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", (void *)godot_icall_String_md5_text);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", (void *)godot_icall_String_rfind);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", (void *)godot_icall_String_rfindn);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", (void *)godot_icall_String_sha256_buffer);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", (void *)godot_icall_String_sha256_text);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", godot_icall_String_rfind);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp
index 9323e3bbb3..fc2bf32b95 100644
--- a/modules/mono/glue/string_name_glue.cpp
+++ b/modules/mono/glue/string_name_glue.cpp
@@ -53,10 +53,10 @@ MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) {
}
void godot_register_string_name_icalls() {
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", (void *)godot_icall_StringName_Ctor);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", (void *)godot_icall_StringName_Dtor);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", (void *)godot_icall_StringName_operator_String);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", (void *)godot_icall_StringName_is_empty);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", godot_icall_StringName_Ctor);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", godot_icall_StringName_Dtor);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", godot_icall_StringName_operator_String);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", godot_icall_StringName_is_empty);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 6575cbc1c8..b734f52e4e 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -290,7 +290,7 @@ bool GDMonoClass::has_public_parameterless_ctor() {
return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC;
}
-GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
+GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) {
MethodKey key = MethodKey(p_name, p_params_count);
GDMonoMethod **match = methods.getptr(key);
@@ -330,7 +330,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName
return get_method(p_raw_method, p_name, params_count);
}
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) {
+GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) {
ERR_FAIL_NULL_V(p_raw_method, nullptr);
MethodKey key = MethodKey(p_name, p_params_count);
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 87db2fa033..b93dfec30a 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -59,13 +59,12 @@ class GDMonoClass {
MethodKey() {}
- MethodKey(const StringName &p_name, int p_params_count) {
- name = p_name;
- params_count = p_params_count;
+ MethodKey(const StringName &p_name, uint16_t p_params_count) :
+ name(p_name), params_count(p_params_count) {
}
StringName name;
- int params_count;
+ uint16_t params_count = 0;
};
StringName namespace_name;
@@ -139,10 +138,10 @@ public:
bool implements_interface(GDMonoClass *p_interface);
bool has_public_parameterless_ctor();
- GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
+ GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0);
GDMonoMethod *get_method(MonoMethod *p_raw_method);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
- GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count);
+ GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count);
GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
GDMonoField *get_field(const StringName &p_name);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 00a1e1e507..61d7f64a2a 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -46,29 +46,15 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
}
void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
-#define SET_FROM_STRUCT(m_type) \
- { \
- GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \
- mono_field_set_value(p_object, mono_field, &from); \
- }
-
-#define SET_FROM_ARRAY(m_type) \
- { \
- MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
- mono_field_set_value(p_object, mono_field, managed); \
- }
-
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN: {
MonoBoolean val = p_value.operator bool();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_CHAR: {
int16_t val = p_value.operator unsigned short();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_I1: {
int8_t val = p_value.operator signed char();
mono_field_set_value(p_object, mono_field, &val);
@@ -85,7 +71,6 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
int64_t val = p_value.operator int64_t();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_U1: {
uint8_t val = p_value.operator unsigned char();
mono_field_set_value(p_object, mono_field, &val);
@@ -102,93 +87,92 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
uint64_t val = p_value.operator uint64_t();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_R4: {
float val = p_value.operator float();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_R8: {
double val = p_value.operator double();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
- case MONO_TYPE_STRING: {
- if (p_value.get_type() == Variant::NIL) {
- // Otherwise, Variant -> String would return the string "Null"
- MonoString *mono_string = nullptr;
- mono_field_set_value(p_object, mono_field, mono_string);
- } else {
- MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
- mono_field_set_value(p_object, mono_field, mono_string);
- }
- } break;
-
case MONO_TYPE_VALUETYPE: {
GDMonoClass *tclass = type.type_class;
if (tclass == CACHED_CLASS(Vector2)) {
- SET_FROM_STRUCT(Vector2);
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Vector2i)) {
- SET_FROM_STRUCT(Vector2i);
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Rect2)) {
- SET_FROM_STRUCT(Rect2);
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Rect2i)) {
- SET_FROM_STRUCT(Rect2i);
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Transform2D)) {
- SET_FROM_STRUCT(Transform2D);
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Vector3)) {
- SET_FROM_STRUCT(Vector3);
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Vector3i)) {
- SET_FROM_STRUCT(Vector3i);
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Basis)) {
- SET_FROM_STRUCT(Basis);
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Quat)) {
- SET_FROM_STRUCT(Quat);
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Transform)) {
- SET_FROM_STRUCT(Transform);
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(AABB)) {
- SET_FROM_STRUCT(AABB);
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Color)) {
- SET_FROM_STRUCT(Color);
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Plane)) {
- SET_FROM_STRUCT(Plane);
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
@@ -267,118 +251,35 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'.");
} break;
-
+ case MONO_TYPE_STRING: {
+ if (p_value.get_type() == Variant::NIL) {
+ // Otherwise, Variant -> String would return the string "Null"
+ MonoString *mono_string = nullptr;
+ mono_field_set_value(p_object, mono_field, mono_string);
+ } else {
+ MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
+ mono_field_set_value(p_object, mono_field, mono_string);
+ }
+ } break;
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- SET_FROM_ARRAY(Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- SET_FROM_ARRAY(PackedByteArray);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- SET_FROM_ARRAY(PackedInt32Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- SET_FROM_ARRAY(PackedInt64Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- SET_FROM_ARRAY(PackedFloat32Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- SET_FROM_ARRAY(PackedFloat64Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- SET_FROM_ARRAY(PackedStringArray);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- SET_FROM_ARRAY(PackedVector2Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- SET_FROM_ARRAY(PackedVector3Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- SET_FROM_ARRAY(PackedColorArray);
- break;
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class);
+ MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class);
+ if (likely(managed != nullptr)) {
mono_field_set_value(p_object, mono_field, managed);
- break;
}
-
- ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type.");
} break;
-
case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
+ MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class);
+ if (likely(managed != nullptr)) {
mono_field_set_value(p_object, mono_field, managed);
- break;
}
-
- if (CACHED_CLASS(StringName) == type_class) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID());
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // Godot.Collections.Dictionary or IDictionary
- if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // Godot.Collections.Array or ICollection or IEnumerable
- if (CACHED_CLASS(Array) == type_class ||
- type_class == CACHED_CLASS(System_Collections_ICollection) ||
- type_class == CACHED_CLASS(System_Collections_IEnumerable)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ } break;
+ case MONO_TYPE_GENERICINST: {
+ MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class);
+ if (likely(managed != nullptr)) {
mono_field_set_value(p_object, mono_field, managed);
- break;
}
-
- ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'.");
} break;
-
case MONO_TYPE_OBJECT: {
// Variant
switch (p_value.get_type()) {
@@ -404,43 +305,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, mono_string);
} break;
case Variant::VECTOR2: {
- SET_FROM_STRUCT(Vector2);
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::VECTOR2I: {
- SET_FROM_STRUCT(Vector2i);
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::RECT2: {
- SET_FROM_STRUCT(Rect2);
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::RECT2I: {
- SET_FROM_STRUCT(Rect2i);
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::VECTOR3: {
- SET_FROM_STRUCT(Vector3);
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::VECTOR3I: {
- SET_FROM_STRUCT(Vector3i);
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::TRANSFORM2D: {
- SET_FROM_STRUCT(Transform2D);
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::PLANE: {
- SET_FROM_STRUCT(Plane);
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::QUAT: {
- SET_FROM_STRUCT(Quat);
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::AABB: {
- SET_FROM_STRUCT(AABB);
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::BASIS: {
- SET_FROM_STRUCT(Basis);
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::TRANSFORM: {
- SET_FROM_STRUCT(Transform);
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::COLOR: {
- SET_FROM_STRUCT(Color);
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::STRING_NAME: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
@@ -475,106 +389,49 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_BYTE_ARRAY: {
- SET_FROM_ARRAY(PackedByteArray);
+ MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_INT32_ARRAY: {
- SET_FROM_ARRAY(PackedInt32Array);
+ MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_INT64_ARRAY: {
- SET_FROM_ARRAY(PackedInt64Array);
+ MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_FLOAT32_ARRAY: {
- SET_FROM_ARRAY(PackedFloat32Array);
+ MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_FLOAT64_ARRAY: {
- SET_FROM_ARRAY(PackedFloat64Array);
+ MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_STRING_ARRAY: {
- SET_FROM_ARRAY(PackedStringArray);
+ MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_VECTOR2_ARRAY: {
- SET_FROM_ARRAY(PackedVector2Array);
+ MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_VECTOR3_ARRAY: {
- SET_FROM_ARRAY(PackedVector3Array);
+ MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_COLOR_ARRAY: {
- SET_FROM_ARRAY(PackedColorArray);
+ MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
default:
break;
}
} break;
-
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(),
- type.type_class, key_reftype, value_reftype);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(),
- type.type_class, elem_reftype);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
-
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- MonoReflectionType *elem_reftype;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
-
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
- } break;
-
default: {
ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + ".");
} break;
}
-
-#undef SET_FROM_ARRAY_AND_BREAK
-#undef SET_FROM_STRUCT_AND_BREAK
}
MonoObject *GDMonoField::get_value(MonoObject *p_object) {
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index b8ee0204c4..7584e7ff0d 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -160,13 +160,13 @@ void GDMonoLog::initialize() {
OS::Date date_now = OS::get_singleton()->get_date();
OS::Time time_now = OS::get_singleton()->get_time();
- String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d",
+ String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d",
date_now.year, date_now.month, date_now.day,
time_now.hour, time_now.min, time_now.sec);
- log_file_name += str_format(" (%d)", OS::get_singleton()->get_process_id());
+ log_file_name += str_format("_%d", OS::get_singleton()->get_process_id());
- log_file_name += ".txt";
+ log_file_name += ".log";
log_file_path = logs_dir.plus_file(log_file_name);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index eee880ba60..64b350f270 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -311,152 +311,590 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
return false;
}
-MonoObject *variant_to_mono_object(const Variant *p_var) {
- ManagedType type;
+MonoString *variant_to_mono_string(const Variant &p_var) {
+ if (p_var.get_type() == Variant::NIL) {
+ return nullptr; // Otherwise, Variant -> String would return the string "Null"
+ }
+ return mono_string_from_godot(p_var.operator String());
+}
+
+MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) {
+ MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
+ return Array_to_mono_array(p_var.operator Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
+ return PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
+ return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
+ return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(float)) {
+ return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(double)) {
+ return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(String)) {
+ return PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
+ return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
+ return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
+ return PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
+ }
+
+ if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) {
+ return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass);
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" +
+ GDMonoClass::get_full_name(array_type->eklass) + "'.");
+}
+
+MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) {
+ // GodotObject
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
+ return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
+ }
+
+ if (CACHED_CLASS(StringName) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator StringName());
+ }
+
+ if (CACHED_CLASS(NodePath) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator NodePath());
+ }
- type.type_encoding = MONO_TYPE_OBJECT;
- // type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding
+ if (CACHED_CLASS(RID) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator ::RID());
+ }
+
+ // Godot.Collections.Dictionary or IDictionary
+ if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
- return variant_to_mono_object(p_var, type);
+ // Godot.Collections.Array or ICollection or IEnumerable
+ if (CACHED_CLASS(Array) == p_type_class ||
+ CACHED_CLASS(System_Collections_ICollection) == p_type_class ||
+ CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" +
+ p_type_class->get_full_name() + "'.");
}
-MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
+MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) {
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type());
+
+ // Godot.Collections.Dictionary<TKey, TValue>
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class);
+ }
+
+ // Godot.Collections.Array<T>
+ if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class);
+ }
+
+ // System.Collections.Generic.Dictionary<TKey, TValue>
+ if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
+ MonoReflectionType *key_reftype = nullptr;
+ MonoReflectionType *value_reftype = nullptr;
+ GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
+ return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype);
+ }
+
+ // System.Collections.Generic.List<T>
+ if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
+ MonoReflectionType *elem_reftype = nullptr;
+ GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
+ return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype);
+ }
+
+ // IDictionary<TKey, TValue>
+ if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
+ MonoReflectionType *key_reftype;
+ MonoReflectionType *value_reftype;
+ GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
+ GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
+
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class);
+ }
+
+ // ICollection<T> or IEnumerable<T>
+ if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
+ MonoReflectionType *elem_reftype;
+ GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
+ GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
+
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class);
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" +
+ p_type_class->get_full_name() + "'.");
+}
+
+MonoObject *variant_to_mono_object(const Variant &p_var) {
+ // Variant
+ switch (p_var.get_type()) {
+ case Variant::BOOL: {
+ MonoBoolean val = p_var.operator bool();
+ return BOX_BOOLEAN(val);
+ }
+ case Variant::INT: {
+ int64_t val = p_var.operator int64_t();
+ return BOX_INT64(val);
+ }
+ case Variant::FLOAT: {
+#ifdef REAL_T_IS_DOUBLE
+ double val = p_var.operator double();
+ return BOX_DOUBLE(val);
+#else
+ float val = p_var.operator float();
+ return BOX_FLOAT(val);
+#endif
+ }
+ case Variant::STRING:
+ return (MonoObject *)mono_string_from_godot(p_var.operator String());
+ case Variant::VECTOR2: {
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+ }
+ case Variant::VECTOR2I: {
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
+ }
+ case Variant::RECT2: {
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+ }
+ case Variant::RECT2I: {
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
+ }
+ case Variant::VECTOR3: {
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+ }
+ case Variant::VECTOR3I: {
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
+ }
+ case Variant::TRANSFORM2D: {
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+ }
+ case Variant::PLANE: {
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+ }
+ case Variant::QUAT: {
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ }
+ case Variant::AABB: {
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+ }
+ case Variant::BASIS: {
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+ }
+ case Variant::TRANSFORM: {
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ }
+ case Variant::COLOR: {
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+ }
+ case Variant::STRING_NAME:
+ return GDMonoUtils::create_managed_from(p_var.operator StringName());
+ case Variant::NODE_PATH:
+ return GDMonoUtils::create_managed_from(p_var.operator NodePath());
+ case Variant::RID:
+ return GDMonoUtils::create_managed_from(p_var.operator ::RID());
+ case Variant::OBJECT:
+ return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
+ case Variant::CALLABLE: {
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
+ }
+ case Variant::SIGNAL: {
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
+ }
+ case Variant::DICTIONARY:
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
+ case Variant::ARRAY:
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
+ case Variant::PACKED_BYTE_ARRAY:
+ return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
+ case Variant::PACKED_INT32_ARRAY:
+ return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
+ case Variant::PACKED_INT64_ARRAY:
+ return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
+ case Variant::PACKED_FLOAT32_ARRAY:
+ return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
+ case Variant::PACKED_FLOAT64_ARRAY:
+ return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
+ case Variant::PACKED_STRING_ARRAY:
+ return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
+ case Variant::PACKED_VECTOR2_ARRAY:
+ return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
+ case Variant::PACKED_VECTOR3_ARRAY:
+ return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
+ case Variant::PACKED_COLOR_ARRAY:
+ return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
+ default:
+ return nullptr;
+ }
+}
+
+size_t variant_get_managed_unboxed_size(const ManagedType &p_type) {
+ // This method prints no errors for unsupported types. It's called on all methods, not only
+ // those that end up being invoked with Variant parameters.
+
+ // For MonoObject* we return 0, as it doesn't need to be stored.
+ constexpr size_t zero_for_mono_object = 0;
+
+ switch (p_type.type_encoding) {
+ case MONO_TYPE_BOOLEAN:
+ return sizeof(MonoBoolean);
+ case MONO_TYPE_CHAR:
+ return sizeof(uint16_t);
+ case MONO_TYPE_I1:
+ return sizeof(int8_t);
+ case MONO_TYPE_I2:
+ return sizeof(int16_t);
+ case MONO_TYPE_I4:
+ return sizeof(int32_t);
+ case MONO_TYPE_I8:
+ return sizeof(int64_t);
+ case MONO_TYPE_U1:
+ return sizeof(uint8_t);
+ case MONO_TYPE_U2:
+ return sizeof(uint16_t);
+ case MONO_TYPE_U4:
+ return sizeof(uint32_t);
+ case MONO_TYPE_U8:
+ return sizeof(uint64_t);
+ case MONO_TYPE_R4:
+ return sizeof(float);
+ case MONO_TYPE_R8:
+ return sizeof(double);
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *vtclass = p_type.type_class;
+
+#define RETURN_CHECK_FOR_STRUCT(m_struct) \
+ if (vtclass == CACHED_CLASS(m_struct)) { \
+ return sizeof(M_##m_struct); \
+ }
+
+ RETURN_CHECK_FOR_STRUCT(Vector2);
+ RETURN_CHECK_FOR_STRUCT(Vector2i);
+ RETURN_CHECK_FOR_STRUCT(Rect2);
+ RETURN_CHECK_FOR_STRUCT(Rect2i);
+ RETURN_CHECK_FOR_STRUCT(Transform2D);
+ RETURN_CHECK_FOR_STRUCT(Vector3);
+ RETURN_CHECK_FOR_STRUCT(Vector3i);
+ RETURN_CHECK_FOR_STRUCT(Basis);
+ RETURN_CHECK_FOR_STRUCT(Quat);
+ RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(AABB);
+ RETURN_CHECK_FOR_STRUCT(Color);
+ RETURN_CHECK_FOR_STRUCT(Plane);
+ RETURN_CHECK_FOR_STRUCT(Callable);
+ RETURN_CHECK_FOR_STRUCT(SignalInfo);
+
+#undef RETURN_CHECK_FOR_STRUCT
+
+ if (mono_class_is_enum(vtclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN:
+ return sizeof(MonoBoolean);
+ case MONO_TYPE_CHAR:
+ return sizeof(uint16_t);
+ case MONO_TYPE_I1:
+ return sizeof(int8_t);
+ case MONO_TYPE_I2:
+ return sizeof(int16_t);
+ case MONO_TYPE_I4:
+ return sizeof(int32_t);
+ case MONO_TYPE_I8:
+ return sizeof(int64_t);
+ case MONO_TYPE_U1:
+ return sizeof(uint8_t);
+ case MONO_TYPE_U2:
+ return sizeof(uint16_t);
+ case MONO_TYPE_U4:
+ return sizeof(uint32_t);
+ case MONO_TYPE_U8:
+ return sizeof(uint64_t);
+ default: {
+ // Enum with unsupported base type. We return nullptr MonoObject* on error.
+ return zero_for_mono_object;
+ }
+ }
+ }
+
+ // Enum with unsupported value type. We return nullptr MonoObject* on error.
+ } break;
+ case MONO_TYPE_STRING:
+ return zero_for_mono_object;
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_GENERICINST:
+ return zero_for_mono_object;
+ case MONO_TYPE_OBJECT:
+ return zero_for_mono_object;
+ }
+
+ // Unsupported type encoding. We return nullptr MonoObject* on error.
+ return zero_for_mono_object;
+}
+
+void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
+#define RETURN_TYPE_VAL(m_type, m_val) \
+ *reinterpret_cast<m_type *>(r_buffer) = m_val; \
+ r_offset += sizeof(m_type); \
+ return r_buffer;
+
+ switch (p_type.type_encoding) {
+ case MONO_TYPE_BOOLEAN:
+ RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool());
+ case MONO_TYPE_CHAR:
+ RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
+ case MONO_TYPE_I1:
+ RETURN_TYPE_VAL(int8_t, p_var.operator signed char());
+ case MONO_TYPE_I2:
+ RETURN_TYPE_VAL(int16_t, p_var.operator signed short());
+ case MONO_TYPE_I4:
+ RETURN_TYPE_VAL(int32_t, p_var.operator signed int());
+ case MONO_TYPE_I8:
+ RETURN_TYPE_VAL(int64_t, p_var.operator int64_t());
+ case MONO_TYPE_U1:
+ RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char());
+ case MONO_TYPE_U2:
+ RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
+ case MONO_TYPE_U4:
+ RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int());
+ case MONO_TYPE_U8:
+ RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t());
+ case MONO_TYPE_R4:
+ RETURN_TYPE_VAL(float, p_var.operator float());
+ case MONO_TYPE_R8:
+ RETURN_TYPE_VAL(double, p_var.operator double());
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *vtclass = p_type.type_class;
+
+#define RETURN_CHECK_FOR_STRUCT(m_struct) \
+ if (vtclass == CACHED_CLASS(m_struct)) { \
+ GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
+ RETURN_TYPE_VAL(M_##m_struct, from); \
+ }
+
+ RETURN_CHECK_FOR_STRUCT(Vector2);
+ RETURN_CHECK_FOR_STRUCT(Vector2i);
+ RETURN_CHECK_FOR_STRUCT(Rect2);
+ RETURN_CHECK_FOR_STRUCT(Rect2i);
+ RETURN_CHECK_FOR_STRUCT(Transform2D);
+ RETURN_CHECK_FOR_STRUCT(Vector3);
+ RETURN_CHECK_FOR_STRUCT(Vector3i);
+ RETURN_CHECK_FOR_STRUCT(Basis);
+ RETURN_CHECK_FOR_STRUCT(Quat);
+ RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(AABB);
+ RETURN_CHECK_FOR_STRUCT(Color);
+ RETURN_CHECK_FOR_STRUCT(Plane);
+
+#undef RETURN_CHECK_FOR_STRUCT
+
+ if (vtclass == CACHED_CLASS(Callable)) {
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
+ RETURN_TYPE_VAL(M_Callable, from);
+ }
+
+ if (vtclass == CACHED_CLASS(SignalInfo)) {
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
+ RETURN_TYPE_VAL(M_SignalInfo, from);
+ }
+
+ if (mono_class_is_enum(vtclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN: {
+ MonoBoolean val = p_var.operator bool();
+ RETURN_TYPE_VAL(MonoBoolean, val);
+ }
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_var.operator unsigned short();
+ RETURN_TYPE_VAL(uint16_t, val);
+ }
+ case MONO_TYPE_I1: {
+ int8_t val = p_var.operator signed char();
+ RETURN_TYPE_VAL(int8_t, val);
+ }
+ case MONO_TYPE_I2: {
+ int16_t val = p_var.operator signed short();
+ RETURN_TYPE_VAL(int16_t, val);
+ }
+ case MONO_TYPE_I4: {
+ int32_t val = p_var.operator signed int();
+ RETURN_TYPE_VAL(int32_t, val);
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_var.operator int64_t();
+ RETURN_TYPE_VAL(int64_t, val);
+ }
+ case MONO_TYPE_U1: {
+ uint8_t val = p_var.operator unsigned char();
+ RETURN_TYPE_VAL(uint8_t, val);
+ }
+ case MONO_TYPE_U2: {
+ uint16_t val = p_var.operator unsigned short();
+ RETURN_TYPE_VAL(uint16_t, val);
+ }
+ case MONO_TYPE_U4: {
+ uint32_t val = p_var.operator unsigned int();
+ RETURN_TYPE_VAL(uint32_t, val);
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_var.operator uint64_t();
+ RETURN_TYPE_VAL(uint64_t, val);
+ }
+ default: {
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" +
+ GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'.");
+ }
+ }
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" +
+ p_type.type_class->get_full_name() + "'.");
+ } break;
+#undef RETURN_TYPE_VAL
+ case MONO_TYPE_STRING:
+ return variant_to_mono_string(p_var);
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ return variant_to_mono_array(p_var, p_type.type_class);
+ case MONO_TYPE_CLASS:
+ return variant_to_mono_object_of_class(p_var, p_type.type_class);
+ case MONO_TYPE_GENERICINST:
+ return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
+ case MONO_TYPE_OBJECT:
+ return variant_to_mono_object(p_var);
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " +
+ itos(p_type.type_encoding) + ".");
+}
+
+MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var->operator bool();
+ MonoBoolean val = p_var.operator bool();
return BOX_BOOLEAN(val);
}
-
case MONO_TYPE_CHAR: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_UINT16(val);
}
-
case MONO_TYPE_I1: {
- int8_t val = p_var->operator signed char();
+ int8_t val = p_var.operator signed char();
return BOX_INT8(val);
}
case MONO_TYPE_I2: {
- int16_t val = p_var->operator signed short();
+ int16_t val = p_var.operator signed short();
return BOX_INT16(val);
}
case MONO_TYPE_I4: {
- int32_t val = p_var->operator signed int();
+ int32_t val = p_var.operator signed int();
return BOX_INT32(val);
}
case MONO_TYPE_I8: {
- int64_t val = p_var->operator int64_t();
+ int64_t val = p_var.operator int64_t();
return BOX_INT64(val);
}
-
case MONO_TYPE_U1: {
- uint8_t val = p_var->operator unsigned char();
+ uint8_t val = p_var.operator unsigned char();
return BOX_UINT8(val);
}
case MONO_TYPE_U2: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_UINT16(val);
}
case MONO_TYPE_U4: {
- uint32_t val = p_var->operator unsigned int();
+ uint32_t val = p_var.operator unsigned int();
return BOX_UINT32(val);
}
case MONO_TYPE_U8: {
- uint64_t val = p_var->operator uint64_t();
+ uint64_t val = p_var.operator uint64_t();
return BOX_UINT64(val);
}
-
case MONO_TYPE_R4: {
- float val = p_var->operator float();
+ float val = p_var.operator float();
return BOX_FLOAT(val);
}
case MONO_TYPE_R8: {
- double val = p_var->operator double();
+ double val = p_var.operator double();
return BOX_DOUBLE(val);
}
-
- case MONO_TYPE_STRING: {
- if (p_var->get_type() == Variant::NIL) {
- return nullptr; // Otherwise, Variant -> String would return the string "Null"
- }
- return (MonoObject *)mono_string_from_godot(p_var->operator String());
- } break;
-
case MONO_TYPE_VALUETYPE: {
GDMonoClass *vtclass = p_type.type_class;
- if (vtclass == CACHED_CLASS(Vector2)) {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
- }
-
- if (vtclass == CACHED_CLASS(Vector2i)) {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
- }
-
- if (vtclass == CACHED_CLASS(Rect2)) {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
- }
-
- if (vtclass == CACHED_CLASS(Rect2i)) {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
- }
-
- if (vtclass == CACHED_CLASS(Transform2D)) {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
- }
-
- if (vtclass == CACHED_CLASS(Vector3)) {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
- }
-
- if (vtclass == CACHED_CLASS(Vector3i)) {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
- }
-
- if (vtclass == CACHED_CLASS(Basis)) {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
- }
-
- if (vtclass == CACHED_CLASS(Quat)) {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
- }
-
- if (vtclass == CACHED_CLASS(Transform)) {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
- }
-
- if (vtclass == CACHED_CLASS(AABB)) {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
- }
-
- if (vtclass == CACHED_CLASS(Color)) {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
- }
+#define RETURN_CHECK_FOR_STRUCT(m_struct) \
+ if (vtclass == CACHED_CLASS(m_struct)) { \
+ GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \
+ }
- if (vtclass == CACHED_CLASS(Plane)) {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
- }
+ RETURN_CHECK_FOR_STRUCT(Vector2);
+ RETURN_CHECK_FOR_STRUCT(Vector2i);
+ RETURN_CHECK_FOR_STRUCT(Rect2);
+ RETURN_CHECK_FOR_STRUCT(Rect2i);
+ RETURN_CHECK_FOR_STRUCT(Transform2D);
+ RETURN_CHECK_FOR_STRUCT(Vector3);
+ RETURN_CHECK_FOR_STRUCT(Vector3i);
+ RETURN_CHECK_FOR_STRUCT(Basis);
+ RETURN_CHECK_FOR_STRUCT(Quat);
+ RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(AABB);
+ RETURN_CHECK_FOR_STRUCT(Color);
+ RETURN_CHECK_FOR_STRUCT(Plane);
+
+#undef RETURN_CHECK_FOR_STRUCT
if (vtclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable());
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
}
if (vtclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal());
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
}
@@ -465,316 +903,84 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
switch (mono_type_get_type(enum_basetype)) {
case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var->operator bool();
+ MonoBoolean val = p_var.operator bool();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_CHAR: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I1: {
- int8_t val = p_var->operator signed char();
+ int8_t val = p_var.operator signed char();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I2: {
- int16_t val = p_var->operator signed short();
+ int16_t val = p_var.operator signed short();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I4: {
- int32_t val = p_var->operator signed int();
+ int32_t val = p_var.operator signed int();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I8: {
- int64_t val = p_var->operator int64_t();
+ int64_t val = p_var.operator int64_t();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U1: {
- uint8_t val = p_var->operator unsigned char();
+ uint8_t val = p_var.operator unsigned char();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U2: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U4: {
- uint32_t val = p_var->operator unsigned int();
+ uint32_t val = p_var.operator unsigned int();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U8: {
- uint64_t val = p_var->operator uint64_t();
+ uint64_t val = p_var.operator uint64_t();
return BOX_ENUM(enum_baseclass, val);
}
default: {
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" +
+ GDMonoClass::get_full_name(enum_baseclass) + "'.");
}
}
}
- } break;
-
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- return (MonoObject *)Array_to_mono_array(p_var->operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray());
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed array of unmarshallable element type.");
- } break;
-
- case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
- }
-
- if (CACHED_CLASS(StringName) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator StringName());
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator NodePath());
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator ::RID());
- }
-
- // Godot.Collections.Dictionary or IDictionary
- if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
- }
-
- // Godot.Collections.Array or ICollection or IEnumerable
- if (CACHED_CLASS(Array) == type_class ||
- CACHED_CLASS(System_Collections_ICollection) == type_class ||
- CACHED_CLASS(System_Collections_IEnumerable) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
- }
- } break;
- case MONO_TYPE_OBJECT: {
- // Variant
- switch (p_var->get_type()) {
- case Variant::BOOL: {
- MonoBoolean val = p_var->operator bool();
- return BOX_BOOLEAN(val);
- }
- case Variant::INT: {
- int64_t val = p_var->operator int64_t();
- return BOX_INT64(val);
- }
- case Variant::FLOAT: {
-#ifdef REAL_T_IS_DOUBLE
- double val = p_var->operator double();
- return BOX_DOUBLE(val);
-#else
- float val = p_var->operator float();
- return BOX_FLOAT(val);
-#endif
- }
- case Variant::STRING:
- return (MonoObject *)mono_string_from_godot(p_var->operator String());
- case Variant::VECTOR2: {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
- }
- case Variant::VECTOR2I: {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
- }
- case Variant::RECT2: {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
- }
- case Variant::RECT2I: {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
- }
- case Variant::VECTOR3: {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
- }
- case Variant::VECTOR3I: {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
- }
- case Variant::TRANSFORM2D: {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
- }
- case Variant::PLANE: {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
- }
- case Variant::QUAT: {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
- }
- case Variant::AABB: {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
- }
- case Variant::BASIS: {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
- }
- case Variant::TRANSFORM: {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
- }
- case Variant::COLOR: {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
- }
- case Variant::STRING_NAME:
- return GDMonoUtils::create_managed_from(p_var->operator StringName());
- case Variant::NODE_PATH:
- return GDMonoUtils::create_managed_from(p_var->operator NodePath());
- case Variant::RID:
- return GDMonoUtils::create_managed_from(p_var->operator ::RID());
- case Variant::OBJECT:
- return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
- case Variant::CALLABLE: {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
- }
- case Variant::SIGNAL: {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
- }
- case Variant::DICTIONARY:
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
- case Variant::ARRAY:
- return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
- case Variant::PACKED_BYTE_ARRAY:
- return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray());
- case Variant::PACKED_INT32_ARRAY:
- return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array());
- case Variant::PACKED_INT64_ARRAY:
- return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array());
- case Variant::PACKED_FLOAT32_ARRAY:
- return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array());
- case Variant::PACKED_FLOAT64_ARRAY:
- return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array());
- case Variant::PACKED_STRING_ARRAY:
- return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray());
- case Variant::PACKED_VECTOR2_ARRAY:
- return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array());
- case Variant::PACKED_VECTOR3_ARRAY:
- return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array());
- case Variant::PACKED_COLOR_ARRAY:
- return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray());
- default:
- return nullptr;
- }
- break;
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype);
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype);
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
-
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class);
- }
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- MonoReflectionType *elem_reftype;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
-
- return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class);
- }
- } break;
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" +
+ p_type.type_class->get_full_name() + "'.");
} break;
+ case MONO_TYPE_STRING:
+ return (MonoObject *)variant_to_mono_string(p_var);
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class);
+ case MONO_TYPE_CLASS:
+ return variant_to_mono_object_of_class(p_var, p_type.type_class);
+ case MONO_TYPE_GENERICINST:
+ return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
+ case MONO_TYPE_OBJECT:
+ return variant_to_mono_object(p_var);
}
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to an unmarshallable managed type. Name: '" +
- p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " +
+ itos(p_type.type_encoding) + ".");
}
Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
ERR_FAIL_COND_V(!p_type.type_class, Variant());
+#ifdef DEBUG_ENABLED
+ CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known.");
+#endif
+
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return (bool)unbox<MonoBoolean>(p_obj);
-
case MONO_TYPE_CHAR:
return unbox<uint16_t>(p_obj);
-
case MONO_TYPE_I1:
return unbox<int8_t>(p_obj);
case MONO_TYPE_I2:
@@ -783,7 +989,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<int32_t>(p_obj);
case MONO_TYPE_I8:
return unbox<int64_t>(p_obj);
-
case MONO_TYPE_U1:
return unbox<uint8_t>(p_obj);
case MONO_TYPE_U2:
@@ -792,19 +997,10 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<uint32_t>(p_obj);
case MONO_TYPE_U8:
return unbox<uint64_t>(p_obj);
-
case MONO_TYPE_R4:
return unbox<float>(p_obj);
case MONO_TYPE_R8:
return unbox<double>(p_obj);
-
- case MONO_TYPE_STRING: {
- if (p_obj == nullptr) {
- return Variant(); // NIL
- }
- return mono_string_to_godot_not_null((MonoString *)p_obj);
- } break;
-
case MONO_TYPE_VALUETYPE: {
GDMonoClass *vtclass = p_type.type_class;
@@ -872,7 +1068,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<int32_t>(p_obj);
}
} break;
-
+ case MONO_TYPE_STRING: {
+ if (p_obj == nullptr) {
+ return Variant(); // NIL
+ }
+ return mono_string_to_godot_not_null((MonoString *)p_obj);
+ } break;
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
@@ -928,7 +1129,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return Variant();
}
} break;
-
case MONO_TYPE_CLASS: {
GDMonoClass *type_class = p_type.type_class;
@@ -973,7 +1173,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return ptr ? Variant(*ptr) : Variant();
}
} break;
-
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
@@ -1052,7 +1251,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
- if (var.get_type() == Variant::NIL && p_obj != nullptr) {
+ if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true
// Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
MonoException *exc = nullptr;
MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc);
@@ -1115,9 +1314,10 @@ Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]]
}
MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) {
- GDMonoClass *elem_class = ManagedType::from_reftype(p_elem_reftype).type_class;
+ MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype);
+ MonoClass *elem_class = mono_class_from_mono_type(elem_type);
- String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + elem_class->get_type_desc() + ">)";
+ String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)";
GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
CRASH_COND(ctor == nullptr);
@@ -1156,9 +1356,9 @@ MonoArray *Array_to_mono_array(const Array &p_array) {
return ret;
}
-MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) {
+MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) {
int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length);
+ MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length);
for (int i = 0; i < length; i++) {
MonoObject *boxed = variant_to_mono_object(p_array[i]);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index d1d5f1f202..6d8227f8b4 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -90,15 +90,40 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
// Variant
-MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type);
-MonoObject *variant_to_mono_object(const Variant *p_var);
-
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) {
- return variant_to_mono_object(&p_var);
+size_t variant_get_managed_unboxed_size(const ManagedType &p_type);
+void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset);
+MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type);
+
+MonoObject *variant_to_mono_object(const Variant &p_var);
+MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class);
+MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class);
+MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class);
+MonoString *variant_to_mono_string(const Variant &p_var);
+
+// These overloads were added to avoid passing a `const Variant *` to the `const Variant &`
+// parameter. That would result in the `Variant(bool)` copy constructor being called as
+// pointers are implicitly converted to bool. Implicit conversions are f-ing evil.
+
+_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
+ return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset);
}
-
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) {
- return variant_to_mono_object(&p_var, p_type);
+_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
+ return variant_to_mono_object(*p_var, p_type);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) {
+ return variant_to_mono_object(*p_var);
+}
+_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) {
+ return variant_to_mono_array(*p_var, p_type_class);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) {
+ return variant_to_mono_object_of_class(*p_var, p_type_class);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) {
+ return variant_to_mono_object_of_genericinst(*p_var, p_type_class);
+}
+_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) {
+ return variant_to_mono_string(*p_var);
}
Variant mono_object_to_variant(MonoObject *p_obj);
@@ -120,7 +145,7 @@ Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, Mono
// Array
MonoArray *Array_to_mono_array(const Array &p_array);
-MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class);
+MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class);
Array mono_array_to_Array(MonoArray *p_array);
// PackedInt32Array
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 04f3b25a70..1d87726234 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -75,6 +75,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
// clear the cache
method_info_fetched = false;
method_info = MethodInfo();
+
+ for (int i = 0; i < params_count; i++) {
+ params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]);
+ }
}
GDMonoClass *GDMonoMethod::get_enclosing_class() const {
@@ -107,14 +111,15 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
MonoObject *ret;
if (params_count > 0) {
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), params_count);
+ void **params = (void **)alloca(params_count * sizeof(void *));
+ uint8_t *buffer = (uint8_t *)alloca(params_buffer_size);
+ unsigned int offset = 0;
for (int i = 0; i < params_count; i++) {
- MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]);
- mono_array_setref(params, i, boxed_param);
+ params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset);
}
- ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc);
+ ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc);
} else {
ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc);
}
@@ -279,16 +284,8 @@ const MethodInfo &GDMonoMethod::get_method_info() {
return method_info;
}
-GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
- name = p_name;
-
- mono_method = p_method;
-
- method_info_fetched = false;
-
- attrs_fetched = false;
- attributes = nullptr;
-
+GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) :
+ name(p_name), mono_method(p_method) {
_update_signature();
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index f78f57dca0..115bd998fa 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -38,15 +38,16 @@
class GDMonoMethod : public IMonoClassMember {
StringName name;
- int params_count;
+ uint16_t params_count;
+ unsigned int params_buffer_size = 0;
ManagedType return_type;
Vector<ManagedType> param_types;
- bool method_info_fetched;
+ bool method_info_fetched = false;
MethodInfo method_info;
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ bool attrs_fetched = false;
+ MonoCustomAttrInfo *attributes = nullptr;
void _update_signature();
void _update_signature(MonoMethodSignature *p_method_sig);
@@ -72,7 +73,7 @@ public:
_FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; }
- _FORCE_INLINE_ int get_parameters_count() const { return params_count; }
+ _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; }
_FORCE_INLINE_ ManagedType get_return_type() const { return return_type; }
MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const;
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index bc3be97102..1027c08a4a 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -149,10 +149,9 @@ bool GDMonoProperty::has_setter() {
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
- mono_array_setref(params, 0, p_value);
+ void *params[1] = { p_value };
MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc);
+ GDMonoUtils::runtime_invoke(prop_method, p_object, params, &exc);
if (exc) {
if (r_exc) {
*r_exc = exc;
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 97fc4c57f9..05fd57255c 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -480,6 +480,7 @@ void set_pending_exception(MonoException *p_exc) {
#else
if (get_runtime_invoke_count() == 0) {
debug_unhandled_exception(p_exc);
+ return;
}
if (!mono_runtime_set_pending_exception(p_exc, false)) {
@@ -498,13 +499,6 @@ MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, M
return ret;
}
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 71c131f77c..5370b1c6fc 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -36,6 +36,9 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
#include "gd_mono_header.h"
+#ifdef JAVASCRIPT_ENABLED
+#include "gd_mono_wasm_m2n.h"
+#endif
#include "core/object/class_db.h"
#include "core/object/reference.h"
@@ -135,7 +138,6 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
}
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc);
MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
@@ -155,6 +157,22 @@ private:
};
StringName get_native_godot_class_name(GDMonoClass *p_class);
+
+template <typename... P>
+void add_internal_call(const char *p_name, void (*p_func)(P...)) {
+#ifdef JAVASCRIPT_ENABLED
+ GDMonoWasmM2n::ICallTrampolines<P...>::add();
+#endif
+ mono_add_internal_call(p_name, (void *)p_func);
+}
+
+template <typename R, typename... P>
+void add_internal_call(const char *p_name, R (*p_func)(P...)) {
+#ifdef JAVASCRIPT_ENABLED
+ GDMonoWasmM2n::ICallTrampolinesR<R, P...>::add();
+#endif
+ mono_add_internal_call(p_name, (void *)p_func);
+}
} // namespace GDMonoUtils
#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class))
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
new file mode 100644
index 0000000000..f4c964c6eb
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* gd_mono_wasm_m2n.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "gd_mono_wasm_m2n.h"
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/templates/oa_hash_map.h"
+
+typedef mono_bool (*GodotMonoM2nIcallTrampolineDispatch)(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs);
+
+// This extern function is implemented in our patched version of Mono
+MONO_API void godot_mono_register_m2n_icall_trampoline_dispatch_hook(GodotMonoM2nIcallTrampolineDispatch hook);
+
+namespace GDMonoWasmM2n {
+
+struct HashMapCookieComparator {
+ static bool compare(const char *p_lhs, const char *p_rhs) {
+ return strcmp(p_lhs, p_rhs) == 0;
+ }
+};
+
+// The default hasher supports 'const char *' C Strings, but we need a custom comparator
+OAHashMap<const char *, TrampolineFunc, HashMapHasherDefault, HashMapCookieComparator> trampolines;
+
+void set_trampoline(const char *cookies, GDMonoWasmM2n::TrampolineFunc trampoline_func) {
+ trampolines.set(cookies, trampoline_func);
+}
+
+mono_bool trampoline_dispatch_hook(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs) {
+ TrampolineFunc *trampoline_func = trampolines.lookup_ptr(cookie);
+
+ if (!trampoline_func) {
+ return false;
+ }
+
+ (*trampoline_func)(target_func, margs);
+ return true;
+}
+
+bool initialized = false;
+
+void lazy_initialize() {
+ // Doesn't need to be thread safe
+ if (!initialized) {
+ initialized = true;
+ godot_mono_register_m2n_icall_trampoline_dispatch_hook(&trampoline_dispatch_hook);
+ }
+}
+} // namespace GDMonoWasmM2n
+
+#endif
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
new file mode 100644
index 0000000000..68a14f15f4
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -0,0 +1,263 @@
+/*************************************************************************/
+/* gd_mono_wasm_m2n.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 GD_MONO_WASM_M2N_H
+#define GD_MONO_WASM_M2N_H
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/string/ustring.h"
+#include "core/typedefs.h"
+
+#include <mono/metadata/loader.h>
+#include <mono/utils/mono-publib.h>
+#include <stdexcept>
+#include <type_traits>
+
+extern "C" {
+
+struct Mono_InterpMethodArguments {
+ size_t ilen;
+ void **iargs;
+ size_t flen;
+ double *fargs;
+ void **retval;
+ size_t is_float_ret;
+ //#ifdef TARGET_WASM
+ void *sig;
+ //#endif
+};
+} // extern "C"
+
+namespace GDMonoWasmM2n {
+
+template <typename T, size_t Size>
+struct array {
+ T elems[Size];
+};
+
+template <typename T>
+constexpr char get_m2n_cookie_impl() {
+#define M2N_REG_COOKIE(m_type, m_cookie) \
+ if constexpr (std::is_same_v<m_type, T>) { \
+ return m_cookie; \
+ }
+
+ M2N_REG_COOKIE(MonoBoolean, 'I');
+ M2N_REG_COOKIE(int8_t, 'I');
+ M2N_REG_COOKIE(uint8_t, 'I');
+ M2N_REG_COOKIE(int16_t, 'I');
+ M2N_REG_COOKIE(uint16_t, 'I');
+ M2N_REG_COOKIE(int32_t, 'I');
+ M2N_REG_COOKIE(uint32_t, 'I');
+ M2N_REG_COOKIE(int64_t, 'L');
+ M2N_REG_COOKIE(uint64_t, 'L');
+ M2N_REG_COOKIE(float, 'F');
+ M2N_REG_COOKIE(double, 'D');
+
+ if constexpr (std::is_pointer_v<T>) {
+ if constexpr (sizeof(void *) == 4) {
+ return 'I';
+ } else {
+ return 'L';
+ }
+ }
+
+ if constexpr (std::is_void_v<T>) {
+ return 'V';
+ }
+
+ return 'X';
+
+#undef M2N_REG_COOKIE
+}
+
+template <typename T>
+constexpr char get_m2n_cookie() {
+ constexpr char cookie = get_m2n_cookie_impl<T>();
+ static_assert(cookie != 'X', "Type not supported in internal call signature.");
+ return cookie;
+}
+
+template <typename... T>
+constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies() {
+ return array<const char, sizeof...(T) + 2>{ 'V', get_m2n_cookie<T>()..., '\0' };
+}
+
+template <typename R, typename... T>
+constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies_r() {
+ return array<const char, sizeof...(T) + 2>{ get_m2n_cookie<R>(), get_m2n_cookie<T>()..., '\0' };
+}
+
+template <typename T>
+constexpr size_t calc_m2n_index(size_t &r_int_idx, size_t &r_float_idx) {
+ constexpr char cookie = get_m2n_cookie<T>();
+
+ static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
+
+ if constexpr (cookie == 'I' || cookie == 'L') {
+ size_t ret = r_int_idx;
+ r_int_idx += cookie == 'I' ? 1 : 2;
+ return ret;
+ } else {
+ size_t ret = r_float_idx;
+ r_float_idx += cookie == 'F' ? 1 : 2;
+ return ret;
+ }
+}
+
+template <typename... P>
+constexpr array<size_t, sizeof...(P)> get_indices_for_type() {
+ size_t int_idx = 0;
+ size_t float_idx = 0;
+ return array<size_t, sizeof...(P)>{ calc_m2n_index<P>(int_idx, float_idx)... };
+}
+
+constexpr size_t fidx(size_t p_x) {
+ if constexpr (sizeof(void *) == 4) {
+ return p_x * 2;
+ } else {
+ return p_x;
+ }
+}
+
+template <typename T>
+T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
+ constexpr char cookie = get_m2n_cookie<T>();
+
+ static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
+
+ if constexpr (cookie == 'I') {
+ return (T)(size_t)p_margs->iargs[p_idx];
+ } else if constexpr (cookie == 'L') {
+ static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t> ||
+ (sizeof(void *) == 8 && std::is_pointer_v<T>),
+ "Invalid type for cookie 'L'.");
+
+ union {
+ T l;
+ struct {
+ int32_t lo;
+ int32_t hi;
+ } pair;
+ } p;
+
+ p.pair.lo = (int32_t)(size_t)p_margs->iargs[p_idx];
+ p.pair.hi = (int32_t)(size_t)p_margs->iargs[p_idx + 1];
+
+ return p.l;
+ } else if constexpr (cookie == 'F') {
+ return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
+ } else if constexpr (cookie == 'D') {
+ return (T)(size_t)p_margs->fargs[p_idx];
+ }
+}
+
+template <typename... P, size_t... Is>
+void m2n_trampoline_with_idx_seq(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
+ constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
+ typedef void (*Func)(P...);
+ Func func = (Func)p_target_func;
+ func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
+}
+
+template <typename R, typename... P, size_t... Is>
+void m2n_trampoline_with_idx_seq_r(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
+ constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
+ typedef R (*Func)(P...);
+ Func func = (Func)p_target_func;
+ R res = func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
+ *reinterpret_cast<R *>(p_margs->retval) = res;
+}
+
+inline void m2n_trampoline_with_idx_seq_0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ typedef void (*Func)();
+ Func func = (Func)p_target_func;
+ func();
+}
+
+template <typename R>
+void m2n_trampoline_with_idx_seq_r0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ typedef R (*Func)();
+ Func func = (Func)p_target_func;
+ R res = func();
+ *reinterpret_cast<R *>(p_margs->retval) = res;
+}
+
+template <typename... P>
+void m2n_trampoline(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ if constexpr (sizeof...(P) == 0) {
+ m2n_trampoline_with_idx_seq_0(p_target_func, p_margs);
+ } else {
+ m2n_trampoline_with_idx_seq<P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
+ }
+}
+
+template <typename R, typename... P>
+void m2n_trampoline_r(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ if constexpr (sizeof...(P) == 0) {
+ m2n_trampoline_with_idx_seq_r0<R>(p_target_func, p_margs);
+ } else {
+ m2n_trampoline_with_idx_seq_r<R, P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
+ }
+}
+
+typedef void (*TrampolineFunc)(void *p_target_func, Mono_InterpMethodArguments *p_margs);
+
+void set_trampoline(const char *cookies, TrampolineFunc trampoline_func);
+
+void lazy_initialize();
+
+template <typename... P>
+struct ICallTrampolines {
+ static constexpr auto cookies = get_m2n_cookies<P...>();
+
+ static void add() {
+ lazy_initialize();
+ set_trampoline(cookies.elems, &m2n_trampoline<P...>);
+ }
+};
+
+template <typename R, typename... P>
+struct ICallTrampolinesR {
+ static constexpr auto cookies = get_m2n_cookies_r<R, P...>();
+
+ static void add() {
+ lazy_initialize();
+ set_trampoline(cookies.elems, &m2n_trampoline_r<R, P...>);
+ }
+};
+
+void initialize();
+} // namespace GDMonoWasmM2n
+
+#endif
+
+#endif // GD_MONO_WASM_M2N_H
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index 18daf859b5..bc2ae03299 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -355,8 +355,8 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
}
void register_internal_calls() {
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store);
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup);
+ GDMonoUtils::add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", _gd_mono_init_cert_store);
+ GDMonoUtils::add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", _gd_mono_android_cert_store_lookup);
}
void initialize() {
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index bd67b03c8e..f220abfb4c 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -48,18 +48,10 @@ Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signa
}
bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Only called if both instances are of type SignalAwaiterCallable. Static cast is safe.
const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a);
const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b);
-
- if (a->target_id != b->target_id) {
- return false;
- }
-
- if (a->signal != b->signal) {
- return false;
- }
-
- return true;
+ return a->awaiter_handle.handle == b->awaiter_handle.handle;
}
bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -109,11 +101,15 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va
"Resumed after await, but class instance is gone.");
#endif
- MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
+ MonoArray *signal_args = nullptr;
- for (int i = 0; i < p_argcount; i++) {
- MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
- mono_array_setref(signal_args, i, boxed);
+ if (p_argcount > 0) {
+ signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
+
+ for (int i = 0; i < p_argcount; i++) {
+ MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
+ mono_array_setref(signal_args, i, boxed);
+ }
}
MonoObject *awaiter = awaiter_handle.get_target();
diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub
index e768fb4ae8..e415d92498 100644
--- a/modules/ogg/SCsub
+++ b/modules/ogg/SCsub
@@ -9,6 +9,9 @@ Import("env_modules")
env_ogg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libogg"]:
thirdparty_dir = "#thirdparty/libogg/"
thirdparty_sources = [
@@ -21,7 +24,16 @@ if env["builtin_libogg"]:
env_thirdparty = env_ogg.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_ogg.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_ogg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/opensimplex/SCsub b/modules/opensimplex/SCsub
index 52d8b145ef..86d77c3dfb 100644
--- a/modules/opensimplex/SCsub
+++ b/modules/opensimplex/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_opensimplex = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/misc/"
thirdparty_sources = [
"open-simplex-noise.c",
@@ -16,7 +19,15 @@ env_opensimplex.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_opensimplex.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_opensimplex.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_opensimplex.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index d89828037f..9fe4c9c249 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -24,7 +24,7 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_image">
+ <method name="get_image" qualifiers="const">
<return type="Image">
</return>
<argument index="0" name="width" type="int">
@@ -35,7 +35,7 @@
Generate a noise image with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters.
</description>
</method>
- <method name="get_noise_1d">
+ <method name="get_noise_1d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -45,7 +45,7 @@
[b]Note:[/b] This method actually returns the 2D noise value [code][-1,1][/code] with fixed y-coordinate value 0.0.
</description>
</method>
- <method name="get_noise_2d">
+ <method name="get_noise_2d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -56,7 +56,7 @@
Returns the 2D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_2dv">
+ <method name="get_noise_2dv" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="pos" type="Vector2">
@@ -65,7 +65,7 @@
Returns the 2D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_3d">
+ <method name="get_noise_3d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -78,7 +78,7 @@
Returns the 3D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_3dv">
+ <method name="get_noise_3dv" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="pos" type="Vector3">
@@ -87,7 +87,7 @@
Returns the 3D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_4d">
+ <method name="get_noise_4d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -102,7 +102,7 @@
Returns the 4D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_seamless_image">
+ <method name="get_seamless_image" qualifiers="const">
<return type="Image">
</return>
<argument index="0" name="size" type="int">
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
index b08219d258..aded4d2a07 100644
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ b/modules/opensimplex/open_simplex_noise.cpp
@@ -63,7 +63,7 @@ void OpenSimplexNoise::set_seed(int p_seed) {
emit_changed();
}
-int OpenSimplexNoise::get_seed() {
+int OpenSimplexNoise::get_seed() const {
return seed;
}
@@ -102,7 +102,7 @@ void OpenSimplexNoise::set_lacunarity(float p_lacunarity) {
emit_changed();
}
-Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) {
+Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) const {
Vector<uint8_t> data;
data.resize(p_width * p_height * 4);
@@ -124,7 +124,7 @@ Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) {
return image;
}
-Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) {
+Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) const {
Vector<uint8_t> data;
data.resize(p_size * p_size * 4);
@@ -193,11 +193,11 @@ void OpenSimplexNoise::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lacunarity", PROPERTY_HINT_RANGE, "0.1,4.0,0.01"), "set_lacunarity", "get_lacunarity");
}
-float OpenSimplexNoise::get_noise_1d(float x) {
+float OpenSimplexNoise::get_noise_1d(float x) const {
return get_noise_2d(x, 1.0);
}
-float OpenSimplexNoise::get_noise_2d(float x, float y) {
+float OpenSimplexNoise::get_noise_2d(float x, float y) const {
x /= period;
y /= period;
@@ -217,7 +217,7 @@ float OpenSimplexNoise::get_noise_2d(float x, float y) {
return sum / max;
}
-float OpenSimplexNoise::get_noise_3d(float x, float y, float z) {
+float OpenSimplexNoise::get_noise_3d(float x, float y, float z) const {
x /= period;
y /= period;
z /= period;
@@ -239,7 +239,7 @@ float OpenSimplexNoise::get_noise_3d(float x, float y, float z) {
return sum / max;
}
-float OpenSimplexNoise::get_noise_4d(float x, float y, float z, float w) {
+float OpenSimplexNoise::get_noise_4d(float x, float y, float z, float w) const {
x /= period;
y /= period;
z /= period;
diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h
index 835f8ed35e..d9bf05115d 100644
--- a/modules/opensimplex/open_simplex_noise.h
+++ b/modules/opensimplex/open_simplex_noise.h
@@ -61,7 +61,7 @@ public:
void _init_seeds();
void set_seed(int seed);
- int get_seed();
+ int get_seed() const;
void set_octaves(int p_octaves);
int get_octaves() const { return octaves; }
@@ -75,22 +75,22 @@ public:
void set_lacunarity(float p_lacunarity);
float get_lacunarity() const { return lacunarity; }
- Ref<Image> get_image(int p_width, int p_height);
- Ref<Image> get_seamless_image(int p_size);
+ Ref<Image> get_image(int p_width, int p_height) const;
+ Ref<Image> get_seamless_image(int p_size) const;
- float get_noise_1d(float x);
- float get_noise_2d(float x, float y);
- float get_noise_3d(float x, float y, float z);
- float get_noise_4d(float x, float y, float z, float w);
+ float get_noise_1d(float x) const;
+ float get_noise_2d(float x, float y) const;
+ float get_noise_3d(float x, float y, float z) const;
+ float get_noise_4d(float x, float y, float z, float w) const;
- _FORCE_INLINE_ float _get_octave_noise_2d(int octave, float x, float y) { return open_simplex_noise2(&(contexts[octave]), x, y); }
- _FORCE_INLINE_ float _get_octave_noise_3d(int octave, float x, float y, float z) { return open_simplex_noise3(&(contexts[octave]), x, y, z); }
- _FORCE_INLINE_ float _get_octave_noise_4d(int octave, float x, float y, float z, float w) { return open_simplex_noise4(&(contexts[octave]), x, y, z, w); }
+ _FORCE_INLINE_ float _get_octave_noise_2d(int octave, float x, float y) const { return open_simplex_noise2(&(contexts[octave]), x, y); }
+ _FORCE_INLINE_ float _get_octave_noise_3d(int octave, float x, float y, float z) const { return open_simplex_noise3(&(contexts[octave]), x, y, z); }
+ _FORCE_INLINE_ float _get_octave_noise_4d(int octave, float x, float y, float z, float w) const { return open_simplex_noise4(&(contexts[octave]), x, y, z, w); }
// Convenience
- _FORCE_INLINE_ float get_noise_2dv(Vector2 v) { return get_noise_2d(v.x, v.y); }
- _FORCE_INLINE_ float get_noise_3dv(Vector3 v) { return get_noise_3d(v.x, v.y, v.z); }
+ _FORCE_INLINE_ float get_noise_2dv(const Vector2 &v) const { return get_noise_2d(v.x, v.y); }
+ _FORCE_INLINE_ float get_noise_3dv(const Vector3 &v) const { return get_noise_3d(v.x, v.y, v.z); }
protected:
static void _bind_methods();
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index 52c61fa708..1437cd86df 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -10,6 +10,10 @@ Import("env_modules")
env_opus = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
+# Thirdparty source files
if env["builtin_opus"]:
thirdparty_dir = "#thirdparty/opus/"
@@ -233,7 +237,16 @@ if env["builtin_opus"]:
env_thirdparty = env_opus.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_opus.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Module files
-env_opus.add_source_files(env.modules_sources, "register_types.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub
index e0baf851f1..36052cffed 100644
--- a/modules/pvr/SCsub
+++ b/modules/pvr/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_pvr = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/pvrtccompressor/"
thirdparty_sources = [
@@ -21,7 +24,15 @@ env_pvr.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_pvr.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_pvr.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_pvr.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp
new file mode 100644
index 0000000000..6695a539d0
--- /dev/null
+++ b/modules/pvr/image_compress_pvrtc.cpp
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* image_compress_pvrtc.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "image_compress_pvrtc.h"
+
+#include "core/io/image.h"
+#include "core/object/reference.h"
+
+#include <PvrTcEncoder.h>
+#include <RgbaBitmap.h>
+
+static void _compress_pvrtc1_4bpp(Image *p_img) {
+ Ref<Image> img = p_img->duplicate();
+
+ bool make_mipmaps = false;
+ if (!img->is_size_po2() || img->get_width() != img->get_height()) {
+ make_mipmaps = img->has_mipmaps();
+ img->resize_to_po2(true);
+ }
+ img->convert(Image::FORMAT_RGBA8);
+ if (!img->has_mipmaps() && make_mipmaps) {
+ img->generate_mipmaps();
+ }
+
+ bool use_alpha = img->detect_alpha();
+
+ Ref<Image> new_img;
+ new_img.instance();
+ new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4);
+
+ Vector<uint8_t> data = new_img->get_data();
+ {
+ uint8_t *wr = data.ptrw();
+ const uint8_t *r = img->get_data().ptr();
+
+ for (int i = 0; i <= new_img->get_mipmap_count(); i++) {
+ int ofs, size, w, h;
+ img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
+ Javelin::RgbaBitmap bm(w, h);
+ void *dst = (void *)bm.GetData();
+ copymem(dst, &r[ofs], size);
+ Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
+ for (int j = 0; j < size / 4; j++) {
+ // Red and blue colors are swapped.
+ SWAP(dp[j].r, dp[j].b);
+ }
+ new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
+ Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
+ }
+ }
+
+ p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data);
+}
+
+void _register_pvrtc_compress_func() {
+ Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp;
+}
diff --git a/modules/pvr/image_compress_pvrtc.h b/modules/pvr/image_compress_pvrtc.h
new file mode 100644
index 0000000000..fde65f4bbe
--- /dev/null
+++ b/modules/pvr/image_compress_pvrtc.h
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* image_compress_pvrtc.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 IMAGE_COMPRESS_PVRTC_H
+#define IMAGE_COMPRESS_PVRTC_H
+
+void _register_pvrtc_compress_func();
+
+#endif // IMAGE_COMPRESS_PVRTC_H
diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp
index 1eb697bba3..9bfc334d76 100644
--- a/modules/pvr/register_types.cpp
+++ b/modules/pvr/register_types.cpp
@@ -30,6 +30,7 @@
#include "register_types.h"
+#include "image_compress_pvrtc.h"
#include "texture_loader_pvr.h"
static Ref<ResourceFormatPVR> resource_loader_pvr;
@@ -37,6 +38,8 @@ static Ref<ResourceFormatPVR> resource_loader_pvr;
void register_pvr_types() {
resource_loader_pvr.instance();
ResourceLoader::add_resource_format_loader(resource_loader_pvr);
+
+ _register_pvrtc_compress_func();
}
void unregister_pvr_types() {
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 0923714387..c9cbb1935a 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -29,11 +29,8 @@
/*************************************************************************/
#include "texture_loader_pvr.h"
-#include "PvrTcEncoder.h"
-#include "RgbaBitmap.h"
+
#include "core/os/file_access.h"
-#include <string.h>
-#include <new>
static void _pvrtc_decompress(Image *p_img);
@@ -111,11 +108,11 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
switch (flags & 0xFF) {
case 0x18:
case 0xC:
- format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC2A : Image::FORMAT_PVRTC2;
+ format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2;
break;
case 0x19:
case 0xD:
- format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4;
+ format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4;
break;
case 0x16:
format = Image::FORMAT_L8;
@@ -183,53 +180,8 @@ String ResourceFormatPVR::get_resource_type(const String &p_path) const {
return "";
}
-static void _compress_pvrtc4(Image *p_img) {
- Ref<Image> img = p_img->duplicate();
-
- bool make_mipmaps = false;
- if (!img->is_size_po2() || img->get_width() != img->get_height()) {
- make_mipmaps = img->has_mipmaps();
- img->resize_to_po2(true);
- }
- img->convert(Image::FORMAT_RGBA8);
- if (!img->has_mipmaps() && make_mipmaps) {
- img->generate_mipmaps();
- }
-
- bool use_alpha = img->detect_alpha();
-
- Ref<Image> new_img;
- new_img.instance();
- new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4);
-
- Vector<uint8_t> data = new_img->get_data();
- {
- uint8_t *wr = data.ptrw();
- const uint8_t *r = img->get_data().ptr();
-
- for (int i = 0; i <= new_img->get_mipmap_count(); i++) {
- int ofs, size, w, h;
- img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
- Javelin::RgbaBitmap bm(w, h);
- void *dst = (void *)bm.GetData();
- copymem(dst, &r[ofs], size);
- Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
- for (int j = 0; j < size / 4; j++) {
- /* red and blue colors are swapped. */
- SWAP(dp[j].r, dp[j].b);
- }
- new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
- Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
- }
- }
-
- p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data);
-}
-
ResourceFormatPVR::ResourceFormatPVR() {
Image::_image_decompress_pvrtc = _pvrtc_decompress;
- Image::_image_compress_pvrtc4_func = _compress_pvrtc4;
- Image::_image_compress_pvrtc2_func = _compress_pvrtc4;
}
/////////////////////////////////////////////////////////
@@ -635,9 +587,9 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int
}
static void _pvrtc_decompress(Image *p_img) {
- ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC2 && p_img->get_format() != Image::FORMAT_PVRTC2A && p_img->get_format() != Image::FORMAT_PVRTC4 && p_img->get_format() != Image::FORMAT_PVRTC4A);
+ ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A);
- bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC2 || p_img->get_format() == Image::FORMAT_PVRTC2A);
+ bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A);
Vector<uint8_t> data = p_img->get_data();
const uint8_t *r = data.ptr();
diff --git a/modules/regex/SCsub b/modules/regex/SCsub
index 2afacc1d9c..deb9db7591 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -5,6 +5,10 @@ Import("env_modules")
env_regex = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_pcre2"]:
thirdparty_dir = "#thirdparty/pcre2/src/"
thirdparty_flags = ["PCRE2_STATIC", "HAVE_CONFIG_H", "SUPPORT_UNICODE"]
@@ -52,11 +56,21 @@ if env["builtin_pcre2"]:
env_pcre2 = env_regex.Clone()
env_pcre2.disable_warnings()
env_pcre2["OBJSUFFIX"] = "_" + width + env_pcre2["OBJSUFFIX"]
- env_pcre2.add_source_files(env.modules_sources, thirdparty_sources)
env_pcre2.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", width)])
+ env_pcre2.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
pcre2_builtin("16")
pcre2_builtin("32")
+
+# Godot source files
+
+module_obj = []
+
env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 0)])
-env_regex.add_source_files(env.modules_sources, "*.cpp")
+env_regex.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/squish/SCsub b/modules/squish/SCsub
index b31032403f..c9e29911d8 100644
--- a/modules/squish/SCsub
+++ b/modules/squish/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_squish = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_squish"]:
thirdparty_dir = "#thirdparty/squish/"
thirdparty_sources = [
@@ -26,7 +29,16 @@ if env["builtin_squish"]:
env_thirdparty = env_squish.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_squish.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_squish.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub
index 266c87c802..8fddb23dc8 100644
--- a/modules/stb_vorbis/SCsub
+++ b/modules/stb_vorbis/SCsub
@@ -6,11 +6,22 @@ Import("env_modules")
env_stb_vorbis = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_sources = ["#thirdparty/misc/stb_vorbis.c"]
env_thirdparty = env_stb_vorbis.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_stb_vorbis.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_stb_vorbis.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 0bfba34fe5..c7228a8d0b 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_svg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/nanosvg/"
thirdparty_sources = [
"nanosvg.cc",
@@ -16,7 +19,15 @@ env_svg.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_svg.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_svg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_svg.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 7403b01a4c..3589c8546d 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -35,10 +35,14 @@ def make_icu_data(target, source, env):
g.write("#endif")
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
+ env_harfbuzz.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/harfbuzz/"
thirdparty_sources = [
"src/hb-aat-layout.cc",
@@ -107,6 +111,15 @@ if env["builtin_harfbuzz"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ env_harfbuzz.Append(
+ CPPPATH=[
+ "#thirdparty/harfbuzz/src",
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ "#thirdparty/icu4c/common/",
+ ]
+ )
+
if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
@@ -117,14 +130,6 @@ if env["builtin_harfbuzz"]:
env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
env_harfbuzz.Append(
- CPPPATH=[
- "#thirdparty/harfbuzz/src",
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
- "#thirdparty/icu4c/common/",
- ]
- )
- env_harfbuzz.Append(
CCFLAGS=[
"-DHAVE_ICU_BUILTIN",
"-DHAVE_ICU",
@@ -133,10 +138,9 @@ if env["builtin_harfbuzz"]:
"-DGRAPHITE2_STATIC",
]
)
- env_harfbuzz.disable_warnings()
- env_thirdparty = env_harfbuzz.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("harfbuzz_builtin", thirdparty_sources)
+
+ lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -151,10 +155,11 @@ if env["builtin_harfbuzz"]:
if not inserted:
env.Append(LIBS=[lib])
+
if env["builtin_graphite"]:
env_graphite = env_modules.Clone()
+ env_graphite.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/graphite/"
thirdparty_sources = [
"src/gr_char_info.cpp",
@@ -203,10 +208,9 @@ if env["builtin_graphite"]:
"-DGRAPHITE2_NFILEFACE",
]
)
- env_graphite.disable_warnings()
- env_thirdparty = env_graphite.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("graphite_builtin", thirdparty_sources)
+
+ lib = env_graphite.add_library("graphite_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -221,12 +225,12 @@ if env["builtin_graphite"]:
if not inserted:
env.Append(LIBS=[lib])
+
if env["builtin_icu"]:
env_icu = env_modules.Clone()
+ env_icu.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/icu4c/"
- # Thirdparty source files
thirdparty_sources = [
"common/appendable.cpp",
"common/bmpset.cpp",
@@ -457,10 +461,8 @@ if env["builtin_icu"]:
]
)
- env_icu.disable_warnings()
- env_thirdparty = env_icu.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("icu_builtin", thirdparty_sources)
+ lib = env_icu.add_library("icu_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -475,6 +477,11 @@ if env["builtin_icu"]:
if not inserted:
env.Append(LIBS=[lib])
+
+# Godot source files
+
+module_obj = []
+
if env_text_server_adv["tools"]:
env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
@@ -486,4 +493,9 @@ env_text_server_adv.Append(
"#thirdparty/icu4c/common/",
]
)
-env_text_server_adv.add_source_files(env.modules_sources, "*.cpp")
+
+env_text_server_adv.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp
index 10c3732fd7..b905b7dabb 100644
--- a/modules/text_server_adv/bitmap_font_adv.cpp
+++ b/modules/text_server_adv/bitmap_font_adv.cpp
@@ -175,8 +175,9 @@ static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *font, void *font_data, hb_
return true;
}
-static hb_font_funcs_t *_hb_bmp_get_font_funcs() {
- hb_font_funcs_t *funcs = hb_font_funcs_create();
+static hb_font_funcs_t *funcs = nullptr;
+void hb_bmp_create_font_funcs() {
+ funcs = hb_font_funcs_create();
hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_bmp_get_font_v_extents, nullptr, nullptr);
@@ -194,12 +195,17 @@ static hb_font_funcs_t *_hb_bmp_get_font_funcs() {
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_bmp_get_glyph_from_name, nullptr, nullptr);
hb_font_funcs_make_immutable(funcs);
+}
- return funcs;
+void hb_bmp_free_font_funcs() {
+ if (funcs != nullptr) {
+ hb_font_funcs_destroy(funcs);
+ funcs = nullptr;
+ }
}
static void _hb_bmp_font_set_funcs(hb_font_t *p_font, BitmapFontDataAdvanced *p_face, int p_size, bool p_unref) {
- hb_font_set_funcs(p_font, _hb_bmp_get_font_funcs(), _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy);
+ hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy);
}
hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_destroy_func_t p_destroy) {
@@ -384,7 +390,6 @@ Error BitmapFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_s
chr.rect.position.y = c[2];
chr.rect.size.x = c[3];
chr.rect.size.y = c[4];
- chr.texture_idx = 0;
if (c[7] < 0) {
chr.advance.x = c[3];
} else {
diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h
index b2fe7f43af..cb1a726f76 100644
--- a/modules/text_server_adv/bitmap_font_adv.h
+++ b/modules/text_server_adv/bitmap_font_adv.h
@@ -33,6 +33,9 @@
#include "font_adv.h"
+void hb_bmp_create_font_funcs();
+void hb_bmp_free_font_funcs();
+
struct BitmapFontDataAdvanced : public FontDataAdvanced {
_THREAD_SAFE_CLASS_
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index 90e5cc8831..08c4ad2727 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -32,8 +32,7 @@
#include FT_STROKER_H
#include FT_ADVANCES_H
-
-HashMap<String, Vector<uint8_t>> DynamicFontDataAdvanced::font_mem_cache;
+#include FT_MULTIPLE_MASTERS_H
DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
ERR_FAIL_COND_V(!valid, nullptr);
@@ -55,11 +54,10 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
if (E != nullptr) {
fds = E->get();
} else {
- // FT_OPEN_STREAM is extremely slow only on Android.
- if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) {
- if (font_mem_cache.has(font_path)) {
- font_mem = font_mem_cache[font_path].ptr();
- font_mem_size = font_mem_cache[font_path].size();
+ if (font_mem == nullptr && font_path != String()) {
+ if (!font_mem_cache.empty()) {
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = font_mem_cache.size();
} else {
FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
if (!f) {
@@ -67,11 +65,9 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
}
size_t len = f->get_len();
- font_mem_cache[font_path] = Vector<uint8_t>();
- Vector<uint8_t> &fontdata = font_mem_cache[font_path];
- fontdata.resize(len);
- f->get_buffer(fontdata.ptrw(), len);
- font_mem = fontdata.ptr();
+ font_mem_cache.resize(len);
+ f->get_buffer(font_mem_cache.ptrw(), len);
+ font_mem = font_mem_cache.ptr();
font_mem_size = len;
f->close();
}
@@ -79,27 +75,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
int error = 0;
fds = memnew(DataAtSize);
- if (font_mem == nullptr && font_path != String()) {
- FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
- if (!f) {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
- }
-
- memset(&fds->stream, 0, sizeof(FT_StreamRec));
- fds->stream.base = nullptr;
- fds->stream.size = f->get_len();
- fds->stream.pos = 0;
- fds->stream.descriptor.pointer = f;
- fds->stream.read = _ft_stream_io;
- fds->stream.close = _ft_stream_close;
-
- FT_Open_Args fargs;
- memset(&fargs, 0, sizeof(FT_Open_Args));
- fargs.flags = FT_OPEN_STREAM;
- fargs.stream = &fds->stream;
- error = FT_Open_Face(library, &fargs, 0, &fds->face);
- } else if (font_mem) {
+ if (font_mem) {
memset(&fds->stream, 0, sizeof(FT_StreamRec));
fds->stream.base = (unsigned char *)font_mem;
fds->stream.size = font_mem_size;
@@ -159,33 +135,89 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
memdelete(fds);
ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
}
+
if (p_outline_size != 0) {
size_cache_outline[id] = fds;
} else {
size_cache[id] = fds;
}
- }
+ // Write variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ Vector<hb_variation_t> hb_vars;
+ Vector<FT_Fixed> coords;
+ coords.resize(amaster->num_axis);
+
+ FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ hb_variation_t var;
+
+ // Reset to default.
+ var.tag = amaster->axis[i].tag;
+ var.value = (double)amaster->axis[i].def / 65536.f;
+ coords.write[i] = amaster->axis[i].def;
+
+ if (variations.has(var.tag)) {
+ var.value = variations[var.tag];
+ coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ }
+
+ hb_vars.push_back(var);
+ }
+
+ FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+ hb_font_set_variations(fds->hb_handle, hb_vars.empty() ? nullptr : &hb_vars[0], hb_vars.size());
+
+ FT_Done_MM_Var(library, amaster);
+ }
+ }
return fds;
}
-unsigned long DynamicFontDataAdvanced::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) {
- FileAccess *f = (FileAccess *)stream->descriptor.pointer;
-
- if (f->get_position() != offset) {
- f->seek(offset);
+Dictionary DynamicFontDataAdvanced::get_variation_list() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ if (fds == nullptr) {
+ return Dictionary();
}
- if (count == 0) {
- return 0;
+
+ Dictionary ret;
+ // Read variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
+ }
+
+ FT_Done_MM_Var(library, amaster);
}
+ return ret;
+}
- return f->get_buffer(buffer, count);
+void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag) || (variations[tag] != p_value)) {
+ variations[tag] = p_value;
+ clear_cache();
+ }
}
-void DynamicFontDataAdvanced::_ft_stream_close(FT_Stream stream) {
- FileAccess *f = (FileAccess *)stream->descriptor.pointer;
- f->close();
- memdelete(f);
+double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag)) {
+ return 0.f;
+ }
+ return variations[tag];
}
Dictionary DynamicFontDataAdvanced::get_feature_list() const {
@@ -222,8 +254,6 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const {
DynamicFontDataAdvanced::TexturePosition DynamicFontDataAdvanced::find_texture_pos_for_glyph(DynamicFontDataAdvanced::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
TexturePosition ret;
ret.index = -1;
- ret.x = 0;
- ret.y = 0;
int mw = p_width;
int mh = p_height;
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
index 61cff3cde9..f9d6735c32 100644
--- a/modules/text_server_adv/dynamic_font_adv.h
+++ b/modules/text_server_adv/dynamic_font_adv.h
@@ -116,7 +116,9 @@ private:
const uint8_t *font_mem = nullptr;
int font_mem_size = 0;
String font_path;
- static HashMap<String, Vector<uint8_t>> font_mem_cache;
+ Vector<uint8_t> font_mem_cache;
+
+ Map<int32_t, double> variations;
float rect_margin = 1.f;
int base_size = 16;
@@ -128,9 +130,6 @@ private:
Map<CacheID, DataAtSize *> size_cache;
Map<CacheID, DataAtSize *> size_cache_outline;
- static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count);
- static void _ft_stream_close(FT_Stream stream);
-
DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0);
TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height);
@@ -149,6 +148,10 @@ public:
virtual float get_descent(int p_size) const override;
virtual Dictionary get_feature_list() const override;
+ virtual Dictionary get_variation_list() const override;
+
+ virtual void set_variation(const String &p_name, double p_value) override;
+ virtual double get_variation(const String &p_name) const override;
virtual float get_underline_position(int p_size) const override;
virtual float get_underline_thickness(int p_size) const override;
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
index 232d6d7d08..88b327f57b 100644
--- a/modules/text_server_adv/font_adv.h
+++ b/modules/text_server_adv/font_adv.h
@@ -50,6 +50,10 @@ struct FontDataAdvanced {
virtual float get_descent(int p_size) const = 0;
virtual Dictionary get_feature_list() const { return Dictionary(); };
+ virtual Dictionary get_variation_list() const { return Dictionary(); };
+
+ virtual void set_variation(const String &p_name, double p_value){};
+ virtual double get_variation(const String &p_name) const { return 0; };
virtual float get_underline_position(int p_size) const = 0;
virtual float get_underline_thickness(int p_size) const = 0;
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index 8a2b2cced0..60a617c3a7 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -56,11 +56,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
int paren_sp = -1;
int start_sp = paren_sp;
UErrorCode err = U_ZERO_ERROR;
+ const char32_t *str = p_string.ptr();
do {
script_code = USCRIPT_COMMON;
for (script_start = script_end; script_end < p_length; script_end++) {
- UChar32 ch = p_string[script_end];
+ UChar32 ch = str[script_end];
UScriptCode sc = uscript_getScript(ch, &err);
if (U_FAILURE(err)) {
ERR_FAIL_MSG(u_errorName(err));
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index e391777eea..3a706286e5 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
/*************************************************************************/
String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
-uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA;
+uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
bool TextServerAdvanced::has_feature(Feature p_feature) {
return (interface_features & p_feature) == p_feature;
@@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
return fd->get_antialiased();
}
+Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+ return fd->get_variation_list();
+}
+
+void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_variation(p_name, p_value);
+}
+
+double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_variation(p_name);
+}
+
void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = font_owner.getornull(p_font);
@@ -1108,7 +1129,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->width = 0;
sd->upos = 0;
sd->uthk = 0;
- for (int i = 0; i < sd->glyphs.size(); i++) {
+ int sd_size = sd->glyphs.size();
+
+ for (int i = 0; i < sd_size; i++) {
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
@@ -1128,8 +1151,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2);
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
@@ -1144,8 +1167,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2);
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
@@ -1160,19 +1183,19 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
sd->descent = MAX(sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
} else {
- sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
sd->width += gl.advance * gl.repeat;
@@ -1248,6 +1271,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->utf16 = new_sd->text.utf16();
new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
+ const FontDataAdvanced *fd = nullptr;
+ RID prev_rid = RID();
+
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
UErrorCode err = U_ZERO_ERROR;
@@ -1280,21 +1308,23 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start);
int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
- for (int j = 0; j < sd->glyphs.size(); j++) {
- if ((sd->glyphs[j].start >= bidi_run_start) && (sd->glyphs[j].end <= bidi_run_end)) {
+ for (int j = 0; j < sd_size; j++) {
+ if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
// Copy glyphs.
- Glyph gl = sd->glyphs[j];
+ Glyph gl = sd_glyphs[j];
Variant key;
+ bool find_embedded = false;
if (gl.count == 1) {
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (E->get().pos == gl.start) {
+ find_embedded = true;
key = E->key();
new_sd->objects[key] = E->get();
break;
}
}
}
- if (key != Variant()) {
+ if (find_embedded) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
@@ -1303,8 +1333,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2);
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
@@ -1318,8 +1348,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2);
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
@@ -1327,23 +1357,26 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
} else {
- const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid);
+ if (prev_rid != gl.font_rid) {
+ fd = font_owner.getornull(gl.font_rid);
+ prev_rid = gl.font_rid;
+ }
if (fd != nullptr) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
new_sd->descent = MAX(new_sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
} else {
- new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
new_sd->width += gl.advance * gl.repeat;
@@ -1491,9 +1524,9 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
float old_adv = gl.advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.advance = MAX(gl.advance + delta_width_per_space, 0.f);
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f));
} else {
- gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size);
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
}
sd->width += (gl.advance - old_adv);
}
@@ -1529,8 +1562,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
delta = -1;
}
+ Glyph *gl = sd->glyphs.ptrw();
+
for (int i = start; i != end; i += delta) {
- if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
float tab_off = 0.f;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
@@ -1539,13 +1574,13 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
tab_index = 0;
}
}
- float old_adv = sd->glyphs.write[i].advance;
- sd->glyphs.write[i].advance = (tab_off - off);
- sd->width += sd->glyphs.write[i].advance - old_adv;
+ float old_adv = gl[i].advance;
+ gl[i].advance = tab_off - off;
+ sd->width += gl[i].advance - old_adv;
off = 0;
continue;
}
- off += sd->glyphs[i].advance * sd->glyphs[i].repeat;
+ off += gl[i].advance * gl[i].repeat;
}
return 0.f;
@@ -1565,8 +1600,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
const UChar *data = sd->utf16.ptr();
- Map<int, bool> breaks;
-
+ HashMap<int, bool> breaks;
UErrorCode err = U_ZERO_ERROR;
for (int i = 0; i < sd->spans.size(); i++) {
UBreakIterator *bi = ubrk_open(UBRK_LINE, sd->spans[i].language.ascii().get_data(), data + _convert_pos_inv(sd, sd->spans[i].start), _convert_pos_inv(sd, sd->spans[i].end - sd->spans[i].start), &err);
@@ -1598,40 +1632,52 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
sd->sort_valid = false;
sd->glyphs_logical.clear();
+ int sd_size = sd->glyphs.size();
+ const char32_t *ch = sd->text.ptr();
+ Glyph *sd_glyphs = sd->glyphs.ptrw();
- for (int i = 0; i < sd->glyphs.size(); i++) {
- if (sd->glyphs[i].count > 0) {
- char32_t c = sd->text[sd->glyphs[i].start - sd->start];
+ for (int i = 0; i < sd_size; i++) {
+ if (sd_glyphs[i].count > 0) {
+ char32_t c = ch[sd_glyphs[i].start - sd->start];
if (c == 0xfffc) {
continue;
}
if (c == 0x0009 || c == 0x000b) {
- sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB;
+ sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
+ }
+ if (is_whitespace(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
+ }
+ if (u_ispunct(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
}
if (breaks.has(sd->glyphs[i].start)) {
if (breaks[sd->glyphs[i].start]) {
- sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD;
+ sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
} else {
if (is_whitespace(c)) {
- sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT;
- sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE;
+ sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
} else {
TextServer::Glyph gl;
- gl.start = sd->glyphs[i].start;
- gl.end = sd->glyphs[i].end;
+ gl.start = sd_glyphs[i].start;
+ gl.end = sd_glyphs[i].end;
gl.count = 1;
- gl.repeat = 1;
- gl.font_rid = sd->glyphs[i].font_rid;
- gl.font_size = sd->glyphs[i].font_size;
+ gl.font_rid = sd_glyphs[i].font_rid;
+ gl.font_size = sd_glyphs[i].font_size;
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
- i += sd->glyphs[i].count;
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
+
+ // Update write pointer and size.
+ sd_size = sd->glyphs.size();
+ sd_glyphs = sd->glyphs.ptrw();
+
+ i += sd_glyphs[i].count;
continue;
}
}
}
- i += (sd->glyphs[i].count - 1);
+ i += (sd_glyphs[i].count - 1);
}
}
@@ -1725,6 +1771,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
shaped_text_update_breaks(p_shaped);
}
+ if (sd->justification_ops_valid) {
+ return true; // Noting to do.
+ }
+
const UChar *data = sd->utf16.ptr();
int32_t data_size = sd->utf16.length();
@@ -1755,9 +1805,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {
int i = _convert_pos(sd, ubrk_current(bi));
jstops[i + sd->start] = false;
- int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start;
+ int ks = _generate_kashida_justification_opportunies(sd->text, limit, i);
if (ks != -1) {
- jstops[ks] = true;
+ jstops[ks + sd->start] = true;
}
limit = i;
}
@@ -1767,9 +1817,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
sd->sort_valid = false;
sd->glyphs_logical.clear();
+ int sd_size = sd->glyphs.size();
if (jstops.size() > 0) {
- for (int i = 0; i < sd->glyphs.size(); i++) {
+ for (int i = 0; i < sd_size; i++) {
if (sd->glyphs[i].count > 0) {
if (jstops.has(sd->glyphs[i].start)) {
char32_t c = sd->text[sd->glyphs[i].start - sd->start];
@@ -1803,7 +1854,6 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
gl.start = sd->glyphs[i].start;
gl.end = sd->glyphs[i].end;
gl.count = 1;
- gl.repeat = 1;
gl.font_rid = sd->glyphs[i].font_rid;
gl.font_size = sd->glyphs[i].font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
@@ -1838,8 +1888,6 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
// Process glyphs.
TextServer::Glyph gl;
- gl.start = -1;
- gl.end = -1;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
@@ -1850,15 +1898,15 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
if (glyph_count > 0) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size));
+ gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size)));
} else {
- gl.advance = -glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size));
+ gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size)));
}
gl.count = 1;
gl.index = glyph_info[0].codepoint;
- gl.x_off = glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size));
- gl.y_off = -glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size));
+ gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size)));
+ gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size)));
if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
gl.flags |= GRAPHEME_IS_VALID;
@@ -1873,8 +1921,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
fd = font_owner.getornull(p_fonts[p_fb_index]);
}
+ int fs = p_sd->spans[p_span].font_size;
if (fd == nullptr) {
- // Add fallback glyohs
+ // Add fallback glyphs
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
TextServer::Glyph gl;
@@ -1882,20 +1931,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.end = i + 1;
gl.count = 1;
gl.index = p_sd->text[i];
- gl.font_size = p_sd->spans[p_span].font_size;
+ gl.font_size = fs;
gl.font_rid = RID();
- gl.flags = 0;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
}
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
- p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ gl.advance = get_hex_code_box_size(fs, gl.index).x;
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
} else {
- gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
- p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ gl.advance = get_hex_code_box_size(fs, gl.index).y;
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
}
p_sd->width += gl.advance;
@@ -1905,7 +1953,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
return;
}
- hb_font_t *hb_font = fd->get_hb_handle(p_sd->spans[p_span].font_size);
+ hb_font_t *hb_font = fd->get_hb_handle(fs);
ERR_FAIL_COND(hb_font == nullptr);
hb_buffer_clear_contents(p_sd->hb_buffer);
@@ -1981,17 +2029,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.count = 0;
gl.font_rid = p_fonts[p_fb_index];
- gl.font_size = p_sd->spans[p_span].font_size;
+ gl.font_size = fs;
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(gl.font_size));
+ gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs)));
} else {
- gl.advance = -glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(gl.font_size));
+ gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs)));
}
- gl.x_off = glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(gl.font_size));
- gl.y_off = -glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(gl.font_size));
+ gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs)));
+ gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs)));
}
if (p_sd->preserve_control) {
@@ -2026,14 +2074,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
for (int j = 0; j < w[i].count; j++) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- p_sd->ascent = MAX(p_sd->ascent, MAX(fd->get_ascent(w[i + j].font_size), w[i + j].y_off));
- p_sd->descent = MAX(p_sd->descent, MAX(fd->get_descent(w[i + j].font_size), w[i + j].y_off));
+ p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
+ p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
} else {
- p_sd->ascent = MAX(p_sd->ascent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5);
- p_sd->descent = MAX(p_sd->descent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5);
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
}
- p_sd->upos = MAX(p_sd->upos, font_get_underline_position(w[i + j].font_rid, w[i + j].font_size));
- p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(w[i + j].font_rid, w[i + j].font_size));
p_sd->width += w[i + j].advance;
p_sd->glyphs.push_back(w[i + j]);
}
@@ -2051,6 +2097,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
if (failed_subrun_start != p_end + 1) {
_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1);
}
+ p_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs));
+ p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs));
+ p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs));
+ p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs));
}
}
@@ -2180,8 +2230,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2);
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
@@ -2195,8 +2245,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2);
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
@@ -2207,7 +2257,6 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
gl.start = span.start;
gl.end = span.end;
gl.count = 1;
- gl.index = 0;
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL;
if (sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = sd->objects[span.embedded_key].rect.size.x;
@@ -2507,9 +2556,11 @@ void TextServerAdvanced::register_server() {
}
TextServerAdvanced::TextServerAdvanced() {
+ hb_bmp_create_font_funcs();
}
TextServerAdvanced::~TextServerAdvanced() {
+ hb_bmp_free_font_funcs();
u_cleanup();
#ifndef ICU_STATIC_DATA
if (icu_data != nullptr) {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index f26b87f67e..8c26554158 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -138,6 +138,10 @@ public:
virtual bool font_get_antialiased(RID p_font) const override;
virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index 7650e27063..03eccbe7bd 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -9,4 +9,5 @@ env_text_server_fb.Append(
"#thirdparty/freetype/include",
]
)
+
env_text_server_fb.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp
index 5ab8edbd71..99cbccb69a 100644
--- a/modules/text_server_fb/bitmap_font_fb.cpp
+++ b/modules/text_server_fb/bitmap_font_fb.cpp
@@ -198,7 +198,6 @@ Error BitmapFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_s
chr.rect.position.y = c[2];
chr.rect.size.x = c[3];
chr.rect.size.y = c[4];
- chr.texture_idx = 0;
if (c[7] < 0) {
chr.advance.x = c[3];
} else {
diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp
index 6feeaec102..6731870e8f 100644
--- a/modules/text_server_fb/dynamic_font_fb.cpp
+++ b/modules/text_server_fb/dynamic_font_fb.cpp
@@ -33,8 +33,6 @@
#include FT_STROKER_H
#include FT_ADVANCES_H
-HashMap<String, Vector<uint8_t>> DynamicFontDataFallback::font_mem_cache;
-
DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(int p_size, int p_outline_size) {
ERR_FAIL_COND_V(!valid, nullptr);
ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr);
@@ -55,11 +53,10 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(
if (E != nullptr) {
fds = E->get();
} else {
- // FT_OPEN_STREAM is extremely slow only on Android.
- if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) {
- if (font_mem_cache.has(font_path)) {
- font_mem = font_mem_cache[font_path].ptr();
- font_mem_size = font_mem_cache[font_path].size();
+ if (font_mem == nullptr && font_path != String()) {
+ if (!font_mem_cache.empty()) {
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = font_mem_cache.size();
} else {
FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
if (!f) {
@@ -67,11 +64,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(
}
size_t len = f->get_len();
- font_mem_cache[font_path] = Vector<uint8_t>();
- Vector<uint8_t> &fontdata = font_mem_cache[font_path];
- fontdata.resize(len);
- f->get_buffer(fontdata.ptrw(), len);
- font_mem = fontdata.ptr();
+ font_mem_cache.resize(len);
+ f->get_buffer(font_mem_cache.ptrw(), len);
+ font_mem = font_mem_cache.ptr();
font_mem_size = len;
f->close();
}
@@ -79,27 +74,7 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(
int error = 0;
fds = memnew(DataAtSize);
- if (font_mem == nullptr && font_path != String()) {
- FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
- if (!f) {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
- }
-
- memset(&fds->stream, 0, sizeof(FT_StreamRec));
- fds->stream.base = nullptr;
- fds->stream.size = f->get_len();
- fds->stream.pos = 0;
- fds->stream.descriptor.pointer = f;
- fds->stream.read = _ft_stream_io;
- fds->stream.close = _ft_stream_close;
-
- FT_Open_Args fargs;
- memset(&fargs, 0, sizeof(FT_Open_Args));
- fargs.flags = FT_OPEN_STREAM;
- fargs.stream = &fds->stream;
- error = FT_Open_Face(library, &fargs, 0, &fds->face);
- } else if (font_mem) {
+ if (font_mem) {
memset(&fds->stream, 0, sizeof(FT_StreamRec));
fds->stream.base = (unsigned char *)font_mem;
fds->stream.size = font_mem_size;
@@ -161,30 +136,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(
return fds;
}
-unsigned long DynamicFontDataFallback::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) {
- FileAccess *f = (FileAccess *)stream->descriptor.pointer;
-
- if (f->get_position() != offset) {
- f->seek(offset);
- }
- if (count == 0) {
- return 0;
- }
-
- return f->get_buffer(buffer, count);
-}
-
-void DynamicFontDataFallback::_ft_stream_close(FT_Stream stream) {
- FileAccess *f = (FileAccess *)stream->descriptor.pointer;
- f->close();
- memdelete(f);
-}
-
DynamicFontDataFallback::TexturePosition DynamicFontDataFallback::find_texture_pos_for_glyph(DynamicFontDataFallback::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
TexturePosition ret;
ret.index = -1;
- ret.x = 0;
- ret.y = 0;
int mw = p_width;
int mh = p_height;
diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h
index 060b8cfbf9..6ac8cb52a8 100644
--- a/modules/text_server_fb/dynamic_font_fb.h
+++ b/modules/text_server_fb/dynamic_font_fb.h
@@ -107,7 +107,7 @@ private:
const uint8_t *font_mem = nullptr;
int font_mem_size = 0;
String font_path;
- static HashMap<String, Vector<uint8_t>> font_mem_cache;
+ Vector<uint8_t> font_mem_cache;
float rect_margin = 1.f;
int base_size = 16;
@@ -119,9 +119,6 @@ private:
Map<CacheID, DataAtSize *> size_cache;
Map<CacheID, DataAtSize *> size_cache_outline;
- static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count);
- static void _ft_stream_close(FT_Stream stream);
-
DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0);
TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index e74a1d9ef9..675d0e5d4d 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -45,6 +45,10 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
}
+_FORCE_INLINE_ bool is_punct(char32_t p_char) {
+ return (p_char >= 0x0020 && p_char <= 0x002F) || (p_char >= 0x003A && p_char <= 0x0040) || (p_char >= 0x005B && p_char <= 0x0060) || (p_char >= 0x007B && p_char <= 0x007E) || (p_char >= 0x2000 && p_char <= 0x206F) || (p_char >= 0x3000 && p_char <= 0x303F);
+}
+
/*************************************************************************/
String TextServerFallback::interface_name = "Fallback";
@@ -625,7 +629,11 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->width = 0;
sd->upos = 0;
sd->uthk = 0;
- for (int i = 0; i < sd->glyphs.size(); i++) {
+ int sd_size = sd->glyphs.size();
+ const FontDataFallback *fd = nullptr;
+ RID prev_rid = RID();
+
+ for (int i = 0; i < sd_size; i++) {
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
@@ -645,8 +653,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2);
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
@@ -661,8 +669,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2);
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
@@ -671,25 +679,28 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
- const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
+ if (prev_rid != gl.font_rid) {
+ fd = font_owner.getornull(gl.font_rid);
+ prev_rid = gl.font_rid;
+ }
if (fd != nullptr) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size));
sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size));
} else {
- sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
sd->width += gl.advance * gl.repeat;
@@ -760,21 +771,25 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (p_length > 0) {
new_sd->text = sd->text.substr(p_start, p_length);
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
- for (int i = 0; i < sd->glyphs.size(); i++) {
- if ((sd->glyphs[i].start >= new_sd->start) && (sd->glyphs[i].end <= new_sd->end)) {
- Glyph gl = sd->glyphs[i];
+ for (int i = 0; i < sd_size; i++) {
+ if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
+ Glyph gl = sd_glyphs[i];
Variant key;
+ bool find_embedded = false;
if (gl.count == 1) {
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (E->get().pos == gl.start) {
+ find_embedded = true;
key = E->key();
new_sd->objects[key] = E->get();
break;
}
}
}
- if (key != Variant()) {
+ if (find_embedded) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
@@ -783,8 +798,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2);
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
@@ -798,8 +813,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2);
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
@@ -813,17 +828,17 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, fd->get_ascent(gl.font_size));
new_sd->descent = MAX(new_sd->descent, fd->get_descent(gl.font_size));
} else {
- new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
new_sd->width += gl.advance * gl.repeat;
@@ -943,7 +958,7 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
float old_adv = gl.advance;
- gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size);
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
sd->width += (gl.advance - old_adv);
}
}
@@ -978,8 +993,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float
delta = -1;
}
+ Glyph *gl = sd->glyphs.ptrw();
+
for (int i = start; i != end; i += delta) {
- if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
float tab_off = 0.f;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
@@ -988,13 +1005,13 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float
tab_index = 0;
}
}
- float old_adv = sd->glyphs.write[i].advance;
- sd->glyphs.write[i].advance = (tab_off - off);
- sd->width += sd->glyphs.write[i].advance - old_adv;
+ float old_adv = gl[i].advance;
+ gl[i].advance = tab_off - off;
+ sd->width += gl[i].advance - old_adv;
off = 0;
continue;
}
- off += sd->glyphs[i].advance * sd->glyphs[i].repeat;
+ off += gl[i].advance * gl[i].repeat;
}
return 0.f;
@@ -1012,9 +1029,13 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
return true; // Noting to do.
}
- for (int i = 0; i < sd->glyphs.size(); i++) {
+ int sd_size = sd->glyphs.size();
+ for (int i = 0; i < sd_size; i++) {
if (sd->glyphs[i].count > 0) {
char32_t c = sd->text[sd->glyphs[i].start];
+ if (is_punct(c)) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ }
if (is_whitespace(c) && !is_linebreak(c)) {
sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE;
sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT;
@@ -1086,8 +1107,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2);
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
@@ -1101,8 +1122,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2);
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
@@ -1157,14 +1178,14 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size));
} else {
gl.advance = fd->get_advance(gl.index, gl.font_size).y;
- gl.x_off = -fd->get_advance(gl.index, gl.font_size).x * 0.5;
+ gl.x_off = -Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5);
gl.y_off = fd->get_ascent(gl.font_size);
- sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
}
- sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
- sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
+ sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size));
+ sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size));
// Add kerning to previous glyph.
if (sd->glyphs.size() > 0) {
@@ -1181,12 +1202,12 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
sd->width += gl.advance;
diff --git a/modules/theora/SCsub b/modules/theora/SCsub
index a01e65b4b0..6038ea086a 100644
--- a/modules/theora/SCsub
+++ b/modules/theora/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_theora = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libtheora"]:
thirdparty_dir = "#thirdparty/libtheora/"
thirdparty_sources = [
@@ -80,7 +83,16 @@ if env["builtin_libtheora"]:
env_thirdparty = env_theora.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_theora.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_theora.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/tinyexr/SCsub b/modules/tinyexr/SCsub
index 84b3b4015b..30bde96fb4 100644
--- a/modules/tinyexr/SCsub
+++ b/modules/tinyexr/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_tinyexr = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled for now as they are not commonly available as shared library
thirdparty_dir = "#thirdparty/tinyexr/"
thirdparty_sources = [
@@ -20,7 +23,15 @@ env_tinyexr.Append(CPPDEFINES=["TINYEXR_USE_THREAD"])
env_thirdparty = env_tinyexr.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_tinyexr.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_tinyexr.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 2e129e15ca..bc0b215be3 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -7,6 +7,8 @@ env_upnp = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_miniupnpc"]:
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
@@ -31,7 +33,16 @@ if env["builtin_miniupnpc"]:
env_thirdparty = env_upnp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_upnp.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_upnp.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/vhacd/SCsub b/modules/vhacd/SCsub
index ecd432b275..1ff4122114 100644
--- a/modules/vhacd/SCsub
+++ b/modules/vhacd/SCsub
@@ -7,6 +7,8 @@ env_vhacd = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/vhacd/"
thirdparty_sources = [
@@ -24,10 +26,19 @@ thirdparty_sources = [
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "/inc"])
+env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "inc"])
env_thirdparty = env_vhacd.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_vhacd.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_vhacd.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index b10d4523f2..f9ef184579 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2367,7 +2367,7 @@ void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p
binds.push_back(p_binds[i]);
}
binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing
- p_obj->connect_compat(p_signal, this, "_signal_callback", binds, CONNECT_ONESHOT);
+ p_obj->connect(p_signal, Callable(this, "_signal_callback"), binds, CONNECT_ONESHOT);
}
bool VisualScriptFunctionState::is_valid() const {
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 85dab4e6cf..59bdfb2fc3 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -33,6 +33,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/doc_data.h"
#include "core/object/script_language.h"
#include "core/os/thread.h"
@@ -342,6 +343,13 @@ public:
virtual void set_source_code(const String &p_code) override;
virtual Error reload(bool p_keep_state = false) override;
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ static Vector<DocData::ClassDoc> docs;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual bool is_tool() const override;
virtual bool is_valid() const override;
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 64abd3dd84..1bd88a2a19 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -2547,7 +2547,7 @@ void VisualScriptEditor::set_edited_resource(const RES &p_res) {
}
_update_graph();
- _update_members();
+ call_deferred("_update_members");
}
void VisualScriptEditor::enable_editor() {
@@ -4858,8 +4858,8 @@ VisualScriptEditor::VisualScriptEditor() {
function_create_dialog = memnew(ConfirmationDialog);
function_create_dialog->set_title(TTR("Create Function"));
function_create_dialog->add_child(function_vb);
- function_create_dialog->get_ok()->set_text(TTR("Create"));
- function_create_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
+ function_create_dialog->get_ok_button()->set_text(TTR("Create"));
+ function_create_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
add_child(function_create_dialog);
select_func_text = memnew(Label);
@@ -4902,7 +4902,7 @@ VisualScriptEditor::VisualScriptEditor() {
graph->connect("connection_to_empty", callable_mp(this, &VisualScriptEditor::_graph_connect_to_empty));
edit_signal_dialog = memnew(AcceptDialog);
- edit_signal_dialog->get_ok()->set_text(TTR("Close"));
+ edit_signal_dialog->get_ok_button()->set_text(TTR("Close"));
add_child(edit_signal_dialog);
signal_editor = memnew(VisualScriptEditorSignalEdit);
@@ -4912,7 +4912,7 @@ VisualScriptEditor::VisualScriptEditor() {
edit_signal_edit->edit(signal_editor);
edit_variable_dialog = memnew(AcceptDialog);
- edit_variable_dialog->get_ok()->set_text(TTR("Close"));
+ edit_variable_dialog->get_ok_button()->set_text(TTR("Close"));
add_child(edit_variable_dialog);
variable_editor = memnew(VisualScriptEditorVariableEdit);
@@ -4944,7 +4944,7 @@ VisualScriptEditor::VisualScriptEditor() {
new_connect_node_select = memnew(VisualScriptPropertySelector);
add_child(new_connect_node_select);
new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node));
- new_connect_node_select->get_cancel()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
+ new_connect_node_select->get_cancel_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
new_virtual_method_select = memnew(VisualScriptPropertySelector);
add_child(new_virtual_method_select);
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 875270e74f..dbb76e19ac 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -31,6 +31,7 @@
#include "visual_script_property_selector.h"
#include "core/os/keyboard.h"
+#include "editor/doc_tools.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "modules/visual_script/visual_script.h"
@@ -309,7 +310,7 @@ void VisualScriptPropertySelector::_update_search() {
found = true;
}
- get_ok()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_children() == nullptr);
}
void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
@@ -437,7 +438,7 @@ void VisualScriptPropertySelector::_item_selected() {
class_type = base_type;
}
- DocData *dd = EditorHelp::get_doc_data();
+ DocTools *dd = EditorHelp::get_doc_data();
String text;
String at_class = class_type;
@@ -704,8 +705,8 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() {
search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input));
search_options = memnew(Tree);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(true);
+ get_ok_button()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed));
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index 05d46757d3..bc31fff066 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -8,9 +8,10 @@ Import("env_modules")
env_vorbis = env_modules.Clone()
-stub = True
-
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libvorbis"]:
thirdparty_dir = "#thirdparty/libvorbis/"
thirdparty_sources = [
@@ -51,7 +52,16 @@ if env["builtin_libvorbis"]:
env_thirdparty = env_vorbis.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_vorbis.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Module files
-env_vorbis.add_source_files(env.modules_sources, "register_types.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webm/SCsub b/modules/webm/SCsub
index 247b4ead37..44e80e2870 100644
--- a/modules/webm/SCsub
+++ b/modules/webm/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_webm = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/libsimplewebm/"
thirdparty_sources = [
"libwebm/mkvparser/mkvparser.cc",
@@ -31,7 +34,15 @@ if env["builtin_libvpx"]:
env_thirdparty = env_webm.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_webm.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_webm.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index d0744fa313..67d3f1bebd 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -278,7 +278,7 @@ if webm_cpu_x86:
try:
yasm_found = True
subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate()
- except:
+ except Exception:
yasm_found = False
if yasm_found:
break
diff --git a/modules/webp/SCsub b/modules/webp/SCsub
index 58f2bb35e6..4c0c2f7893 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_webp = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libwebp"]:
thirdparty_dir = "#thirdparty/libwebp/"
thirdparty_sources = [
@@ -130,7 +133,16 @@ if env["builtin_libwebp"]:
env_thirdparty = env_webp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_webp.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_webp.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub
index 4f870ddb2f..31b8a73bf2 100644
--- a/modules/webrtc/SCsub
+++ b/modules/webrtc/SCsub
@@ -3,8 +3,6 @@
Import("env")
Import("env_modules")
-# Thirdparty source files
-
env_webrtc = env_modules.Clone()
use_gdnative = env_webrtc["module_gdnative_enabled"]
diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js
index f725a10a6f..9f029407d2 100644
--- a/modules/webrtc/library_godot_webrtc.js
+++ b/modules/webrtc/library_godot_webrtc.js
@@ -90,6 +90,7 @@ const GodotRTCDataChannel = {
},
},
+ godot_js_rtc_datachannel_ready_state_get__sig: 'ii',
godot_js_rtc_datachannel_ready_state_get: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -109,6 +110,7 @@ const GodotRTCDataChannel = {
}
},
+ godot_js_rtc_datachannel_send__sig: 'iiiii',
godot_js_rtc_datachannel_send: function (p_id, p_buffer, p_length, p_raw) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -129,14 +131,17 @@ const GodotRTCDataChannel = {
return 0;
},
+ godot_js_rtc_datachannel_is_ordered__sig: 'ii',
godot_js_rtc_datachannel_is_ordered: function (p_id) {
return IDHandler.get_prop(p_id, 'ordered', true);
},
+ godot_js_rtc_datachannel_id_get__sig: 'ii',
godot_js_rtc_datachannel_id_get: function (p_id) {
return IDHandler.get_prop(p_id, 'id', 65535);
},
+ godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii',
godot_js_rtc_datachannel_max_packet_lifetime_get: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -151,14 +156,17 @@ const GodotRTCDataChannel = {
return 65535;
},
+ godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii',
godot_js_rtc_datachannel_max_retransmits_get: function (p_id) {
return IDHandler.get_prop(p_id, 'maxRetransmits', 65535);
},
- godot_js_rtc_datachannel_is_negotiated: function (p_id, p_def) {
+ godot_js_rtc_datachannel_is_negotiated__sig: 'ii',
+ godot_js_rtc_datachannel_is_negotiated: function (p_id) {
return IDHandler.get_prop(p_id, 'negotiated', 65535);
},
+ godot_js_rtc_datachannel_label_get__sig: 'ii',
godot_js_rtc_datachannel_label_get: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref || !ref.label) {
@@ -167,6 +175,7 @@ const GodotRTCDataChannel = {
return GodotRuntime.allocString(ref.label);
},
+ godot_js_rtc_datachannel_protocol_get__sig: 'ii',
godot_js_rtc_datachannel_protocol_get: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref || !ref.protocol) {
@@ -175,11 +184,13 @@ const GodotRTCDataChannel = {
return GodotRuntime.allocString(ref.protocol);
},
+ godot_js_rtc_datachannel_destroy__sig: 'vi',
godot_js_rtc_datachannel_destroy: function (p_id) {
GodotRTCDataChannel.close(p_id);
IDHandler.remove(p_id);
},
+ godot_js_rtc_datachannel_connect__sig: 'viiiiii',
godot_js_rtc_datachannel_connect: function (p_id, p_ref, p_on_open, p_on_message, p_on_error, p_on_close) {
const onopen = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
const onmessage = GodotRuntime.get_func(p_on_message).bind(null, p_ref);
@@ -188,6 +199,7 @@ const GodotRTCDataChannel = {
GodotRTCDataChannel.connect(p_id, onopen, onmessage, onerror, onclose);
},
+ godot_js_rtc_datachannel_close__sig: 'vi',
godot_js_rtc_datachannel_close: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -280,6 +292,7 @@ const GodotRTCPeerConnection = {
},
},
+ godot_js_rtc_pc_create__sig: 'iiiiii',
godot_js_rtc_pc_create: function (p_config, p_ref, p_on_state_change, p_on_candidate, p_on_datachannel) {
const onstatechange = GodotRuntime.get_func(p_on_state_change).bind(null, p_ref);
const oncandidate = GodotRuntime.get_func(p_on_candidate).bind(null, p_ref);
@@ -302,6 +315,7 @@ const GodotRTCPeerConnection = {
return id;
},
+ godot_js_rtc_pc_close__sig: 'vi',
godot_js_rtc_pc_close: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -310,6 +324,7 @@ const GodotRTCPeerConnection = {
ref.close();
},
+ godot_js_rtc_pc_destroy__sig: 'vi',
godot_js_rtc_pc_destroy: function (p_id) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -321,6 +336,7 @@ const GodotRTCPeerConnection = {
IDHandler.remove(p_id);
},
+ godot_js_rtc_pc_offer_create__sig: 'viiii',
godot_js_rtc_pc_offer_create: function (p_id, p_obj, p_on_session, p_on_error) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -335,6 +351,7 @@ const GodotRTCPeerConnection = {
});
},
+ godot_js_rtc_pc_local_description_set__sig: 'viiiii',
godot_js_rtc_pc_local_description_set: function (p_id, p_type, p_sdp, p_obj, p_on_error) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -351,6 +368,7 @@ const GodotRTCPeerConnection = {
});
},
+ godot_js_rtc_pc_remote_description_set__sig: 'viiiiii',
godot_js_rtc_pc_remote_description_set: function (p_id, p_type, p_sdp, p_obj, p_session_created, p_on_error) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -375,6 +393,7 @@ const GodotRTCPeerConnection = {
});
},
+ godot_js_rtc_pc_ice_candidate_add__sig: 'viiii',
godot_js_rtc_pc_ice_candidate_add: function (p_id, p_mid_name, p_mline_idx, p_sdp) {
const ref = IDHandler.get(p_id);
if (!ref) {
@@ -390,6 +409,7 @@ const GodotRTCPeerConnection = {
},
godot_js_rtc_pc_datachannel_create__deps: ['$GodotRTCDataChannel'],
+ godot_js_rtc_pc_datachannel_create__sig: 'iiii',
godot_js_rtc_pc_datachannel_create: function (p_id, p_label, p_config) {
try {
const ref = IDHandler.get(p_id);
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index 13e51a39c0..4c022c43cf 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -5,28 +5,44 @@ Import("env_modules")
env_ws = env_modules.Clone()
+thirdparty_obj = []
+
if env["platform"] == "javascript":
# Our JavaScript/C++ interface.
env.AddJSLibraries(["library_godot_websocket.js"])
+
elif env["builtin_wslay"]:
# Thirdparty source files
- wslay_dir = "#thirdparty/wslay/"
- wslay_sources = [
+ thirdparty_dir = "#thirdparty/wslay/"
+ thirdparty_sources = [
"wslay_net.c",
"wslay_event.c",
"wslay_queue.c",
"wslay_stack.c",
"wslay_frame.c",
]
- wslay_sources = [wslay_dir + s for s in wslay_sources]
- env_ws.Prepend(CPPPATH=[wslay_dir + "includes/"])
+ thirdparty_sources = [thirdparty_dir + s for s in thirdparty_sources]
+
+ env_ws.Prepend(CPPPATH=[thirdparty_dir + "includes/"])
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
+
if env["platform"] == "windows" or env["platform"] == "uwp":
env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
else:
env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
- env_wslay = env_ws.Clone()
- env_wslay.disable_warnings()
- env_wslay.add_source_files(env.modules_sources, wslay_sources)
-env_ws.add_source_files(env.modules_sources, "*.cpp")
+ env_thirdparty = env_ws.Clone()
+ env_thirdparty.disable_warnings()
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_ws.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js
index 6ada4e7335..cf2c00a6a6 100644
--- a/modules/websocket/library_godot_websocket.js
+++ b/modules/websocket/library_godot_websocket.js
@@ -135,6 +135,7 @@ const GodotWebSocket = {
},
},
+ godot_js_websocket_create__sig: 'iiiiiiii',
godot_js_websocket_create: function (p_ref, p_url, p_proto, p_on_open, p_on_message, p_on_error, p_on_close) {
const on_open = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
const on_message = GodotRuntime.get_func(p_on_message).bind(null, p_ref);
@@ -156,6 +157,7 @@ const GodotWebSocket = {
return GodotWebSocket.create(socket, on_open, on_message, on_error, on_close);
},
+ godot_js_websocket_send__sig: 'iiiii',
godot_js_websocket_send: function (p_id, p_buf, p_buf_len, p_raw) {
const bytes_array = new Uint8Array(p_buf_len);
let i = 0;
@@ -169,12 +171,14 @@ const GodotWebSocket = {
return GodotWebSocket.send(p_id, out);
},
+ godot_js_websocket_close__sig: 'viii',
godot_js_websocket_close: function (p_id, p_code, p_reason) {
const code = p_code;
const reason = GodotRuntime.parseString(p_reason);
GodotWebSocket.close(p_id, code, reason);
},
+ godot_js_websocket_destroy__sig: 'vi',
godot_js_websocket_destroy: function (p_id) {
GodotWebSocket.destroy(p_id);
},
diff --git a/modules/xatlas_unwrap/SCsub b/modules/xatlas_unwrap/SCsub
index c659349d05..aa6bdaea33 100644
--- a/modules/xatlas_unwrap/SCsub
+++ b/modules/xatlas_unwrap/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_xatlas_unwrap = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_xatlas"]:
thirdparty_dir = "#thirdparty/xatlas/"
thirdparty_sources = [
@@ -17,7 +20,16 @@ if env["builtin_xatlas"]:
env_thirdparty = env_xatlas_unwrap.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_xatlas_unwrap.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_xatlas_unwrap.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 65350518c3..224038d604 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -141,11 +141,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
xatlas::Atlas *atlas = xatlas::Create();
printf("Adding mesh..\n");
- xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1);
- ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err));
+ xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
+ ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
printf("Generate..\n");
- xatlas::Generate(atlas, chart_options, xatlas::ParameterizeOptions(), pack_options);
+ xatlas::Generate(atlas, chart_options, pack_options);
*r_size_hint_x = atlas->width;
*r_size_hint_y = atlas->height;