diff options
Diffstat (limited to 'modules')
156 files changed, 2243 insertions, 701 deletions
diff --git a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml index a4dc61d0bc..1f91349f32 100644 --- a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml +++ b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.1"> +<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/bullet/doc_classes/BulletPhysicsServer.xml b/modules/bullet/doc_classes/BulletPhysicsServer.xml index 1486936cf4..8adc659b2c 100644 --- a/modules/bullet/doc_classes/BulletPhysicsServer.xml +++ b/modules/bullet/doc_classes/BulletPhysicsServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.1"> +<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 1aba31f03d..b590d63167 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -510,16 +510,17 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { // Compute min and max heights if not specified. if (!d.has("min_height") && !d.has("max_height")) { - PoolVector<real_t>::Read r = heights.read(); - int heights_size = heights.size(); + PoolVector<real_t>::Read r = l_heights.read(); + int heights_size = l_heights.size(); for (int i = 0; i < heights_size; ++i) { real_t h = r[i]; - if (h < l_min_height) + if (h < l_min_height) { l_min_height = h; - else if (h > l_max_height) + } else if (h > l_max_height) { l_max_height = h; + } } } diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index fb7f829cf0..0eb539b182 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -953,13 +953,15 @@ void CSGBrushOperation::_merge_poly(MeshMerge &mesh, int p_face_idx, const Build //duplicate point int insert_at = with_outline_vertex; - polys.write[i].points.insert(insert_at, polys[i].points[insert_at]); + int point = polys[i].points[insert_at]; + polys.write[i].points.insert(insert_at, point); insert_at++; //insert all others, outline should be backwards (must check) int holesize = polys[i].holes[j].size(); for (int k = 0; k <= holesize; k++) { int idx = (from_hole_vertex + k) % holesize; - polys.write[i].points.insert(insert_at, polys[i].holes[j][idx]); + int point2 = polys[i].holes[j][idx]; + polys.write[i].points.insert(insert_at, point2); insert_at++; } diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 3044887ef5..d4069b901f 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -283,6 +283,10 @@ String CSGShapeSpatialGizmoPlugin::get_name() const { return "CSGShapes"; } +int CSGShapeSpatialGizmoPlugin::get_priority() const { + return -1; +} + bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const { return true; } diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index b208c39938..0915d05111 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -42,6 +42,7 @@ class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { public: bool has_gizmo(Spatial *p_spatial); String get_name() const; + int get_priority() const; bool is_selectable_when_hidden() const; void redraw(EditorSpatialGizmo *p_gizmo); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index f274fff3f3..775ec67ba6 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -806,8 +806,8 @@ CSGBrush *CSGMesh::_build_brush() { uvw[as + j + 1] = uv[1]; uvw[as + j + 2] = uv[2]; - sw[j / 3] = !flat; - mw[j / 3] = mat; + sw[(as + j) / 3] = !flat; + mw[(as + j) / 3] = mat; } } else { int as = vertices.size(); @@ -849,8 +849,8 @@ CSGBrush *CSGMesh::_build_brush() { uvw[as + j + 1] = uv[1]; uvw[as + j + 2] = uv[2]; - sw[j / 3] = !flat; - mw[j / 3] = mat; + sw[(as + j) / 3] = !flat; + mw[(as + j) / 3] = mat; } } } diff --git a/modules/csg/doc_classes/CSGBox.xml b/modules/csg/doc_classes/CSGBox.xml index 5ec7b5089d..1684850f0a 100644 --- a/modules/csg/doc_classes/CSGBox.xml +++ b/modules/csg/doc_classes/CSGBox.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGBox" inherits="CSGPrimitive" category="Core" version="3.1"> +<class name="CSGBox" inherits="CSGPrimitive" category="Core" version="3.2"> <brief_description> A CSG Box shape. </brief_description> diff --git a/modules/csg/doc_classes/CSGCombiner.xml b/modules/csg/doc_classes/CSGCombiner.xml index 69c5df5840..819a4a3a22 100644 --- a/modules/csg/doc_classes/CSGCombiner.xml +++ b/modules/csg/doc_classes/CSGCombiner.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGCombiner" inherits="CSGShape" category="Core" version="3.1"> +<class name="CSGCombiner" inherits="CSGShape" category="Core" version="3.2"> <brief_description> A CSG node that allows you to combine other CSG modifiers. </brief_description> diff --git a/modules/csg/doc_classes/CSGCylinder.xml b/modules/csg/doc_classes/CSGCylinder.xml index 92b170ed1f..50a88d6773 100644 --- a/modules/csg/doc_classes/CSGCylinder.xml +++ b/modules/csg/doc_classes/CSGCylinder.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGCylinder" inherits="CSGPrimitive" category="Core" version="3.1"> +<class name="CSGCylinder" inherits="CSGPrimitive" category="Core" version="3.2"> <brief_description> A CSG Cylinder shape. </brief_description> diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh.xml index 58e2bc1c4b..fc9815d7c0 100644 --- a/modules/csg/doc_classes/CSGMesh.xml +++ b/modules/csg/doc_classes/CSGMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGMesh" inherits="CSGPrimitive" category="Core" version="3.1"> +<class name="CSGMesh" inherits="CSGPrimitive" category="Core" version="3.2"> <brief_description> A CSG Mesh shape that uses a mesh resource. </brief_description> diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon.xml index a33e5557cb..ae75f7e01b 100644 --- a/modules/csg/doc_classes/CSGPolygon.xml +++ b/modules/csg/doc_classes/CSGPolygon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGPolygon" inherits="CSGPrimitive" category="Core" version="3.1"> +<class name="CSGPolygon" inherits="CSGPrimitive" category="Core" version="3.2"> <brief_description> Extrudes a 2D polygon shape to create a 3D mesh. </brief_description> diff --git a/modules/csg/doc_classes/CSGPrimitive.xml b/modules/csg/doc_classes/CSGPrimitive.xml index 2591bab7e3..502a8230e4 100644 --- a/modules/csg/doc_classes/CSGPrimitive.xml +++ b/modules/csg/doc_classes/CSGPrimitive.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGPrimitive" inherits="CSGShape" category="Core" version="3.1"> +<class name="CSGPrimitive" inherits="CSGShape" category="Core" version="3.2"> <brief_description> Base class for CSG primitives. </brief_description> diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml index d304d0179f..ccfc5a04c0 100644 --- a/modules/csg/doc_classes/CSGShape.xml +++ b/modules/csg/doc_classes/CSGShape.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGShape" inherits="VisualInstance" category="Core" version="3.1"> +<class name="CSGShape" inherits="VisualInstance" category="Core" version="3.2"> <brief_description> The CSG base class. </brief_description> diff --git a/modules/csg/doc_classes/CSGSphere.xml b/modules/csg/doc_classes/CSGSphere.xml index a0069879cb..088c9f14eb 100644 --- a/modules/csg/doc_classes/CSGSphere.xml +++ b/modules/csg/doc_classes/CSGSphere.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGSphere" inherits="CSGPrimitive" category="Core" version="3.1"> +<class name="CSGSphere" inherits="CSGPrimitive" category="Core" version="3.2"> <brief_description> A CSG Sphere shape. </brief_description> diff --git a/modules/csg/doc_classes/CSGTorus.xml b/modules/csg/doc_classes/CSGTorus.xml index 187d71a2fa..946637bd2c 100644 --- a/modules/csg/doc_classes/CSGTorus.xml +++ b/modules/csg/doc_classes/CSGTorus.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGTorus" inherits="CSGPrimitive" category="Core" version="3.1"> +<class name="CSGTorus" inherits="CSGPrimitive" category="Core" version="3.2"> <brief_description> A CSG Torus shape. </brief_description> diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml index c9a7d96ae7..c1bec533dd 100644 --- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml +++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1"> +<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" category="Core" version="3.2"> <brief_description> PacketPeer implementation using the ENet library. </brief_description> diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml index be86ff0541..afb014d608 100644 --- a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml +++ b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.1"> +<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.2"> <brief_description> GDNative wrapper for an ARVR interface </brief_description> diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml index ca0457623f..e5a59aad07 100644 --- a/modules/gdnative/doc_classes/GDNative.xml +++ b/modules/gdnative/doc_classes/GDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDNative" inherits="Reference" category="Core" version="3.1"> +<class name="GDNative" inherits="Reference" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml index 754a6d2514..ba5278d440 100644 --- a/modules/gdnative/doc_classes/GDNativeLibrary.xml +++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.1"> +<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml index 4433179726..ba481a6d6e 100644 --- a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml +++ b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1"> +<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml index 37d5b79e7a..c50f9eee22 100644 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NativeScript" inherits="Script" category="Core" version="3.1"> +<class name="NativeScript" inherits="Script" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/PacketPeerGDNative.xml b/modules/gdnative/doc_classes/PacketPeerGDNative.xml index 0ae54bc9c7..f4d7d22f5b 100644 --- a/modules/gdnative/doc_classes/PacketPeerGDNative.xml +++ b/modules/gdnative/doc_classes/PacketPeerGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PacketPeerGDNative" inherits="PacketPeer" category="Core" version="3.1"> +<class name="PacketPeerGDNative" inherits="PacketPeer" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/PluginScript.xml b/modules/gdnative/doc_classes/PluginScript.xml index 1876d06c20..8510708124 100644 --- a/modules/gdnative/doc_classes/PluginScript.xml +++ b/modules/gdnative/doc_classes/PluginScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PluginScript" inherits="Script" category="Core" version="3.1"> +<class name="PluginScript" inherits="Script" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml b/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml index 61a7f60499..8e7f4698ff 100644 --- a/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml +++ b/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ResourceFormatLoaderVideoStreamGDNative" inherits="ResourceFormatLoader" category="Core" version="3.1"> +<class name="ResourceFormatLoaderVideoStreamGDNative" inherits="ResourceFormatLoader" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/StreamPeerGDNative.xml b/modules/gdnative/doc_classes/StreamPeerGDNative.xml index d86cd2c25a..eddebf4889 100644 --- a/modules/gdnative/doc_classes/StreamPeerGDNative.xml +++ b/modules/gdnative/doc_classes/StreamPeerGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="StreamPeerGDNative" inherits="StreamPeer" category="Core" version="3.1"> +<class name="StreamPeerGDNative" inherits="StreamPeer" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/VideoStreamGDNative.xml b/modules/gdnative/doc_classes/VideoStreamGDNative.xml index 20575c768b..d5c5ed7ccf 100644 --- a/modules/gdnative/doc_classes/VideoStreamGDNative.xml +++ b/modules/gdnative/doc_classes/VideoStreamGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VideoStreamGDNative" inherits="VideoStream" category="Core" version="3.1"> +<class name="VideoStreamGDNative" inherits="VideoStream" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 34325db9fd..e8278825bc 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -414,6 +414,7 @@ bool GDNative::terminate() { if (error || !library_terminate) { OS::get_singleton()->close_dynamic_library(native_handle); native_handle = NULL; + initialized = false; return true; } diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index b99c5d31ab..7eb4294732 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -279,7 +279,7 @@ List<ClassAPI> generate_c_api_classes() { MethodInfo &method_info = m->get(); //method name - method_api.method_name = m->get().name; + method_api.method_name = method_info.name; //method return type if (method_api.method_name.find(":") != -1) { method_api.return_type = method_api.method_name.get_slice(":", 1); @@ -321,6 +321,8 @@ List<ClassAPI> generate_c_api_classes() { arg_type = arg_info.hint_string; } else if (arg_info.type == Variant::NIL) { arg_type = "Variant"; + } else if (arg_info.type == Variant::OBJECT) { + arg_type = arg_info.class_name; } else { arg_type = Variant::get_type_name(arg_info.type); } diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index c2b772df85..5cf144d4fe 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -160,8 +160,10 @@ bool NativeScript::can_instance() const { NativeScriptDesc *script_data = get_script_desc(); #ifdef TOOLS_ENABLED - - return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled()); + // Only valid if this is either a tool script or a "regular" script. + // (so an environment whre scripting is disabled (and not the editor) would not + // create objects). + return script_data && (is_tool() || ScriptServer::is_scripting_enabled()); #else return script_data; #endif @@ -199,25 +201,6 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) { return NULL; } -#ifdef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled() && !is_tool()) { - // placeholder for nodes. For tools we want the rool thing. - - PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); - placeholders.insert(sins); - - if (script_data->create_func.create_func) { - script_data->create_func.create_func( - (godot_object *)p_this, - script_data->create_func.method_data); - } - - _update_placeholder(sins); - - return sins; - } -#endif - NativeScriptInstance *nsi = memnew(NativeScriptInstance); nsi->owner = p_this; @@ -246,6 +229,19 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) { return nsi; } +PlaceHolderScriptInstance *NativeScript::placeholder_instance_create(Object *p_this) { +#ifdef TOOLS_ENABLED + PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); + placeholders.insert(sins); + + _update_placeholder(sins); + + return sins; +#else + return NULL; +#endif +} + bool NativeScript::instance_has(const Object *p_this) const { return instance_owners.has((Object *)p_this); } @@ -1036,8 +1032,16 @@ NativeScriptLanguage::~NativeScriptLanguage() { for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { - if (L->get().is_valid()) - L->get()->terminate(); + Ref<GDNative> lib = L->get(); + // only shut down valid libs, duh! + if (lib.is_valid()) { + + // If it's a singleton-library then the gdnative module + // manages the destruction at engine shutdown, not NativeScript. + if (!lib->get_library()->is_singleton()) { + lib->terminate(); + } + } } NSL->library_classes.clear(); @@ -1641,10 +1645,19 @@ void NativeReloadNode::_notification(int p_what) { continue; } + // Don't unload what should not be reloaded! if (!gdn->get_library()->is_reloadable()) { continue; } + // singleton libraries might have alive pointers living inside the + // editor. Also reloading a singleton library would mean that + // the singleton entry will not be called again, as this only + // happens at engine startup. + if (gdn->get_library()->is_singleton()) { + continue; + } + gdn->terminate(); } @@ -1672,6 +1685,12 @@ void NativeReloadNode::_notification(int p_what) { continue; } + // since singleton libraries are not unloaded there is no point + // in loading them again. + if (gdn->get_library()->is_singleton()) { + continue; + } + if (!gdn->initialize()) { libs_to_remove.insert(L->key()); continue; diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index 8dd5ba3b9c..a6865c6243 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -149,6 +149,7 @@ public: virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this); + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; virtual bool has_source_code() const; diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp index d1794b6c36..8fcebe7855 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp @@ -117,18 +117,20 @@ bool VideoStreamPlaybackGDNative::open_file(const String &p_file) { file = FileAccess::open(p_file, FileAccess::READ); bool file_opened = interface->open_file(data_struct, file); - num_channels = interface->get_channels(data_struct); - mix_rate = interface->get_mix_rate(data_struct); + if (file_opened) { + num_channels = interface->get_channels(data_struct); + mix_rate = interface->get_mix_rate(data_struct); - godot_vector2 vec = interface->get_texture_size(data_struct); - texture_size = *(Vector2 *)&vec; + godot_vector2 vec = interface->get_texture_size(data_struct); + texture_size = *(Vector2 *)&vec; - pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float)); - memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float)); - pcm_write_idx = -1; - samples_decoded = 0; + pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float)); + memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float)); + pcm_write_idx = -1; + samples_decoded = 0; - texture->create((int)texture_size.width, (int)texture_size.height, Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); + texture->create((int)texture_size.width, (int)texture_size.height, Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); + } return file_opened; } @@ -355,9 +357,9 @@ RES ResourceFormatLoaderVideoStreamGDNative::load(const String &p_path, const St if (r_error) { *r_error = ERR_CANT_OPEN; } - memdelete(f); return RES(); } + memdelete(f); VideoStreamGDNative *stream = memnew(VideoStreamGDNative); stream->set_file(p_path); Ref<VideoStreamGDNative> ogv_stream = Ref<VideoStreamGDNative>(stream); diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 4cefdbd7cb..46796c68eb 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDScript" inherits="Script" category="Core" version="3.1"> +<class name="GDScript" inherits="Script" category="Core" version="3.2"> <brief_description> A script implemented in the GDScript programming language. </brief_description> diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml index c205cedef5..f38f39b612 100644 --- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml +++ b/modules/gdscript/doc_classes/GDScriptFunctionState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDScriptFunctionState" inherits="Reference" category="Core" version="3.1"> +<class name="GDScriptFunctionState" inherits="Reference" category="Core" version="3.2"> <brief_description> State of a function call after yielding. </brief_description> diff --git a/modules/gdscript/doc_classes/GDScriptNativeClass.xml b/modules/gdscript/doc_classes/GDScriptNativeClass.xml index 90935b5c22..e86b69c31c 100644 --- a/modules/gdscript/doc_classes/GDScriptNativeClass.xml +++ b/modules/gdscript/doc_classes/GDScriptNativeClass.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDScriptNativeClass" inherits="Reference" category="Core" version="3.1"> +<class name="GDScriptNativeClass" inherits="Reference" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index e07911fa44..4385cf12ad 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1835,73 +1835,92 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b PoolVector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { return String(); } - int len = f->get_len(); - sourcef.resize(len + 1); - PoolVector<uint8_t>::Write w = sourcef.write(); - int r = f->get_buffer(w.ptr(), len); - f->close(); - memdelete(f); - ERR_FAIL_COND_V(r != len, String()); - w[len] = 0; - - String s; - if (s.parse_utf8((const char *)w.ptr())) { - return String(); - } + String source = f->get_as_utf8_string(); GDScriptParser parser; - - parser.parse(s, p_path.get_base_dir(), true, p_path); + parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true); if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) { const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree()); + if (r_icon_path) { + if (c->icon_path.empty() || c->icon_path.is_abs_path()) + *r_icon_path = c->icon_path; + else if (c->icon_path.is_rel_path()) + *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path(); + } if (r_base_type) { - GDScriptParser::DataType base_type; - if (c->base_type.has_type) { - base_type = c->base_type; - while (base_type.has_type && base_type.kind != GDScriptParser::DataType::NATIVE) { - switch (base_type.kind) { - case GDScriptParser::DataType::CLASS: { - base_type = base_type.class_type->base_type; - } break; - case GDScriptParser::DataType::GDSCRIPT: { - Ref<GDScript> gds = base_type.script_type; - if (gds.is_valid()) { - base_type.kind = GDScriptParser::DataType::NATIVE; - base_type.native_type = gds->get_instance_base_type(); - } else { - base_type = GDScriptParser::DataType(); + + const GDScriptParser::ClassNode *subclass = c; + String path = p_path; + GDScriptParser subparser; + while (subclass) { + if (subclass->extends_used) { + if (subclass->extends_file) { + if (subclass->extends_class.size() == 0) { + get_global_class_name(subclass->extends_file, r_base_type); + subclass = NULL; + break; + } else { + Vector<StringName> extend_classes = subclass->extends_class; + + FileAccessRef subfile = FileAccess::open(subclass->extends_file, FileAccess::READ); + if (!subfile) { + break; + } + String subsource = subfile->get_as_utf8_string(); + + if (subsource.empty()) { + break; + } + String subpath = subclass->extends_file; + if (subpath.is_rel_path()) { + subpath = path.get_base_dir().plus_file(subpath).simplify_path(); + } + + if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, NULL, true)) { + break; + } + path = subpath; + if (!subparser.get_parse_tree() || subparser.get_parse_tree()->type != GDScriptParser::Node::TYPE_CLASS) { + break; } - } break; - default: { - base_type = GDScriptParser::DataType(); - } break; + subclass = static_cast<const GDScriptParser::ClassNode *>(subparser.get_parse_tree()); + + while (extend_classes.size() > 0) { + bool found = false; + for (int i = 0; i < subclass->subclasses.size(); i++) { + const GDScriptParser::ClassNode *inner_class = subclass->subclasses[i]; + if (inner_class->name == extend_classes[0]) { + extend_classes.remove(0); + found = true; + subclass = inner_class; + break; + } + } + if (!found) { + subclass = NULL; + break; + } + } + } + } else if (subclass->extends_class.size() == 1) { + *r_base_type = subclass->extends_class[0]; + subclass = NULL; + } else { + break; } - } - } - if (base_type.has_type) { - *r_base_type = base_type.native_type; - } else { - // Fallback - if (c->extends_used && c->extends_class.size() == 1) { - *r_base_type = c->extends_class[0]; - } else if (!c->extends_used) { + } else { *r_base_type = "Reference"; + subclass = NULL; } } } - if (r_icon_path) { - if (c->icon_path.empty() || c->icon_path.is_abs_path()) - *r_icon_path = c->icon_path; - else if (c->icon_path.is_rel_path()) - *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path(); - } return c->name; } @@ -1946,7 +1965,7 @@ String GDScriptWarning::get_message() const { return "Assignment operation, but the function '" + symbols[0] + "()' returns void."; } break; case NARROWING_CONVERSION: { - return "Narrowing coversion (float is converted to int and lose precision)."; + return "Narrowing conversion (float is converted to int and loses precision)."; } break; case FUNCTION_MAY_YIELD: { CHECK_SYMBOLS(1); @@ -2183,6 +2202,26 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con return ""; } +void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { + + FileAccessRef file = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND(!file); + + String source = file->get_as_utf8_string(); + if (source.empty()) { + return; + } + + GDScriptParser parser; + if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true)) { + return; + } + + for (const List<String>::Element *E = parser.get_dependencies().front(); E; E = E->next()) { + p_dependencies->push_back(E->get()); + } +} + Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { Ref<GDScript> sqscr = p_resource; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 86c00c0b59..ded873c7d3 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -511,6 +511,7 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; + virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); }; class ResourceFormatSaverGDScript : public ResourceFormatSaver { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index b2b7b1c260..ae67521749 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -139,17 +139,32 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D result.native_type = result.script_type->get_instance_base_type(); } break; case GDScriptParser::DataType::CLASS: { - result.kind = GDScriptDataType::GDSCRIPT; - if (!p_datatype.class_type->owner) { - result.script_type = Ref<GDScript>(main_script); - } else { - result.script_type = class_map[p_datatype.class_type->name]; + // Locate class by constructing the path to it and following that path + GDScriptParser::ClassNode *class_type = p_datatype.class_type; + List<StringName> names; + while (class_type->owner) { + names.push_back(class_type->name); + class_type = class_type->owner; } - result.native_type = result.script_type->get_instance_base_type(); + + Ref<GDScript> script = Ref<GDScript>(main_script); + while (names.back()) { + if (!script->subclasses.has(names.back()->get())) { + ERR_PRINT("Parser bug: Cannot locate datatype class."); + result.has_type = false; + return GDScriptDataType(); + } + script = script->subclasses[names.back()->get()]; + names.pop_back(); + } + + result.kind = GDScriptDataType::GDSCRIPT; + result.script_type = script; + result.native_type = script->get_instance_base_type(); } break; default: { ERR_PRINT("Parser bug: converting unresolved type."); - result.has_type = false; + return GDScriptDataType(); } } @@ -460,12 +475,14 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.alloc_stack(slevel); } - switch (cn->cast_type.kind) { - case GDScriptParser::DataType::BUILTIN: { + GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type); + + switch (cast_type.kind) { + case GDScriptDataType::BUILTIN: { codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN); codegen.opcodes.push_back(cn->cast_type.builtin_type); } break; - case GDScriptParser::DataType::NATIVE: { + case GDScriptDataType::NATIVE: { int class_idx; if (GDScriptLanguage::get_singleton()->get_global_map().has(cn->cast_type.native_type)) { @@ -478,32 +495,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator codegen.opcodes.push_back(class_idx); // variable type } break; - case GDScriptParser::DataType::CLASS: { - - Variant script; - int idx = -1; - if (!cn->cast_type.class_type->owner) { - script = codegen.script; - } else { - StringName name = cn->cast_type.class_type->name; - if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) { - idx = codegen.get_name_map_pos(name); - idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS; - } else { - script = class_map[name]; - } - } - - if (idx < 0) { - idx = codegen.get_constant_pos(script); - idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) - } - - codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator - codegen.opcodes.push_back(idx); // variable type - } break; - case GDScriptParser::DataType::SCRIPT: - case GDScriptParser::DataType::GDSCRIPT: { + case GDScriptDataType::SCRIPT: + case GDScriptDataType::GDSCRIPT: { Variant script = cn->cast_type.script_type; int idx = codegen.get_constant_pos(script); @@ -1149,18 +1142,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: if (src_address_b < 0) return -1; - GDScriptParser::DataType assign_type = on->arguments[0]->get_datatype(); + GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype()); if (assign_type.has_type && !on->arguments[1]->get_datatype().has_type) { // Typed assignment switch (assign_type.kind) { - case GDScriptParser::DataType::BUILTIN: { + case GDScriptDataType::BUILTIN: { codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator codegen.opcodes.push_back(assign_type.builtin_type); // variable type codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 } break; - case GDScriptParser::DataType::NATIVE: { + case GDScriptDataType::NATIVE: { int class_idx; if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) { @@ -1175,34 +1168,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 } break; - case GDScriptParser::DataType::CLASS: { - - Variant script; - int idx = -1; - if (!assign_type.class_type->owner) { - script = codegen.script; - } else { - StringName name = assign_type.class_type->name; - if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) { - idx = codegen.get_name_map_pos(name); - idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS; - } else { - script = class_map[name]; - } - } - - if (idx < 0) { - idx = codegen.get_constant_pos(script); - idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) - } - - codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator - codegen.opcodes.push_back(idx); // variable type - codegen.opcodes.push_back(dst_address_a); // argument 1 - codegen.opcodes.push_back(src_address_b); // argument 2 - } break; - case GDScriptParser::DataType::SCRIPT: - case GDScriptParser::DataType::GDSCRIPT: { + case GDScriptDataType::SCRIPT: + case GDScriptDataType::GDSCRIPT: { Variant script = assign_type.script_type; int idx = codegen.get_constant_pos(script); @@ -1396,11 +1363,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo case GDScriptParser::ControlFlowNode::CF_IF: { -#ifdef DEBUG_ENABLED - codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE); - codegen.opcodes.push_back(cf->line); - codegen.current_line = cf->line; -#endif int ret2 = _parse_expression(codegen, cf->arguments[0], p_stack_level, false); if (ret2 < 0) return ERR_PARSE_ERROR; @@ -1850,22 +1812,21 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser return OK; } -Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { +Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { + + parsing_classes.insert(p_script); if (p_class->owner && p_class->owner->owner) { // Owner is not root - StringName owner_name = p_class->owner->name; - if (!parsed_classes.has(owner_name)) { - if (parsing_classes.has(owner_name)) { - _set_error("Cyclic class reference for '" + String(owner_name) + "'.", p_class); + if (!parsed_classes.has(p_script->_owner)) { + if (parsing_classes.has(p_script->_owner)) { + _set_error("Cyclic class reference for '" + String(p_class->name) + "'.", p_class); return ERR_PARSE_ERROR; } - parsing_classes.insert(owner_name); - Error err = _parse_class_level(class_map[owner_name].ptr(), class_map[owner_name]->_owner, p_class->owner, p_keep_state); + Error err = _parse_class_level(p_script->_owner, p_class->owner, p_keep_state); if (err) { return err; } - parsing_classes.erase(owner_name); } } @@ -1883,47 +1844,26 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner p_script->_signals.clear(); p_script->initializer = NULL; - p_script->subclasses.clear(); - p_script->_owner = p_owner; p_script->tool = p_class->tool; p_script->name = p_class->name; Ref<GDScriptNativeClass> native; + GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type); // Inheritance - switch (p_class->base_type.kind) { - case GDScriptParser::DataType::CLASS: { - StringName base_name = p_class->base_type.class_type->name; - // Make sure dependency is parsed first - if (!parsed_classes.has(base_name)) { - if (parsing_classes.has(base_name)) { - _set_error("Cyclic class reference for '" + String(base_name) + "'.", p_class); - return ERR_PARSE_ERROR; - } - parsing_classes.insert(base_name); - Error err = _parse_class_level(class_map[base_name].ptr(), class_map[base_name]->_owner, p_class->base_type.class_type, p_keep_state); - if (err) { - return err; - } - parsing_classes.erase(base_name); - } - Ref<GDScript> base = class_map[base_name]; - p_script->base = base; - p_script->_base = p_script->base.ptr(); - p_script->member_indices = base->member_indices; - } break; - case GDScriptParser::DataType::GDSCRIPT: { - Ref<GDScript> base = p_class->base_type.script_type; - p_script->base = base; - p_script->_base = p_script->base.ptr(); - p_script->member_indices = base->member_indices; - } break; - case GDScriptParser::DataType::NATIVE: { - int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_class->base_type.native_type]; + switch (base_type.kind) { + case GDScriptDataType::NATIVE: { + int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type]; native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; ERR_FAIL_COND_V(native.is_null(), ERR_BUG); p_script->native = native; } break; + case GDScriptDataType::GDSCRIPT: { + Ref<GDScript> base = base_type.script_type; + p_script->base = base; + p_script->_base = base.ptr(); + p_script->member_indices = base->member_indices; + } break; default: { _set_error("Parser bug: invalid inheritance.", p_class); return ERR_BUG; @@ -2017,24 +1957,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner p_script->_signals[name] = p_class->_signals[i].arguments; } - if (p_class->owner) { - parsed_classes.insert(p_class->name); - if (parsing_classes.has(p_class->name)) { - parsing_classes.erase(p_class->name); - } - } + parsed_classes.insert(p_script); + parsing_classes.erase(p_script); //parse sub-classes for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; - Ref<GDScript> subclass = class_map[name]; + GDScript *subclass = p_script->subclasses[name].ptr(); // Subclass might still be parsing, just skip it - if (!parsed_classes.has(name) && !parsing_classes.has(name)) { - parsing_classes.insert(name); - Error err = _parse_class_level(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state); + if (!parsed_classes.has(subclass) && !parsing_classes.has(subclass)) { + Error err = _parse_class_level(subclass, p_class->subclasses[i], p_keep_state); if (err) return err; } @@ -2045,7 +1980,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner #endif p_script->constants.insert(name, subclass); //once parsed, goes to the list of constants - p_script->subclasses.insert(name, subclass); } return OK; @@ -2144,9 +2078,9 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; - Ref<GDScript> subclass = class_map[name]; + GDScript *subclass = p_script->subclasses[name].ptr(); - Error err = _parse_class_blocks(subclass.ptr(), p_class->subclasses[i], p_keep_state); + Error err = _parse_class_blocks(subclass, p_class->subclasses[i], p_keep_state); if (err) { return err; } @@ -2156,7 +2090,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa return OK; } -void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { +void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { Map<StringName, Ref<GDScript> > old_subclasses; @@ -2164,6 +2098,8 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar old_subclasses = p_script->subclasses; } + p_script->subclasses.clear(); + for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; @@ -2175,10 +2111,10 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar subclass.instance(); } - subclass->_owner = const_cast<GDScript *>(p_script); - class_map.insert(name, subclass); + subclass->_owner = p_script; + p_script->subclasses.insert(name, subclass); - _make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state); + _make_scripts(subclass.ptr(), p_class->subclasses[i], false); } } @@ -2197,7 +2133,8 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri // Create scripts for subclasses beforehand so they can be referenced _make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); - Error err = _parse_class_level(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); + p_script->_owner = NULL; + Error err = _parse_class_level(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); if (err) return err; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 8440807a56..2cf630ba72 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -38,9 +38,8 @@ class GDScriptCompiler { const GDScriptParser *parser; - Map<StringName, Ref<GDScript> > class_map; - Set<StringName> parsed_classes; - Set<StringName> parsing_classes; + Set<GDScript *> parsed_classes; + Set<GDScript *> parsing_classes; GDScript *main_script; struct CodeGen { @@ -149,9 +148,9 @@ class GDScriptCompiler { int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false); Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1); Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false); - Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); - void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + void _make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); int err_line; int err_column; StringName source; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 98871ddec3..cff9ba55b8 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -329,10 +329,15 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (!argument_types[i].is_type(*p_args[i], true)) { - r_err.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_err.argument = i; - r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; - return Variant(); + if (argument_types[i].is_type(Variant(), true)) { + memnew_placement(&stack[i], Variant); + continue; + } else { + r_err.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_err.argument = i; + r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; + return Variant(); + } } if (argument_types[i].kind == GDScriptDataType::BUILTIN) { Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err); diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 44d44462ca..46c9efd54f 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -768,11 +768,30 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ (void)VariantParser::parse(&ss, r_ret, errs, line); } break; case VAR_TO_BYTES: { - VALIDATE_ARG_COUNT(1); + bool full_objects = false; + if (p_arg_count < 1) { + r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 1; + r_ret = Variant(); + return; + } else if (p_arg_count > 2) { + r_error.error = Variant::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 = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::BOOL; + r_ret = Variant(); + return; + } + full_objects = *p_args[1]; + } PoolByteArray barr; int len; - Error err = encode_variant(*p_args[0], NULL, len); + Error err = encode_variant(*p_args[0], NULL, len, full_objects); if (err) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -784,15 +803,35 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ barr.resize(len); { PoolByteArray::Write w = barr.write(); - encode_variant(*p_args[0], w.ptr(), len); + encode_variant(*p_args[0], w.ptr(), len, full_objects); } r_ret = barr; } break; case BYTES_TO_VAR: { - VALIDATE_ARG_COUNT(1); + bool allow_objects = false; + if (p_arg_count < 1) { + r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 1; + r_ret = Variant(); + return; + } else if (p_arg_count > 2) { + r_error.error = Variant::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 = Variant::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::POOL_BYTE_ARRAY) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; + r_error.argument = 1; r_error.expected = Variant::POOL_BYTE_ARRAY; r_ret = Variant(); return; @@ -802,7 +841,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ Variant ret; { PoolByteArray::Read r = varr.read(); - Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects); if (err != OK) { r_ret = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -1805,13 +1844,15 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case VAR_TO_BYTES: { - MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); + 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::POOL_BYTE_ARRAY; return mi; } break; case BYTES_TO_VAR: { - MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes")); + MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::POOL_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; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 5ebf68177d..e75b8a14a3 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -473,29 +473,31 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } Ref<Resource> res; - if (!validating) { + dependencies.push_back(path); + if (!dependencies_only) { + if (!validating) { - //this can be too slow for just validating code - if (for_completion && ScriptCodeCompletionCache::get_singleton() && FileAccess::exists(path)) { - res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); - } else if (!for_completion || FileAccess::exists(path)) { - res = ResourceLoader::load(path); - } - } else { + //this can be too slow for just validating code + if (for_completion && ScriptCodeCompletionCache::get_singleton() && FileAccess::exists(path)) { + res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); + } else if (!for_completion || FileAccess::exists(path)) { + res = ResourceLoader::load(path); + } + } else { - if (!FileAccess::exists(path)) { + if (!FileAccess::exists(path)) { + _set_error("Can't preload resource at path: " + path); + return NULL; + } else if (ScriptCodeCompletionCache::get_singleton()) { + res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); + } + } + if (!res.is_valid()) { _set_error("Can't preload resource at path: " + path); return NULL; - } else if (ScriptCodeCompletionCache::get_singleton()) { - res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); } } - if (!res.is_valid()) { - _set_error("Can't preload resource at path: " + path); - return NULL; - } - if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ')' after 'preload' path"); return NULL; @@ -775,7 +777,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String()); } - } // fallthrough + FALLTHROUGH; + } case GDScriptTokenizer::TK_OP_ASSIGN: { lv->assignments += 1; lv->usages--; // Assignment is not really usage @@ -812,19 +815,31 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s bfn = true; } - // Check parents for the constant - if (!bfn && cln->extends_file != StringName()) { - Ref<GDScript> parent = ResourceLoader::load(cln->extends_file); - if (parent.is_valid() && parent->is_valid()) { - Map<StringName, Variant> parent_constants; - parent->get_constants(&parent_constants); - if (parent_constants.has(identifier)) { + if (!dependencies_only) { + if (!bfn && ScriptServer::is_global_class(identifier)) { + Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(identifier)); + if (scr.is_valid() && scr->is_valid()) { ConstantNode *constant = alloc_node<ConstantNode>(); - constant->value = parent_constants[identifier]; + constant->value = scr; expr = constant; bfn = true; } } + + // Check parents for the constant + if (!bfn && cln->extends_file != StringName()) { + Ref<GDScript> parent = ResourceLoader::load(cln->extends_file); + if (parent.is_valid() && parent->is_valid()) { + Map<StringName, Variant> parent_constants; + parent->get_constants(&parent_constants); + if (parent_constants.has(identifier)) { + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value = parent_constants[identifier]; + expr = constant; + bfn = true; + } + } + } } } @@ -2082,7 +2097,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { return NULL; } pattern->pt_type = GDScriptParser::PatternNode::PT_BIND; - pattern->bind = tokenizer->get_token_identifier(); + pattern->bind = tokenizer->get_token_literal(); // Check if variable name is already used BlockNode *bl = current_block; while (bl) { @@ -2211,6 +2226,8 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static) { int indent_level = tab_level.back()->get(); + p_block->has_return = true; + while (true) { while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) @@ -2268,8 +2285,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran current_block = p_block; - if (catch_all && branch->body->has_return) { - p_block->has_return = true; + if (!branch->body->has_return) { + p_block->has_return = false; } p_branches.push_back(branch); @@ -2727,6 +2744,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } break; case GDScriptTokenizer::TK_NEWLINE: { + int line = tokenizer->get_token_line(); + if (!_parse_newline()) { if (!error_set) { p_block->end_line = tokenizer->get_token_line(); @@ -2736,7 +2755,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } NewLineNode *nl2 = alloc_node<NewLineNode>(); - nl2->line = tokenizer->get_token_line(); + nl2->line = line; p_block->statements.push_back(nl2); } break; @@ -3053,7 +3072,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } DataType iter_type; - iter_type.is_constant = true; if (container->type == Node::TYPE_OPERATOR) { @@ -3378,6 +3396,13 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { p_class->extends_file = constant; tokenizer->advance(); + // Add parent script as a dependency + String parent = constant; + if (parent.is_rel_path()) { + parent = base_path.plus_file(parent).simplify_path(); + } + dependencies.push_back(parent); + if (tokenizer->get_token() != GDScriptTokenizer::TK_PERIOD) { return; } else @@ -3612,7 +3637,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - }; //fallthrough to function + FALLTHROUGH; + } case GDScriptTokenizer::TK_PR_FUNCTION: { bool _static = false; @@ -4062,7 +4088,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { break; } - }; //fallthrough to use the same + FALLTHROUGH; + } case Variant::REAL: { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EASE") { @@ -4487,6 +4514,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { #ifdef DEBUG_ENABLED _add_warning(GDScriptWarning::DEPRECATED_KEYWORD, tokenizer->get_token_line(), "slave", "puppet"); #endif + FALLTHROUGH; case GDScriptTokenizer::TK_PR_PUPPET: { //may be fallthrough from export, ignore if so @@ -4554,7 +4582,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_VAR: { - //variale declaration and (eventual) initialization + // variable declaration and (eventual) initialization ClassNode::Member member; @@ -5266,7 +5294,8 @@ String GDScriptParser::DataType::to_string() const { if (!gds_class.empty()) { return gds_class; } - } // fallthrough + FALLTHROUGH; + } case SCRIPT: { if (is_meta_type) { return script_type->get_class_name().operator String(); @@ -5434,7 +5463,7 @@ GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source, String script_path = ScriptServer::get_global_class_path(id); if (script_path == self_path) { result.kind = DataType::CLASS; - result.class_type = current_class; + result.class_type = static_cast<ClassNode *>(head); } else { Ref<Script> script = ResourceLoader::load(script_path); Ref<GDScript> gds = script; @@ -7237,6 +7266,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType DataType result; result.has_type = true; result.script_type = scr; + result.is_constant = true; result.is_meta_type = true; Ref<GDScript> gds = scr; if (gds.is_valid()) { @@ -7287,6 +7317,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType if (singleton.is_valid()) { DataType result; result.has_type = true; + result.is_constant = true; result.script_type = singleton; Ref<GDScript> gds = singleton; @@ -7842,13 +7873,16 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { return; } - if (!lh_type.has_type && check_types) { - if (op->arguments[0]->type == Node::TYPE_OPERATOR) { - _mark_line_as_unsafe(op->line); + if (check_types) { + if (!lh_type.has_type) { + if (op->arguments[0]->type == Node::TYPE_OPERATOR) { + _mark_line_as_unsafe(op->line); + } + } + if (lh_type.is_constant) { + _set_error("Cannot assign a new value to a constant.", op->line); + return; } - } else if (lh_type.is_constant) { - _set_error("Cannot assign a new value to a constant.", op->line); - return; } DataType rh_type; @@ -8017,7 +8051,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { if (cn->value.get_type() == Variant::STRING) { break; } - } // falthrough + FALLTHROUGH; + } default: { _mark_line_as_safe(statement->line); _reduce_node_type(statement); // Test for safety anyway @@ -8149,6 +8184,10 @@ Error GDScriptParser::_parse(const String &p_base_path) { return ERR_PARSE_ERROR; } + if (dependencies_only) { + return OK; + } + _determine_inheritance(main_class); if (error_set) { @@ -8227,7 +8266,7 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St return ret; } -Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion, Set<int> *r_safe_lines) { +Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion, Set<int> *r_safe_lines, bool p_dependencies_only) { clear(); @@ -8237,6 +8276,7 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo validating = p_just_validate; for_completion = p_for_completion; + dependencies_only = p_dependencies_only; #ifdef DEBUG_ENABLED safe_lines = r_safe_lines; #endif // DEBUG_ENABLED @@ -8293,6 +8333,8 @@ void GDScriptParser::clear() { parenthesis = 0; current_export.type = Variant::NIL; check_types = true; + dependencies_only = false; + dependencies.clear(); error = ""; #ifdef DEBUG_ENABLED safe_lines = NULL; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 9c1ea1c7e4..809bff8f20 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -533,6 +533,8 @@ private: int error_line; int error_column; bool check_types; + bool dependencies_only; + List<String> dependencies; #ifdef DEBUG_ENABLED Set<int> *safe_lines; #endif // DEBUG_ENABLED @@ -634,7 +636,7 @@ public: #ifdef DEBUG_ENABLED const List<GDScriptWarning> &get_warnings() const { return warnings; } #endif // DEBUG_ENABLED - Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL); + Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL, bool p_dependencies_only = false); Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = ""); bool is_tool_script() const; @@ -653,6 +655,8 @@ public: int get_completion_argument_index(); int get_completion_identifier_is_function(); + const List<String> &get_dependencies() const { return dependencies; } + void clear(); GDScriptParser(); ~GDScriptParser(); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 8b22d6f085..abc739d645 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -744,7 +744,7 @@ void GDScriptTokenizerText::_advance() { } INCPOS(1); is_node_path = true; - + FALLTHROUGH; case '\'': case '"': { @@ -1199,7 +1199,8 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) Variant v; int len; - Error err = decode_variant(v, b, total_len, &len); + // An object cannot be constant, never decode objects + Error err = decode_variant(v, b, total_len, &len, false); if (err) return err; b += len; @@ -1367,11 +1368,12 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) for (Map<int, Variant>::Element *E = rev_constant_map.front(); E; E = E->next()) { int len; - Error err = encode_variant(E->get(), NULL, len); + // Objects cannot be constant, never encode objects + Error err = encode_variant(E->get(), NULL, len, false); ERR_FAIL_COND_V(err != OK, Vector<uint8_t>()); int pos = buf.size(); buf.resize(pos + len); - encode_variant(E->get(), &buf.write[pos], len); + encode_variant(E->get(), &buf.write[pos], len, false); } for (Map<int, uint32_t>::Element *E = rev_line_map.front(); E; E = E->next()) { diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 2ea116d79b..655be4eb20 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GridMap" inherits="Spatial" category="Core" version="3.1"> +<class name="GridMap" inherits="Spatial" category="Core" version="3.2"> <brief_description> Node for 3D tile-based maps. </brief_description> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index fe1eac6dc9..32a014e76d 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -517,7 +517,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Ref<NavigationMesh> navmesh = mesh_library->get_item_navmesh(c.item); if (navmesh.is_valid()) { Octant::NavMesh nm; - nm.xform = xform; + nm.xform = xform * mesh_library->get_item_navmesh_transform(c.item); if (navigation) { nm.id = navigation->navmesh_add(navmesh, xform, this); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index bc7a576785..17eb6f674c 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -717,6 +717,26 @@ void GridMapEditor::_set_display_mode(int p_mode) { update_palette(); } +void GridMapEditor::_text_changed(const String &p_text) { + update_palette(); +} + +void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) { + + Ref<InputEventKey> k = p_ie; + + if (k.is_valid() && (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_PAGEUP || k->get_scancode() == KEY_PAGEDOWN)) { + + mesh_library_palette->call("_gui_input", k); + search_box->accept_event(); + } +} + +void GridMapEditor::_icon_size_changed(float p_value) { + mesh_library_palette->set_icon_scale(p_value); + update_palette(); +} + void GridMapEditor::update_palette() { int selected = mesh_library_palette->get_current(); @@ -730,8 +750,9 @@ void GridMapEditor::update_palette() { } float min_size = EDITOR_DEF("editors/grid_map/preview_size", 64); + min_size *= EDSCALE; mesh_library_palette->set_fixed_icon_size(Size2(min_size, min_size)); - mesh_library_palette->set_fixed_column_width(min_size * 3 / 2); + mesh_library_palette->set_fixed_column_width(min_size * MAX(size_slider->get_value(), 1.5)); mesh_library_palette->set_max_text_lines(2); Ref<MeshLibrary> mesh_library = node->get_mesh_library(); @@ -754,23 +775,28 @@ void GridMapEditor::update_palette() { } il.sort(); + String filter = search_box->get_text().strip_edges(); + int item = 0; for (List<_CGMEItemSort>::Element *E = il.front(); E; E = E->next()) { int id = E->get().id; - - mesh_library_palette->add_item(""); - String name = mesh_library->get_item_name(id); Ref<Texture> preview = mesh_library->get_item_preview(id); + if (name == "") { + name = "#" + itos(id); + } + + if (filter != "" && !filter.is_subsequence_ofi(name)) + continue; + + mesh_library_palette->add_item(""); if (!preview.is_null()) { mesh_library_palette->set_item_icon(item, preview); mesh_library_palette->set_item_tooltip(item, name); } - if (name != "") { - mesh_library_palette->set_item_text(item, name); - } + mesh_library_palette->set_item_text(item, name); mesh_library_palette->set_item_metadata(item, id); item++; @@ -985,6 +1011,7 @@ void GridMapEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { options->set_icon(get_icon("GridMap", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); } break; } } @@ -1031,6 +1058,9 @@ void GridMapEditor::_floor_changed(float p_value) { void GridMapEditor::_bind_methods() { + ClassDB::bind_method("_text_changed", &GridMapEditor::_text_changed); + ClassDB::bind_method("_sbox_input", &GridMapEditor::_sbox_input); + ClassDB::bind_method("_icon_size_changed", &GridMapEditor::_icon_size_changed); ClassDB::bind_method("_menu_option", &GridMapEditor::_menu_option); ClassDB::bind_method("_configure", &GridMapEditor::_configure); ClassDB::bind_method("_item_selected_cbk", &GridMapEditor::_item_selected_cbk); @@ -1132,6 +1162,12 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { add_child(hb); hb->set_h_size_flags(SIZE_EXPAND_FILL); + search_box = memnew(LineEdit); + search_box->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(search_box); + search_box->connect("text_changed", this, "_text_changed"); + search_box->connect("gui_input", this, "_sbox_input"); + mode_thumbnail = memnew(ToolButton); mode_thumbnail->set_toggle_mode(true); mode_thumbnail->set_pressed(true); @@ -1146,6 +1182,15 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { hb->add_child(mode_list); mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST)); + size_slider = memnew(HSlider); + size_slider->set_h_size_flags(SIZE_EXPAND_FILL); + size_slider->set_min(0.1f); + size_slider->set_max(4.0f); + size_slider->set_step(0.1f); + size_slider->set_value(1.0f); + size_slider->connect("value_changed", this, "_icon_size_changed"); + add_child(size_slider); + EDITOR_DEF("editors/grid_map/preview_size", 64); display_mode = DISPLAY_THUMBNAIL; diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 81a21a76ae..59b8ac13da 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -79,6 +79,8 @@ class GridMapEditor : public VBoxContainer { double accumulated_floor_delta; ToolButton *mode_thumbnail; ToolButton *mode_list; + LineEdit *search_box; + HSlider *size_slider; HBoxContainer *spatial_editor_hb; ConfirmationDialog *settings_dialog; VBoxContainer *settings_vbc; @@ -193,6 +195,11 @@ class GridMapEditor : public VBoxContainer { void _update_cursor_instance(); void _update_clip(); + void _text_changed(const String &p_text); + void _sbox_input(const Ref<InputEvent> &p_ie); + + void _icon_size_changed(float p_value); + void _update_duplicate_indicator(); void _duplicate_paste(); void _update_selection_transform(); diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml index 359d654433..0a75ad4784 100644 --- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml +++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.1"> +<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.2"> <brief_description> Generic mobile VR implementation </brief_description> diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index a7ac7f46c5..dfdb4a0b3a 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -499,6 +499,47 @@ String CSharpLanguage::_get_indentation() const { return "\t"; } +String CSharpLanguage::debug_get_error() const { + + return _debug_error; +} + +int CSharpLanguage::debug_get_stack_level_count() const { + + if (_debug_parse_err_line >= 0) + return 1; + + // TODO: StackTrace + return 1; +} + +int CSharpLanguage::debug_get_stack_level_line(int p_level) const { + + if (_debug_parse_err_line >= 0) + return _debug_parse_err_line; + + // TODO: StackTrace + return 1; +} + +String CSharpLanguage::debug_get_stack_level_function(int p_level) const { + + if (_debug_parse_err_line >= 0) + return String(); + + // TODO: StackTrace + return String(); +} + +String CSharpLanguage::debug_get_stack_level_source(int p_level) const { + + if (_debug_parse_err_line >= 0) + return _debug_parse_err_file; + + // TODO: StackTrace + return String(); +} + Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() { #ifdef DEBUG_ENABLED @@ -958,12 +999,11 @@ void CSharpLanguage::thread_exit() { bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) { - // Break because of parse error + // Not a parser error in our case, but it's still used for other type of errors if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) { - // TODO - //_debug_parse_err_line = p_line; - //_debug_parse_err_file = p_file; - //_debug_error = p_error; + _debug_parse_err_line = p_line; + _debug_parse_err_file = p_file; + _debug_error = p_error; ScriptDebugger::get_singleton()->debug(this, false); return true; } else { @@ -974,10 +1014,9 @@ bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const S bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) { if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) { - // TODO - //_debug_parse_err_line = -1; - //_debug_parse_err_file = ""; - //_debug_error = p_error; + _debug_parse_err_line = -1; + _debug_parse_err_file = ""; + _debug_error = p_error; ScriptDebugger::get_singleton()->debug(this, p_allow_continue); return true; } else { @@ -985,6 +1024,13 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) { } } +void CSharpLanguage::_uninitialize_script_bindings() { + for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { + CSharpScriptBinding &script_binding = E->value(); + script_binding.inited = false; + } +} + void CSharpLanguage::set_language_index(int p_idx) { ERR_FAIL_COND(lang_idx != -1); @@ -1269,14 +1315,14 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { GDMonoClass *top = script->script_class; while (top && top != script->native) { - GDMonoField *field = script->script_class->get_field(p_name); + GDMonoField *field = top->get_field(p_name); if (field) { field->set_value_from_variant(mono_object, p_value); return true; } - GDMonoProperty *property = script->script_class->get_property(p_name); + GDMonoProperty *property = top->get_property(p_name); if (property) { property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type())); @@ -1528,6 +1574,15 @@ MonoObject *CSharpInstance::_internal_new_managed() { CRASH_COND(!gchandle.is_valid()); #endif + // Search the constructor first, to fail with an error if it's not found before allocating anything else. + GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0); + if (ctor == NULL) { + ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + script->get_path()); + + ERR_EXPLAIN("Constructor not found"); + ERR_FAIL_V(NULL); + } + CSharpLanguage::get_singleton()->release_script_gchandle(gchandle); ERR_FAIL_NULL_V(owner, NULL); @@ -1557,7 +1612,6 @@ MonoObject *CSharpInstance::_internal_new_managed() { CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner); // Construct - GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0); ctor->invoke_raw(mono_object, NULL); return mono_object; @@ -1879,6 +1933,9 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED + if (!Engine::get_singleton()->is_editor_hint()) + return false; + placeholder_fallback_enabled = true; // until proven otherwise if (!valid) @@ -1900,13 +1957,21 @@ bool CSharpScript::_update_exports() { MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr()); if (!tmp_object) { - ERR_PRINT("Failed to create temporary MonoObject"); + ERR_PRINT("Failed to allocate temporary MonoObject"); return false; } uint32_t tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed) GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0); + + if (ctor == NULL) { + ERR_PRINTS("Cannot construct temporary MonoObject because the class does not define a parameterless constructor: " + get_path()); + + ERR_EXPLAIN("Constructor not found"); + ERR_FAIL_V(NULL); + } + MonoException *ctor_exc = NULL; ctor->invoke(tmp_object, NULL, &ctor_exc); @@ -2187,8 +2252,11 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ hint_string = name_only_hint_string; } } else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) { + GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(type.type_class); + CRASH_COND(field_native_class == NULL); + hint = PROPERTY_HINT_RESOURCE_TYPE; - hint_string = NATIVE_GDMONOCLASS_NAME(type.type_class); + hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class); } else { hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); @@ -2387,6 +2455,18 @@ StringName CSharpScript::get_instance_base_type() const { CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) { /* STEP 1, CREATE */ + + // Search the constructor first, to fail with an error if it's not found before allocating anything else. + GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount); + if (ctor == NULL) { + if (p_argcount == 0) { + ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + get_path()); + } + + ERR_EXPLAIN("Constructor not found"); + ERR_FAIL_V(NULL); + } + Ref<Reference> ref; if (p_isref) { // Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance. @@ -2453,7 +2533,6 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner); // Construct - GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount); ctor->invoke(mono_object, p_args); /* STEP 3, PARTY */ @@ -2672,6 +2751,7 @@ Error CSharpScript::reload(bool p_keep_state) { } load_script_signals(script_class, native); + _update_exports(); } return OK; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 8b1a4b5f7e..99877a4379 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -162,7 +162,7 @@ public: virtual bool has_script_signal(const StringName &p_signal) const; virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; - /* TODO */ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; virtual void get_script_property_list(List<PropertyInfo> *p_list) const; virtual void update_exports(); @@ -309,6 +309,14 @@ class CSharpLanguage : public ScriptLanguage { Dictionary scripts_metadata; + // For debug_break and debug_break_parse + int _debug_parse_err_line; + String _debug_parse_err_file; + String _debug_error; + + friend class GDMono; + void _uninitialize_script_bindings(); + public: StringNameCache string_names; @@ -365,11 +373,11 @@ public: /* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {} /* DEBUGGER FUNCTIONS */ - /* TODO */ virtual String debug_get_error() const { return ""; } - /* TODO */ virtual int debug_get_stack_level_count() const { return 1; } - /* TODO */ virtual int debug_get_stack_level_line(int p_level) const { return 1; } - /* TODO */ virtual String debug_get_stack_level_function(int p_level) const { return ""; } - /* TODO */ virtual String debug_get_stack_level_source(int p_level) const { return ""; } + virtual String debug_get_error() const; + virtual int debug_get_stack_level_count() const; + virtual int debug_get_stack_level_line(int p_level) const; + virtual String debug_get_stack_level_function(int p_level) const; + virtual String debug_get_stack_level_source(int p_level) const; /* TODO */ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} /* TODO */ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} /* TODO */ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} diff --git a/modules/mono/doc_classes/@C#.xml b/modules/mono/doc_classes/@C#.xml index 082bc30fd8..a821713d0d 100644 --- a/modules/mono/doc_classes/@C#.xml +++ b/modules/mono/doc_classes/@C#.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="@C#" category="Core" version="3.1"> +<class name="@C#" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml index a1f7399653..7f22388132 100644 --- a/modules/mono/doc_classes/CSharpScript.xml +++ b/modules/mono/doc_classes/CSharpScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSharpScript" inherits="Script" category="Core" version="3.1"> +<class name="CSharpScript" inherits="Script" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml index 921c1ca825..21835e639c 100644 --- a/modules/mono/doc_classes/GodotSharp.xml +++ b/modules/mono/doc_classes/GodotSharp.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GodotSharp" inherits="Object" category="Core" version="3.1"> +<class name="GodotSharp" inherits="Object" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs index e7d0486c76..967e3bcc19 100644 --- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs @@ -21,6 +21,8 @@ namespace GodotSharpTools.Build private extern static string godot_icall_BuildInstance_get_MonoWindowsBinDir(); [MethodImpl(MethodImplOptions.InternalCall)] private extern static bool godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows(); + [MethodImpl(MethodImplOptions.InternalCall)] + private extern static bool godot_icall_BuildInstance_get_PrintBuildOutput(); private static string GetMSBuildPath() { @@ -53,6 +55,14 @@ namespace GodotSharpTools.Build } } + private static bool PrintBuildOutput + { + get + { + return godot_icall_BuildInstance_get_PrintBuildOutput(); + } + } + private string solution; private string config; @@ -71,8 +81,6 @@ namespace GodotSharpTools.Build public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null) { - bool debugMSBuild = IsDebugMSBuildRequested(); - List<string> customPropertiesList = new List<string>(); if (customProperties != null) @@ -82,7 +90,10 @@ namespace GodotSharpTools.Build ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs); - bool redirectOutput = !debugMSBuild; + bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput; + + if (!redirectOutput) // TODO: or if stdout verbose + Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}"); startInfo.RedirectStandardOutput = redirectOutput; startInfo.RedirectStandardError = redirectOutput; @@ -123,8 +134,6 @@ namespace GodotSharpTools.Build public bool BuildAsync(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null) { - bool debugMSBuild = IsDebugMSBuildRequested(); - if (process != null) throw new InvalidOperationException("Already in use"); @@ -137,7 +146,10 @@ namespace GodotSharpTools.Build ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs); - bool redirectOutput = !debugMSBuild; + bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput; + + if (!redirectOutput) // TODO: or if stdout verbose + Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}"); startInfo.RedirectStandardOutput = redirectOutput; startInfo.RedirectStandardError = redirectOutput; diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj index 9a5dd24bb1..2871c041f5 100644 --- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj @@ -41,6 +41,7 @@ <Compile Include="Build\BuildSystem.cs" /> <Compile Include="Editor\MonoDevelopInstance.cs" /> <Compile Include="Project\ProjectExtensions.cs" /> + <Compile Include="Project\IdentifierUtils.cs" /> <Compile Include="Project\ProjectGenerator.cs" /> <Compile Include="Project\ProjectUtils.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> diff --git a/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs b/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs new file mode 100644 index 0000000000..83e2d2cf8d --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace GodotSharpTools.Project +{ + public static class IdentifierUtils + { + public static string SanitizeQualifiedIdentifier(string qualifiedIdentifier, bool allowEmptyIdentifiers) + { + if (string.IsNullOrEmpty(qualifiedIdentifier)) + throw new ArgumentException($"{nameof(qualifiedIdentifier)} cannot be empty", nameof(qualifiedIdentifier)); + + string[] identifiers = qualifiedIdentifier.Split(new[] { '.' }); + + for (int i = 0; i < identifiers.Length; i++) + { + identifiers[i] = SanitizeIdentifier(identifiers[i], allowEmpty: allowEmptyIdentifiers); + } + + return string.Join(".", identifiers); + } + + public static string SanitizeIdentifier(string identifier, bool allowEmpty) + { + if (string.IsNullOrEmpty(identifier)) + { + if (allowEmpty) + return "Empty"; // Default value for empty identifiers + + throw new ArgumentException($"{nameof(identifier)} cannot be empty if {nameof(allowEmpty)} is false", nameof(identifier)); + } + + if (identifier.Length > 511) + identifier = identifier.Substring(0, 511); + + var identifierBuilder = new StringBuilder(); + int startIndex = 0; + + if (identifier[0] == '@') + { + identifierBuilder.Append('@'); + startIndex += 1; + } + + for (int i = startIndex; i < identifier.Length; i++) + { + char @char = identifier[i]; + + switch (Char.GetUnicodeCategory(@char)) + { + case UnicodeCategory.UppercaseLetter: + case UnicodeCategory.LowercaseLetter: + case UnicodeCategory.TitlecaseLetter: + case UnicodeCategory.ModifierLetter: + case UnicodeCategory.LetterNumber: + case UnicodeCategory.OtherLetter: + identifierBuilder.Append(@char); + break; + case UnicodeCategory.NonSpacingMark: + case UnicodeCategory.SpacingCombiningMark: + case UnicodeCategory.ConnectorPunctuation: + case UnicodeCategory.DecimalDigitNumber: + // Identifiers may start with underscore + if (identifierBuilder.Length > startIndex || @char == '_') + identifierBuilder.Append(@char); + break; + default: + break; + } + } + + if (identifierBuilder.Length == startIndex) + { + // All characters were invalid so now it's empty. Fill it with something. + identifierBuilder.Append("Empty"); + } + + identifier = identifierBuilder.ToString(); + + if (identifier[0] != '@' && IsKeyword(identifier, anyDoubleUnderscore: true)) + identifier = '@' + identifier; + + return identifier; + } + + static bool IsKeyword(string value, bool anyDoubleUnderscore) + { + // Identifiers that start with double underscore are meant to be used for reserved keywords. + // Only existing keywords are enforced, but it may be useful to forbid any identifier + // that begins with double underscore to prevent issues with future C# versions. + if (anyDoubleUnderscore) + { + if (value.Length > 2 && value[0] == '_' && value[1] == '_' && value[2] != '_') + return true; + } + else + { + if (_doubleUnderscoreKeywords.Contains(value)) + return true; + } + + return _keywords.Contains(value); + } + + static HashSet<string> _doubleUnderscoreKeywords = new HashSet<string> + { + "__arglist", + "__makeref", + "__reftype", + "__refvalue", + }; + + static HashSet<string> _keywords = new HashSet<string> + { + "as", + "do", + "if", + "in", + "is", + "for", + "int", + "new", + "out", + "ref", + "try", + "base", + "bool", + "byte", + "case", + "char", + "else", + "enum", + "goto", + "lock", + "long", + "null", + "this", + "true", + "uint", + "void", + "break", + "catch", + "class", + "const", + "event", + "false", + "fixed", + "float", + "sbyte", + "short", + "throw", + "ulong", + "using", + "where", + "while", + "yield", + "double", + "extern", + "object", + "params", + "public", + "return", + "sealed", + "sizeof", + "static", + "string", + "struct", + "switch", + "typeof", + "unsafe", + "ushort", + "checked", + "decimal", + "default", + "finally", + "foreach", + "partial", + "private", + "virtual", + "abstract", + "continue", + "delegate", + "explicit", + "implicit", + "internal", + "operator", + "override", + "readonly", + "volatile", + "interface", + "namespace", + "protected", + "unchecked", + "stackalloc", + }; + } +} diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs index 9135006172..89279c69a6 100644 --- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs @@ -140,6 +140,9 @@ namespace GodotSharpTools.Project public static ProjectRootElement CreateLibraryProject(string name, out ProjectPropertyGroupElement mainGroup) { + if (string.IsNullOrEmpty(name)) + throw new ArgumentException($"{nameof(name)} cannot be empty", nameof(name)); + var root = ProjectRootElement.Create(); root.DefaultTargets = "Build"; @@ -149,7 +152,7 @@ namespace GodotSharpTools.Project mainGroup.AddProperty("ProjectGuid", "{" + Guid.NewGuid().ToString().ToUpper() + "}"); mainGroup.AddProperty("OutputType", "Library"); mainGroup.AddProperty("OutputPath", Path.Combine("bin", "$(Configuration)")); - mainGroup.AddProperty("RootNamespace", name); + mainGroup.AddProperty("RootNamespace", IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true)); mainGroup.AddProperty("AssemblyName", name); mainGroup.AddProperty("TargetFrameworkVersion", "v4.5"); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 890bea0d1d..84e2303cf6 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -38,6 +38,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/os/os.h" +#include "core/string_builder.h" #include "core/ucaps.h" #include "../glue/cs_compressed.gen.h" @@ -97,7 +98,7 @@ #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array" -#define BINDINGS_GENERATOR_VERSION UINT32_C(7) +#define BINDINGS_GENERATOR_VERSION UINT32_C(8) const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n"; @@ -105,6 +106,16 @@ bool BindingsGenerator::verbose_output = false; BindingsGenerator *BindingsGenerator::singleton = NULL; +static String fix_doc_description(const String &p_bbcode) { + + // This seems to be the correct way to do this. It's the same EditorHelp does. + + return p_bbcode.dedent() + .replace("\t", "") + .replace("\r", "") + .strip_edges(); +} + static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) { String ret; @@ -173,6 +184,457 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up return ret; } +String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype) { + + // Based on the version in EditorHelp + + if (p_bbcode.empty()) + return String(); + + DocData *doc = EditorHelp::get_doc_data(); + + String bbcode = p_bbcode; + + StringBuilder xml_output; + + xml_output.append("<para>"); + + List<String> tag_stack; + bool code_tag = false; + + int pos = 0; + while (pos < bbcode.length()) { + int brk_pos = bbcode.find("[", pos); + + if (brk_pos < 0) + brk_pos = bbcode.length(); + + if (brk_pos > pos) { + String text = bbcode.substr(pos, brk_pos - pos); + if (code_tag || tag_stack.size() > 0) { + xml_output.append(text.xml_escape()); + } else { + Vector<String> lines = text.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (i != 0) + xml_output.append("<para>"); + + xml_output.append(lines[i].xml_escape()); + + if (i != lines.size() - 1) + xml_output.append("</para>\n"); + } + } + } + + if (brk_pos == bbcode.length()) + break; // nothing else to add + + int brk_end = bbcode.find("]", brk_pos + 1); + + if (brk_end == -1) { + String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos); + if (code_tag || tag_stack.size() > 0) { + xml_output.append(text.xml_escape()); + } else { + Vector<String> lines = text.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (i != 0) + xml_output.append("<para>"); + + xml_output.append(lines[i].xml_escape()); + + if (i != lines.size() - 1) + xml_output.append("</para>\n"); + } + } + + break; + } + + String tag = bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1); + + if (tag.begins_with("/")) { + bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length()); + + if (!tag_ok) { + xml_output.append("["); + pos = brk_pos + 1; + continue; + } + + tag_stack.pop_front(); + pos = brk_end + 1; + code_tag = false; + + if (tag == "/url") { + xml_output.append("</a>"); + } else if (tag == "/code") { + xml_output.append("</c>"); + } else if (tag == "/codeblock") { + xml_output.append("</code>"); + } + } else if (code_tag) { + xml_output.append("["); + pos = brk_pos + 1; + } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) { + String link_target = tag.substr(tag.find(" ") + 1, tag.length()); + String link_tag = tag.substr(0, tag.find(" ")); + + Vector<String> link_target_parts = link_target.split("."); + + if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) { + ERR_PRINTS("Invalid reference format: " + tag); + + xml_output.append("<c>"); + xml_output.append(tag); + xml_output.append("</c>"); + + pos = brk_end + 1; + continue; + } + + const TypeInterface *target_itype; + StringName target_cname; + + if (link_target_parts.size() == 2) { + target_itype = _get_type_or_null(TypeReference(link_target_parts[0])); + if (!target_itype) { + target_itype = _get_type_or_null(TypeReference("_" + link_target_parts[0])); + } + target_cname = link_target_parts[1]; + } else { + target_itype = p_itype; + target_cname = link_target_parts[0]; + } + + if (link_tag == "method") { + if (!target_itype || !target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (target_itype) { + OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data()); + } + } + + // TODO Map what we can + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else { + const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname); + + if (target_imethod) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("."); + xml_output.append(target_imethod->proxy_name); + xml_output.append("\"/>"); + } + } + } else if (link_tag == "member") { + if (!target_itype || !target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (target_itype) { + OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data()); + } + } + + // TODO Map what we can + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else { + const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname); + + if (target_iprop) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("."); + xml_output.append(target_iprop->proxy_name); + xml_output.append("\"/>"); + } + } + } else if (link_tag == "signal") { + // We do not declare signals in any way in C#, so there is nothing to reference + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else if (link_tag == "enum") { + StringName search_cname = !target_itype ? target_cname : + StringName(target_itype->name + "." + (String)target_cname); + + const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname); + + if (!enum_match && search_cname != target_cname) { + enum_match = enum_types.find(target_cname); + } + + if (enum_match) { + const TypeInterface &target_enum_itype = enum_match->value(); + + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any + xml_output.append("\"/>"); + } else { + ERR_PRINTS("Cannot resolve enum reference in documentation: " + link_target); + + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } + } else if (link_tag == "const") { + if (!target_itype || !target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (target_itype) { + OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data()); + } + } + + // TODO Map what we can + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) { + String target_name = (String)target_cname; + + // Try to find as a global constant + const ConstantInterface *target_iconst = find_constant_by_name(target_name, global_constants); + + if (target_iconst) { + // Found global constant + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS "."); + xml_output.append(target_iconst->proxy_name); + xml_output.append("\"/>"); + } else { + // Try to find as global enum constant + const EnumInterface *target_ienum = NULL; + + for (const List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) { + target_ienum = &E->get(); + target_iconst = find_constant_by_name(target_name, target_ienum->constants); + if (target_iconst) + break; + } + + if (target_iconst) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_ienum->cname); + xml_output.append("."); + xml_output.append(target_iconst->proxy_name); + xml_output.append("\"/>"); + } else { + ERR_PRINTS("Cannot resolve global constant reference in documentation: " + link_target); + + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } + } + } else { + String target_name = (String)target_cname; + + // Try to find the constant in the current class + const ConstantInterface *target_iconst = find_constant_by_name(target_name, target_itype->constants); + + if (target_iconst) { + // Found constant in current class + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("."); + xml_output.append(target_iconst->proxy_name); + xml_output.append("\"/>"); + } else { + // Try to find as enum constant in the current class + const EnumInterface *target_ienum = NULL; + + for (const List<EnumInterface>::Element *E = target_itype->enums.front(); E; E = E->next()) { + target_ienum = &E->get(); + target_iconst = find_constant_by_name(target_name, target_ienum->constants); + if (target_iconst) + break; + } + + if (target_iconst) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("."); + xml_output.append(target_ienum->cname); + xml_output.append("."); + xml_output.append(target_iconst->proxy_name); + xml_output.append("\"/>"); + } else { + ERR_PRINTS("Cannot resolve constant reference in documentation: " + link_target); + + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } + } + } + } + + pos = brk_end + 1; + } else if (doc->class_list.has(tag)) { + if (tag == "Array" || tag == "Dictionary") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE_COLLECTIONS "."); + xml_output.append(tag); + xml_output.append("\"/>"); + } else if (tag == "bool" || tag == "int") { + xml_output.append("<see cref=\""); + xml_output.append(tag); + xml_output.append("\"/>"); + } else if (tag == "float") { + xml_output.append("<see cref=\"" +#ifdef REAL_T_IS_DOUBLE + "double" +#else + "float" +#endif + "\"/>"); + } else if (tag == "Variant") { + // We use System.Object for Variant, so there is no Variant type in C# + xml_output.append("<c>Variant</c>"); + } else if (tag == "String") { + xml_output.append("<see cref=\"string\"/>"); + } else if (tag == "Nil") { + xml_output.append("<see langword=\"null\"/>"); + } else if (tag.begins_with("@")) { + // @GlobalScope, @GDScript, etc + xml_output.append("<c>"); + xml_output.append(tag); + xml_output.append("</c>"); + } else if (tag == "PoolByteArray") { + xml_output.append("<see cref=\"byte\"/>"); + } else if (tag == "PoolIntArray") { + xml_output.append("<see cref=\"int\"/>"); + } else if (tag == "PoolRealArray") { +#ifdef REAL_T_IS_DOUBLE + xml_output.append("<see cref=\"double\"/>"); +#else + xml_output.append("<see cref=\"float\"/>"); +#endif + } else if (tag == "PoolStringArray") { + xml_output.append("<see cref=\"string\"/>"); + } else if (tag == "PoolVector2Array") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>"); + } else if (tag == "PoolVector3Array") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>"); + } else if (tag == "PoolColorArray") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>"); + } else { + const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag)); + + if (!target_itype) { + target_itype = _get_type_or_null(TypeReference("_" + tag)); + } + + if (target_itype) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("\"/>"); + } else { + ERR_PRINTS("Cannot resolve type reference in documentation: " + tag); + + xml_output.append("<c>"); + xml_output.append(tag); + xml_output.append("</c>"); + } + } + + pos = brk_end + 1; + } else if (tag == "b") { + // bold is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "i") { + // italics is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "code") { + xml_output.append("<c>"); + + code_tag = true; + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "codeblock") { + xml_output.append("<code>"); + + code_tag = true; + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "center") { + // center is alignment not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "br") { + xml_output.append("\n"); // FIXME: Should use <para> instead. Luckily this tag isn't used for now. + pos = brk_end + 1; + } else if (tag == "u") { + // underline is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "s") { + // strikethrough is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "url") { + int end = bbcode.find("[", brk_end); + if (end == -1) + end = bbcode.length(); + String url = bbcode.substr(brk_end + 1, end - brk_end - 1); + xml_output.append("<a href=\""); + xml_output.append(url); + xml_output.append("\">"); + xml_output.append(url); + + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag.begins_with("url=")) { + String url = tag.substr(4, tag.length()); + xml_output.append("<a href=\""); + xml_output.append(url); + xml_output.append("\">"); + + pos = brk_end + 1; + tag_stack.push_front("url"); + } else if (tag == "img") { + int end = bbcode.find("[", brk_end); + if (end == -1) + end = bbcode.length(); + String image = bbcode.substr(brk_end + 1, end - brk_end - 1); + + // Not supported. Just append the bbcode. + xml_output.append("[img]"); + xml_output.append(image); + xml_output.append("[/img]"); + + pos = end; + tag_stack.push_front(tag); + } else if (tag.begins_with("color=")) { + // Not supported. + pos = brk_end + 1; + tag_stack.push_front("color"); + } else if (tag.begins_with("font=")) { + // Not supported. + pos = brk_end + 1; + tag_stack.push_front("font"); + } else { + xml_output.append("["); // ignore + pos = brk_pos + 1; + } + } + + xml_output.append("</para>"); + + return xml_output.as_string(); +} + int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { CRASH_COND(p_ienum.constants.empty()); @@ -299,6 +761,9 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { // Constants (in partial GD class) + p_output.push_back("\n#pragma warning disable CS1591 // Disable warning: " + "'Missing XML comment for publicly visible type or member'\n"); + p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{"); @@ -306,20 +771,20 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { const ConstantInterface &iconstant = E->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - p_output.push_back(INDENT2 "/// </summary>"); + p_output.push_back(INDENT2 "/// </summary>"); + } } p_output.push_back(MEMBER_BEGIN "public const int "); @@ -369,20 +834,20 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { const ConstantInterface &iconstant = F->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - p_output.push_back(INDENT2 "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + p_output.push_back(INDENT2 "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - p_output.push_back(INDENT2 "/// </summary>\n"); + p_output.push_back(INDENT2 "/// </summary>\n"); + } } p_output.push_back(INDENT2); @@ -399,6 +864,8 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { } p_output.push_back(CLOSE_BLOCK); // end of namespace + + p_output.push_back("\n#pragma warning restore CS1591\n"); } Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) { @@ -712,28 +1179,31 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back("using System;\n"); // IntPtr output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable - output.push_back("\n#pragma warning disable CS1591 // Disable warning: " - "'Missing XML comment for publicly visible type or member'\n"); + output.push_back("\n" + "#pragma warning disable CS1591 // Disable warning: " + "'Missing XML comment for publicly visible type or member'\n" + "#pragma warning disable CS1573 // Disable warning: " + "'Parameter has no matching param tag in the XML comment'\n"); output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); const DocData::ClassDoc *class_doc = itype.class_doc; if (class_doc && class_doc->description.size()) { - output.push_back(INDENT1 "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(class_doc->description), &itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = class_doc->description.split("\n"); + if (summary_lines.size()) { + output.push_back(INDENT1 "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { output.push_back(INDENT1 "/// "); - output.push_back(description_line.xml_escape()); + output.push_back(summary_lines[i]); output.push_back("\n"); } - } - output.push_back(INDENT1 "/// </summary>\n"); + output.push_back(INDENT1 "/// </summary>\n"); + } } output.push_back(INDENT1 "public "); @@ -767,20 +1237,20 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str const ConstantInterface &iconstant = E->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { output.push_back(INDENT2 "/// "); - output.push_back(description_line.xml_escape()); + output.push_back(summary_lines[i]); output.push_back("\n"); } - } - output.push_back(INDENT2 "/// </summary>"); + output.push_back(INDENT2 "/// </summary>"); + } } output.push_back(MEMBER_BEGIN "public const int "); @@ -808,20 +1278,20 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str const ConstantInterface &iconstant = F->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - output.push_back(INDENT3 "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + output.push_back(INDENT3 "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { output.push_back(INDENT3 "/// "); - output.push_back(description_line.xml_escape()); + output.push_back(summary_lines[i]); output.push_back("\n"); } - } - output.push_back(INDENT3 "/// </summary>\n"); + output.push_back(INDENT3 "/// </summary>\n"); + } } output.push_back(INDENT3); @@ -928,7 +1398,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back(INDENT1 CLOSE_BLOCK /* class */ CLOSE_BLOCK /* namespace */); - output.push_back("\n#pragma warning restore CS1591\n"); + output.push_back("\n" + "#pragma warning restore CS1591\n" + "#pragma warning restore CS1573\n"); return _save_file(p_output_file, output); } @@ -978,33 +1450,21 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte const TypeInterface *prop_itype = _get_type_or_null(proptype_name); ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found - String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname)); - - // Prevent property and enclosing type from sharing the same name - if (prop_proxy_name == p_itype.proxy_name) { - if (verbose_output) { - WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" + - p_itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`"); - } - - prop_proxy_name += "_"; - } - if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) { - p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = p_iprop.prop_doc->description.split("\n"); + if (summary_lines.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - p_output.push_back(INDENT2 "/// </summary>"); + p_output.push_back(INDENT2 "/// </summary>"); + } } p_output.push_back(MEMBER_BEGIN "public "); @@ -1014,7 +1474,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.push_back(prop_itype->cs_type); p_output.push_back(" "); - p_output.push_back(prop_proxy_name.replace("/", "__")); + p_output.push_back(p_iprop.proxy_name); p_output.push_back("\n" INDENT2 OPEN_BLOCK); if (getter) { @@ -1135,7 +1595,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in); - default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param is null, then the default value is " + def_arg + "</param>\n"); + // Apparently the name attribute must not include the @ + String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name; + + default_args_doc.push_back(INDENT2 "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + def_arg + "</param>\n"); } else { icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name); } @@ -1151,24 +1614,24 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf } if (p_imethod.method_doc && p_imethod.method_doc->description.size()) { - p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(p_imethod.method_doc->description), &p_itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = p_imethod.method_doc->description.split("\n"); + if (summary_lines.size() || default_args_doc.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) { - p_output.push_back(E->get().xml_escape()); - } + for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) { + p_output.push_back(E->get()); + } - p_output.push_back(INDENT2 "/// </summary>"); + p_output.push_back(INDENT2 "/// </summary>"); + } } if (!p_imethod.is_internal) { @@ -1540,20 +2003,13 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte String vararg_arg = "arg" + argc_str; String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg - p_output.push_back("\tVector<Variant> varargs;\n" - "\tint vararg_length = mono_array_length("); + p_output.push_back("\tint vararg_length = mono_array_length("); p_output.push_back(vararg_arg); p_output.push_back(");\n\tint total_length = "); p_output.push_back(real_argc_str); - p_output.push_back(" + vararg_length;\n\t"); - p_output.push_back(err_fail_macro); - p_output.push_back("(varargs.resize(vararg_length) != OK"); - p_output.push_back(fail_ret); - p_output.push_back(");\n\tVector<Variant*> " C_LOCAL_PTRCALL_ARGS ";\n\t"); - p_output.push_back(err_fail_macro); - p_output.push_back("(call_args.resize(total_length) != OK"); - p_output.push_back(fail_ret); - p_output.push_back(");\n"); + p_output.push_back(" + vararg_length;\n" + "\tArgumentsVector<Variant> varargs(vararg_length);\n" + "\tArgumentsVector<const Variant *> " C_LOCAL_PTRCALL_ARGS "(total_length);\n"); p_output.push_back(c_in_statements); p_output.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK "\t\tMonoObject* elem = mono_array_get("); @@ -1562,7 +2018,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n" "\t\t" C_LOCAL_PTRCALL_ARGS ".set("); p_output.push_back(real_argc_str); - p_output.push_back(" + i, &varargs.write[i]);\n\t" CLOSE_BLOCK); + p_output.push_back(" + i, &varargs.get(i));\n\t" CLOSE_BLOCK); } else { p_output.push_back(c_in_statements); p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "["); @@ -1584,7 +2040,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } p_output.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", "); - p_output.push_back(p_imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL"); + p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL"); p_output.push_back(", total_length, vcall_error);\n"); // See the comment on the C_LOCAL_VARARG_RET declaration @@ -1728,7 +2184,6 @@ void BindingsGenerator::_populate_object_type_interfaces() { PropertyInterface iprop; iprop.cname = property.name; - iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname)); iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname); iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname); @@ -1736,6 +2191,8 @@ void BindingsGenerator::_populate_object_type_interfaces() { iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid); ERR_FAIL_COND(!valid); + iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname)); + // Prevent property and enclosing type from sharing the same name if (iprop.proxy_name == itype.proxy_name) { if (verbose_output) { @@ -1746,6 +2203,8 @@ void BindingsGenerator::_populate_object_type_interfaces() { iprop.proxy_name += "_"; } + iprop.proxy_name = iprop.proxy_name.replace("/", "__"); // Some members have a slash... + iprop.prop_doc = NULL; for (int i = 0; i < itype.class_doc->properties.size(); i++) { @@ -2038,6 +2497,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg r_iarg.default_argument = "null"; break; } + FALLTHROUGH; case Variant::DICTIONARY: case Variant::_RID: r_iarg.default_argument = "new %s()"; diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 8a1c942f6b..42071f9c0d 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -87,8 +87,13 @@ class BindingsGenerator { StringName cname; bool is_enum; - TypeReference() { - is_enum = false; + TypeReference() : + is_enum(false) { + } + + TypeReference(const StringName &p_cname) : + cname(p_cname), + is_enum(false) { } }; @@ -321,6 +326,15 @@ class BindingsGenerator { return NULL; } + const PropertyInterface *find_property_by_name(const StringName &p_cname) const { + for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().cname == p_cname) + return &E->get(); + } + + return NULL; + } + const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const { for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { if (E->get().proxy_name == p_proxy_name) @@ -482,6 +496,8 @@ class BindingsGenerator { StringName type_VarArg; StringName type_Object; StringName type_Reference; + StringName type_String; + StringName type_at_GlobalScope; StringName enum_Error; NameCache() { @@ -493,6 +509,8 @@ class BindingsGenerator { type_VarArg = StaticCString::create("VarArg"); type_Object = StaticCString::create("Object"); type_Reference = StaticCString::create("Reference"); + type_String = StaticCString::create("String"); + type_at_GlobalScope = StaticCString::create("@GlobalScope"); enum_Error = StaticCString::create("Error"); } @@ -511,6 +529,15 @@ class BindingsGenerator { return NULL; } + const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const { + for (const List<ConstantInterface>::Element *E = p_constants.front(); E; E = E->next()) { + if (E->get().name == p_name) + return &E->get(); + } + + return NULL; + } + inline String get_unique_sig(const TypeInterface &p_type) { if (p_type.is_reference) return "Ref"; @@ -522,6 +549,8 @@ class BindingsGenerator { return p_type.name; } + String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype); + int _determine_enum_prefix(const EnumInterface &p_ienum); void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length); diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 5e1c9875f0..00c780d1b7 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -195,6 +195,11 @@ MonoBoolean godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows() { #endif } +MonoBoolean godot_icall_BuildInstance_get_PrintBuildOutput() { + + return (bool)EDITOR_GET("mono/builds/print_build_output"); +} + void GodotSharpBuilds::register_internal_calls() { static bool registered = false; @@ -205,6 +210,7 @@ void GodotSharpBuilds::register_internal_calls() { mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildPath", (void *)godot_icall_BuildInstance_get_MSBuildPath); mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MonoWindowsBinDir", (void *)godot_icall_BuildInstance_get_MonoWindowsBinDir); mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows", (void *)godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows); + mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_PrintBuildOutput", (void *)godot_icall_BuildInstance_get_PrintBuildOutput); } void GodotSharpBuilds::show_build_error_dialog(const String &p_message) { @@ -457,6 +463,8 @@ GodotSharpBuilds::GodotSharpBuilds() { "," PROP_NAME_MSBUILD_VS #endif "," PROP_NAME_XBUILD)); + + EDITOR_DEF("mono/builds/print_build_output", false); } GodotSharpBuilds::~GodotSharpBuilds() { diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 5b68810017..921b9f987b 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -185,6 +185,16 @@ void GodotSharpEditor::_toggle_about_dialog_on_start(bool p_enabled) { } } +void GodotSharpEditor::_build_solution_pressed() { + + if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) { + if (!_create_project_solution()) + return; // Failed to create solution + } + + MonoBottomPanel::get_singleton()->call("_build_project_pressed"); +} + void GodotSharpEditor::_menu_option_pressed(int p_id) { switch (p_id) { @@ -220,6 +230,7 @@ void GodotSharpEditor::_notification(int p_notification) { void GodotSharpEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_build_solution_pressed"), &GodotSharpEditor::_build_solution_pressed); ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution); ClassDB::bind_method(D_METHOD("_make_api_solutions_if_needed"), &GodotSharpEditor::_make_api_solutions_if_needed); ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option); @@ -446,12 +457,12 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { about_label->set_v_size_flags(Control::SIZE_EXPAND_FILL); about_label->set_autowrap(true); String about_text = - String("C# support in Godot Engine is a brand new feature and a work in progress.\n") + - "It is currently in an alpha stage and is not suitable for use in production.\n\n" + - "As of Godot 3.1, C# support is not feature-complete and may crash in some situations. " + - "Bugs and usability issues will be addressed gradually over future 3.x releases, " + - "including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + - "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc:\n\n" + + String("C# support in Godot Engine is in late alpha stage and, while already usable, ") + + "it is not meant for use in production.\n\n" + + "Projects can be exported to Linux, macOS and Windows, but not yet to mobile or web platforms. " + + "Bugs and usability issues will be addressed gradually over future releases, " + + "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + + "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" + " https://github.com/godotengine/godot/issues\n\n" + "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!"; about_label->set_text(about_text); @@ -482,7 +493,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { build_button->set_text("Build"); build_button->set_tooltip("Build solution"); build_button->set_focus_mode(Control::FOCUS_NONE); - build_button->connect("pressed", MonoBottomPanel::get_singleton(), "_build_project_pressed"); + build_button->connect("pressed", this, "_build_solution_pressed"); editor->get_menu_hb()->add_child(build_button); // External editor settings diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h index c9744a9eed..cf0d2aec84 100644 --- a/modules/mono/editor/godotsharp_editor.h +++ b/modules/mono/editor/godotsharp_editor.h @@ -65,6 +65,8 @@ class GodotSharpEditor : public Node { void _menu_option_pressed(int p_id); + void _build_solution_pressed(); + static GodotSharpEditor *singleton; protected: diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp index fcc58c22e8..dfb652a7aa 100644 --- a/modules/mono/editor/script_class_parser.cpp +++ b/modules/mono/editor/script_class_parser.cpp @@ -266,6 +266,20 @@ Error ScriptClassParser::_skip_generic_type_params() { if (tk == TK_IDENTIFIER) { tk = get_token(); + // Type specifications can end with "?" to denote nullable types, such as IList<int?> + if (tk == TK_SYMBOL) { + tk = get_token(); + if (value.operator String() != "?") { + error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found unexpected symbol '" + value + "'"; + error = true; + return ERR_PARSE_ERROR; + } + if (tk != TK_OP_GREATER && tk != TK_COMMA) { + error_str = "Nullable type symbol '?' is only allowed after an identifier, but found " + get_token_name(tk) + " next."; + error = true; + return ERR_PARSE_ERROR; + } + } if (tk == TK_PERIOD) { while (true) { @@ -322,6 +336,15 @@ Error ScriptClassParser::_parse_type_full_name(String &r_full_name) { r_full_name += String(value); + if (code[idx] == '<') { + idx++; + + // We don't mind if the base is generic, but we skip it any ways since this information is not needed + Error err = _skip_generic_type_params(); + if (err) + return err; + } + if (code[idx] != '.') // We only want to take the next token if it's a period return OK; @@ -344,16 +367,6 @@ Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) { Token tk = get_token(); - bool generic = false; - if (tk == TK_OP_LESS) { - err = _skip_generic_type_params(); - if (err) - return err; - // We don't add it to the base list if it's generic - generic = true; - tk = get_token(); - } - if (tk == TK_COMMA) { err = _parse_class_base(r_base); if (err) @@ -373,9 +386,7 @@ Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) { return ERR_PARSE_ERROR; } - if (!generic) { - r_base.push_back(name); - } + r_base.push_back(name); return OK; } @@ -567,7 +578,7 @@ Error ScriptClassParser::parse(const String &p_code) { if (full_name.length()) full_name += "."; full_name += class_decl.name; - OS::get_singleton()->print("%s", String("Ignoring generic class declaration: " + class_decl.name).utf8().get_data()); + OS::get_singleton()->print("Ignoring generic class declaration: %s\n", class_decl.name.utf8().get_data()); } } } else if (tk == TK_IDENTIFIER && String(value) == "struct") { diff --git a/modules/mono/glue/Managed/Files/DebuggingUtils.cs b/modules/mono/glue/Managed/Files/DebuggingUtils.cs index b27816084e..edfe3464ec 100644 --- a/modules/mono/glue/Managed/Files/DebuggingUtils.cs +++ b/modules/mono/glue/Managed/Files/DebuggingUtils.cs @@ -19,6 +19,12 @@ namespace Godot sb.Append(" "); } + public static void InstallTraceListener() + { + Trace.Listeners.Clear(); + Trace.Listeners.Add(new GodotTraceListener()); + } + public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl) { fileName = frame.GetFileName(); diff --git a/modules/mono/glue/Managed/Files/DynamicObject.cs b/modules/mono/glue/Managed/Files/DynamicObject.cs new file mode 100644 index 0000000000..9504415664 --- /dev/null +++ b/modules/mono/glue/Managed/Files/DynamicObject.cs @@ -0,0 +1,213 @@ + +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; + +namespace Godot +{ + /// <summary> + /// Represents an <see cref="Godot.Object"/> whose members can be dynamically accessed at runtime through the Variant API. + /// </summary> + /// <remarks> + /// <para> + /// The <see cref="Godot.DynamicGodotObject"/> class enables access to the Variant + /// members of a <see cref="Godot.Object"/> instance at runtime. + /// </para> + /// <para> + /// This allows accessing the class members using their original names in the engine as well as the members from the + /// script attached to the <see cref="Godot.Object"/>, regardless of the scripting language it was written in. + /// </para> + /// </remarks> + /// <example> + /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>. + /// <code> + /// dynamic sprite = GetNode("Sprite").DynamicGodotObject; + /// sprite.add_child(this); + /// + /// if ((sprite.hframes * sprite.vframes) > 0) + /// sprite.frame = 0; + /// </code> + /// </example> + /// <example> + /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Godot.Object"/>. + /// <code> + /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject; + /// + /// if (childNode.print_allowed) + /// { + /// childNode.message = "Hello from C#"; + /// childNode.print_message(3); + /// } + /// </code> + /// The <c>ChildNode</c> node has the following GDScript script attached: + /// <code> + /// // # ChildNode.gd + /// // var print_allowed = true + /// // var message = "" + /// // + /// // func print_message(times): + /// // for i in times: + /// // print(message) + /// </code> + /// </example> + public class DynamicGodotObject : DynamicObject + { + /// <summary> + /// Gets the <see cref="Godot.Object"/> associated with this <see cref="Godot.DynamicGodotObject"/>. + /// </summary> + public Object Value { get; } + + /// <summary> + /// Initializes a new instance of the <see cref="Godot.DynamicGodotObject"/> class. + /// </summary> + /// <param name="godotObject"> + /// The <see cref="Godot.Object"/> that will be associated with this <see cref="Godot.DynamicGodotObject"/>. + /// </param> + /// <exception cref="System.ArgumentNullException"> + /// Thrown when the <paramref name="godotObject"/> parameter is null. + /// </exception> + public DynamicGodotObject(Object godotObject) + { + if (godotObject == null) + throw new ArgumentNullException(nameof(godotObject)); + + this.Value = godotObject; + } + + public override IEnumerable<string> GetDynamicMemberNames() + { + return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value)); + } + + public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) + { + switch (binder.Operation) + { + case ExpressionType.Equal: + case ExpressionType.NotEqual: + if (binder.ReturnType == typeof(bool) || binder.ReturnType.IsAssignableFrom(typeof(bool))) + { + if (arg == null) + { + bool boolResult = Object.IsInstanceValid(Value); + + if (binder.Operation == ExpressionType.Equal) + boolResult = !boolResult; + + result = boolResult; + return true; + } + + if (arg is Object other) + { + bool boolResult = (Value == other); + + if (binder.Operation == ExpressionType.NotEqual) + boolResult = !boolResult; + + result = boolResult; + return true; + } + } + + break; + default: + // We're not implementing operators <, <=, >, and >= (LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual). + // These are used on the actual pointers in variant_op.cpp. It's better to let the user do that explicitly. + break; + } + + return base.TryBinaryOperation(binder, arg, out result); + } + + public override bool TryConvert(ConvertBinder binder, out object result) + { + if (binder.Type == typeof(Object)) + { + result = Value; + return true; + } + + if (typeof(Object).IsAssignableFrom(binder.Type)) + { + // Throws InvalidCastException when the cast fails + result = Convert.ChangeType(Value, binder.Type); + return true; + } + + return base.TryConvert(binder, out result); + } + + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + { + if (indexes.Length == 1) + { + if (indexes[0] is string name) + { + return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), name, out result); + } + } + + return base.TryGetIndex(binder, indexes, out result); + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result); + } + + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result); + } + + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + if (indexes.Length == 1) + { + if (indexes[0] is string name) + { + return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), name, value); + } + } + + return base.TrySetIndex(binder, indexes, value); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value); + + #region We don't override these methods + + // Looks like this is not usable from C# + //public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result); + + // Object members cannot be deleted + //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes); + //public override bool TryDeleteMember(DeleteMemberBinder binder); + + // Invokation on the object itself, e.g.: obj(param) + //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result); + + // No unnary operations to handle + //public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result); + + #endregion + } +} diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs index 3afaf5d08b..d968f8a78f 100644 --- a/modules/mono/glue/Managed/Files/GD.cs +++ b/modules/mono/glue/Managed/Files/GD.cs @@ -13,12 +13,12 @@ namespace Godot { public static partial class GD { - public static object Bytes2Var(byte[] bytes) + public static object Bytes2Var(byte[] bytes, bool allow_objects = false) { - return godot_icall_GD_bytes2var(bytes); + return godot_icall_GD_bytes2var(bytes, allow_objects); } - public static object Convert(object what, int type) + public static object Convert(object what, Variant.Type type) { return godot_icall_GD_convert(what, type); } @@ -186,9 +186,9 @@ namespace Godot return godot_icall_GD_type_exists(type); } - public static byte[] Var2Bytes(object var) + public static byte[] Var2Bytes(object var, bool full_objects = false) { - return godot_icall_GD_var2bytes(var); + return godot_icall_GD_var2bytes(var, full_objects); } public static string Var2Str(object var) @@ -197,10 +197,10 @@ namespace Godot } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_GD_bytes2var(byte[] bytes); + internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allow_objects); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_GD_convert(object what, int type); + internal extern static object godot_icall_GD_convert(object what, Variant.Type type); [MethodImpl(MethodImplOptions.InternalCall)] internal extern static int godot_icall_GD_hash(object var); @@ -251,7 +251,7 @@ namespace Godot internal extern static bool godot_icall_GD_type_exists(string type); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static byte[] godot_icall_GD_var2bytes(object what); + internal extern static byte[] godot_icall_GD_var2bytes(object what, bool full_objects); [MethodImpl(MethodImplOptions.InternalCall)] internal extern static string godot_icall_GD_var2str(object var); diff --git a/modules/mono/glue/Managed/Files/GodotTraceListener.cs b/modules/mono/glue/Managed/Files/GodotTraceListener.cs new file mode 100644 index 0000000000..f1a00ae0fa --- /dev/null +++ b/modules/mono/glue/Managed/Files/GodotTraceListener.cs @@ -0,0 +1,37 @@ +using System; +using System.Diagnostics; + +namespace Godot +{ + internal class GodotTraceListener : TraceListener + { + public override void Write(string message) + { + GD.PrintRaw(message); + } + + public override void WriteLine(string message) + { + GD.Print(message); + } + + public override void Fail(string message, string detailMessage) + { + GD.PrintErr("Assertion failed: ", message); + if (detailMessage != null) + { + GD.PrintErr(" Details: ", detailMessage); + } + + try + { + var stackTrace = new StackTrace(true).ToString(); + GD.PrintErr(stackTrace); + } + catch + { + // ignored + } + } + } +} diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index dcab3c1ffc..5f5de12959 100644 --- a/modules/mono/glue/Managed/Files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs @@ -289,13 +289,13 @@ namespace Godot public static int Wrap(int value, int min, int max) { int rng = max - min; - return min + ((value - min) % rng + rng) % rng; + return rng != 0 ? min + ((value - min) % rng + rng) % rng : min; } public static real_t Wrap(real_t value, real_t min, real_t max) { real_t rng = max - min; - return min + ((value - min) % rng + rng) % rng; + return !IsEqualApprox(rng, default(real_t)) ? min + ((value - min) % rng + rng) % rng : min; } } } diff --git a/modules/mono/glue/Managed/Files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs index 2ef02cc288..414762f7b1 100644 --- a/modules/mono/glue/Managed/Files/MathfEx.cs +++ b/modules/mono/glue/Managed/Files/MathfEx.cs @@ -35,5 +35,10 @@ namespace Godot { return (int)Math.Round(s); } + + public static bool IsEqualApprox(real_t a, real_t b, real_t ratio = Mathf.Epsilon) + { + return Abs(a - b) < ratio; + } } }
\ No newline at end of file diff --git a/modules/mono/glue/Managed/Files/Object.base.cs b/modules/mono/glue/Managed/Files/Object.base.cs index 41fc43996f..e152d56871 100644 --- a/modules/mono/glue/Managed/Files/Object.base.cs +++ b/modules/mono/glue/Managed/Files/Object.base.cs @@ -73,11 +73,39 @@ namespace Godot disposed = true; } + /// <summary> + /// Returns a new <see cref="Godot.SignalAwaiter"/> awaiter configured to complete when the instance + /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter. + /// </summary> + /// <param name="source"> + /// The instance the awaiter will be listening to. + /// </param> + /// <param name="signal"> + /// The signal the awaiter will be waiting for. + /// </param> + /// <example> + /// This sample prints a message once every frame up to 100 times. + /// <code> + /// public override void _Ready() + /// { + /// for (int i = 0; i < 100; i++) + /// { + /// await ToSignal(GetTree(), "idle_frame"); + /// GD.Print($"Frame {i}"); + /// } + /// } + /// </code> + /// </example> public SignalAwaiter ToSignal(Object source, string signal) { return new SignalAwaiter(source, signal, this); } + /// <summary> + /// Gets a new <see cref="Godot.DynamicGodotObject"/> associated with this instance. + /// </summary> + public dynamic DynamicObject => new DynamicGodotObject(this); + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static IntPtr godot_icall_Object_Ctor(Object obj); diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h new file mode 100644 index 0000000000..8c0f308c15 --- /dev/null +++ b/modules/mono/glue/arguments_vector.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* arguments_vector.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 ARGUMENTS_VECTOR_H +#define ARGUMENTS_VECTOR_H + +#include "core/os/memory.h" + +template <typename T, int POOL_SIZE = 5> +struct ArgumentsVector { + +private: + T pool[POOL_SIZE]; + T *_ptr; + int size; + + ArgumentsVector(); + ArgumentsVector(const ArgumentsVector &); + +public: + T *ptr() { return _ptr; } + T &get(int p_idx) { return _ptr[p_idx]; } + void set(int p_idx, const T &p_value) { _ptr[p_idx] = p_value; } + + explicit ArgumentsVector(int p_size) : + size(p_size) { + if (p_size <= POOL_SIZE) { + _ptr = pool; + } else { + _ptr = memnew_arr(T, p_size); + } + } + + ~ArgumentsVector() { + if (size > POOL_SIZE) { + memdelete_arr(_ptr); + } + } +}; + +#endif // ARGUMENTS_VECTOR_H diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index fad02b01d3..b690de0d20 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -36,9 +36,11 @@ #include "core/string_name.h" #include "../csharp_script.h" +#include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_internals.h" #include "../mono_gd/gd_mono_utils.h" #include "../signal_awaiter_utils.h" +#include "arguments_vector.h" Object *godot_icall_Object_Ctor(MonoObject *p_obj) { Object *instance = memnew(Object); @@ -75,7 +77,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer) { +void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == NULL); // This is only called with Reference derived classes @@ -155,6 +157,67 @@ Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter); } +MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) { + List<PropertyInfo> property_list; + p_ptr->get_property_list(&property_list); + + MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size()); + + int i = 0; + for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { + MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name); + mono_array_set(result, MonoString *, i, boxed); + i++; + } + + return result; +} + +MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result) { + String name = GDMonoMarshal::mono_string_to_godot(p_name); + + int argc = mono_array_length(p_args); + + ArgumentsVector<Variant> arg_store(argc); + ArgumentsVector<const Variant *> args(argc); + + for (int i = 0; i < argc; i++) { + MonoObject *elem = mono_array_get(p_args, MonoObject *, i); + arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem)); + args.set(i, &arg_store.get(i)); + } + + Variant::CallError error; + Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error); + + *r_result = GDMonoMarshal::variant_to_mono_object(result); + + return error.error == OK; +} + +MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) { + String name = GDMonoMarshal::mono_string_to_godot(p_name); + + bool valid; + Variant value = p_ptr->get(StringName(name), &valid); + + if (valid) { + *r_result = GDMonoMarshal::variant_to_mono_object(value); + } + + return valid; +} + +MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value) { + String name = GDMonoMarshal::mono_string_to_godot(p_name); + Variant value = GDMonoMarshal::mono_object_to_variant(p_value); + + bool valid; + p_ptr->set(StringName(name), value, &valid); + + return valid; +} + 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); @@ -162,6 +225,10 @@ void godot_register_object_icalls() { 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_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); } #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/base_object_glue.h b/modules/mono/glue/base_object_glue.h index e126fac6ca..9b5224a347 100644 --- a/modules/mono/glue/base_object_glue.h +++ b/modules/mono/glue/base_object_glue.h @@ -42,7 +42,7 @@ Object *godot_icall_Object_Ctor(MonoObject *p_obj); void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr); -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer); +void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer); MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method); @@ -50,6 +50,16 @@ MonoObject *godot_icall_Object_weakref(Object *p_obj); Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter); +// DynamicGodotObject + +MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr); + +MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result); + +MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result); + +MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value); + // Register internal calls void godot_register_object_icalls(); diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 1065ff0868..1aad1c53bc 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -81,7 +81,7 @@ void godot_icall_Array_Clear(Array *ptr) { ptr->clear(); } -bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) { +MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) { return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1; } @@ -113,7 +113,7 @@ void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) { ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item)); } -bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) { +MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) { int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item)); if (idx >= 0) { ptr->remove(idx); @@ -208,21 +208,21 @@ void godot_icall_Dictionary_Clear(Dictionary *ptr) { ptr->clear(); } -bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) { +MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) { // no dupes Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value); } -bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) { +MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) { return ptr->has(GDMonoMarshal::mono_object_to_variant(key)); } -bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { +MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { return ptr->erase(GDMonoMarshal::mono_object_to_variant(key)); } -bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) { +MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) { Variant varKey = GDMonoMarshal::mono_object_to_variant(key); // no dupes @@ -235,7 +235,7 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject return false; } -bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) { +MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) { Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); if (ret == NULL) { *value = NULL; @@ -245,7 +245,7 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb return true; } -bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { +MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); if (ret == NULL) { *value = NULL; diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h index c0056d3bce..85a2e243a2 100644 --- a/modules/mono/glue/collections_glue.h +++ b/modules/mono/glue/collections_glue.h @@ -55,7 +55,7 @@ void godot_icall_Array_Add(Array *ptr, MonoObject *item); void godot_icall_Array_Clear(Array *ptr); -bool godot_icall_Array_Contains(Array *ptr, MonoObject *item); +MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item); void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index); @@ -63,7 +63,7 @@ int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item); void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item); -bool godot_icall_Array_Remove(Array *ptr, MonoObject *item); +MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item); void godot_icall_Array_RemoveAt(Array *ptr, int index); @@ -93,17 +93,17 @@ void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *va void godot_icall_Dictionary_Clear(Dictionary *ptr); -bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value); +MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value); -bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key); +MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key); -bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key); +MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key); -bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value); +MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value); -bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); +MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); -bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class); +MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class); void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class); diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp index 5edf49d2bf..d756131ac9 100644 --- a/modules/mono/glue/gd_glue.cpp +++ b/modules/mono/glue/gd_glue.cpp @@ -41,11 +41,11 @@ #include "../mono_gd/gd_mono_utils.h" -MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes) { +MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) { Variant ret; PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes); PoolByteArray::Read r = varr.read(); - Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, p_allow_objects); if (err != OK) { ret = RTR("Not enough bytes for decoding bytes, or invalid format."); } @@ -175,7 +175,7 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str) { return GDMonoMarshal::variant_to_mono_object(ret); } -bool godot_icall_GD_type_exists(MonoString *p_type) { +MonoBoolean godot_icall_GD_type_exists(MonoString *p_type) { return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type)); } @@ -187,19 +187,19 @@ void godot_icall_GD_pushwarning(MonoString *p_str) { WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str)); } -MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) { +MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) { Variant var = GDMonoMarshal::mono_object_to_variant(p_var); PoolByteArray barr; int len; - Error err = encode_variant(var, NULL, len); + Error err = encode_variant(var, NULL, len, p_full_objects); ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); ERR_FAIL_COND_V(err != OK, NULL); barr.resize(len); { PoolByteArray::Write w = barr.write(); - encode_variant(var, w.ptr(), len); + encode_variant(var, w.ptr(), len, p_full_objects); } return GDMonoMarshal::PoolByteArray_to_mono_array(barr); diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h index ba75d85343..910979aae3 100644 --- a/modules/mono/glue/gd_glue.h +++ b/modules/mono/glue/gd_glue.h @@ -35,7 +35,7 @@ #include "../mono_gd/gd_mono_marshal.h" -MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes); +MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects); MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type); @@ -69,9 +69,9 @@ MonoString *godot_icall_GD_str(MonoArray *p_what); MonoObject *godot_icall_GD_str2var(MonoString *p_str); -bool godot_icall_GD_type_exists(MonoString *p_type); +MonoBoolean godot_icall_GD_type_exists(MonoString *p_type); -MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var); +MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects); MonoString *godot_icall_GD_var2str(MonoObject *p_var); diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index b6e8ac6909..1836130b76 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -74,4 +74,6 @@ void godot_register_glue_header_icalls() { } \ Object *m_instance = ci->creation_func(); +#include "arguments_vector.h" + #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index dfabfddd64..bba7df2c6a 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -34,6 +34,7 @@ #include <mono/metadata/mono-config.h> #include <mono/metadata/mono-debug.h> #include <mono/metadata/mono-gc.h> +#include <mono/metadata/profiler.h> #include "core/os/dir_access.h" #include "core/os/file_access.h" @@ -54,6 +55,10 @@ #include "main/main.h" #endif +#define OUT_OF_SYNC_ERR_MESSAGE(m_assembly_name) "The assembly '" m_assembly_name "' is out of sync. " \ + "This error is expected if you just upgraded to a newer Godot version. " \ + "Building the project will update the assembly to the correct version." + GDMono *GDMono::singleton = NULL; namespace { @@ -79,6 +84,14 @@ void setup_runtime_main_args() { mono_runtime_set_main_args(main_args.size(), main_args.ptrw()); } +void gdmono_profiler_init() { + String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd"); + bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false); + if (profiler_enabled) { + mono_profiler_load(profiler_args.utf8()); + } +} + #ifdef DEBUG_ENABLED static bool _wait_for_debugger_msecs(uint32_t p_msecs) { @@ -265,6 +278,8 @@ void GDMono::initialize() { GDMonoAssembly::initialize(); + gdmono_profiler_init(); + #ifdef DEBUG_ENABLED gdmono_debug_init(); #endif @@ -273,7 +288,7 @@ void GDMono::initialize() { mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL); -#ifdef TOOLS_ENABLED +#ifndef TOOLS_ENABLED if (!DirAccess::exists("res://.mono")) { // 'res://.mono/' is missing so there is nothing to load. We don't need to initialize mono, but // we still do so unless mscorlib is missing (which is the case for projects that don't use C#). @@ -353,15 +368,15 @@ void GDMono::initialize() { // metadata, so we invalidate the version in the metadata and unload the script domain. if (core_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Core API assembly is out of sync"); + ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME)); metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { - ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); + ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed"); metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); } if (editor_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Editor API assembly is out of sync"); + ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME)); metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); } @@ -572,6 +587,8 @@ bool GDMono::_load_core_api_assembly() { CS_GLUE_VERSION != api_assembly_ver.cs_glue_version; if (!core_api_assembly_out_of_sync) { GDMonoUtils::update_godot_api_cache(); + + _install_trace_listener(); } #else GDMonoUtils::update_godot_api_cache(); @@ -675,6 +692,23 @@ bool GDMono::_load_api_assemblies() { return true; } +void GDMono::_install_trace_listener() { + +#ifdef DEBUG_ENABLED + // Install the trace listener now before the project assembly is loaded + typedef void (*DebuggingUtils_InstallTraceListener)(MonoObject **); + MonoException *exc = NULL; + GDMonoClass *debug_utils = core_api_assembly->get_class(BINDINGS_NAMESPACE, "DebuggingUtils"); + DebuggingUtils_InstallTraceListener install_func = + (DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener"); + install_func((MonoObject **)&exc); + if (exc) { + ERR_PRINT("Failed to install System.Diagnostics.Trace listener"); + GDMonoUtils::debug_print_unhandled_exception(exc); + } +#endif +} + #ifdef TOOLS_ENABLED String GDMono::_get_api_assembly_metadata_path() { @@ -764,8 +798,6 @@ Error GDMono::_unload_scripts_domain() { if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); - mono_gc_collect(mono_gc_max_generation()); - finalizing_scripts_domain = true; if (!mono_domain_finalize(scripts_domain, 2000)) { @@ -833,6 +865,8 @@ Error GDMono::reload_scripts_domain() { } } + CSharpLanguage::get_singleton()->_uninitialize_script_bindings(); + Error err = _load_scripts_domain(); if (err != OK) { ERR_PRINT("Mono: Failed to load scripts domain"); @@ -852,7 +886,7 @@ Error GDMono::reload_scripts_domain() { // metadata, so we invalidate the version in the metadata and unload the script domain. if (core_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Core API assembly is out of sync"); + ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME)); metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); @@ -860,7 +894,7 @@ Error GDMono::reload_scripts_domain() { } if (editor_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Editor API assembly is out of sync"); + ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME)); metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); } @@ -901,14 +935,20 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { if (mono_domain_get() == p_domain) mono_domain_set(root_domain, true); - mono_gc_collect(mono_gc_max_generation()); if (!mono_domain_finalize(p_domain, 2000)) { ERR_PRINT("Mono: Domain finalization timeout"); } + mono_gc_collect(mono_gc_max_generation()); _domain_assemblies_cleanup(mono_domain_get_id(p_domain)); +#ifdef TOOLS_ENABLED + if (p_domain == tools_domain) { + editor_tools_assembly = NULL; + } +#endif + MonoException *exc = NULL; mono_domain_try_unload(p_domain, (MonoObject **)&exc); @@ -1010,11 +1050,19 @@ GDMono::~GDMono() { if (is_runtime_initialized()) { - if (scripts_domain) { +#ifdef TOOLS_ENABLED + if (tools_domain) { + Error err = finalize_and_unload_domain(tools_domain); + if (err != OK) { + ERR_PRINT("Mono: Failed to unload tools domain"); + } + } +#endif + if (scripts_domain) { Error err = _unload_scripts_domain(); if (err != OK) { - WARN_PRINT("Mono: Failed to unload scripts domain"); + ERR_PRINT("Mono: Failed to unload scripts domain"); } } @@ -1035,6 +1083,8 @@ GDMono::~GDMono() { mono_jit_cleanup(root_domain); + print_verbose("Mono: Finalized"); + runtime_initialized = false; } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 785b65ce13..216c96a612 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -125,6 +125,8 @@ class GDMono { String _get_api_assembly_metadata_path(); #endif + void _install_trace_listener(); + void _register_internal_calls(); Error _load_scripts_domain(); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 85273bfdb4..8fec28b186 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -50,7 +50,7 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin const char *rootdir = mono_assembly_getrootdir(); if (rootdir) { - String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5"); + String framework_dir = String::utf8(rootdir).plus_file("mono").plus_file("4.5"); r_search_dirs.push_back(framework_dir); r_search_dirs.push_back(framework_dir.plus_file("Facades")); } @@ -277,6 +277,7 @@ Error GDMonoAssembly::load(bool p_refonly) { ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN); #ifdef DEBUG_ENABLED + Vector<uint8_t> pdb_data; String pdb_path(path + ".pdb"); if (!FileAccess::exists(pdb_path)) { @@ -286,8 +287,9 @@ Error GDMonoAssembly::load(bool p_refonly) { goto no_pdb; } - pdb_data.clear(); pdb_data = FileAccess::get_file_as_array(pdb_path); + + // mono_debug_close_image doesn't seem to be needed mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size()); no_pdb: @@ -306,6 +308,9 @@ no_pdb: ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN); + // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name + mono_image_close(image); + loaded = true; modified_time = last_modified_time; @@ -321,8 +326,6 @@ Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) { image = p_image; - mono_image_addref(image); - loaded = true; return OK; @@ -332,13 +335,6 @@ void GDMonoAssembly::unload() { ERR_FAIL_COND(!loaded); -#ifdef DEBUG_ENABLED - if (pdb_data.size()) { - mono_debug_close_image(image); - pdb_data.clear(); - } -#endif - for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) { memdelete(E->value()); } @@ -346,8 +342,6 @@ void GDMonoAssembly::unload() { cached_classes.clear(); cached_raw.clear(); - mono_image_close(image); - assembly = NULL; image = NULL; loaded = false; diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 8f47ee26f8..32432af37d 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -84,10 +84,6 @@ class GDMonoAssembly { bool gdobject_class_cache_updated; Map<StringName, GDMonoClass *> gdobject_class_cache; -#ifdef DEBUG_ENABLED - Vector<uint8_t> pdb_data; -#endif - static bool no_search; static bool in_preload; static Vector<String> search_dirs; diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 48fa380456..5e9d4db122 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -49,7 +49,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ #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); \ + mono_field_set_value(p_object, mono_field, managed); \ } switch (type.type_encoding) { diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index 0eb4b3b8b3..d7f9b22c31 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "mono_reg_utils.h" +#include "core/os/dir_access.h" #ifdef WINDOWS_ENABLED @@ -200,6 +201,13 @@ String find_msbuild_tools_path() { val += "\\"; } + // Since VS2019, the directory is simply named "Current" + String msBuildDirectory = val + "MSBuild\\Current\\Bin"; + if (DirAccess::exists(msBuildDirectory)) { + return msBuildDirectory; + } + + // Directory name "15.0" is used in VS 2017 return val + "MSBuild\\15.0\\Bin"; } } diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index ba54160a90..25f104b221 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NoiseTexture" inherits="Texture" category="Core" version="3.1"> +<class name="NoiseTexture" inherits="Texture" category="Core" version="3.2"> <brief_description> [OpenSimplexNoise] filled texture. </brief_description> @@ -17,6 +17,8 @@ <member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap"> If true, the resulting texture contains a normal map created from the original noise interpreted as a bump map. </member> + <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength"> + </member> <member name="height" type="int" setter="set_height" getter="get_height"> Height of the generated texture. </member> diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index 31f13f341c..b5bc35df69 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="OpenSimplexNoise" inherits="Resource" category="Core" version="3.1"> +<class name="OpenSimplexNoise" inherits="Resource" category="Core" version="3.2"> <brief_description> Noise generator based on Open Simplex. </brief_description> diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index b8126ab775..9240183265 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -41,6 +41,7 @@ NoiseTexture::NoiseTexture() { size = Vector2i(512, 512); seamless = false; as_normalmap = false; + bump_strength = 8.0; flags = FLAGS_DEFAULT; noise = Ref<OpenSimplexNoise>(); @@ -68,6 +69,9 @@ void NoiseTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_normalmap", "as_normalmap"), &NoiseTexture::set_as_normalmap); ClassDB::bind_method(D_METHOD("is_normalmap"), &NoiseTexture::is_normalmap); + ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength); + ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength); + ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture); ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture); ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done); @@ -76,9 +80,19 @@ void NoiseTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "seamless"), "set_seamless", "get_seamless"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normalmap"), "set_as_normalmap", "is_normalmap"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise"); } +void NoiseTexture::_validate_property(PropertyInfo &property) const { + + if (property.name == "bump_strength") { + if (!as_normalmap) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } +} + void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) { data = p_image; if (data.is_valid()) { @@ -129,7 +143,7 @@ Ref<Image> NoiseTexture::_generate_texture() { } if (as_normalmap) { - image->bumpmap_to_normalmap(); + image->bumpmap_to_normalmap(bump_strength); } return image; @@ -202,12 +216,26 @@ void NoiseTexture::set_as_normalmap(bool p_as_normalmap) { if (p_as_normalmap == as_normalmap) return; as_normalmap = p_as_normalmap; _queue_update(); + _change_notify(); } bool NoiseTexture::is_normalmap() { return as_normalmap; } +void NoiseTexture::set_bump_strength(float p_bump_strength) { + + if (p_bump_strength == bump_strength) return; + bump_strength = p_bump_strength; + if (as_normalmap) + _queue_update(); +} + +float NoiseTexture::get_bump_strength() { + + return bump_strength; +} + int NoiseTexture::get_width() const { return size.x; diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h index d1705f4070..0d00ee154d 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/opensimplex/noise_texture.h @@ -58,6 +58,7 @@ private: Vector2i size; bool seamless; bool as_normalmap; + float bump_strength; void _thread_done(const Ref<Image> &p_image); static void _thread_function(void *p_ud); @@ -69,6 +70,7 @@ private: protected: static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const; public: void set_noise(Ref<OpenSimplexNoise> p_noise); @@ -83,6 +85,9 @@ public: void set_as_normalmap(bool p_seamless); bool is_normalmap(); + void set_bump_strength(float p_bump_strength); + float get_bump_strength(); + int get_width() const; int get_height() const; diff --git a/modules/opus/SCsub b/modules/opus/SCsub index cd5da75bab..b72144c679 100644 --- a/modules/opus/SCsub +++ b/modules/opus/SCsub @@ -138,7 +138,7 @@ if env['builtin_opus']: opus_sources_silk = [] - if("opus_fixed_point" in env and env.opus_fixed_point == "yes"): + if env["platform"] in ["android", "iphone", "javascript"]: env_opus.Append(CFLAGS=["-DFIXED_POINT"]) opus_sources_silk = [ "silk/fixed/LTP_analysis_filter_FIX.c", @@ -220,6 +220,17 @@ if env['builtin_opus']: ] env_opus.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths]) + if env["platform"] == "android": + if ("android_arch" in env and env["android_arch"] in ["armv6", "armv7"]): + env_opus.Append(CFLAGS=["-DOPUS_ARM_OPT"]) + elif ("android_arch" in env and env["android_arch"] == "arm64v8"): + env_opus.Append(CFLAGS=["-DOPUS_ARM64_OPT"]) + elif env["platform"] == "iphone": + if ("arch" in env and env["arch"] == "arm"): + env_opus.Append(CFLAGS=["-DOPUS_ARM_OPT"]) + elif ("arch" in env and env["arch"] == "arm64"): + env_opus.Append(CFLAGS=["-DOPUS_ARM64_OPT"]) + env_thirdparty = env_opus.Clone() env_thirdparty.disable_warnings() env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index 75e8903ff8..20857572f3 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RegEx" inherits="Reference" category="Core" version="3.1"> +<class name="RegEx" inherits="Reference" category="Core" version="3.2"> <brief_description> Class for searching text for patterns using regular expressions. </brief_description> diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml index 3d070d2786..9efec91bdc 100644 --- a/modules/regex/doc_classes/RegExMatch.xml +++ b/modules/regex/doc_classes/RegExMatch.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RegExMatch" inherits="Reference" category="Core" version="3.1"> +<class name="RegExMatch" inherits="Reference" category="Core" version="3.2"> <brief_description> Contains the results of a regex search. </brief_description> diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml index e2281babf7..574ff1ff2a 100644 --- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core" version="3.1"> +<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core" version="3.2"> <brief_description> OGG Vorbis audio stream driver. </brief_description> diff --git a/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml b/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml index 018f4734ec..ade485e717 100644 --- a/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml +++ b/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ResourceImporterOGGVorbis" inherits="ResourceImporter" category="Core" version="3.1"> +<class name="ResourceImporterOGGVorbis" inherits="ResourceImporter" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml index e7c4727332..2bd8ad862f 100644 --- a/modules/theora/doc_classes/VideoStreamTheora.xml +++ b/modules/theora/doc_classes/VideoStreamTheora.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VideoStreamTheora" inherits="VideoStream" category="Core" version="3.1"> +<class name="VideoStreamTheora" inherits="VideoStream" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index e69d9a0ae3..bd84a28c84 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -107,22 +107,31 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f } } - if (idxR == -1) { - ERR_PRINT("TinyEXR: R channel not found."); - // @todo { free exr_image } - return ERR_FILE_CORRUPT; - } + if (exr_header.num_channels == 1) { + // Grayscale channel only. + idxR = 0; + idxG = 0; + idxB = 0; + idxA = 0; + } else { + // Assume RGB(A) + if (idxR == -1) { + ERR_PRINT("TinyEXR: R channel not found."); + // @todo { free exr_image } + return ERR_FILE_CORRUPT; + } - if (idxG == -1) { - ERR_PRINT("TinyEXR: G channel not found.") - // @todo { free exr_image } - return ERR_FILE_CORRUPT; - } + if (idxG == -1) { + ERR_PRINT("TinyEXR: G channel not found.") + // @todo { free exr_image } + return ERR_FILE_CORRUPT; + } - if (idxB == -1) { - ERR_PRINT("TinyEXR: B channel not found.") - // @todo { free exr_image } - return ERR_FILE_CORRUPT; + if (idxB == -1) { + ERR_PRINT("TinyEXR: B channel not found.") + // @todo { free exr_image } + return ERR_FILE_CORRUPT; + } } // EXR image data loaded, now parse it into Godot-friendly image data diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml index b98327c60d..0f967c993b 100644 --- a/modules/upnp/doc_classes/UPNP.xml +++ b/modules/upnp/doc_classes/UPNP.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UPNP" inherits="Reference" category="Core" version="3.1"> +<class name="UPNP" inherits="Reference" category="Core" version="3.2"> <brief_description> UPNP network functions. </brief_description> diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index 9de8042daf..c9b695a651 100644 --- a/modules/upnp/doc_classes/UPNPDevice.xml +++ b/modules/upnp/doc_classes/UPNPDevice.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UPNPDevice" inherits="Reference" category="Core" version="3.1"> +<class name="UPNPDevice" inherits="Reference" category="Core" version="3.2"> <brief_description> UPNP device. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml index 70849c5a80..f4a9bc68e6 100644 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ b/modules/visual_script/doc_classes/VisualScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScript" inherits="Script" category="Core" version="3.1"> +<class name="VisualScript" inherits="Script" category="Core" version="3.2"> <brief_description> A script implemented in the Visual Script programming environment. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml index 5ec155fbc6..ce49cdf3a0 100644 --- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node representing a constant from the base types. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml index 3a1d773058..dd14d60327 100644 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node used to call built-in functions. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml index dc9044e9ed..32b5924cdc 100644 --- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptClassConstant" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptClassConstant" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Gets a constant from a given class. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml index a4a890ea8a..990e0ecb85 100644 --- a/modules/visual_script/doc_classes/VisualScriptComment.xml +++ b/modules/visual_script/doc_classes/VisualScriptComment.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptComment" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptComment" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node used to annotate the script. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml index a7b1028c0c..94c075205d 100644 --- a/modules/visual_script/doc_classes/VisualScriptCondition.xml +++ b/modules/visual_script/doc_classes/VisualScriptCondition.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCondition" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptCondition" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node which branches the flow. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml index ed633c4135..0fc4e87db4 100644 --- a/modules/visual_script/doc_classes/VisualScriptConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptConstant" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptConstant" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Gets a contant's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml index 14c44c6970..05fc3f318d 100644 --- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml +++ b/modules/visual_script/doc_classes/VisualScriptConstructor.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptConstructor" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptConstructor" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node which calls a base type constructor. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml index ff3ed66e81..0ad4e7c1f5 100644 --- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCustomNode" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptCustomNode" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A scripted Visual Script node. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml index d3158df357..b933a25f1d 100644 --- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml +++ b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node which deconstructs a base type instance into its parts. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptEditor.xml b/modules/visual_script/doc_classes/VisualScriptEditor.xml index fc49cfc07b..be4606b57c 100644 --- a/modules/visual_script/doc_classes/VisualScriptEditor.xml +++ b/modules/visual_script/doc_classes/VisualScriptEditor.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.1"> +<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml index 4bb05525bd..3282269811 100644 --- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Emits a specified signal. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml index 93d7ce3516..3e52fb818c 100644 --- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml +++ b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> A Visual Script node returning a singleton from [@GlobalScope] </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml index 343e83cb55..4760685bfb 100644 --- a/modules/visual_script/doc_classes/VisualScriptExpression.xml +++ b/modules/visual_script/doc_classes/VisualScriptExpression.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptExpression" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptExpression" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml index ec8e955cf7..dc021196cd 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunction.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunction.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunction" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptFunction" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml index f6116cf539..e978437542 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml index c75dd0cdbc..a5e15b8da2 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionState" inherits="Reference" category="Core" version="3.1"> +<class name="VisualScriptFunctionState" inherits="Reference" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml index 9d43204f02..2d609ed262 100644 --- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml index 73c1f47e1a..16499e9ec9 100644 --- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIndexGet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptIndexGet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml index 652c29a9ac..06844ac4ae 100644 --- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIndexSet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptIndexSet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml index ab4c23012b..01887e0764 100644 --- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml +++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptInputAction" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptInputAction" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml index 7090621bd7..496c24dee4 100644 --- a/modules/visual_script/doc_classes/VisualScriptIterator.xml +++ b/modules/visual_script/doc_classes/VisualScriptIterator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Steps through items in a given input. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml index 5c8ee6453c..cd7286b59b 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLocalVar" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptLocalVar" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Gets a local variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml index f2e6c48907..f8fe2f4b6b 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Changes a local variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml index d456e880b7..733b48203d 100644 --- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptMathConstant" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptMathConstant" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Commonly used mathematical constants. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml index 941a0cd91a..86bd469d5c 100644 --- a/modules/visual_script/doc_classes/VisualScriptNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptNode" inherits="Resource" category="Core" version="3.1"> +<class name="VisualScriptNode" inherits="Resource" category="Core" version="3.2"> <brief_description> A node which is part of a [VisualScript]. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml index e60d50c977..d722477653 100644 --- a/modules/visual_script/doc_classes/VisualScriptOperator.xml +++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptOperator" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptOperator" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml index 5a2886ccac..b811252c42 100644 --- a/modules/visual_script/doc_classes/VisualScriptPreload.xml +++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Creates a new [Resource] or loads one from the filesystem. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml index 60cc8fdd4f..7f652b7012 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml index 8f29e9d152..ef9938c6a7 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPropertySet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptPropertySet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml index f6300e03f0..2a5c56cf69 100644 --- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml +++ b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptResourcePath" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptResourcePath" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml index 0ca3e3b612..7daddc7639 100644 --- a/modules/visual_script/doc_classes/VisualScriptReturn.xml +++ b/modules/visual_script/doc_classes/VisualScriptReturn.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptReturn" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptReturn" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Exits a function and returns an optional value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml index 7704eaba04..8604a0f5eb 100644 --- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSceneNode" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSceneNode" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Node reference. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml index 2c2af9262d..72a2faaa78 100644 --- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml +++ b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSceneTree" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSceneTree" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml index 0731fc77e1..c87f77ea65 100644 --- a/modules/visual_script/doc_classes/VisualScriptSelect.xml +++ b/modules/visual_script/doc_classes/VisualScriptSelect.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Chooses between two input values. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml index 61a73e104c..42c75e56a6 100644 --- a/modules/visual_script/doc_classes/VisualScriptSelf.xml +++ b/modules/visual_script/doc_classes/VisualScriptSelf.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSelf" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSelf" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Outputs a reference to the current instance. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml index c71e068045..c26c72dd50 100644 --- a/modules/visual_script/doc_classes/VisualScriptSequence.xml +++ b/modules/visual_script/doc_classes/VisualScriptSequence.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSequence" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSequence" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Executes a series of Sequence ports. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml index 46aeebab9c..712b4ed09b 100644 --- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSubCall" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSubCall" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml index a00811a29b..0053733b34 100644 --- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml +++ b/modules/visual_script/doc_classes/VisualScriptSwitch.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSwitch" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptSwitch" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Branches program flow based on a given input's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml index 0bdc4ce89d..85b3980e21 100644 --- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml +++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptTypeCast" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptTypeCast" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml index 06178a399d..27bf223aac 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Gets a variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml index 5969f25060..c55c72d55e 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Changes a variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml index b9e7f6a553..b7ed56e7d2 100644 --- a/modules/visual_script/doc_classes/VisualScriptWhile.xml +++ b/modules/visual_script/doc_classes/VisualScriptWhile.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> Conditional loop. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml index c4698f746a..5aa0f76a55 100644 --- a/modules/visual_script/doc_classes/VisualScriptYield.xml +++ b/modules/visual_script/doc_classes/VisualScriptYield.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptYield" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptYield" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml index b67e4ab1b8..8e3b2aec1d 100644 --- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" category="Core" version="3.1"> +<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 2c89e5a35c..581809fec9 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -48,22 +48,12 @@ bool VisualScriptNode::is_breakpoint() const { void VisualScriptNode::_notification(int p_what) { if (p_what == NOTIFICATION_POSTINITIALIZE) { - _update_input_ports(); - } -} - -void VisualScriptNode::_update_input_ports() { - default_input_values.resize(MAX(default_input_values.size(), get_input_value_port_count())); //let it grow as big as possible, we don't want to lose values on resize - int port_count = get_input_value_port_count(); - for (int i = 0; i < port_count; i++) { - Variant::Type expected = get_input_value_port_info(i).type; - Variant::CallError ce; - set_default_input_value(i, Variant::construct(expected, NULL, 0, ce, false)); + validate_input_default_values(); } } void VisualScriptNode::ports_changed_notify() { - _update_input_ports(); + validate_input_default_values(); emit_signal("ports_changed"); } @@ -92,8 +82,7 @@ void VisualScriptNode::_set_default_input_values(Array p_values) { } void VisualScriptNode::validate_input_default_values() { - - default_input_values.resize(get_input_value_port_count()); + default_input_values.resize(MAX(default_input_values.size(), get_input_value_port_count())); //let it grow as big as possible, we don't want to lose values on resize //actually validate on save for (int i = 0; i < get_input_value_port_count(); i++) { @@ -119,8 +108,10 @@ void VisualScriptNode::validate_input_default_values() { Array VisualScriptNode::_get_default_input_values() const { //validate on save, since on load there is little info about this + Array values = default_input_values; + values.resize(get_input_value_port_count()); - return default_input_values; + return values; } String VisualScriptNode::get_text() const { diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 0768ff61f7..0171b8e6f1 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -52,7 +52,6 @@ class VisualScriptNode : public Resource { Array _get_default_input_values() const; void validate_input_default_values(); - void _update_input_ports(); protected: void _notification(int p_what); diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 9f2d1a49c0..0d379205e4 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -183,10 +183,10 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case TEXT_PRINTRAW: case VAR_TO_STR: case STR_TO_VAR: - case VAR_TO_BYTES: - case BYTES_TO_VAR: case TYPE_EXISTS: return 1; + case VAR_TO_BYTES: + case BYTES_TO_VAR: case MATH_ATAN2: case MATH_FMOD: case MATH_FPOSMOD: @@ -491,12 +491,18 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::STRING, "string"); } break; case VAR_TO_BYTES: { - return PropertyInfo(Variant::NIL, "var"); + if (p_idx == 0) + return PropertyInfo(Variant::NIL, "var"); + else + return PropertyInfo(Variant::BOOL, "full_objects"); } break; case BYTES_TO_VAR: { - return PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes"); + if (p_idx == 0) + return PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes"); + else + return PropertyInfo(Variant::BOOL, "allow_objects"); } break; case COLORN: { @@ -655,11 +661,15 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } break; case VAR_TO_BYTES: { - t = Variant::POOL_BYTE_ARRAY; + if (p_idx == 0) + t = Variant::POOL_BYTE_ARRAY; + else + t = Variant::BOOL; } break; case BYTES_TO_VAR: { - + if (p_idx == 1) + t = Variant::BOOL; } break; case COLORN: { t = Variant::COLOR; @@ -1192,9 +1202,16 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in } break; case VisualScriptBuiltinFunc::VAR_TO_BYTES: { + if (p_inputs[1]->get_type() != Variant::BOOL) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::BOOL; + return; + } PoolByteArray barr; int len; - Error err = encode_variant(*p_inputs[0], NULL, len); + bool full_objects = *p_inputs[1]; + Error err = encode_variant(*p_inputs[0], NULL, len, full_objects); if (err) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -1206,7 +1223,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in barr.resize(len); { PoolByteArray::Write w = barr.write(); - encode_variant(*p_inputs[0], w.ptr(), len); + encode_variant(*p_inputs[0], w.ptr(), len, full_objects); } *r_return = barr; } break; @@ -1216,15 +1233,21 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::POOL_BYTE_ARRAY; - + return; + } + if (p_inputs[1]->get_type() != Variant::BOOL) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::BOOL; return; } PoolByteArray varr = *p_inputs[0]; + bool allow_objects = *p_inputs[1]; Variant ret; { PoolByteArray::Read r = varr.read(); - Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects); if (err != OK) { r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 7dba8fd488..bb0435a679 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -129,9 +129,8 @@ StringName VisualScriptFunctionCall::_get_base_type() const { int VisualScriptFunctionCall::get_input_value_port_count() const { if (call_mode == CALL_MODE_BASIC_TYPE) { - - Vector<StringName> names = Variant::get_method_argument_names(basic_type, function); - return names.size() + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) + 1; + Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type, function); + return types.size() + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) + 1; } else { diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml index c02a7a8016..33dff0e93b 100644 --- a/modules/webm/doc_classes/VideoStreamWebm.xml +++ b/modules/webm/doc_classes/VideoStreamWebm.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VideoStreamWebm" inherits="VideoStream" category="Core" version="3.1"> +<class name="VideoStreamWebm" inherits="VideoStream" category="Core" version="3.2"> <brief_description> </brief_description> <description> diff --git a/modules/webp/SCsub b/modules/webp/SCsub index d215f19cef..fa3896c457 100644 --- a/modules/webp/SCsub +++ b/modules/webp/SCsub @@ -29,13 +29,11 @@ if env['builtin_libwebp']: "dsp/cost.c", "dsp/cost_mips32.c", "dsp/cost_mips_dsp_r2.c", + "dsp/cost_neon.c", "dsp/cost_sse2.c", "dsp/cpu.c", "dsp/dec.c", "dsp/dec_clip_tables.c", - "dsp/ssim.c", - "dsp/ssim_sse2.c", - "dsp/yuv_neon.c", "dsp/dec_mips32.c", "dsp/dec_mips_dsp_r2.c", "dsp/dec_msa.c", @@ -72,6 +70,8 @@ if env['builtin_libwebp']: "dsp/rescaler_msa.c", "dsp/rescaler_neon.c", "dsp/rescaler_sse2.c", + "dsp/ssim.c", + "dsp/ssim_sse2.c", "dsp/upsampling.c", "dsp/upsampling_mips_dsp_r2.c", "dsp/upsampling_msa.c", @@ -81,6 +81,7 @@ if env['builtin_libwebp']: "dsp/yuv.c", "dsp/yuv_mips32.c", "dsp/yuv_mips_dsp_r2.c", + "dsp/yuv_neon.c", "dsp/yuv_sse2.c", "dsp/yuv_sse41.c", "enc/alpha_enc.c", diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub index b67a836fe8..0345e533bc 100644 --- a/modules/websocket/SCsub +++ b/modules/websocket/SCsub @@ -9,85 +9,90 @@ env_lws = env_modules.Clone() if env['builtin_libwebsockets'] and not env["platform"] == "javascript": # already builtin for javascript thirdparty_dir = "#thirdparty/libwebsockets/" - helper_dir = "win32helpers/" + helper_dir = "#thirdparty/libwebsockets/win32helpers/" thirdparty_sources = [ - "core/alloc.c", - "core/context.c", - "core/libwebsockets.c", - "core/output.c", - "core/pollfd.c", - "core/service.c", - - "event-libs/poll/poll.c", - - "misc/base64-decode.c", - "misc/lejp.c", - "misc/sha-1.c", - - "roles/h1/ops-h1.c", - "roles/http/header.c", - "roles/http/client/client.c", - "roles/http/client/client-handshake.c", - "roles/http/server/fops-zip.c", - "roles/http/server/lejp-conf.c", - "roles/http/server/parsers.c", - "roles/http/server/server.c", - "roles/listen/ops-listen.c", - "roles/pipe/ops-pipe.c", - "roles/raw/ops-raw.c", - - "roles/ws/client-ws.c", - "roles/ws/client-parser-ws.c", - "roles/ws/ops-ws.c", - "roles/ws/server-ws.c", - - "tls/tls.c", - "tls/tls-client.c", - "tls/tls-server.c", - - "tls/mbedtls/wrapper/library/ssl_cert.c", - "tls/mbedtls/wrapper/library/ssl_pkey.c", - "tls/mbedtls/wrapper/library/ssl_stack.c", - "tls/mbedtls/wrapper/library/ssl_methods.c", - "tls/mbedtls/wrapper/library/ssl_lib.c", - "tls/mbedtls/wrapper/library/ssl_x509.c", - "tls/mbedtls/wrapper/platform/ssl_port.c", - "tls/mbedtls/wrapper/platform/ssl_pm.c", - "tls/mbedtls/lws-genhash.c", - "tls/mbedtls/mbedtls-client.c", - "tls/mbedtls/lws-genrsa.c", - "tls/mbedtls/ssl.c", - "tls/mbedtls/mbedtls-server.c" + "lib/core/adopt.c", + "lib/core/alloc.c", + "lib/core/connect.c", + "lib/core/context.c", + "lib/core/dummy-callback.c", + "lib/core/libwebsockets.c", + "lib/core/output.c", + "lib/core/pollfd.c", + "lib/core/service.c", + + "lib/event-libs/poll/poll.c", + + "lib/misc/base64-decode.c", + "lib/misc/lejp.c", + "lib/misc/sha-1.c", + + "lib/roles/h1/ops-h1.c", + "lib/roles/http/header.c", + "lib/roles/http/client/client.c", + "lib/roles/http/client/client-handshake.c", + "lib/roles/http/server/fops-zip.c", + "lib/roles/http/server/lejp-conf.c", + "lib/roles/http/server/parsers.c", + "lib/roles/http/server/server.c", + "lib/roles/listen/ops-listen.c", + "lib/roles/pipe/ops-pipe.c", + "lib/roles/raw-skt/ops-raw-skt.c", + "lib/roles/raw-file/ops-raw-file.c", + + "lib/roles/ws/client-ws.c", + "lib/roles/ws/client-parser-ws.c", + "lib/roles/ws/ops-ws.c", + "lib/roles/ws/server-ws.c", + + "lib/tls/tls.c", + "lib/tls/tls-client.c", + "lib/tls/tls-server.c", + + "lib/tls/mbedtls/wrapper/library/ssl_cert.c", + "lib/tls/mbedtls/wrapper/library/ssl_pkey.c", + "lib/tls/mbedtls/wrapper/library/ssl_stack.c", + "lib/tls/mbedtls/wrapper/library/ssl_methods.c", + "lib/tls/mbedtls/wrapper/library/ssl_lib.c", + "lib/tls/mbedtls/wrapper/library/ssl_x509.c", + "lib/tls/mbedtls/wrapper/platform/ssl_port.c", + "lib/tls/mbedtls/wrapper/platform/ssl_pm.c", + "lib/tls/mbedtls/lws-genhash.c", + "lib/tls/mbedtls/mbedtls-client.c", + "lib/tls/mbedtls/lws-genrsa.c", + "lib/tls/mbedtls/ssl.c", + "lib/tls/mbedtls/mbedtls-server.c" ] if env["platform"] == "android": # Builtin getifaddrs - thirdparty_sources += ["misc/getifaddrs.c"] + thirdparty_sources += ["lib/misc/getifaddrs.c"] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] if env["platform"] == "windows" or env["platform"] == "uwp": # Winsock - thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"] + thirdparty_sources += Glob(thirdparty_dir + "lib/plat/windows/*.c") + [helper_dir + src for src in ["getopt.c", "getopt_long.c", "gettimeofday.c"]] else: # Unix socket - thirdparty_sources += ["plat/lws-plat-unix.c"] - - thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + thirdparty_sources += Glob(thirdparty_dir + "lib/plat/unix/*.c") - env_lws.Append(CPPPATH=[thirdparty_dir]) + env_lws.Append(CPPPATH=[thirdparty_dir + 'include/']) if env['builtin_mbedtls']: mbedtls_includes = "#thirdparty/mbedtls/include" env_lws.Prepend(CPPPATH=[mbedtls_includes]) - wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] + wrapper_includes = ["#thirdparty/libwebsockets/lib/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] env_lws.Prepend(CPPPATH=wrapper_includes) if env["platform"] == "windows" or env["platform"] == "uwp": - env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir]) + env_lws.Append(CPPPATH=[helper_dir]) if env["platform"] == "uwp": env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"]) env_thirdparty = env_lws.Clone() env_thirdparty.disable_warnings() + env_thirdparty.Append(CPPPATH=[thirdparty_dir + 'lib/']) env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) env_lws.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml index ffb6d40e30..cb85fe864d 100644 --- a/modules/websocket/doc_classes/WebSocketClient.xml +++ b/modules/websocket/doc_classes/WebSocketClient.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" category="Core" version="3.1"> +<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" category="Core" version="3.2"> <brief_description> A WebSocket client implementation </brief_description> diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index 1a841f85ed..139480c31f 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketMultiplayerPeer" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1"> +<class name="WebSocketMultiplayerPeer" inherits="NetworkedMultiplayerPeer" category="Core" version="3.2"> <brief_description> Base class for WebSocket server and client. </brief_description> diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml index 5dda012899..3b3692dd87 100644 --- a/modules/websocket/doc_classes/WebSocketPeer.xml +++ b/modules/websocket/doc_classes/WebSocketPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketPeer" inherits="PacketPeer" category="Core" version="3.1"> +<class name="WebSocketPeer" inherits="PacketPeer" category="Core" version="3.2"> <brief_description> A class representing a specific WebSocket connection. </brief_description> diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index 2932bf782a..4740bd6dcf 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" category="Core" version="3.1"> +<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" category="Core" version="3.2"> <brief_description> A WebSocket server implementation </brief_description> diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp index 2dce0ed1f5..d09558ab22 100644 --- a/modules/websocket/lws_client.cpp +++ b/modules/websocket/lws_client.cpp @@ -34,7 +34,10 @@ #include "core/io/ip.h" #include "core/io/stream_peer_ssl.h" #include "core/project_settings.h" -#include "tls/mbedtls/wrapper/include/openssl/ssl.h" +#if defined(LWS_OPENSSL_SUPPORT) +// Not openssl, just the mbedtls wrapper +#include "openssl/ssl.h" +#endif Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) { @@ -121,6 +124,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user; switch (reason) { +#if defined(LWS_OPENSSL_SUPPORT) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: { PoolByteArray arr = StreamPeerSSL::get_project_cert_array(); if (arr.size() > 0) @@ -128,7 +132,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi else if (verify_ssl) WARN_PRINTS("No CA cert specified in project settings, SSL will not work"); } break; - +#endif case LWS_CALLBACK_CLIENT_ESTABLISHED: peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size); peer_data->peer_id = 0; diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h index 47786a87a6..057fecfb56 100644 --- a/modules/websocket/packet_buffer.h +++ b/modules/websocket/packet_buffer.h @@ -59,7 +59,7 @@ public: ERR_FAIL_V(ERR_OUT_OF_MEMORY); } #else - ERR_FAIL_COND_V(p_payload && _payload.space_left() < p_size, ERR_OUT_OF_MEMORY); + ERR_FAIL_COND_V(p_payload && (uint32_t)_payload.space_left() < p_size, ERR_OUT_OF_MEMORY); ERR_FAIL_COND_V(p_info && _packets.space_left() < 1, ERR_OUT_OF_MEMORY); #endif |