summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml9
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml6
-rw-r--r--modules/gdnative/gdnative/basis.cpp2
-rw-r--r--modules/gdnative/gdnative/string.cpp24
-rw-r--r--modules/gdnative/gdnative_api.json17
-rw-r--r--modules/gdnative/include/gdnative/array.h9
-rw-r--r--modules/gdnative/include/gdnative/basis.h11
-rw-r--r--modules/gdnative/include/gdnative/color.h9
-rw-r--r--modules/gdnative/include/gdnative/dictionary.h9
-rw-r--r--modules/gdnative/include/gdnative/node_path.h9
-rw-r--r--modules/gdnative/include/gdnative/plane.h9
-rw-r--r--modules/gdnative/include/gdnative/pool_arrays.h9
-rw-r--r--modules/gdnative/include/gdnative/quat.h9
-rw-r--r--modules/gdnative/include/gdnative/rect2.h9
-rw-r--r--modules/gdnative/include/gdnative/rect3.h9
-rw-r--r--modules/gdnative/include/gdnative/rid.h9
-rw-r--r--modules/gdnative/include/gdnative/string.h10
-rw-r--r--modules/gdnative/include/gdnative/string_name.h9
-rw-r--r--modules/gdnative/include/gdnative/transform.h9
-rw-r--r--modules/gdnative/include/gdnative/transform2d.h9
-rw-r--r--modules/gdnative/include/gdnative/variant.h9
-rw-r--r--modules/gdnative/include/gdnative/vector2.h9
-rw-r--r--modules/gdnative/include/gdnative/vector3.h9
-rw-r--r--modules/gdnative/include/nativearvr/godot_nativearvr.h1
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h1
-rw-r--r--modules/gdnative/nativearvr/arvr_interface_gdnative.cpp12
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp7
-rw-r--r--modules/gdnative/nativescript/nativescript.h3
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp5
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp5
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h3
-rw-r--r--modules/gdnative/register_types.cpp5
-rw-r--r--modules/gdscript/gd_editor.cpp15
-rw-r--r--modules/gdscript/gd_functions.cpp22
-rw-r--r--modules/gdscript/gd_functions.h2
-rw-r--r--modules/gdscript/gd_parser.cpp3
-rw-r--r--modules/gdscript/gd_script.cpp5
-rw-r--r--modules/gdscript/gd_script.h2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml20
-rw-r--r--modules/gridmap/grid_map.cpp33
-rw-r--r--modules/gridmap/grid_map.h5
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/mobile_vr/mobile_interface.h2
-rw-r--r--modules/mono/SCsub141
-rw-r--r--modules/mono/config.py87
-rw-r--r--modules/mono/csharp_script.cpp111
-rw-r--r--modules/mono/csharp_script.h13
-rw-r--r--modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs66
-rw-r--r--modules/mono/editor/bindings_generator.cpp1184
-rw-r--r--modules/mono/editor/bindings_generator.h7
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp97
-rw-r--r--modules/mono/editor/godotsharp_builds.h9
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp72
-rw-r--r--modules/mono/editor/godotsharp_editor.h24
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp37
-rw-r--r--modules/mono/editor/mono_bottom_panel.h4
-rw-r--r--modules/mono/godotsharp_dirs.cpp9
-rw-r--r--modules/mono/mono_gc_handle.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp31
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp9
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp16
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp41
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h4
-rw-r--r--modules/mono/mono_reg_utils.py94
-rw-r--r--modules/mono/utils/path_utils.cpp6
-rw-r--r--modules/opus/audio_stream_opus.cpp6
-rw-r--r--modules/opus/audio_stream_opus.h2
-rw-r--r--modules/regex/SCsub2
-rw-r--r--modules/visual_script/visual_script.cpp9
-rw-r--r--modules/visual_script/visual_script.h3
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp49
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h3
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp4
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp8
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h2
77 files changed, 1691 insertions, 844 deletions
diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
index 74f71ff603..308a7d5946 100644
--- a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
+++ b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
@@ -11,15 +11,6 @@
<demos>
</demos>
<methods>
- <method name="set_gdnative_library">
- <return type="void">
- </return>
- <argument index="0" name="library" type="GDNativeLibrary">
- </argument>
- <description>
- Bind this GDNative library to our interface. The library must be a GDNative ARVR Interface for this to work.
- </description>
- </method>
</methods>
<constants>
</constants>
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
index ba813c4564..83a1cf06f0 100644
--- a/modules/gdnative/doc_classes/GDNative.xml
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -12,11 +12,11 @@
<method name="call_native">
<return type="Variant">
</return>
- <argument index="0" name="procedure_name" type="String">
+ <argument index="0" name="calling_type" type="String">
</argument>
- <argument index="1" name="arguments" type="String">
+ <argument index="1" name="procedure_name" type="String">
</argument>
- <argument index="2" name="arg2" type="Array">
+ <argument index="2" name="arguments" type="Array">
</argument>
<description>
</description>
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index b1327cdaef..28af93f942 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -172,7 +172,7 @@ void GDAPI godot_basis_new_with_euler_quat(godot_basis *r_dest, const godot_quat
}
// p_elements is a pointer to an array of 3 (!!) vector3
-void GDAPI godot_basis_get_elements(godot_basis *p_self, godot_vector3 *p_elements) {
+void GDAPI godot_basis_get_elements(const godot_basis *p_self, godot_vector3 *p_elements) {
const Basis *self = (const Basis *)p_self;
Vector3 *elements = (Vector3 *)p_elements;
elements[0] = self->elements[0];
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 905c513d9d..619003083d 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -65,11 +65,20 @@ void GDAPI godot_string_new_unicode_data(godot_string *r_dest, const wchar_t *p_
void GDAPI godot_string_get_data(const godot_string *p_self, char *p_dest, int *p_size) {
String *self = (String *)p_self;
- if (p_size != NULL) {
- *p_size = self->utf8().length();
- }
- if (p_dest != NULL) {
- memcpy(p_dest, self->utf8().get_data(), *p_size);
+
+ if (p_size) {
+ // we have a length pointer, that means we either want to know
+ // the length or want to write *p_size bytes into a buffer
+
+ CharString utf8_string = self->utf8();
+
+ int len = utf8_string.length();
+
+ if (p_dest) {
+ memcpy(p_dest, utf8_string.get_data(), *p_size);
+ } else {
+ *p_size = len;
+ }
}
}
@@ -78,6 +87,11 @@ wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int
return &(self->operator[](p_idx));
}
+wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx) {
+ const String *self = (const String *)p_self;
+ return self->operator[](p_idx);
+}
+
const char GDAPI *godot_string_c_str(const godot_string *p_self) {
const String *self = (const String *)p_self;
return self->utf8().get_data();
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 31b021b751..3a92afd7ab 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -847,7 +847,7 @@
"name": "godot_basis_get_elements",
"return_type": "void",
"arguments": [
- ["godot_basis *", "p_self"],
+ ["const godot_basis *", "p_self"],
["godot_vector3 *", "p_elements"]
]
},
@@ -3927,6 +3927,14 @@
]
},
{
+ "name": "godot_string_operator_index_const",
+ "return_type": "wchar_t",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
"name": "godot_string_c_str",
"return_type": "const char *",
"arguments": [
@@ -5308,6 +5316,13 @@
["godot_real", "p_value"],
["godot_bool", "p_can_be_negative"]
]
+ },
+ {
+ "name": "godot_arvr_get_controller_rumble",
+ "return_type": "godot_real",
+ "arguments": [
+ ["godot_int", "p_controller_id"]
+ ]
}
]
}
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index edab028cba..d0639589b7 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -46,11 +46,20 @@ typedef struct {
} godot_array;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/pool_arrays.h>
#include <gdnative/variant.h>
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_array_new(godot_array *r_dest);
void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src);
void GDAPI godot_array_new_pool_color_array(godot_array *r_dest, const godot_pool_color_array *p_pca);
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index 8ff6a6f541..49ca765a01 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -45,10 +45,19 @@ typedef struct {
} godot_basis;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/quat.h>
#include <gdnative/vector3.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis);
void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi);
void GDAPI godot_basis_new_with_euler(godot_basis *r_dest, const godot_vector3 *p_euler);
@@ -88,7 +97,7 @@ void GDAPI godot_basis_new(godot_basis *r_dest);
void GDAPI godot_basis_new_with_euler_quat(godot_basis *r_dest, const godot_quat *p_euler);
// p_elements is a pointer to an array of 3 (!!) vector3
-void GDAPI godot_basis_get_elements(godot_basis *p_self, godot_vector3 *p_elements);
+void GDAPI godot_basis_get_elements(const godot_basis *p_self, godot_vector3 *p_elements);
godot_vector3 GDAPI godot_basis_get_axis(const godot_basis *p_self, const godot_int p_axis);
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index 14265466b9..857e86a738 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -45,9 +45,18 @@ typedef struct {
} godot_color;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a);
void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b);
diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h
index c85c3f3830..e68d0fdc29 100644
--- a/modules/gdnative/include/gdnative/dictionary.h
+++ b/modules/gdnative/include/gdnative/dictionary.h
@@ -45,10 +45,19 @@ typedef struct {
} godot_dictionary;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/array.h>
#include <gdnative/gdnative.h>
#include <gdnative/variant.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_dictionary_new(godot_dictionary *r_dest);
void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src);
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self);
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 0cfdbc1127..42446175d8 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -45,9 +45,18 @@ typedef struct {
} godot_node_path;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from);
void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src);
void GDAPI godot_node_path_destroy(godot_node_path *p_self);
diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h
index 6a8915e08b..dddd172122 100644
--- a/modules/gdnative/include/gdnative/plane.h
+++ b/modules/gdnative/include/gdnative/plane.h
@@ -45,9 +45,18 @@ typedef struct {
} godot_plane;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/vector3.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d);
void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3);
void GDAPI godot_plane_new_with_normal(godot_plane *r_dest, const godot_vector3 *p_normal, const godot_real p_d);
diff --git a/modules/gdnative/include/gdnative/pool_arrays.h b/modules/gdnative/include/gdnative/pool_arrays.h
index cb1095ee8c..93181f2a6b 100644
--- a/modules/gdnative/include/gdnative/pool_arrays.h
+++ b/modules/gdnative/include/gdnative/pool_arrays.h
@@ -113,6 +113,11 @@ typedef struct {
} godot_pool_color_array;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/array.h>
#include <gdnative/color.h>
#include <gdnative/vector2.h>
@@ -120,6 +125,10 @@ typedef struct {
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// byte
void GDAPI godot_pool_byte_array_new(godot_pool_byte_array *r_dest);
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index 4ffb96eb26..acae6e3e90 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -45,9 +45,18 @@ typedef struct {
} godot_quat;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/vector3.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w);
void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle);
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index 9e6cf60342..1c66443d4f 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -43,9 +43,18 @@ typedef struct godot_rect2 {
} godot_rect2;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/vector2.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size);
void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height);
diff --git a/modules/gdnative/include/gdnative/rect3.h b/modules/gdnative/include/gdnative/rect3.h
index f94b6fea25..f603a9268a 100644
--- a/modules/gdnative/include/gdnative/rect3.h
+++ b/modules/gdnative/include/gdnative/rect3.h
@@ -45,10 +45,19 @@ typedef struct {
} godot_rect3;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/plane.h>
#include <gdnative/vector3.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size);
godot_vector3 GDAPI godot_rect3_get_position(const godot_rect3 *p_self);
diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h
index d9b5336fc9..caa1bb967e 100644
--- a/modules/gdnative/include/gdnative/rid.h
+++ b/modules/gdnative/include/gdnative/rid.h
@@ -45,8 +45,17 @@ typedef struct {
} godot_rid;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_rid_new(godot_rid *r_dest);
godot_int GDAPI godot_rid_get_id(const godot_rid *p_self);
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index aca23a81d8..29510313c9 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -46,9 +46,18 @@ typedef struct {
} godot_string;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/variant.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
void GDAPI godot_string_new_data(godot_string *r_dest, const char *p_contents, const int p_size);
@@ -57,6 +66,7 @@ void GDAPI godot_string_new_unicode_data(godot_string *r_dest, const wchar_t *p_
void GDAPI godot_string_get_data(const godot_string *p_self, char *p_dest, int *p_size);
wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx);
+wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx);
const char GDAPI *godot_string_c_str(const godot_string *p_self);
const wchar_t GDAPI *godot_string_unicode_str(const godot_string *p_self);
diff --git a/modules/gdnative/include/gdnative/string_name.h b/modules/gdnative/include/gdnative/string_name.h
index e217487250..ee9f603d20 100644
--- a/modules/gdnative/include/gdnative/string_name.h
+++ b/modules/gdnative/include/gdnative/string_name.h
@@ -46,8 +46,17 @@ typedef struct {
} godot_string_name;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_string_name_new(godot_string_name *r_dest, const godot_string *p_name);
void GDAPI godot_string_name_new_data(godot_string_name *r_dest, const char *p_name);
diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h
index 656afae129..8f50b01fb5 100644
--- a/modules/gdnative/include/gdnative/transform.h
+++ b/modules/gdnative/include/gdnative/transform.h
@@ -45,11 +45,20 @@ typedef struct {
} godot_transform;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/basis.h>
#include <gdnative/gdnative.h>
#include <gdnative/variant.h>
#include <gdnative/vector3.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin);
void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin);
diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h
index a945868b17..c68bd2963f 100644
--- a/modules/gdnative/include/gdnative/transform2d.h
+++ b/modules/gdnative/include/gdnative/transform2d.h
@@ -45,10 +45,19 @@ typedef struct {
} godot_transform2d;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/variant.h>
#include <gdnative/vector2.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos);
void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin);
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 7b804c1eaf..3d744ef1f2 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -99,6 +99,11 @@ typedef struct godot_variant_call_error {
godot_variant_type expected;
} godot_variant_call_error;
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/array.h>
#include <gdnative/basis.h>
#include <gdnative/color.h>
@@ -119,6 +124,10 @@ typedef struct godot_variant_call_error {
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v);
void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_src);
diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h
index 0af4abae27..07105abaf2 100644
--- a/modules/gdnative/include/gdnative/vector2.h
+++ b/modules/gdnative/include/gdnative/vector2.h
@@ -45,8 +45,17 @@ typedef struct {
} godot_vector2;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y);
godot_string GDAPI godot_vector2_as_string(const godot_vector2 *p_self);
diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h
index a27d516ec5..3ed23778ec 100644
--- a/modules/gdnative/include/gdnative/vector3.h
+++ b/modules/gdnative/include/gdnative/vector3.h
@@ -45,9 +45,18 @@ typedef struct {
} godot_vector3;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/basis.h>
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum {
GODOT_VECTOR3_AXIS_X,
GODOT_VECTOR3_AXIS_Y,
diff --git a/modules/gdnative/include/nativearvr/godot_nativearvr.h b/modules/gdnative/include/nativearvr/godot_nativearvr.h
index 1a8970d396..a4f4d6a9f1 100644
--- a/modules/gdnative/include/nativearvr/godot_nativearvr.h
+++ b/modules/gdnative/include/nativearvr/godot_nativearvr.h
@@ -70,6 +70,7 @@ void GDAPI godot_arvr_remove_controller(godot_int p_controller_id);
void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed);
void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative);
+godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index ec109bac83..d1c210529c 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -129,6 +129,7 @@ typedef struct {
const char **comment_delimiters; // NULL terminated array
const char **string_delimiters; // NULL terminated array
godot_bool has_named_classes;
+ godot_bool supports_builtin_mode;
godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name);
godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_pool_string_array *r_functions);
diff --git a/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp b/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp
index ff8bda162f..e2a7019fa4 100644
--- a/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp
+++ b/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp
@@ -383,4 +383,16 @@ void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p
}
}
}
+
+godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, 0.0);
+
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != NULL) {
+ return tracker->get_rumble();
+ }
+
+ return 0.0;
+}
}
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index aa1fdc32da..c1df7def2e 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -270,10 +270,6 @@ bool NativeScript::is_tool() const {
return false;
}
-String NativeScript::get_node_type() const {
- return ""; // NOTE(karroffel): uhm?
-}
-
ScriptLanguage *NativeScript::get_language() const {
return NativeScriptLanguage::get_singleton();
}
@@ -908,6 +904,9 @@ Script *NativeScriptLanguage::create_script() const {
bool NativeScriptLanguage::has_named_classes() const {
return true;
}
+bool NativeScriptLanguage::supports_builtin_mode() const {
+ return true;
+}
int NativeScriptLanguage::find_function(const String &p_function, const String &p_code) const {
return -1;
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index b5db641179..e8fc9e6880 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -142,8 +142,6 @@ public:
virtual bool is_tool() const;
- virtual String get_node_type() const;
-
virtual ScriptLanguage *get_language() const;
virtual bool has_script_signal(const StringName &p_signal) const;
@@ -271,6 +269,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() const;
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 2198e66ae4..40feb5ae43 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -28,7 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include <stdlib.h>
// Godot imports
#include "core/os/file_access.h"
#include "core/os/os.h"
@@ -134,6 +133,10 @@ bool PluginScriptLanguage::has_named_classes() const {
return _desc.has_named_classes;
}
+bool PluginScriptLanguage::supports_builtin_mode() const {
+ return _desc.supports_builtin_mode;
+}
+
int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const {
if (_desc.find_function) {
return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code);
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index a48dde97ce..79b95ff4e6 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -77,6 +77,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() const;
virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 7dd10a8bdf..4169b07f63 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -346,11 +346,6 @@ bool PluginScript::get_property_default_value(const StringName &p_property, Vari
return false;
}
-String PluginScript::get_node_type() const {
- // Even GDscript doesn't know what to put here !
- return ""; // ?
-}
-
ScriptLanguage *PluginScript::get_language() const {
return _language;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index 051ef46bae..5600bca5ef 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -31,7 +31,6 @@
#ifndef PLUGINSCRIPT_SCRIPT_H
#define PLUGINSCRIPT_SCRIPT_H
-#include <iostream>
// Godot imports
#include "core/script_language.h"
// PluginScript imports
@@ -104,8 +103,6 @@ public:
bool is_tool() const { return _tool; }
- virtual String get_node_type() const;
-
virtual ScriptLanguage *get_language() const;
virtual bool has_script_signal(const StringName &p_signal) const;
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index d2a3e29849..87f9cddaa2 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -163,7 +163,10 @@ void register_gdnative_types() {
// run singletons
- Array singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ Array singletons = Array();
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
+ singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ }
singleton_gdnatives.resize(singletons.size());
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index b0408917a4..d9b10ff3fa 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -61,7 +61,11 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str
"func _ready():\n" +
"%TS%# Called every time the node is added to the scene.\n" +
"%TS%# Initialization here\n" +
- "%TS%pass\n";
+ "%TS%pass\n\n" +
+ "#func _process(delta):\n" +
+ "#%TS%# Called every frame. Delta is time since last frame.\n" +
+ "#%TS%# Update game logic here.\n" +
+ "#%TS%pass\n";
_template = _template.replace("%BASE%", p_base_class_name);
_template = _template.replace("%TS%", _get_indentation());
@@ -127,6 +131,11 @@ bool GDScriptLanguage::has_named_classes() const {
return false;
}
+bool GDScriptLanguage::supports_builtin_mode() const {
+
+ return true;
+}
+
int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const {
GDTokenizerText tokenizer;
@@ -2102,9 +2111,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
for (List<String>::Element *E = opts.front(); E; E = E->next()) {
String opt = E->get().strip_edges();
- if (opt.begins_with("\"") && opt.ends_with("\"")) {
+ if (opt.is_quoted()) {
r_forced = true;
- String idopt = opt.substr(1, opt.length() - 2);
+ String idopt = opt.unquote();
if (idopt.replace("/", "_").is_valid_identifier()) {
options.insert(idopt);
} else {
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 34d01c6beb..b43ec409a1 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -83,6 +83,8 @@ const char *GDFunctions::get_func_name(Function p_func) {
"rad2deg",
"linear2db",
"db2linear",
+ "wrapi",
+ "wrapf",
"max",
"min",
"clamp",
@@ -405,6 +407,14 @@ void GDFunctions::call(Function p_func, const Variant **p_args, int p_arg_count,
VALIDATE_ARG_NUM(0);
r_ret = Math::db2linear((double)*p_args[0]);
} break;
+ case MATH_WRAP: {
+ VALIDATE_ARG_COUNT(3);
+ r_ret = Math::wrapi((int64_t)*p_args[0], (int64_t)*p_args[1], (int64_t)*p_args[2]);
+ } break;
+ case MATH_WRAPF: {
+ VALIDATE_ARG_COUNT(3);
+ r_ret = Math::wrapf((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
+ } break;
case LOGIC_MAX: {
VALIDATE_ARG_COUNT(2);
if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
@@ -1285,6 +1295,8 @@ bool GDFunctions::is_deterministic(Function p_func) {
case MATH_RAD2DEG:
case MATH_LINEAR2DB:
case MATH_DB2LINEAR:
+ case MATH_WRAP:
+ case MATH_WRAPF:
case LOGIC_MAX:
case LOGIC_MIN:
case LOGIC_CLAMP:
@@ -1513,6 +1525,16 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::REAL;
return mi;
} break;
+ case MATH_WRAP: {
+ MethodInfo mi("wrapi", PropertyInfo(Variant::INT, "value"), PropertyInfo(Variant::INT, "min"), PropertyInfo(Variant::INT, "max"));
+ mi.return_val.type = Variant::INT;
+ return mi;
+ } break;
+ case MATH_WRAPF: {
+ MethodInfo mi("wrapf", PropertyInfo(Variant::REAL, "value"), PropertyInfo(Variant::REAL, "min"), PropertyInfo(Variant::REAL, "max"));
+ mi.return_val.type = Variant::REAL;
+ return mi;
+ } break;
case LOGIC_MAX: {
MethodInfo mi("max", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b"));
mi.return_val.type = Variant::REAL;
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index a568c8f1cf..0de09f2e71 100644
--- a/modules/gdscript/gd_functions.h
+++ b/modules/gdscript/gd_functions.h
@@ -75,6 +75,8 @@ public:
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
+ MATH_WRAP,
+ MATH_WRAPF,
LOGIC_MAX,
LOGIC_MIN,
LOGIC_CLAMP,
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 36aaa1f807..94385dc0d0 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -1906,7 +1906,8 @@ GDParser::PatternNode *GDParser::_parse_pattern(bool p_static) {
// all the constants like strings and numbers
default: {
Node *value = _parse_and_reduce_expression(pattern, p_static);
- if (error_set) {
+ if (!value) {
+ _set_error("Expect constant expression or variables in a pattern");
return NULL;
}
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index cf6529d5ae..3f3818ffb9 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -609,11 +609,6 @@ Error GDScript::reload(bool p_keep_state) {
return OK;
}
-String GDScript::get_node_type() const {
-
- return ""; // ?
-}
-
ScriptLanguage *GDScript::get_language() const {
return GDScriptLanguage::get_singleton();
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 5e1a8b19ac..e0d142014a 100644
--- a/modules/gdscript/gd_script.h
+++ b/modules/gdscript/gd_script.h
@@ -172,7 +172,6 @@ public:
virtual Error reload(bool p_keep_state = false);
- virtual String get_node_type() const;
void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too...
Error load_source_code(const String &p_path);
Error load_byte_code(const String &p_path);
@@ -386,6 +385,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() const;
virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index ed8c27e5d0..5b0fe56f25 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -103,6 +103,18 @@
Array of [Vector3] with the non empty cell coordinates in the grid map.
</description>
</method>
+ <method name="map_to_world" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="x" type="int">
+ </argument>
+ <argument index="1" name="y" type="int">
+ </argument>
+ <argument index="2" name="z" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="resource_changed">
<return type="void">
</return>
@@ -198,6 +210,14 @@
Sets the collection of meshes for the map.
</description>
</method>
+ <method name="world_to_map" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="pos" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
<constant name="INVALID_CELL_ITEM" value="-1" enum="">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 4e8b67e4e8..cb14a5ee9c 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -333,6 +333,23 @@ int GridMap::get_cell_item_orientation(int p_x, int p_y, int p_z) const {
return cell_map[key].rot;
}
+Vector3 GridMap::world_to_map(const Vector3 &p_world_pos) const {
+ Vector3 map_pos = p_world_pos / cell_size;
+ map_pos.x = floor(map_pos.x);
+ map_pos.y = floor(map_pos.y);
+ map_pos.z = floor(map_pos.z);
+ return map_pos;
+}
+
+Vector3 GridMap::map_to_world(int p_x, int p_y, int p_z) const {
+ Vector3 offset = _get_offset();
+ Vector3 world_pos(
+ p_x * cell_size.x + offset.x,
+ p_y * cell_size.y + offset.y,
+ p_z * cell_size.z + offset.z);
+ return world_pos;
+}
+
void GridMap::_octant_transform(const OctantKey &p_key) {
ERR_FAIL_COND(!octant_map.has(p_key));
@@ -407,7 +424,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
//print_line("OCTANT, CELLS: "+itos(ii.cells.size()));
Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z);
- Vector3 ofs(cell_size.x * 0.5 * int(center_x), cell_size.y * 0.5 * int(center_y), cell_size.z * 0.5 * int(center_z));
+ Vector3 ofs = _get_offset();
Transform xform;
@@ -754,6 +771,9 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cell_item", "x", "y", "z"), &GridMap::get_cell_item);
ClassDB::bind_method(D_METHOD("get_cell_item_orientation", "x", "y", "z"), &GridMap::get_cell_item_orientation);
+ ClassDB::bind_method(D_METHOD("world_to_map", "pos"), &GridMap::world_to_map);
+ ClassDB::bind_method(D_METHOD("map_to_world", "x", "y", "z"), &GridMap::map_to_world);
+
//ClassDB::bind_method(D_METHOD("_recreate_octants"),&GridMap::_recreate_octants);
ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback);
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed);
@@ -801,7 +821,7 @@ void GridMap::set_clip(bool p_enabled, bool p_clip_above, int p_floor, Vector3::
void GridMap::set_cell_scale(float p_scale) {
cell_scale = p_scale;
- _queue_octants_dirty();
+ _recreate_octant_data();
}
float GridMap::get_cell_scale() const {
@@ -827,7 +847,7 @@ Array GridMap::get_meshes() {
if (theme.is_null())
return Array();
- Vector3 ofs(cell_size.x * 0.5 * int(center_x), cell_size.y * 0.5 * int(center_y), cell_size.z * 0.5 * int(center_z));
+ Vector3 ofs = _get_offset();
Array meshes;
for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
@@ -857,6 +877,13 @@ Array GridMap::get_meshes() {
return meshes;
}
+Vector3 GridMap::_get_offset() const {
+ return Vector3(
+ cell_size.x * 0.5 * int(center_x),
+ cell_size.y * 0.5 * int(center_y),
+ cell_size.z * 0.5 * int(center_z));
+}
+
GridMap::GridMap() {
cell_size = Vector3(2, 2, 2);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 296956ff5d..5bfdf1dac3 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -184,6 +184,8 @@ class GridMap : public Spatial {
void _clear_internal();
+ Vector3 _get_offset() const;
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -218,6 +220,9 @@ public:
int get_cell_item(int p_x, int p_y, int p_z) const;
int get_cell_item_orientation(int p_x, int p_y, int p_z) const;
+ Vector3 world_to_map(const Vector3 &p_pos) const;
+ Vector3 map_to_world(int p_x, int p_y, int p_z) const;
+
void set_clip(bool p_enabled, bool p_clip_above = true, int p_floor = 0, Vector3::Axis p_axis = Vector3::AXIS_X);
void set_cell_scale(float p_scale);
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 92d88207b3..08ac624504 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -38,7 +38,6 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
String header = f->get_token();
- print_line("HEADER: " + header);
ERR_FAIL_COND_V(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED);
while (true) {
@@ -64,8 +63,6 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
int width = f->get_line().to_int();
- print_line("HDR w: " + itos(width) + " h:" + itos(height));
-
PoolVector<uint8_t> imgdata;
imgdata.resize(height * width * sizeof(uint32_t));
@@ -102,7 +99,6 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
len <<= 8;
len |= f->get_8();
- print_line("line: " + itos(len));
if (len != width) {
ERR_EXPLAIN("invalid decoded scanline length, corrupt HDR");
ERR_FAIL_V(ERR_FILE_CORRUPT);
diff --git a/modules/mobile_vr/mobile_interface.h b/modules/mobile_vr/mobile_interface.h
index 6a5e01c163..747377ae46 100644
--- a/modules/mobile_vr/mobile_interface.h
+++ b/modules/mobile_vr/mobile_interface.h
@@ -90,7 +90,7 @@ private:
///@TODO a few support functions for trackers, most are math related and should likely be moved elsewhere
float floor_decimals(float p_value, float p_decimals) {
- float power_of_10 = pow(10.0, p_decimals);
+ float power_of_10 = pow(10.0f, p_decimals);
return floor(p_value * power_of_10) / power_of_10;
};
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index caf4fdb3ca..27e60c4623 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -53,68 +53,151 @@ if env['tools']:
vars = Variables()
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
+vars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
vars.Update(env)
# Glue sources
if env['mono_glue']:
env.add_source_files(env.modules_sources, 'glue/*.cpp')
else:
- env.Append(CPPDEFINES = [ 'MONO_GLUE_DISABLED' ])
+ env.Append(CPPDEFINES=['MONO_GLUE_DISABLED'])
if ARGUMENTS.get('yolo_copy', False):
- env.Append(CPPDEFINES = [ 'YOLO_COPY' ])
+ env.Append(CPPDEFINES=['YOLO_COPY'])
+
# Build GodotSharpTools solution
+
import os
-import subprocess
-import mono_reg_utils as monoreg
+
+
+def find_msbuild_unix(filename):
+ import os.path
+ import sys
+
+ hint_dirs = ['/opt/novell/mono/bin']
+ if sys.platform == "darwin":
+ hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin'] + hint_dirs
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, filename)
+ if os.path.isfile(hint_path):
+ return hint_path
+
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, filename)
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+ return None
+
+
+def find_msbuild_windows():
+ import mono_reg_utils as monoreg
+
+ bits = env['bits']
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if not mono_root:
+ raise RuntimeError('Cannot find mono root directory')
+
+ msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
+
+ if msbuild_tools_path:
+ return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), os.path.join(mono_root, 'lib', 'mono', '4.5'))
+ else:
+ msbuild_mono = os.path.join(mono_root, 'bin', 'msbuild.bat')
+
+ if os.path.isfile(msbuild_mono):
+ return (msbuild_mono, '')
+
+ return None
def mono_build_solution(source, target, env):
+ import subprocess
+ import mono_reg_utils as monoreg
+ from shutil import copyfile
+
+ framework_path_override = ''
+
if os.name == 'nt':
- msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
- if not msbuild_tools_path:
- raise RuntimeError('Cannot find MSBuild Tools Path in the registry')
- msbuild_path = os.path.join(msbuild_tools_path, 'MSBuild.exe')
+ msbuild_info = find_msbuild_windows()
+ if msbuild_info is None:
+ raise RuntimeError('Cannot find MSBuild executable')
+ msbuild_path = msbuild_info[0]
+ framework_path_override = msbuild_info[1]
else:
- msbuild_path = 'msbuild'
+ msbuild_path = find_msbuild_unix('msbuild')
+ if msbuild_path is None:
+ xbuild_fallback = env['xbuild_fallback']
+
+ if xbuild_fallback and os.name == 'nt':
+ print("Option 'xbuild_fallback' not supported on Windows")
+ xbuild_fallback = False
+
+ if xbuild_fallback:
+ print('Cannot find MSBuild executable, trying with xbuild')
+ print('Warning: xbuild is deprecated')
+
+ msbuild_path = find_msbuild_unix('xbuild')
+
+ if msbuild_path is None:
+ raise RuntimeError('Cannot find xbuild executable')
+ else:
+ raise RuntimeError('Cannot find MSBuild executable')
+
+ print('MSBuild path: ' + msbuild_path)
- output_path = os.path.abspath(os.path.join(str(target[0]), os.pardir))
+ build_config = 'Release'
msbuild_args = [
msbuild_path,
os.path.abspath(str(source[0])),
- '/p:Configuration=Release',
- '/p:OutputPath=' + output_path
+ '/p:Configuration=' + build_config,
]
+ if framework_path_override:
+ msbuild_args += ['/p:FrameworkPathOverride=' + framework_path_override]
+
msbuild_env = os.environ.copy()
# Needed when running from Developer Command Prompt for VS
if 'PLATFORM' in msbuild_env:
del msbuild_env['PLATFORM']
- msbuild_alt_paths = [ 'xbuild' ]
-
- while True:
- try:
- subprocess.check_call(msbuild_args, env = msbuild_env)
- break
- except subprocess.CalledProcessError:
- raise RuntimeError('GodotSharpTools build failed')
- except OSError:
- if os.name != 'nt':
- if not msbuild_alt_paths:
- raise RuntimeError('Could not find commands msbuild or xbuild')
- # Try xbuild
- msbuild_args[0] = msbuild_alt_paths.pop(0)
- else:
- raise RuntimeError('Could not find command MSBuild.exe')
+ try:
+ subprocess.check_call(msbuild_args, env=msbuild_env)
+ except subprocess.CalledProcessError:
+ raise RuntimeError('GodotSharpTools build failed')
+
+ src_dir = os.path.abspath(os.path.join(str(source[0]), os.pardir, 'bin', build_config))
+ dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
+
+ if not os.path.isdir(dst_dir):
+ if os.path.exists(dst_dir):
+ raise RuntimeError('Target directory is a file')
+ os.makedirs(dst_dir)
+
+ asm_file = 'GodotSharpTools.dll'
+
+ copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
mono_sln_builder = Builder(action = mono_build_solution)
-env.Append(BUILDERS = { 'MonoBuildSolution' : mono_sln_builder })
+env.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder})
env.MonoBuildSolution(
os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'),
'editor/GodotSharpTools/GodotSharpTools.sln'
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 13b9a4b1e6..7ad135e0b9 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -2,7 +2,6 @@
import imp
import os
import sys
-from shutil import copyfile
from SCons.Script import BoolVariable, Environment, Variables
@@ -16,8 +15,7 @@ def find_file_in_dir(directory, files, prefix='', extension=''):
for curfile in files:
if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
return curfile
-
- return None
+ return ''
def can_build(platform):
@@ -31,13 +29,32 @@ def is_enabled():
return False
+def copy_file_no_replace(src_dir, dst_dir, name):
+ from shutil import copyfile
+
+ src_path = os.path.join(src_dir, name)
+ dst_path = os.path.join(dst_dir, name)
+ need_copy = True
+
+ if not os.path.isdir(dst_dir):
+ os.mkdir(dst_dir)
+ elif os.path.exists(dst_path):
+ need_copy = False
+
+ if need_copy:
+ copyfile(src_path, dst_path)
+
+
def configure(env):
env.use_ptrcall = True
+ env.add_module_version_string("mono")
envvars = Variables()
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
envvars.Update(env)
+ bits = env['bits']
+
mono_static = env['mono_static']
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
@@ -46,18 +63,18 @@ def configure(env):
if mono_static:
raise RuntimeError('mono-static: Not supported on Windows')
- if env['bits'] == '32':
+ if bits == '32':
if os.getenv('MONO32_PREFIX'):
mono_root = os.getenv('MONO32_PREFIX')
elif os.name == 'nt':
- mono_root = monoreg.find_mono_root_dir()
+ mono_root = monoreg.find_mono_root_dir(bits)
else:
if os.getenv('MONO64_PREFIX'):
mono_root = os.getenv('MONO64_PREFIX')
elif os.name == 'nt':
- mono_root = monoreg.find_mono_root_dir()
+ mono_root = monoreg.find_mono_root_dir(bits)
- if mono_root is None:
+ if not mono_root:
raise RuntimeError('Mono installation directory not found')
mono_lib_path = os.path.join(mono_root, 'lib')
@@ -67,7 +84,7 @@ def configure(env):
mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
- if mono_lib_name is None:
+ if not mono_lib_name:
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
if os.getenv('VCINSTALLDIR'):
@@ -79,28 +96,23 @@ def configure(env):
mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
- mono_dll_src = os.path.join(mono_bin_path, mono_dll_name + '.dll')
- mono_dll_dst = os.path.join('bin', mono_dll_name + '.dll')
- copy_mono_dll = True
+ if not mono_dll_name:
+ raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
- if not os.path.isdir('bin'):
- os.mkdir('bin')
- elif os.path.exists(mono_dll_dst):
- copy_mono_dll = False
-
- if copy_mono_dll:
- copyfile(mono_dll_src, mono_dll_dst)
+ copy_file_no_replace(mono_bin_path, 'bin', mono_dll_name + '.dll')
else:
- mono_root = None
+ sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so'
+
+ mono_root = ''
- if env['bits'] == '32':
+ if bits == '32':
if os.getenv('MONO32_PREFIX'):
mono_root = os.getenv('MONO32_PREFIX')
else:
if os.getenv('MONO64_PREFIX'):
mono_root = os.getenv('MONO64_PREFIX')
- if mono_root is not None:
+ if mono_root:
mono_lib_path = os.path.join(mono_root, 'lib')
env.Append(LIBPATH=mono_lib_path)
@@ -108,7 +120,7 @@ def configure(env):
mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
- if mono_lib is None:
+ if not mono_lib:
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
env.Append(CPPFLAGS=['-D_REENTRANT'])
@@ -125,13 +137,42 @@ def configure(env):
else:
env.Append(LIBS=[mono_lib])
- env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
+ if sys.platform == "darwin":
+ env.Append(LIBS=['iconv', 'pthread'])
+ elif sys.platform == "linux" or sys.platform == "linux2":
+ env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
+
+ if not mono_static:
+ mono_so_name = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+
+ if not mono_so_name:
+ raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
+
+ copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
else:
if mono_static:
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
+ mono_lib_path = ''
+ mono_so_name = ''
+
+ tmpenv = Environment()
+ tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
+
+ for hint_dir in tmpenv['LIBPATH']:
+ name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+ if name_found:
+ mono_lib_path = hint_dir
+ mono_so_name = name_found
+ break
+
+ if not mono_so_name:
+ raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
+
+ copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+
env.Append(LINKFLAGS='-rdynamic')
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ba8c7df9cc..161e130a07 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -122,6 +122,9 @@ void CSharpLanguage::init() {
void CSharpLanguage::finish() {
+ // Release gchandle bindings before finalizing mono runtime
+ gchandle_bindings.clear();
+
if (gdmono) {
memdelete(gdmono);
gdmono = NULL;
@@ -277,17 +280,40 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin
" // Initialization here\n"
" \n"
" }\n"
+ "\n"
+ "// public override void _Process(float delta)\n"
+ "// {\n"
+ "// // Called every frame. Delta is time since last frame.\n"
+ "// // Update game logic here.\n"
+ "// \n"
+ "// }\n"
"}\n";
- script_template = script_template.replace("%BASE_CLASS_NAME%", p_base_class_name).replace("%CLASS_NAME%", p_class_name);
+ script_template = script_template.replace("%BASE_CLASS_NAME%", p_base_class_name)
+ .replace("%CLASS_NAME%", p_class_name);
Ref<CSharpScript> script;
script.instance();
script->set_source_code(script_template);
+ script->set_name(p_class_name);
return script;
}
+bool CSharpLanguage::is_using_templates() {
+
+ return true;
+}
+
+void CSharpLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {
+
+ String src = p_script->get_source_code();
+ src = src.replace("%BASE%", p_base_class_name)
+ .replace("%CLASS%", p_class_name)
+ .replace("%TS%", _get_indentation());
+ p_script->set_source_code(src);
+}
+
Script *CSharpLanguage::create_script() const {
return memnew(CSharpScript);
@@ -295,7 +321,12 @@ Script *CSharpLanguage::create_script() const {
bool CSharpLanguage::has_named_classes() const {
- return true;
+ return false;
+}
+
+bool CSharpLanguage::supports_builtin_mode() const {
+
+ return false;
}
static String variant_type_to_managed_name(const String &p_var_type_name) {
@@ -382,6 +413,25 @@ String CSharpLanguage::make_function(const String &p_class, const String &p_name
#endif
}
+String CSharpLanguage::_get_indentation() const {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0);
+
+ if (use_space_indentation) {
+ int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
+
+ String space_indent = "";
+ for (int i = 0; i < indent_size; i++) {
+ space_indent += " ";
+ }
+ return space_indent;
+ }
+ }
+#endif
+ return "\t";
+}
+
void CSharpLanguage::frame() {
const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle;
@@ -463,6 +513,7 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
(void)p_script; // UNUSED
#ifdef TOOLS_ENABLED
+ MonoReloadNode::get_singleton()->restart_reload_timer();
reload_assemblies_if_needed(p_soft_reload);
#endif
}
@@ -474,13 +525,17 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
if (proj_assembly) {
String proj_asm_path = proj_assembly->get_path();
if (!FileAccess::exists(proj_assembly->get_path())) {
// Maybe it wasn't loaded from the default path, so check this as well
- String proj_asm_name = ProjectSettings::get_singleton()->get("application/config/name");
- proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(proj_asm_name);
+ proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name);
if (!FileAccess::exists(proj_asm_path))
return; // No assembly to load
}
@@ -488,8 +543,7 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time())
return; // Already up to date
} else {
- String proj_asm_name = ProjectSettings::get_singleton()->get("application/config/name");
- if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(proj_asm_name)))
+ if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name)))
return; // No assembly to load
}
}
@@ -607,6 +661,9 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
//if instance states were saved, set them!
}
+
+ if (Engine::get_singleton()->is_editor_hint())
+ EditorNode::get_singleton()->get_property_editor()->update_tree();
}
#endif
@@ -773,6 +830,14 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
void CSharpLanguage::free_instance_binding_data(void *p_data) {
+ if (GDMono::get_singleton() == NULL) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!gchandle_bindings.empty());
+#endif
+ // Mono runtime finalized, all the gchandle bindings were already released
+ return;
+ }
+
#ifndef NO_THREADS
script_bind_lock->lock();
#endif
@@ -1390,6 +1455,34 @@ void CSharpScript::_resource_path_changed() {
}
}
+bool CSharpScript::_get(const StringName &p_name, Variant &r_ret) const {
+
+ if (p_name == CSharpLanguage::singleton->string_names._script_source) {
+
+ r_ret = get_source_code();
+ return true;
+ }
+
+ return false;
+}
+
+bool CSharpScript::_set(const StringName &p_name, const Variant &p_value) {
+
+ if (p_name == CSharpLanguage::singleton->string_names._script_source) {
+
+ set_source_code(p_value);
+ reload();
+ return true;
+ }
+
+ return false;
+}
+
+void CSharpScript::_get_property_list(List<PropertyInfo> *p_properties) const {
+
+ p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+}
+
void CSharpScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo(Variant::OBJECT, "new"));
@@ -1706,11 +1799,6 @@ Error CSharpScript::reload(bool p_keep_state) {
return ERR_FILE_MISSING_DEPENDENCIES;
}
-String CSharpScript::get_node_type() const {
-
- return ""; // ?
-}
-
ScriptLanguage *CSharpScript::get_language() const {
return CSharpLanguage::get_singleton();
@@ -1968,5 +2056,6 @@ CSharpLanguage::StringNameCache::StringNameCache() {
_set = StaticCString::create("_set");
_get = StaticCString::create("_get");
_notification = StaticCString::create("_notification");
+ _script_source = StaticCString::create("script/source");
dotctor = StaticCString::create(".ctor");
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 6b8475fb61..255665b495 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -116,6 +116,9 @@ protected:
Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
virtual void _resource_path_changed();
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ bool _set(const StringName &p_name, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_properties) const;
public:
virtual bool can_instance() const;
@@ -138,7 +141,6 @@ public:
virtual bool is_tool() const { return tool; }
virtual Ref<Script> get_base_script() const;
- virtual String get_node_type() const;
virtual ScriptLanguage *get_language() const;
/* TODO */ virtual void get_script_method_list(List<MethodInfo> *p_list) const {}
@@ -229,16 +231,17 @@ class CSharpLanguage : public ScriptLanguage {
StringName _set;
StringName _get;
StringName _notification;
+ StringName _script_source;
StringName dotctor; // .ctor
StringNameCache();
};
- StringNameCache string_names;
-
int lang_idx;
public:
+ StringNameCache string_names;
+
_FORCE_INLINE_ int get_language_index() { return lang_idx; }
void set_language_index(int p_idx);
@@ -267,12 +270,16 @@ public:
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
+ virtual bool is_using_templates();
+ virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
/* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { return true; }
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() const;
/* TODO? */ virtual int find_function(const String &p_function, const String &p_code) const { return -1; }
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
/* TODO? */ Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; }
+ virtual String _get_indentation() const;
/* TODO? */ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {}
/* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {}
diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
index 5544233eb7..04da0600cc 100644
--- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
@@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Security;
using Microsoft.Build.Framework;
@@ -12,22 +13,27 @@ namespace GodotSharpTools.Build
public class BuildInstance : IDisposable
{
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
+ private extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static string godot_icall_BuildInstance_get_MSBuildPath();
+ private extern static void godot_icall_BuildInstance_get_MSBuildInfo(ref string msbuildPath, ref string frameworkPath);
- private static string MSBuildPath
+ private struct MSBuildInfo
{
- get
- {
- string ret = godot_icall_BuildInstance_get_MSBuildPath();
+ public string path;
+ public string frameworkPathOverride;
+ }
- if (ret == null)
- throw new FileNotFoundException("Cannot find the MSBuild executable.");
+ private static MSBuildInfo GetMSBuildInfo()
+ {
+ MSBuildInfo msbuildInfo = new MSBuildInfo();
- return ret;
- }
+ godot_icall_BuildInstance_get_MSBuildInfo(ref msbuildInfo.path, ref msbuildInfo.frameworkPathOverride);
+
+ if (msbuildInfo.path == null)
+ throw new FileNotFoundException("Cannot find the MSBuild executable.");
+
+ return msbuildInfo;
}
private string solution;
@@ -48,9 +54,19 @@ namespace GodotSharpTools.Build
public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
{
- string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties);
+ MSBuildInfo msbuildInfo = GetMSBuildInfo();
+
+ List<string> customPropertiesList = new List<string>();
+
+ if (customProperties != null)
+ customPropertiesList.AddRange(customProperties);
+
+ if (msbuildInfo.frameworkPathOverride != null)
+ customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.frameworkPathOverride);
- ProcessStartInfo startInfo = new ProcessStartInfo(MSBuildPath, compilerArgs);
+ string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
+
+ ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.path, compilerArgs);
// No console output, thanks
startInfo.RedirectStandardOutput = true;
@@ -82,9 +98,19 @@ namespace GodotSharpTools.Build
if (process != null)
throw new InvalidOperationException("Already in use");
- string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties);
+ MSBuildInfo msbuildInfo = GetMSBuildInfo();
+
+ List<string> customPropertiesList = new List<string>();
+
+ if (customProperties != null)
+ customPropertiesList.AddRange(customProperties);
+
+ if (msbuildInfo.frameworkPathOverride.Length > 0)
+ customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.frameworkPathOverride);
- ProcessStartInfo startInfo = new ProcessStartInfo("msbuild", compilerArgs);
+ string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
+
+ ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.path, compilerArgs);
// No console output, thanks
startInfo.RedirectStandardOutput = true;
@@ -101,10 +127,13 @@ namespace GodotSharpTools.Build
process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
return true;
}
- private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties)
+ private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, List<string> customProperties)
{
string arguments = string.Format(@"""{0}"" /v:normal /t:Build ""/p:{1}"" ""/l:{2},{3};{4}""",
solution,
@@ -114,12 +143,9 @@ namespace GodotSharpTools.Build
loggerOutputDir
);
- if (customProperties != null)
+ foreach (string customProperty in customProperties)
{
- foreach (string customProperty in customProperties)
- {
- arguments += " /p:" + customProperty;
- }
+ arguments += " \"/p:" + customProperty + "\"";
}
return arguments;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 95e75f9103..eb504ec021 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -438,6 +438,9 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
return sln_error;
}
+ if (verbose_output)
+ OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n");
+
return OK;
}
@@ -530,6 +533,9 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
return sln_error;
}
+ if (verbose_output)
+ OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
+
return OK;
}
@@ -537,8 +543,6 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
// e.g.: warning CS0108: 'SpriteBase3D.FLAG_MAX' hides inherited member 'GeometryInstance.FLAG_MAX'. Use the new keyword if hiding was intended.
Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const String &p_output_file) {
- int method_bind_count = 0;
-
bool is_derived_type = itype.base_name.length();
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
@@ -548,51 +552,51 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
- List<String> cs_file;
+ List<String> output;
- cs_file.push_back("using System;\n"); // IntPtr
+ output.push_back("using System;\n"); // IntPtr
if (itype.requires_collections)
- cs_file.push_back("using System.Collections.Generic;\n"); // Dictionary
+ output.push_back("using System.Collections.Generic;\n"); // Dictionary
- cs_file.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
const DocData::ClassDoc *class_doc = itype.class_doc;
if (class_doc && class_doc->description.size()) {
- cs_file.push_back(INDENT1 "/// <summary>\n");
+ output.push_back(INDENT1 "/// <summary>\n");
Vector<String> description_lines = class_doc->description.split("\n");
for (int i = 0; i < description_lines.size(); i++) {
if (description_lines[i].size()) {
- cs_file.push_back(INDENT1 "/// ");
- cs_file.push_back(description_lines[i].strip_edges().xml_escape());
- cs_file.push_back("\n");
+ output.push_back(INDENT1 "/// ");
+ output.push_back(description_lines[i].strip_edges().xml_escape());
+ output.push_back("\n");
}
}
- cs_file.push_back(INDENT1 "/// </summary>\n");
+ output.push_back(INDENT1 "/// </summary>\n");
}
- cs_file.push_back(INDENT1 "public ");
- cs_file.push_back(itype.is_singleton ? "static class " : "class ");
- cs_file.push_back(itype.proxy_name);
+ output.push_back(INDENT1 "public ");
+ output.push_back(itype.is_singleton ? "static class " : "class ");
+ output.push_back(itype.proxy_name);
if (itype.is_singleton || !itype.is_object_type) {
- cs_file.push_back("\n");
+ output.push_back("\n");
} else if (!is_derived_type) {
- cs_file.push_back(" : IDisposable\n");
+ output.push_back(" : IDisposable\n");
} else if (obj_types.has(itype.base_name)) {
- cs_file.push_back(" : ");
- cs_file.push_back(obj_types[itype.base_name].proxy_name);
- cs_file.push_back("\n");
+ output.push_back(" : ");
+ output.push_back(obj_types[itype.base_name].proxy_name);
+ output.push_back("\n");
} else {
- ERR_PRINTS("Base type ' " + itype.base_name + "' does not exist");
+ ERR_PRINTS("Base type '" + itype.base_name + "' does not exist, for class " + itype.name);
return ERR_INVALID_DATA;
}
- cs_file.push_back(INDENT1 "{");
+ output.push_back(INDENT1 "{");
if (class_doc) {
@@ -602,270 +606,165 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
const DocData::ConstantDoc &const_doc = class_doc->constants[i];
if (const_doc.description.size()) {
- cs_file.push_back(MEMBER_BEGIN "/// <summary>\n");
+ output.push_back(MEMBER_BEGIN "/// <summary>\n");
Vector<String> description_lines = const_doc.description.split("\n");
for (int i = 0; i < description_lines.size(); i++) {
if (description_lines[i].size()) {
- cs_file.push_back(INDENT2 "/// ");
- cs_file.push_back(description_lines[i].strip_edges().xml_escape());
- cs_file.push_back("\n");
+ output.push_back(INDENT2 "/// ");
+ output.push_back(description_lines[i].strip_edges().xml_escape());
+ output.push_back("\n");
}
}
- cs_file.push_back(INDENT2 "/// </summary>");
+ output.push_back(INDENT2 "/// </summary>");
}
- cs_file.push_back(MEMBER_BEGIN "public const int ");
- cs_file.push_back(const_doc.name);
- cs_file.push_back(" = ");
- cs_file.push_back(const_doc.value);
- cs_file.push_back(";");
+ output.push_back(MEMBER_BEGIN "public const int ");
+ output.push_back(const_doc.name);
+ output.push_back(" = ");
+ output.push_back(const_doc.value);
+ output.push_back(";");
}
if (class_doc->constants.size())
- cs_file.push_back("\n");
+ output.push_back("\n");
// Add properties
- const Vector<DocData::PropertyDoc> &properties = itype.class_doc->properties;
+ const Vector<DocData::PropertyDoc> &properties = class_doc->properties;
for (int i = 0; i < properties.size(); i++) {
const DocData::PropertyDoc &prop_doc = properties[i];
-
- const MethodInterface *setter = itype.find_method_by_name(prop_doc.setter);
-
- // Search it in base types too
- const TypeInterface *current_type = &itype;
- while (!setter && current_type->base_name.length()) {
- Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
- ERR_FAIL_NULL_V(base_match, ERR_BUG);
- current_type = &base_match->get();
- setter = current_type->find_method_by_name(prop_doc.setter);
- }
-
- const MethodInterface *getter = itype.find_method_by_name(prop_doc.getter);
-
- // Search it in base types too
- current_type = &itype;
- while (!getter && current_type->base_name.length()) {
- Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
- ERR_FAIL_NULL_V(base_match, ERR_BUG);
- current_type = &base_match->get();
- getter = current_type->find_method_by_name(prop_doc.getter);
- }
-
- ERR_FAIL_COND_V(!setter && !getter, ERR_BUG);
-
- bool is_valid = false;
- int prop_index = ClassDB::get_property_index(itype.name, prop_doc.name, &is_valid);
- ERR_FAIL_COND_V(!is_valid, ERR_BUG);
-
- if (setter) {
- int setter_argc = prop_index != -1 ? 2 : 1;
- ERR_FAIL_COND_V(setter->arguments.size() != setter_argc, ERR_BUG);
- }
-
- if (getter) {
- int getter_argc = prop_index != -1 ? 1 : 0;
- ERR_FAIL_COND_V(getter->arguments.size() != getter_argc, ERR_BUG);
- }
-
- if (getter && setter) {
- ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG);
- }
-
- // Let's not trust PropertyDoc::type
- String proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
-
- const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name);
- if (!prop_itype) {
- // Try with underscore prefix
- prop_itype = _get_type_by_name_or_null("_" + proptype_name);
- }
-
- ERR_FAIL_NULL_V(prop_itype, ERR_BUG);
-
- String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(prop_doc.name));
-
- // Prevent property and enclosing type from sharing the same name
- if (prop_proxy_name == itype.proxy_name) {
- if (verbose_output) {
- WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" +
- itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`");
- }
-
- prop_proxy_name += "_";
- }
-
- if (prop_doc.description.size()) {
- cs_file.push_back(MEMBER_BEGIN "/// <summary>\n");
-
- Vector<String> description_lines = prop_doc.description.split("\n");
-
- for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
- cs_file.push_back(INDENT2 "/// ");
- cs_file.push_back(description_lines[i].strip_edges().xml_escape());
- cs_file.push_back("\n");
- }
- }
-
- cs_file.push_back(INDENT2 "/// </summary>");
- }
-
- cs_file.push_back(MEMBER_BEGIN "public ");
-
- if (itype.is_singleton)
- cs_file.push_back("static ");
-
- cs_file.push_back(prop_itype->cs_type);
- cs_file.push_back(" ");
- cs_file.push_back(prop_proxy_name.replace("/", "__"));
- cs_file.push_back("\n" INDENT2 OPEN_BLOCK);
-
- if (getter) {
- cs_file.push_back(INDENT3 "get\n" OPEN_BLOCK_L3);
- cs_file.push_back("return ");
- cs_file.push_back(getter->proxy_name + "(");
- if (prop_index != -1)
- cs_file.push_back(itos(prop_index));
- cs_file.push_back(");\n" CLOSE_BLOCK_L3);
- }
-
- if (setter) {
- cs_file.push_back(INDENT3 "set\n" OPEN_BLOCK_L3);
- cs_file.push_back(setter->proxy_name + "(");
- if (prop_index != -1)
- cs_file.push_back(itos(prop_index) + ", ");
- cs_file.push_back("value);\n" CLOSE_BLOCK_L3);
+ Error prop_err = _generate_cs_property(itype, prop_doc, output);
+ if (prop_err != OK) {
+ ERR_EXPLAIN("Failed to generate property '" + prop_doc.name + "' for class '" + itype.name + "'");
+ ERR_FAIL_V(prop_err);
}
-
- cs_file.push_back(CLOSE_BLOCK_L2);
}
if (class_doc->properties.size())
- cs_file.push_back("\n");
+ output.push_back("\n");
}
if (!itype.is_object_type) {
- cs_file.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"" + itype.name + "\";\n");
- cs_file.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
- cs_file.push_back(MEMBER_BEGIN "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
+ output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"" + itype.name + "\";\n");
+ output.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
+ output.push_back(MEMBER_BEGIN "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
- cs_file.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back(" instance)\n" OPEN_BLOCK_L2 "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(");
+ output.push_back(itype.proxy_name);
+ output.push_back(" instance)\n" OPEN_BLOCK_L2 "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
// Add Destructor
- cs_file.push_back(MEMBER_BEGIN "~");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "~");
+ output.push_back(itype.proxy_name);
+ output.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
// Add the Dispose from IDisposable
- cs_file.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
// Add the virtual Dispose
- cs_file.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
- "if (disposed) return;\n" INDENT3
- "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "NativeCalls.godot_icall_");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back("_Dtor(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L3 INDENT3
- "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
-
- cs_file.push_back(MEMBER_BEGIN "internal ");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back("(IntPtr " BINDINGS_PTR_FIELD ")\n" OPEN_BLOCK_L2 "this." BINDINGS_PTR_FIELD " = " BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
-
- cs_file.push_back(MEMBER_BEGIN "public bool HasValidHandle()\n" OPEN_BLOCK_L2
- "return " BINDINGS_PTR_FIELD " == IntPtr.Zero;\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
+ "if (disposed) return;\n" INDENT3
+ "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "NativeCalls.godot_icall_");
+ output.push_back(itype.proxy_name);
+ output.push_back("_Dtor(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L3 INDENT3
+ "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
+
+ output.push_back(MEMBER_BEGIN "internal ");
+ output.push_back(itype.proxy_name);
+ output.push_back("(IntPtr " BINDINGS_PTR_FIELD ")\n" OPEN_BLOCK_L2 "this." BINDINGS_PTR_FIELD " = " BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
+
+ output.push_back(MEMBER_BEGIN "public IntPtr NativeInstance\n" OPEN_BLOCK_L2
+ "get { return " BINDINGS_PTR_FIELD "; }\n" CLOSE_BLOCK_L2);
} else if (itype.is_singleton) {
// Add the type name and the singleton pointer as static fields
- cs_file.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
- cs_file.push_back(itype.name);
- cs_file.push_back("\";\n");
+ output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.push_back(itype.name);
+ output.push_back("\";\n");
- cs_file.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
- cs_file.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
- cs_file.push_back("." ICALL_PREFIX);
- cs_file.push_back(itype.name);
- cs_file.push_back(SINGLETON_ICALL_SUFFIX "();\n");
+ output.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
+ output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
+ output.push_back("." ICALL_PREFIX);
+ output.push_back(itype.name);
+ output.push_back(SINGLETON_ICALL_SUFFIX "();\n");
} else {
// Add member fields
- cs_file.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
- cs_file.push_back(itype.name);
- cs_file.push_back("\";\n");
+ output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.push_back(itype.name);
+ output.push_back("\";\n");
// Only the base class stores the pointer to the native object
// This pointer is expected to be and must be of type Object*
if (!is_derived_type) {
- cs_file.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
- cs_file.push_back(INDENT2 "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
- cs_file.push_back(INDENT2 "internal bool " CS_FIELD_MEMORYOWN ";\n");
+ output.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
+ output.push_back(INDENT2 "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
+ output.push_back(INDENT2 "internal bool " CS_FIELD_MEMORYOWN ";\n");
}
// Add default constructor
if (itype.is_instantiable) {
- cs_file.push_back(MEMBER_BEGIN "public ");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back("() : this(");
- cs_file.push_back(itype.memory_own ? "true" : "false");
+ output.push_back(MEMBER_BEGIN "public ");
+ output.push_back(itype.proxy_name);
+ output.push_back("() : this(");
+ output.push_back(itype.memory_own ? "true" : "false");
// The default constructor may also be called by the engine when instancing existing native objects
// The engine will initialize the pointer field of the managed side before calling the constructor
// This is why we only allocate a new native object from the constructor if the pointer field is not set
- cs_file.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
- cs_file.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
- cs_file.push_back("." + ctor_method);
- cs_file.push_back("(this);\n" CLOSE_BLOCK_L2);
+ output.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
+ output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
+ output.push_back("." + ctor_method);
+ output.push_back("(this);\n" CLOSE_BLOCK_L2);
} else {
// Hide the constructor
- cs_file.push_back(MEMBER_BEGIN "internal ");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back("() {}\n");
+ output.push_back(MEMBER_BEGIN "internal ");
+ output.push_back(itype.proxy_name);
+ output.push_back("() {}\n");
}
// Add.. em.. trick constructor. Sort of.
- cs_file.push_back(MEMBER_BEGIN "internal ");
- cs_file.push_back(itype.proxy_name);
+ output.push_back(MEMBER_BEGIN "internal ");
+ output.push_back(itype.proxy_name);
if (is_derived_type) {
- cs_file.push_back("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
+ output.push_back("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
} else {
- cs_file.push_back("(bool " CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L2
- "this." CS_FIELD_MEMORYOWN " = " CS_FIELD_MEMORYOWN ";\n" CLOSE_BLOCK_L2);
+ output.push_back("(bool " CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L2
+ "this." CS_FIELD_MEMORYOWN " = " CS_FIELD_MEMORYOWN ";\n" CLOSE_BLOCK_L2);
}
// Add methods
if (!is_derived_type) {
- cs_file.push_back(MEMBER_BEGIN "public bool HasValidHandle()\n" OPEN_BLOCK_L2
- "return " BINDINGS_PTR_FIELD " == IntPtr.Zero;\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "public IntPtr NativeInstance\n" OPEN_BLOCK_L2
+ "get { return " BINDINGS_PTR_FIELD "; }\n" CLOSE_BLOCK_L2);
- cs_file.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(Object instance)\n" OPEN_BLOCK_L2
- "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(Object instance)\n" OPEN_BLOCK_L2
+ "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
}
if (!is_derived_type) {
// Add destructor
- cs_file.push_back(MEMBER_BEGIN "~");
- cs_file.push_back(itype.proxy_name);
- cs_file.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "~");
+ output.push_back(itype.proxy_name);
+ output.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
// Add the Dispose from IDisposable
- cs_file.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
// Add the virtual Dispose
- cs_file.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
- "if (disposed) return;\n" INDENT3
- "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
- "if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
- " = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
- "(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD
- " = IntPtr.Zero;\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
- "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
+ "if (disposed) return;\n" INDENT3
+ "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
+ "if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
+ " = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
+ "(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD
+ " = IntPtr.Zero;\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
+ "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
Map<String, TypeInterface>::Element *array_itype = builtin_types.find("Array");
@@ -877,409 +776,387 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
Map<String, TypeInterface>::Element *object_itype = obj_types.find("Object");
if (!object_itype) {
- ERR_PRINT("BUG: Array type interface not found!");
+ ERR_PRINT("BUG: Object type interface not found!");
return ERR_BUG;
}
- cs_file.push_back(MEMBER_BEGIN "public " CS_CLASS_SIGNALAWAITER " ToSignal(");
- cs_file.push_back(object_itype->get().cs_type);
- cs_file.push_back(" source, string signal)\n" OPEN_BLOCK_L2
- "return new " CS_CLASS_SIGNALAWAITER "(source, signal, this);\n" CLOSE_BLOCK_L2);
+ output.push_back(MEMBER_BEGIN "public " CS_CLASS_SIGNALAWAITER " ToSignal(");
+ output.push_back(object_itype->get().cs_type);
+ output.push_back(" source, string signal)\n" OPEN_BLOCK_L2
+ "return new " CS_CLASS_SIGNALAWAITER "(source, signal, this);\n" CLOSE_BLOCK_L2);
}
}
Map<String, String>::Element *extra_member = extra_members.find(itype.name);
if (extra_member)
- cs_file.push_back(extra_member->get());
+ output.push_back(extra_member->get());
+ int method_bind_count = 0;
for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
const MethodInterface &imethod = E->get();
+ Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
+ if (method_err != OK) {
+ ERR_EXPLAIN("Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'");
+ ERR_FAIL_V(method_err);
+ }
+ }
- const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type);
+ if (itype.is_singleton) {
+ InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr");
- String method_bind_field = "method_bind_" + itos(method_bind_count);
+ if (!find_icall_by_name(singleton_icall.name, custom_icalls))
+ custom_icalls.push_back(singleton_icall);
+ }
- String icall_params = method_bind_field + ", " + sformat(itype.cs_in, "this");
- String arguments_sig;
- String cs_in_statements;
+ if (itype.is_instantiable) {
+ InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
- List<String> default_args_doc;
+ if (!find_icall_by_name(ctor_icall.name, custom_icalls))
+ custom_icalls.push_back(ctor_icall);
+ }
- // Retrieve information from the arguments
- for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
- const ArgumentInterface &iarg = F->get();
- const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
+ output.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
- // Add the current arguments to the signature
- // If the argument has a default value which is not a constant, we will make it Nullable
- {
- if (F != imethod.arguments.front())
- arguments_sig += ", ";
+ return _save_file(p_output_file, output);
+}
- if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
- arguments_sig += "Nullable<";
+Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output) {
- arguments_sig += arg_type->cs_type;
+ const MethodInterface *setter = p_itype.find_method_by_name(p_prop_doc.setter);
- if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
- arguments_sig += "> ";
- else
- arguments_sig += " ";
+ // Search it in base types too
+ const TypeInterface *current_type = &p_itype;
+ while (!setter && current_type->base_name.length()) {
+ Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
+ ERR_FAIL_NULL_V(base_match, ERR_BUG);
+ current_type = &base_match->get();
+ setter = current_type->find_method_by_name(p_prop_doc.setter);
+ }
- arguments_sig += iarg.name;
+ const MethodInterface *getter = p_itype.find_method_by_name(p_prop_doc.getter);
- if (iarg.default_argument.size()) {
- if (iarg.def_param_mode != ArgumentInterface::CONSTANT)
- arguments_sig += " = null";
- else
- arguments_sig += " = " + sformat(iarg.default_argument, arg_type->cs_type);
- }
- }
+ // Search it in base types too
+ current_type = &p_itype;
+ while (!getter && current_type->base_name.length()) {
+ Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
+ ERR_FAIL_NULL_V(base_match, ERR_BUG);
+ current_type = &base_match->get();
+ getter = current_type->find_method_by_name(p_prop_doc.getter);
+ }
- icall_params += ", ";
+ ERR_FAIL_COND_V(!setter && !getter, ERR_BUG);
- if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
- // The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
- // Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
- String arg_in = iarg.name;
- arg_in += "_in";
+ bool is_valid = false;
+ int prop_index = ClassDB::get_property_index(p_itype.name, p_prop_doc.name, &is_valid);
+ ERR_FAIL_COND_V(!is_valid, ERR_BUG);
- cs_in_statements += arg_type->cs_type;
- cs_in_statements += " ";
- cs_in_statements += arg_in;
- cs_in_statements += " = ";
- cs_in_statements += iarg.name;
+ if (setter) {
+ int setter_argc = prop_index != -1 ? 2 : 1;
+ ERR_FAIL_COND_V(setter->arguments.size() != setter_argc, ERR_BUG);
+ }
- if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
- cs_in_statements += ".HasValue ? ";
- else
- cs_in_statements += " != null ? ";
+ if (getter) {
+ int getter_argc = prop_index != -1 ? 1 : 0;
+ ERR_FAIL_COND_V(getter->arguments.size() != getter_argc, ERR_BUG);
+ }
- cs_in_statements += iarg.name;
+ if (getter && setter) {
+ ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG);
+ }
- if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
- cs_in_statements += ".Value : ";
- else
- cs_in_statements += " : ";
+ // Let's not trust PropertyDoc::type
+ String proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
- String def_arg = sformat(iarg.default_argument, arg_type->cs_type);
+ const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name);
+ if (!prop_itype) {
+ // Try with underscore prefix
+ prop_itype = _get_type_by_name_or_null("_" + proptype_name);
+ }
- cs_in_statements += def_arg;
- cs_in_statements += ";\n" INDENT3;
+ ERR_FAIL_NULL_V(prop_itype, ERR_BUG);
- icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
+ String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_prop_doc.name));
- default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param 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);
- }
+ // 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 + "_`");
}
- // Generate method
- {
- if (!imethod.is_virtual && !imethod.requires_object_call) {
- cs_file.push_back(MEMBER_BEGIN "private ");
- cs_file.push_back(itype.is_singleton ? "static IntPtr " : "IntPtr ");
- cs_file.push_back(method_bind_field + " = " CS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
- cs_file.push_back(imethod.name);
- cs_file.push_back("\");\n");
- }
+ prop_proxy_name += "_";
+ }
- if (imethod.method_doc && imethod.method_doc->description.size()) {
- cs_file.push_back(MEMBER_BEGIN "/// <summary>\n");
+ if (p_prop_doc.description.size()) {
+ p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
- Vector<String> description_lines = imethod.method_doc->description.split("\n");
+ Vector<String> description_lines = p_prop_doc.description.split("\n");
- for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
- cs_file.push_back(INDENT2 "/// ");
- cs_file.push_back(description_lines[i].strip_edges().xml_escape());
- cs_file.push_back("\n");
- }
- }
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ p_output.push_back(INDENT2 "/// ");
+ p_output.push_back(description_lines[i].strip_edges().xml_escape());
+ p_output.push_back("\n");
+ }
+ }
- for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
- cs_file.push_back(E->get().xml_escape());
- }
+ p_output.push_back(INDENT2 "/// </summary>");
+ }
- cs_file.push_back(INDENT2 "/// </summary>");
- }
+ p_output.push_back(MEMBER_BEGIN "public ");
- if (!imethod.is_internal) {
- cs_file.push_back(MEMBER_BEGIN "[GodotMethod(\"");
- cs_file.push_back(imethod.name);
- cs_file.push_back("\")]");
- }
+ if (p_itype.is_singleton)
+ p_output.push_back("static ");
- cs_file.push_back(MEMBER_BEGIN);
- cs_file.push_back(imethod.is_internal ? "internal " : "public ");
+ p_output.push_back(prop_itype->cs_type);
+ p_output.push_back(" ");
+ p_output.push_back(prop_proxy_name.replace("/", "__"));
+ p_output.push_back("\n" INDENT2 OPEN_BLOCK);
- if (itype.is_singleton) {
- cs_file.push_back("static ");
- } else if (imethod.is_virtual) {
- cs_file.push_back("virtual ");
- }
+ if (getter) {
+ p_output.push_back(INDENT3 "get\n" OPEN_BLOCK_L3);
+ p_output.push_back("return ");
+ p_output.push_back(getter->proxy_name + "(");
+ if (prop_index != -1)
+ p_output.push_back(itos(prop_index));
+ p_output.push_back(");\n" CLOSE_BLOCK_L3);
+ }
- cs_file.push_back(return_type->cs_type + " ");
- cs_file.push_back(imethod.proxy_name + "(");
- cs_file.push_back(arguments_sig + ")\n" OPEN_BLOCK_L2);
+ if (setter) {
+ p_output.push_back(INDENT3 "set\n" OPEN_BLOCK_L3);
+ p_output.push_back(setter->proxy_name + "(");
+ if (prop_index != -1)
+ p_output.push_back(itos(prop_index) + ", ");
+ p_output.push_back("value);\n" CLOSE_BLOCK_L3);
+ }
- if (imethod.is_virtual) {
- // Godot virtual method must be overridden, therefore we return a default value by default.
+ p_output.push_back(CLOSE_BLOCK_L2);
- if (return_type->name == "void") {
- cs_file.push_back("return;\n" CLOSE_BLOCK_L2);
- } else {
- cs_file.push_back("return default(");
- cs_file.push_back(return_type->cs_type);
- cs_file.push_back(");\n" CLOSE_BLOCK_L2);
- }
+ return OK;
+}
- continue;
- }
+Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output) {
- if (imethod.requires_object_call) {
- // Fallback to Godot's object.Call(string, params)
+ const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
- cs_file.push_back(CS_METHOD_CALL "(\"");
- cs_file.push_back(imethod.name);
- cs_file.push_back("\"");
+ String method_bind_field = "method_bind_" + itos(p_method_bind_count);
- for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
- cs_file.push_back(", ");
- cs_file.push_back(F->get().name);
- }
+ String icall_params = method_bind_field + ", " + sformat(p_itype.cs_in, "this");
+ String arguments_sig;
+ String cs_in_statements;
- cs_file.push_back(");\n" CLOSE_BLOCK_L2);
+ List<String> default_args_doc;
- continue;
- }
+ // Retrieve information from the arguments
+ for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
+ const ArgumentInterface &iarg = F->get();
+ const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
- const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&E->get());
- ERR_FAIL_NULL_V(match, ERR_BUG);
+ // Add the current arguments to the signature
+ // If the argument has a default value which is not a constant, we will make it Nullable
+ {
+ if (F != p_imethod.arguments.front())
+ arguments_sig += ", ";
- const InternalCall *im_icall = match->value();
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ arguments_sig += "Nullable<";
- String im_call = im_icall->editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS;
- im_call += "." + im_icall->name + "(" + icall_params + ");\n";
+ arguments_sig += arg_type->cs_type;
- if (imethod.arguments.size())
- cs_file.push_back(cs_in_statements);
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ arguments_sig += "> ";
+ else
+ arguments_sig += " ";
- if (return_type->name == "void") {
- cs_file.push_back(im_call);
- } else if (return_type->cs_out.empty()) {
- cs_file.push_back("return " + im_call);
- } else {
- cs_file.push_back(return_type->im_type_out);
- cs_file.push_back(" " LOCAL_RET " = ");
- cs_file.push_back(im_call);
- cs_file.push_back(INDENT3);
- cs_file.push_back(sformat(return_type->cs_out, LOCAL_RET) + "\n");
- }
+ arguments_sig += iarg.name;
- cs_file.push_back(CLOSE_BLOCK_L2);
+ if (iarg.default_argument.size()) {
+ if (iarg.def_param_mode != ArgumentInterface::CONSTANT)
+ arguments_sig += " = null";
+ else
+ arguments_sig += " = " + sformat(iarg.default_argument, arg_type->cs_type);
+ }
}
- method_bind_count++;
- }
+ icall_params += ", ";
- if (itype.is_singleton) {
- InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr");
+ if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
+ // The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
+ // Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
+ String arg_in = iarg.name;
+ arg_in += "_in";
- if (!find_icall_by_name(singleton_icall.name, custom_icalls))
- custom_icalls.push_back(singleton_icall);
- }
+ cs_in_statements += arg_type->cs_type;
+ cs_in_statements += " ";
+ cs_in_statements += arg_in;
+ cs_in_statements += " = ";
+ cs_in_statements += iarg.name;
- if (itype.is_instantiable) {
- InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ cs_in_statements += ".HasValue ? ";
+ else
+ cs_in_statements += " != null ? ";
- if (!find_icall_by_name(ctor_icall.name, custom_icalls))
- custom_icalls.push_back(ctor_icall);
- }
+ cs_in_statements += iarg.name;
- cs_file.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ cs_in_statements += ".Value : ";
+ else
+ cs_in_statements += " : ";
- return _save_file(p_output_file, cs_file);
-}
+ String def_arg = sformat(iarg.default_argument, arg_type->cs_type);
-Error BindingsGenerator::generate_glue(const String &p_output_dir) {
+ cs_in_statements += def_arg;
+ cs_in_statements += ";\n" INDENT3;
- verbose_output = true;
+ icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
- bool dir_exists = DirAccess::exists(p_output_dir);
- ERR_EXPLAIN("The output directory does not exist.");
- ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
+ default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param 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);
+ }
+ }
- List<String> cpp_file;
+ // Generate method
+ {
+ if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
+ p_output.push_back(MEMBER_BEGIN "private ");
+ p_output.push_back(p_itype.is_singleton ? "static IntPtr " : "IntPtr ");
+ p_output.push_back(method_bind_field + " = " CS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
+ p_output.push_back(p_imethod.name);
+ p_output.push_back("\");\n");
+ }
- cpp_file.push_back("#include \"" GLUE_HEADER_FILE "\"\n"
- "\n");
+ if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
+ p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
- List<const InternalCall *> generated_icall_funcs;
+ Vector<String> description_lines = p_imethod.method_doc->description.split("\n");
- for (Map<String, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) {
- const TypeInterface &itype = type_elem->get();
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ p_output.push_back(INDENT2 "/// ");
+ p_output.push_back(description_lines[i].strip_edges().xml_escape());
+ p_output.push_back("\n");
+ }
+ }
- List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
+ for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
+ p_output.push_back(E->get().xml_escape());
+ }
- OS::get_singleton()->print(String("Generating " + itype.name + "...\n").utf8());
+ p_output.push_back(INDENT2 "/// </summary>");
+ }
- String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
+ if (!p_imethod.is_internal) {
+ p_output.push_back(MEMBER_BEGIN "[GodotMethod(\"");
+ p_output.push_back(p_imethod.name);
+ p_output.push_back("\")]");
+ }
- for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
- const MethodInterface &imethod = E->get();
+ p_output.push_back(MEMBER_BEGIN);
+ p_output.push_back(p_imethod.is_internal ? "internal " : "public ");
- if (imethod.is_virtual)
- continue;
+ if (p_itype.is_singleton) {
+ p_output.push_back("static ");
+ } else if (p_imethod.is_virtual) {
+ p_output.push_back("virtual ");
+ }
- bool ret_void = imethod.return_type == "void";
+ p_output.push_back(return_type->cs_type + " ");
+ p_output.push_back(p_imethod.proxy_name + "(");
+ p_output.push_back(arguments_sig + ")\n" OPEN_BLOCK_L2);
- const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type);
+ if (p_imethod.is_virtual) {
+ // Godot virtual method must be overridden, therefore we return a default value by default.
- String argc_str = itos(imethod.arguments.size());
+ if (return_type->name == "void") {
+ p_output.push_back("return;\n" CLOSE_BLOCK_L2);
+ } else {
+ p_output.push_back("return default(");
+ p_output.push_back(return_type->cs_type);
+ p_output.push_back(");\n" CLOSE_BLOCK_L2);
+ }
- String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND ", " + itype.c_type_in + " " CS_PARAM_INSTANCE;
- String c_in_statements;
- String c_args_var_content;
+ return OK; // Won't increment method bind count
+ }
- // Get arguments information
- int i = 0;
- for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
- const ArgumentInterface &iarg = F->get();
- const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
+ if (p_imethod.requires_object_call) {
+ // Fallback to Godot's object.Call(string, params)
- String c_param_name = "arg" + itos(i + 1);
+ p_output.push_back(CS_METHOD_CALL "(\"");
+ p_output.push_back(p_imethod.name);
+ p_output.push_back("\"");
- if (imethod.is_vararg) {
- if (i < imethod.arguments.size() - 1) {
- c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name);
- c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(0, ";
- c_in_statements += sformat("&%s_in", c_param_name);
- c_in_statements += ");\n";
- }
- } else {
- if (i > 0)
- c_args_var_content += ", ";
- if (arg_type->c_in.size())
- c_in_statements += sformat(arg_type->c_in, arg_type->c_type, c_param_name);
- c_args_var_content += sformat(arg_type->c_arg_in, c_param_name);
- }
+ for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
+ p_output.push_back(", ");
+ p_output.push_back(F->get().name);
+ }
- c_func_sig += ", ";
- c_func_sig += arg_type->c_type_in;
- c_func_sig += " ";
- c_func_sig += c_param_name;
+ p_output.push_back(");\n" CLOSE_BLOCK_L2);
- i++;
- }
+ return OK; // Won't increment method bind count
+ }
- const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&E->get());
- ERR_FAIL_NULL_V(match, ERR_BUG);
+ const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ ERR_FAIL_NULL_V(match, ERR_BUG);
- const InternalCall *im_icall = match->value();
- String icall_method = im_icall->name;
+ const InternalCall *im_icall = match->value();
- if (!generated_icall_funcs.find(im_icall)) {
- generated_icall_funcs.push_back(im_icall);
+ String im_call = im_icall->editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS;
+ im_call += "." + im_icall->name + "(" + icall_params + ");\n";
- if (im_icall->editor_only)
- cpp_file.push_back("#ifdef TOOLS_ENABLED\n");
+ if (p_imethod.arguments.size())
+ p_output.push_back(cs_in_statements);
- // Generate icall function
+ if (return_type->name == "void") {
+ p_output.push_back(im_call);
+ } else if (return_type->cs_out.empty()) {
+ p_output.push_back("return " + im_call);
+ } else {
+ p_output.push_back(return_type->im_type_out);
+ p_output.push_back(" " LOCAL_RET " = ");
+ p_output.push_back(im_call);
+ p_output.push_back(INDENT3);
+ p_output.push_back(sformat(return_type->cs_out, LOCAL_RET) + "\n");
+ }
- cpp_file.push_back(ret_void ? "void " : return_type->c_type_out + " ");
- cpp_file.push_back(icall_method);
- cpp_file.push_back("(");
- cpp_file.push_back(c_func_sig);
- cpp_file.push_back(") " OPEN_BLOCK);
+ p_output.push_back(CLOSE_BLOCK_L2);
+ }
- String fail_ret = ret_void ? "" : ", " + (return_type->c_type_out.ends_with("*") ? "NULL" : return_type->c_type_out + "()");
+ p_method_bind_count++;
+ return OK;
+}
- if (!ret_void) {
- String ptrcall_return_type;
- String initialization;
+Error BindingsGenerator::generate_glue(const String &p_output_dir) {
- if (return_type->is_object_type) {
- ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type;
- initialization = return_type->is_reference ? "" : " = NULL";
- } else {
- ptrcall_return_type = return_type->c_type;
- }
+ verbose_output = true;
- cpp_file.push_back("\t" + ptrcall_return_type);
- cpp_file.push_back(" " LOCAL_RET);
- cpp_file.push_back(initialization + ";\n");
- cpp_file.push_back("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE);
- cpp_file.push_back(fail_ret);
- cpp_file.push_back(");\n");
- } else {
- cpp_file.push_back("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
- }
+ bool dir_exists = DirAccess::exists(p_output_dir);
+ ERR_EXPLAIN("The output directory does not exist.");
+ ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
- if (imethod.arguments.size()) {
- if (imethod.is_vararg) {
- String err_fail_macro = ret_void ? "ERR_FAIL_COND" : "ERR_FAIL_COND_V";
- String vararg_arg = "arg" + argc_str;
- String real_argc_str = itos(imethod.arguments.size() - 1); // Arguments count without vararg
-
- cpp_file.push_back("\tVector<Variant> varargs;\n"
- "\tint vararg_length = mono_array_length(");
- cpp_file.push_back(vararg_arg);
- cpp_file.push_back(");\n\tint total_length = ");
- cpp_file.push_back(real_argc_str);
- cpp_file.push_back(" + vararg_length;\n\t");
- cpp_file.push_back(err_fail_macro);
- cpp_file.push_back("(varargs.resize(vararg_length) != OK");
- cpp_file.push_back(fail_ret);
- cpp_file.push_back(");\n\tVector<Variant*> " C_LOCAL_PTRCALL_ARGS ";\n\t");
- cpp_file.push_back(err_fail_macro);
- cpp_file.push_back("(call_args.resize(total_length) != OK");
- cpp_file.push_back(fail_ret);
- cpp_file.push_back(");\n");
- cpp_file.push_back(c_in_statements);
- cpp_file.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
- "\t\tMonoObject* elem = mono_array_get(");
- cpp_file.push_back(vararg_arg);
- cpp_file.push_back(", MonoObject*, i);\n"
- "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
- "\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
- cpp_file.push_back(real_argc_str);
- cpp_file.push_back(" + i, &varargs[i]);\n\t" CLOSE_BLOCK);
- } else {
- cpp_file.push_back(c_in_statements);
- cpp_file.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
- cpp_file.push_back(argc_str + "] = { ");
- cpp_file.push_back(c_args_var_content + " };\n");
- }
- }
+ List<String> output;
- if (imethod.is_vararg) {
- cpp_file.push_back("\tVariant::CallError vcall_error;\n\t");
+ output.push_back("#include \"" GLUE_HEADER_FILE "\"\n"
+ "\n");
- if (!ret_void)
- cpp_file.push_back(LOCAL_RET " = ");
+ generated_icall_funcs.clear();
- cpp_file.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
- cpp_file.push_back(imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
- cpp_file.push_back(", total_length, vcall_error);\n");
- } else {
- cpp_file.push_back("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
- cpp_file.push_back(imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
- cpp_file.push_back(!ret_void ? "&" LOCAL_RET ");\n" : "NULL);\n");
- }
+ for (Map<String, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) {
+ const TypeInterface &itype = type_elem->get();
- if (!ret_void) {
- if (return_type->c_out.empty())
- cpp_file.push_back("\treturn " LOCAL_RET ";\n");
- else
- cpp_file.push_back(sformat(return_type->c_out, return_type->c_type_out, LOCAL_RET, return_type->name));
- }
+ List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
- cpp_file.push_back(CLOSE_BLOCK "\n");
+ OS::get_singleton()->print(String("Generating " + itype.name + "...\n").utf8());
- if (im_icall->editor_only)
- cpp_file.push_back("#endif // TOOLS_ENABLED\n");
+ String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
+
+ for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
+ const MethodInterface &imethod = E->get();
+ Error method_err = _generate_glue_method(itype, imethod, output);
+ if (method_err != OK) {
+ ERR_EXPLAIN("Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'");
+ ERR_FAIL_V(method_err);
}
}
@@ -1290,11 +1167,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (!find_icall_by_name(singleton_icall.name, custom_icalls))
custom_icalls.push_back(singleton_icall);
- cpp_file.push_back("Object* ");
- cpp_file.push_back(singleton_icall_name);
- cpp_file.push_back("() " OPEN_BLOCK "\treturn ProjectSettings::get_singleton()->get_singleton_object(\"");
- cpp_file.push_back(itype.proxy_name);
- cpp_file.push_back("\");\n" CLOSE_BLOCK "\n");
+ output.push_back("Object* ");
+ output.push_back(singleton_icall_name);
+ output.push_back("() " OPEN_BLOCK "\treturn ProjectSettings::get_singleton()->get_singleton_object(\"");
+ output.push_back(itype.proxy_name);
+ output.push_back("\");\n" CLOSE_BLOCK "\n");
}
if (itype.is_instantiable) {
@@ -1303,36 +1180,36 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (!find_icall_by_name(ctor_icall.name, custom_icalls))
custom_icalls.push_back(ctor_icall);
- cpp_file.push_back("Object* ");
- cpp_file.push_back(ctor_method);
- cpp_file.push_back("(MonoObject* obj) " OPEN_BLOCK
- "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
- cpp_file.push_back(itype.name);
- cpp_file.push_back("\");\n"
- "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
- "\treturn instance;\n" CLOSE_BLOCK "\n");
+ output.push_back("Object* ");
+ output.push_back(ctor_method);
+ output.push_back("(MonoObject* obj) " OPEN_BLOCK
+ "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
+ output.push_back(itype.name);
+ output.push_back("\");\n"
+ "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
+ "\treturn instance;\n" CLOSE_BLOCK "\n");
}
}
- cpp_file.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK);
- cpp_file.push_back("uint64_t get_core_api_hash() { return ");
- cpp_file.push_back(itos(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
- cpp_file.push_back("#ifdef TOOLS_ENABLED\n"
- "uint64_t get_editor_api_hash() { return ");
- cpp_file.push_back(itos(GDMono::get_singleton()->get_api_editor_hash()) +
- "; }\n#endif // TOOLS_ENABLED\n");
- cpp_file.push_back("void register_generated_icalls() " OPEN_BLOCK);
-
-#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
- { \
- cpp_file.push_back("\tmono_add_internal_call("); \
- cpp_file.push_back("\"" BINDINGS_NAMESPACE "."); \
- cpp_file.push_back(m_icall.editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); \
- cpp_file.push_back("::"); \
- cpp_file.push_back(m_icall.name); \
- cpp_file.push_back("\", (void*)"); \
- cpp_file.push_back(m_icall.name); \
- cpp_file.push_back(");\n"); \
+ output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK);
+ output.push_back("uint64_t get_core_api_hash() { return ");
+ output.push_back(itos(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
+ output.push_back("#ifdef TOOLS_ENABLED\n"
+ "uint64_t get_editor_api_hash() { return ");
+ output.push_back(itos(GDMono::get_singleton()->get_api_editor_hash()) +
+ "; }\n#endif // TOOLS_ENABLED\n");
+ output.push_back("void register_generated_icalls() " OPEN_BLOCK);
+
+#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
+ { \
+ output.push_back("\tmono_add_internal_call("); \
+ output.push_back("\"" BINDINGS_NAMESPACE "."); \
+ output.push_back(m_icall.editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); \
+ output.push_back("::"); \
+ output.push_back(m_icall.name); \
+ output.push_back("\", (void*)"); \
+ output.push_back(m_icall.name); \
+ output.push_back(");\n"); \
}
bool tools_sequence = false;
@@ -1341,11 +1218,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (tools_sequence) {
if (!E->get().editor_only) {
tools_sequence = false;
- cpp_file.push_back("#endif\n");
+ output.push_back("#endif\n");
}
} else {
if (E->get().editor_only) {
- cpp_file.push_back("#ifdef TOOLS_ENABLED\n");
+ output.push_back("#ifdef TOOLS_ENABLED\n");
tools_sequence = true;
}
}
@@ -1355,24 +1232,23 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (tools_sequence) {
tools_sequence = false;
- cpp_file.push_back("#endif\n");
+ output.push_back("#endif\n");
}
- cpp_file.push_back("#ifdef TOOLS_ENABLED\n");
+ output.push_back("#ifdef TOOLS_ENABLED\n");
for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
ADD_INTERNAL_CALL_REGISTRATION(E->get());
- cpp_file.push_back("#endif // TOOLS_ENABLED\n");
+ output.push_back("#endif // TOOLS_ENABLED\n");
for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) {
-
if (tools_sequence) {
if (!E->get().editor_only) {
tools_sequence = false;
- cpp_file.push_back("#endif\n");
+ output.push_back("#endif\n");
}
} else {
if (E->get().editor_only) {
- cpp_file.push_back("#ifdef TOOLS_ENABLED\n");
+ output.push_back("#ifdef TOOLS_ENABLED\n");
tools_sequence = true;
}
}
@@ -1382,20 +1258,27 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (tools_sequence) {
tools_sequence = false;
- cpp_file.push_back("#endif\n");
+ output.push_back("#endif\n");
}
#undef ADD_INTERNAL_CALL_REGISTRATION
- cpp_file.push_back(CLOSE_BLOCK "}\n");
+ output.push_back(CLOSE_BLOCK "}\n");
+
+ Error save_err = _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), output);
+ if (save_err != OK)
+ return save_err;
- return _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), cpp_file);
+ OS::get_singleton()->print("Mono glue generated successfully\n");
+
+ return OK;
}
Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) {
FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_EXPLAIN("Cannot open file: " + p_path);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
for (const List<String>::Element *E = p_content.front(); E; E = E->next()) {
@@ -1407,6 +1290,163 @@ Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_
return OK;
}
+Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, List<String> &p_output) {
+
+ if (p_imethod.is_virtual)
+ return OK; // Ignore
+
+ bool ret_void = p_imethod.return_type == "void";
+
+ const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
+
+ String argc_str = itos(p_imethod.arguments.size());
+
+ String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ String c_in_statements;
+ String c_args_var_content;
+
+ // Get arguments information
+ int i = 0;
+ for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
+ const ArgumentInterface &iarg = F->get();
+ const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
+
+ String c_param_name = "arg" + itos(i + 1);
+
+ if (p_imethod.is_vararg) {
+ if (i < p_imethod.arguments.size() - 1) {
+ c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name);
+ c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(0, ";
+ c_in_statements += sformat("&%s_in", c_param_name);
+ c_in_statements += ");\n";
+ }
+ } else {
+ if (i > 0)
+ c_args_var_content += ", ";
+ if (arg_type->c_in.size())
+ c_in_statements += sformat(arg_type->c_in, arg_type->c_type, c_param_name);
+ c_args_var_content += sformat(arg_type->c_arg_in, c_param_name);
+ }
+
+ c_func_sig += ", ";
+ c_func_sig += arg_type->c_type_in;
+ c_func_sig += " ";
+ c_func_sig += c_param_name;
+
+ i++;
+ }
+
+ const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ ERR_FAIL_NULL_V(match, ERR_BUG);
+
+ const InternalCall *im_icall = match->value();
+ String icall_method = im_icall->name;
+
+ if (!generated_icall_funcs.find(im_icall)) {
+ generated_icall_funcs.push_back(im_icall);
+
+ if (im_icall->editor_only)
+ p_output.push_back("#ifdef TOOLS_ENABLED\n");
+
+ // Generate icall function
+
+ p_output.push_back(ret_void ? "void " : return_type->c_type_out + " ");
+ p_output.push_back(icall_method);
+ p_output.push_back("(");
+ p_output.push_back(c_func_sig);
+ p_output.push_back(") " OPEN_BLOCK);
+
+ String fail_ret = ret_void ? "" : ", " + (return_type->c_type_out.ends_with("*") ? "NULL" : return_type->c_type_out + "()");
+
+ if (!ret_void) {
+ String ptrcall_return_type;
+ String initialization;
+
+ if (return_type->is_object_type) {
+ ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type;
+ initialization = return_type->is_reference ? "" : " = NULL";
+ } else {
+ ptrcall_return_type = return_type->c_type;
+ }
+
+ p_output.push_back("\t" + ptrcall_return_type);
+ p_output.push_back(" " LOCAL_RET);
+ p_output.push_back(initialization + ";\n");
+ p_output.push_back("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE);
+ p_output.push_back(fail_ret);
+ p_output.push_back(");\n");
+ } else {
+ p_output.push_back("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ }
+
+ if (p_imethod.arguments.size()) {
+ if (p_imethod.is_vararg) {
+ String err_fail_macro = ret_void ? "ERR_FAIL_COND" : "ERR_FAIL_COND_V";
+ 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(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(c_in_statements);
+ p_output.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
+ "\t\tMonoObject* elem = mono_array_get(");
+ p_output.push_back(vararg_arg);
+ p_output.push_back(", MonoObject*, i);\n"
+ "\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[i]);\n\t" CLOSE_BLOCK);
+ } else {
+ p_output.push_back(c_in_statements);
+ p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
+ p_output.push_back(argc_str + "] = { ");
+ p_output.push_back(c_args_var_content + " };\n");
+ }
+ }
+
+ if (p_imethod.is_vararg) {
+ p_output.push_back("\tVariant::CallError vcall_error;\n\t");
+
+ if (!ret_void)
+ p_output.push_back(LOCAL_RET " = ");
+
+ 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(", total_length, vcall_error);\n");
+ } else {
+ p_output.push_back("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
+ p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
+ p_output.push_back(!ret_void ? "&" LOCAL_RET ");\n" : "NULL);\n");
+ }
+
+ if (!ret_void) {
+ if (return_type->c_out.empty())
+ p_output.push_back("\treturn " LOCAL_RET ";\n");
+ else
+ p_output.push_back(sformat(return_type->c_out, return_type->c_type_out, LOCAL_RET, return_type->name));
+ }
+
+ p_output.push_back(CLOSE_BLOCK "\n");
+
+ if (im_icall->editor_only)
+ p_output.push_back("#endif // TOOLS_ENABLED\n");
+ }
+
+ return OK;
+}
+
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const String &p_name) {
const Map<String, TypeInterface>::Element *match = builtin_types.find(p_name);
@@ -1471,7 +1511,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
itype.memory_own = itype.is_reference;
if (!ClassDB::is_class_exposed(type_cname)) {
- WARN_PRINTS("Ignoring type " + String(type_cname) + " because it's not exposed");
+ if (verbose_output)
+ WARN_PRINTS("Ignoring type " + String(type_cname) + " because it's not exposed");
class_list.pop_front();
continue;
}
@@ -1535,9 +1576,11 @@ void BindingsGenerator::_populate_object_type_interfaces() {
// which could actually will return something differnet.
// Let's put this to notify us if that ever happens.
if (itype.name != "Object" || imethod.name != "free") {
- WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
- "We only expected Object.free, but found " +
- itype.name + "." + imethod.name);
+ if (verbose_output) {
+ WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
+ "We only expected Object.free, but found " +
+ itype.name + "." + imethod.name);
+ }
}
} else {
ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
@@ -2043,7 +2086,8 @@ BindingsGenerator::BindingsGenerator() {
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
- int options_count = 3;
+ const int NUM_OPTIONS = 3;
+ int options_left = NUM_OPTIONS;
String mono_glue_option = "--generate-mono-glue";
String cs_core_api_option = "--generate-cs-core-api";
@@ -2053,33 +2097,35 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
const List<String>::Element *elem = p_cmdline_args.front();
- while (elem && options_count) {
+ while (elem && options_left) {
if (elem->get() == mono_glue_option) {
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- get_singleton().generate_glue(path_elem->get());
+ if (get_singleton().generate_glue(path_elem->get()) != OK)
+ ERR_PRINT("Mono glue generation failed");
elem = elem->next();
} else {
ERR_PRINTS("--generate-mono-glue: No output directory specified");
}
- --options_count;
+ --options_left;
} else if (elem->get() == cs_core_api_option) {
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- get_singleton().generate_cs_core_project(path_elem->get());
+ if (get_singleton().generate_cs_core_project(path_elem->get()) != OK)
+ ERR_PRINT("Generation of solution and C# project for the Core API failed");
elem = elem->next();
} else {
ERR_PRINTS(cs_core_api_option + ": No output directory specified");
}
- --options_count;
+ --options_left;
} else if (elem->get() == cs_editor_api_option) {
@@ -2087,7 +2133,8 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
if (path_elem) {
if (path_elem->next()) {
- get_singleton().generate_cs_editor_project(path_elem->get(), path_elem->next()->get());
+ if (get_singleton().generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK)
+ ERR_PRINT("Generation of solution and C# project for the Editor API failed");
elem = path_elem->next();
} else {
ERR_PRINTS(cs_editor_api_option + ": No hint path for the Core API dll specified");
@@ -2096,13 +2143,16 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
ERR_PRINTS(cs_editor_api_option + ": No output directory specified");
}
- --options_count;
+ --options_left;
}
elem = elem->next();
}
verbose_output = false;
+
+ if (options_left != NUM_OPTIONS)
+ exit(0);
}
#endif
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 437a566556..dfa3aa9911 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -368,6 +368,8 @@ class BindingsGenerator {
List<InternalCall> method_icalls;
Map<const MethodInterface *, const InternalCall *> method_icalls_map;
+ List<const InternalCall *> generated_icall_funcs;
+
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
@@ -404,6 +406,11 @@ class BindingsGenerator {
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
+ Error _generate_cs_property(const TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output);
+ Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output);
+
+ Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output);
+
Error _save_file(const String &path, const List<String> &content);
BindingsGenerator();
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index 1bad8a3f85..dbe0cc294c 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -32,6 +32,7 @@
#include "main/main.h"
#include "../godotsharp_dirs.h"
+#include "../mono_gd/gd_mono.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/path_utils.h"
@@ -60,10 +61,10 @@ String _find_build_engine_on_unix(const String &p_name) {
};
for (int i = 0; i < sizeof(locations) / sizeof(const char *); i++) {
- String location = locations[i];
+ String hint_path = locations[i] + p_name;
- if (FileAccess::exists(location + p_name)) {
- return location;
+ if (FileAccess::exists(hint_path)) {
+ return hint_path;
}
}
@@ -71,7 +72,7 @@ String _find_build_engine_on_unix(const String &p_name) {
}
#endif
-MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
+void godot_icall_BuildInstance_get_MSBuildInfo(MonoString **r_msbuild_path, MonoString **r_framework_path) {
GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
@@ -84,11 +85,23 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
if (!msbuild_tools_path.ends_with("\\"))
msbuild_tools_path += "\\";
- return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
+ // FrameworkPathOverride
+ const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info();
+ if (mono_reg_info.assembly_dir.length()) {
+ *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
+
+ String framework_path = path_join(mono_reg_info.assembly_dir, "mono", "4.5");
+ *r_framework_path = GDMonoMarshal::mono_string_from_godot(framework_path);
+ } else {
+ ERR_PRINT("Cannot find Mono's assemblies directory in the registry");
+ }
+
+ return;
}
- OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n");
- }
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n");
+ } // fall through
case GodotSharpBuilds::MSBUILD_MONO: {
String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
@@ -96,17 +109,10 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
WARN_PRINTS("Cannot find msbuild ('mono/builds/build_tool'). Tried with path: " + msbuild_path);
}
- return GDMonoMarshal::mono_string_from_godot(msbuild_path);
- }
- case GodotSharpBuilds::XBUILD: {
- String xbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("xbuild.bat");
+ *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(msbuild_path);
- if (!FileAccess::exists(xbuild_path)) {
- WARN_PRINTS("Cannot find xbuild ('mono/builds/build_tool'). Tried with path: " + xbuild_path);
- }
-
- return GDMonoMarshal::mono_string_from_godot(xbuild_path);
- }
+ return;
+ } break;
default:
ERR_EXPLAIN("You don't deserve to live");
CRASH_NOW();
@@ -118,25 +124,28 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
if (build_tool != GodotSharpBuilds::XBUILD) {
if (msbuild_path.empty()) {
WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool').");
- return NULL;
+ return;
}
} else {
if (xbuild_path.empty()) {
WARN_PRINT("Cannot find xbuild ('mono/builds/build_tool').");
- return NULL;
+ return;
}
}
- return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
+ *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
+
+ return;
#else
- return NULL;
+ ERR_PRINT("Not implemented on this platform");
+ return;
#endif
}
void GodotSharpBuilds::_register_internal_calls() {
mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback);
- 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_MSBuildInfo", (void *)godot_icall_BuildInstance_get_MSBuildInfo);
}
void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
@@ -269,7 +278,7 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
return true;
}
-bool godotsharp_build_callback() {
+bool GodotSharpBuilds::build_project_blocking() {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
@@ -348,14 +357,27 @@ GodotSharpBuilds::GodotSharpBuilds() {
singleton = this;
- EditorNode::get_singleton()->add_build_callback(&godotsharp_build_callback);
+ EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::build_project_blocking);
// Build tool settings
EditorSettings *ed_settings = EditorSettings::get_singleton();
if (!ed_settings->has_setting("mono/builds/build_tool")) {
- ed_settings->set_setting("mono/builds/build_tool", MSBUILD);
+ ed_settings->set_setting("mono/builds/build_tool",
+#ifdef WINDOWS_ENABLED
+ // TODO: Default to MSBUILD_MONO if its csc.exe issue is fixed in the installed mono version
+ MSBUILD
+#else
+ MSBUILD_MONO
+#endif
+ );
}
- ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM, "MSBuild (System),MSBuild (Mono),xbuild"));
+ ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM,
+#ifdef WINDOWS_ENABLED
+ "MSBuild (Mono),MSBuild (System)"
+#else
+ "MSBuild (Mono),xbuild (Deprecated)"
+#endif
+ ));
}
GodotSharpBuilds::~GodotSharpBuilds() {
@@ -395,10 +417,11 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
}
if (!exited) {
- ERR_PRINT("BuildProcess::start called, but process still running");
exited = true;
- build_tab->on_build_exec_failed("!exited");
- return;
+ String message = "Tried to start build process, but it is already running";
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
+ ERR_FAIL();
}
exited = false;
@@ -410,10 +433,12 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
if (d->file_exists(issues_file)) {
Error err = d->remove(issues_file);
if (err != OK) {
- ERR_PRINTS("Cannot remove file: " + logs_dir.plus_file(issues_file));
exited = true;
- build_tab->on_build_exec_failed("Cannot remove file: " + issues_file);
- return;
+ String file_path = ProjectSettings::get_singleton()->localize_path(logs_dir).plus_file(issues_file);
+ String message = "Cannot remove issues file: " + file_path;
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
+ ERR_FAIL();
}
}
@@ -434,7 +459,9 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
if (ex) {
exited = true;
- build_tab->on_build_exec_failed("The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex));
+ String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
ERR_FAIL();
}
@@ -452,7 +479,9 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
if (ex) {
exited = true;
- build_tab->on_build_exec_failed("The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex));
+ String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
ERR_FAIL();
}
diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h
index 6d5fa3b44a..7d2f38a774 100644
--- a/modules/mono/editor/godotsharp_builds.h
+++ b/modules/mono/editor/godotsharp_builds.h
@@ -67,9 +67,12 @@ public:
};
enum BuildTool {
- MSBUILD,
MSBUILD_MONO,
- XBUILD
+#ifdef WINDOWS_ENABLED
+ MSBUILD
+#else
+ XBUILD // Deprecated
+#endif
};
_FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }
@@ -89,6 +92,8 @@ public:
static bool make_api_sln(APIType p_api_type);
+ static bool build_project_blocking();
+
GodotSharpBuilds();
~GodotSharpBuilds();
};
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index 30e7653256..837dbfde66 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -46,21 +46,6 @@
#include "../utils/mono_reg_utils.h"
#endif
-class MonoReloadNode : public Node {
- GDCLASS(MonoReloadNode, Node)
-
-protected:
- void _notification(int p_what) {
- switch (p_what) {
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
- CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
- } break;
- default: {
- } break;
- };
- }
-};
-
GodotSharpEditor *GodotSharpEditor::singleton = NULL;
bool GodotSharpEditor::_create_project_solution() {
@@ -71,6 +56,10 @@ bool GodotSharpEditor::_create_project_solution() {
String path = OS::get_singleton()->get_resource_dir();
String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
String guid = CSharpProject::generate_game_project(path, name);
if (guid.length()) {
@@ -182,11 +171,6 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int
String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
monodevel_instance->execute(script_path);
} break;
- case EDITOR_VISUAL_STUDIO:
- // TODO
- // devenv <PathToSolutionFolder>
- // devenv /edit <PathToCsFile> /command "edit.goto <Line>"
- // HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7
default:
return ERR_UNAVAILABLE;
}
@@ -240,7 +224,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
if (!ed_settings->has_setting("mono/editor/external_editor")) {
ed_settings->set_setting("mono/editor/external_editor", EDITOR_NONE);
}
- ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio,Visual Studio Code"));
+ ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio Code"));
}
GodotSharpEditor::~GodotSharpEditor() {
@@ -254,3 +238,49 @@ GodotSharpEditor::~GodotSharpEditor() {
monodevel_instance = NULL;
}
}
+
+MonoReloadNode *MonoReloadNode::singleton = NULL;
+
+void MonoReloadNode::_reload_timer_timeout() {
+
+ CSharpLanguage::get_singleton()->reload_assemblies_if_needed(false);
+}
+
+void MonoReloadNode::restart_reload_timer() {
+
+ reload_timer->stop();
+ reload_timer->start();
+}
+
+void MonoReloadNode::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_reload_timer_timeout"), &MonoReloadNode::_reload_timer_timeout);
+}
+
+void MonoReloadNode::_notification(int p_what) {
+ switch (p_what) {
+ case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ restart_reload_timer();
+ CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
+ } break;
+ default: {
+ } break;
+ };
+}
+
+MonoReloadNode::MonoReloadNode() {
+
+ singleton = this;
+
+ reload_timer = memnew(Timer);
+ add_child(reload_timer);
+ reload_timer->set_one_shot(false);
+ reload_timer->set_wait_time(EDITOR_DEF("mono/assembly_watch_interval_sec", 0.5));
+ reload_timer->connect("timeout", this, "_reload_timer_timeout");
+ reload_timer->start();
+}
+
+MonoReloadNode::~MonoReloadNode() {
+
+ singleton = NULL;
+}
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
index 1ecb8c7a94..0f2c163582 100644
--- a/modules/mono/editor/godotsharp_editor.h
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -69,7 +69,6 @@ public:
enum ExternalEditor {
EDITOR_NONE,
EDITOR_MONODEVELOP,
- EDITOR_VISUAL_STUDIO,
EDITOR_CODE,
};
@@ -84,4 +83,27 @@ public:
~GodotSharpEditor();
};
+class MonoReloadNode : public Node {
+ GDCLASS(MonoReloadNode, Node)
+
+ Timer *reload_timer;
+
+ void _reload_timer_timeout();
+
+ static MonoReloadNode *singleton;
+
+protected:
+ static void _bind_methods();
+
+ void _notification(int p_what);
+
+public:
+ _FORCE_INLINE_ static MonoReloadNode *get_singleton() { return singleton; }
+
+ void restart_reload_timer();
+
+ MonoReloadNode();
+ ~MonoReloadNode();
+};
+
#endif // GODOTSHARP_EDITOR_H
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
index 07109eaac7..31dc09856a 100644
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -139,6 +139,14 @@ void MonoBottomPanel::_errors_toggled(bool p_pressed) {
build_tab->_update_issues_list();
}
+void MonoBottomPanel::_build_project_pressed() {
+
+ GodotSharpBuilds::get_singleton()->build_project_blocking();
+
+ MonoReloadNode::get_singleton()->restart_reload_timer();
+ CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
+}
+
void MonoBottomPanel::_notification(int p_what) {
switch (p_what) {
@@ -153,6 +161,7 @@ void MonoBottomPanel::_notification(int p_what) {
void MonoBottomPanel::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_build_project_pressed"), &MonoBottomPanel::_build_project_pressed);
ClassDB::bind_method(D_METHOD("_warnings_toggled", "pressed"), &MonoBottomPanel::_warnings_toggled);
ClassDB::bind_method(D_METHOD("_errors_toggled", "pressed"), &MonoBottomPanel::_errors_toggled);
ClassDB::bind_method(D_METHOD("_build_tab_item_selected", "idx"), &MonoBottomPanel::_build_tab_item_selected);
@@ -187,6 +196,12 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
panel_builds_tab->add_child(toolbar_hbc);
+ ToolButton *build_project_btn = memnew(ToolButton);
+ build_project_btn->set_text("Build Project");
+ build_project_btn->set_focus_mode(FOCUS_NONE);
+ build_project_btn->connect("pressed", this, "_build_project_pressed");
+ toolbar_hbc->add_child(build_project_btn);
+
toolbar_hbc->add_spacer();
warnings_btn = memnew(ToolButton);
@@ -280,7 +295,11 @@ void MonoBuildTab::_update_issues_list() {
String tooltip;
tooltip += String("Message: ") + issue.message;
- tooltip += String("\nCode: ") + issue.code;
+
+ if (issue.code.length()) {
+ tooltip += String("\nCode: ") + issue.code;
+ }
+
tooltip += String("\nType: ") + (issue.warning ? "warning" : "error");
String text;
@@ -356,23 +375,21 @@ void MonoBuildTab::on_build_exit(BuildResult result) {
MonoBottomPanel::get_singleton()->raise_build_tab(this);
}
-void MonoBuildTab::on_build_exec_failed(const String &p_cause, const String &p_detailed) {
+void MonoBuildTab::on_build_exec_failed(const String &p_cause) {
build_exited = true;
build_result = RESULT_ERROR;
issues_list->clear();
- String tooltip;
+ BuildIssue issue;
+ issue.message = p_cause;
+ issue.warning = false;
- tooltip += "Message: " + (p_detailed.length() ? p_detailed : p_cause);
- tooltip += "\nType: error";
+ error_count += 1;
+ issues.push_back(issue);
- int line_break_idx = p_cause.find("\n");
- issues_list->add_item(line_break_idx == -1 ? p_cause : p_cause.substr(0, line_break_idx),
- get_icon("Error", "EditorIcons"));
- int index = issues_list->get_item_count() - 1;
- issues_list->set_item_tooltip(index, tooltip);
+ _update_issues_list();
MonoBottomPanel::get_singleton()->raise_build_tab(this);
}
diff --git a/modules/mono/editor/mono_bottom_panel.h b/modules/mono/editor/mono_bottom_panel.h
index 909fa4b385..5cc4aa3240 100644
--- a/modules/mono/editor/mono_bottom_panel.h
+++ b/modules/mono/editor/mono_bottom_panel.h
@@ -61,6 +61,8 @@ class MonoBottomPanel : public VBoxContainer {
void _warnings_toggled(bool p_pressed);
void _errors_toggled(bool p_pressed);
+ void _build_project_pressed();
+
static MonoBottomPanel *singleton;
protected:
@@ -134,7 +136,7 @@ public:
void on_build_start();
void on_build_exit(BuildResult result);
- void on_build_exec_failed(const String &p_cause, const String &p_detailed = String());
+ void on_build_exec_failed(const String &p_cause);
void restart_build();
void stop_build();
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 6bcf0e2355..7cc2168b70 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -122,7 +122,14 @@ private:
#ifdef TOOLS_ENABLED
mono_solutions_dir = mono_user_dir.plus_file("solutions");
build_logs_dir = mono_user_dir.plus_file("build_logs");
- String base_path = String("res://") + ProjectSettings::get_singleton()->get("application/config/name");
+
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
+ String base_path = String("res://") + name;
+
sln_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".sln");
csproj_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".csproj");
#endif
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index d3ad968135..e10e06df0e 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -59,6 +59,10 @@ Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
void MonoGCHandle::release() {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(GDMono::get_singleton() == NULL);
+#endif
+
if (!released && GDMono::get_singleton()->is_runtime_initialized()) {
mono_gchandle_free(handle);
released = true;
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 98b57adc50..c997b0f000 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "gd_mono.h"
+#include <mono/metadata/exception.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-gc.h>
@@ -47,6 +48,15 @@
#include "../editor/godotsharp_editor.h"
#endif
+void gdmono_unhandled_exception_hook(MonoObject *exc, void *user_data) {
+
+ (void)user_data; // UNUSED
+
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ abort();
+}
+
#ifdef MONO_PRINT_HANDLER_ENABLED
void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
@@ -132,7 +142,7 @@ void GDMono::initialize() {
ERR_FAIL_NULL(Engine::get_singleton());
- OS::get_singleton()->print("Initializing mono...\n");
+ OS::get_singleton()->print("Mono: Initializing module...\n");
#ifdef DEBUG_METHODS_ENABLED
_initialize_and_check_api_hashes();
@@ -214,7 +224,9 @@ void GDMono::initialize() {
// The following assemblies are not required at initialization
_load_all_script_assemblies();
- OS::get_singleton()->print("Mono: EVERYTHING OK\n");
+ mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL);
+
+ OS::get_singleton()->print("Mono: ALL IS GOOD\n");
}
#ifndef MONO_GLUE_DISABLED
@@ -357,9 +369,12 @@ bool GDMono::_load_project_assembly() {
if (project_assembly)
return true;
- String project_assembly_name = ProjectSettings::get_singleton()->get("application/config/name");
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
- bool success = _load_assembly(project_assembly_name, &project_assembly);
+ bool success = _load_assembly(name, &project_assembly);
if (success)
mono_assembly_set_main(project_assembly->get_assembly());
@@ -610,6 +625,8 @@ GDMono::~GDMono() {
if (gdmono_log)
memdelete(gdmono_log);
+
+ singleton = NULL;
}
_GodotSharp *_GodotSharp::singleton = NULL;
@@ -688,7 +705,7 @@ bool _GodotSharp::is_domain_loaded() {
void _GodotSharp::queue_dispose(Object *p_object) {
- if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
_dispose_object(p_object);
} else {
#ifndef NO_THREADS
@@ -705,7 +722,7 @@ void _GodotSharp::queue_dispose(Object *p_object) {
void _GodotSharp::queue_dispose(NodePath *p_node_path) {
- if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
memdelete(p_node_path);
} else {
#ifndef NO_THREADS
@@ -722,7 +739,7 @@ void _GodotSharp::queue_dispose(NodePath *p_node_path) {
void _GodotSharp::queue_dispose(RID *p_rid) {
- if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
memdelete(p_rid);
} else {
#ifndef NO_THREADS
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 4b370295f3..7dc7043eec 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -95,7 +95,9 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
(void)user_data; // UNUSED
if (search_dirs.empty()) {
+#ifdef TOOLS_DOMAIN
search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
+#endif
search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
search_dirs.push_back(OS::get_singleton()->get_resource_dir());
search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
@@ -105,10 +107,11 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5"));
}
- while (assemblies_path) {
- if (*assemblies_path)
+ if (assemblies_path) {
+ while (*assemblies_path) {
search_dirs.push_back(*assemblies_path);
- ++assemblies_path;
+ ++assemblies_path;
+ }
}
}
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 81315ee87a..1643f8cfc5 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -183,19 +183,19 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
break;
}
if (CACHED_CLASS(NodePath) == type_class) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
break;
}
if (CACHED_CLASS(RID) == type_class) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
break;
}
@@ -204,8 +204,6 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
} break;
case MONO_TYPE_OBJECT: {
- GDMonoClass *type_class = type.type_class;
-
// Variant
switch (p_value.get_type()) {
case Variant::BOOL: {
@@ -237,11 +235,11 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
case Variant::COLOR: SET_FROM_STRUCT_AND_BREAK(Color);
case Variant::NODE_PATH: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::_RID: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::OBJECT: {
MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
@@ -250,7 +248,7 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
}
case Variant::DICTIONARY: {
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array);
case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
@@ -268,7 +266,7 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
case MONO_TYPE_GENERICINST: {
if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_raw()) {
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
- mono_field_set_value(p_object, mono_field, &managed);
+ mono_field_set_value(p_object, mono_field, managed);
break;
}
} break;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 77a1ef3cb0..01392447f3 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -600,7 +600,7 @@ MonoArray *Array_to_mono_array(const Array &p_array) {
for (int i = 0; i < p_array.size(); i++) {
MonoObject *boxed = variant_to_mono_object(p_array[i]);
- mono_array_set(ret, MonoObject *, i, boxed);
+ mono_array_setref(ret, i, boxed);
}
return ret;
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 6468e0d3d9..eb97d62900 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -83,9 +83,32 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
mono_array_set(params, MonoObject *, i, boxed_param);
}
- return mono_runtime_invoke_array(mono_method, p_object, params, r_exc);
+ MonoObject *exc = NULL;
+ MonoObject *ret = mono_runtime_invoke_array(mono_method, p_object, params, &exc);
+
+ if (exc) {
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ }
+ }
+
+ return ret;
} else {
- mono_runtime_invoke(mono_method, p_object, NULL, r_exc);
+ MonoObject *exc = NULL;
+ mono_runtime_invoke(mono_method, p_object, NULL, &exc);
+
+ if (exc) {
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ }
+ }
+
return NULL;
}
}
@@ -96,7 +119,19 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoObject **r_exc) {
}
MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
- return mono_runtime_invoke(mono_method, p_object, p_params, r_exc);
+ MonoObject *exc = NULL;
+ MonoObject *ret = mono_runtime_invoke(mono_method, p_object, p_params, &exc);
+
+ if (exc) {
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ }
+ }
+
+ return ret;
}
bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index e3af57e78a..ebb5d28e4d 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -149,6 +149,10 @@ void attach_current_thread();
void detach_current_thread();
MonoThread *get_current_thread();
+_FORCE_INLINE_ bool is_main_thread() {
+ return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
+}
+
GDMonoClass *get_object_class(MonoObject *p_object);
GDMonoClass *type_get_proxy_class(const StringName &p_type);
GDMonoClass *get_class_native_base(GDMonoClass *p_class);
diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/mono_reg_utils.py
index e9988625f5..8ddddb3a24 100644
--- a/modules/mono/mono_reg_utils.py
+++ b/modules/mono/mono_reg_utils.py
@@ -1,4 +1,7 @@
import os
+import platform
+
+from compat import decode_utf8
if os.name == 'nt':
import sys
@@ -11,8 +14,7 @@ if os.name == 'nt':
def _reg_open_key(key, subkey):
try:
return winreg.OpenKey(key, subkey)
- except (WindowsError, EnvironmentError) as e:
- import platform
+ except (WindowsError, OSError):
if platform.architecture()[0] == '32bit':
bitness_sam = winreg.KEY_WOW64_64KEY
else:
@@ -20,39 +22,93 @@ def _reg_open_key(key, subkey):
return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
-def _find_mono_in_reg(subkey):
+def _reg_open_key_bits(key, subkey, bits):
+ sam = winreg.KEY_READ
+
+ if platform.architecture()[0] == '32bit':
+ if bits == '64':
+ # Force 32bit process to search in 64bit registry
+ sam |= winreg.KEY_WOW64_64KEY
+ else:
+ if bits == '32':
+ # Force 64bit process to search in 32bit registry
+ sam |= winreg.KEY_WOW64_32KEY
+
+ return winreg.OpenKey(key, subkey, 0, sam)
+
+
+def _find_mono_in_reg(subkey, bits):
try:
- with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
+ with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
return value
- except (WindowsError, EnvironmentError) as e:
+ except (WindowsError, OSError):
return None
-def _find_mono_in_reg_old(subkey):
+
+def _find_mono_in_reg_old(subkey, bits):
try:
- with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
+ with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
if default_clr:
- return _find_mono_in_reg(subkey + '\\' + default_clr)
+ return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
return None
except (WindowsError, EnvironmentError):
return None
-def find_mono_root_dir():
- dir = _find_mono_in_reg(r'SOFTWARE\Mono')
- if dir:
- return dir
- dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono')
- if dir:
- return dir
- return None
+def find_mono_root_dir(bits):
+ root_dir = _find_mono_in_reg(r'SOFTWARE\Mono', bits)
+ if root_dir is not None:
+ return root_dir
+ root_dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono', bits)
+ if root_dir is not None:
+ return root_dir
+ return ''
def find_msbuild_tools_path_reg():
+ import subprocess
+
+ vswhere = os.getenv('PROGRAMFILES(X86)')
+ if not vswhere:
+ vswhere = os.getenv('PROGRAMFILES')
+ vswhere += r'\Microsoft Visual Studio\Installer\vswhere.exe'
+
+ vswhere_args = ['-latest', '-requires', 'Microsoft.Component.MSBuild']
+
try:
- with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0') as hKey:
+ lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
+
+ for line in lines:
+ parts = decode_utf8(line).split(':', 1)
+
+ if len(parts) < 2 or parts[0] != 'installationPath':
+ continue
+
+ val = parts[1].strip()
+
+ if not val:
+ raise ValueError('Value of `installationPath` entry is empty')
+
+ return os.path.join(val, "MSBuild\\15.0\\Bin")
+
+ raise ValueError('Cannot find `installationPath` entry')
+ except ValueError as e:
+ print('Error reading output from vswhere: ' + e.message)
+ except WindowsError:
+ pass # Fine, vswhere not found
+ except (subprocess.CalledProcessError, OSError):
+ pass
+
+ # Try to find 14.0 in the Registry
+
+ try:
+ subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
+ with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
return value
- except (WindowsError, EnvironmentError) as e:
- return None
+ except (WindowsError, OSError):
+ return ''
+
+ return ''
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index c8581f6122..105c2c981e 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -56,9 +56,6 @@ String path_which(const String &p_name) {
for (int i = 0; i < env_path.size(); i++) {
String p = path_join(env_path[i], p_name);
- if (FileAccess::exists(p))
- return p;
-
#ifdef WINDOWS_ENABLED
for (int j = 0; j < exts.size(); j++) {
String p2 = p + exts[j];
@@ -66,6 +63,9 @@ String path_which(const String &p_name) {
if (FileAccess::exists(p2))
return p2;
}
+#else
+ if (FileAccess::exists(p))
+ return p;
#endif
}
diff --git a/modules/opus/audio_stream_opus.cpp b/modules/opus/audio_stream_opus.cpp
index c7748b9b21..06eab4c94d 100644
--- a/modules/opus/audio_stream_opus.cpp
+++ b/modules/opus/audio_stream_opus.cpp
@@ -267,7 +267,7 @@ void AudioStreamPlaybackOpus::seek(float p_time) {
frames_mixed = osrate * p_time;
}
-int AudioStreamPlaybackOpus::mix(int16_t *p_bufer, int p_frames) {
+int AudioStreamPlaybackOpus::mix(int16_t *p_buffer, int p_frames) {
if (!playing)
return 0;
@@ -281,7 +281,7 @@ int AudioStreamPlaybackOpus::mix(int16_t *p_bufer, int p_frames) {
break;
}
- int ret = op_read(opus_file, (opus_int16 *)p_bufer, todo * stream_channels, &current_section);
+ int ret = op_read(opus_file, (opus_int16 *)p_buffer, todo * stream_channels, &current_section);
if (ret < 0) {
playing = false;
ERR_EXPLAIN("Error reading Opus File: " + file);
@@ -325,7 +325,7 @@ int AudioStreamPlaybackOpus::mix(int16_t *p_bufer, int p_frames) {
frames_mixed += ret;
- p_bufer += ret * stream_channels;
+ p_buffer += ret * stream_channels;
p_frames -= ret;
}
diff --git a/modules/opus/audio_stream_opus.h b/modules/opus/audio_stream_opus.h
index 7b7740a804..f8d8f585cf 100644
--- a/modules/opus/audio_stream_opus.h
+++ b/modules/opus/audio_stream_opus.h
@@ -107,7 +107,7 @@ public:
virtual int get_minimum_buffer_size() const;
- virtual int mix(int16_t *p_bufer, int p_frames);
+ virtual int mix(int16_t *p_buffer, int p_frames);
AudioStreamPlaybackOpus();
~AudioStreamPlaybackOpus();
diff --git a/modules/regex/SCsub b/modules/regex/SCsub
index 2bab144a28..18b4051afe 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -8,7 +8,7 @@ env_regex.Append(CPPFLAGS=["-DPCRE2_CODE_UNIT_WIDTH=0"])
env_regex.add_source_files(env.modules_sources, "*.cpp")
if env['builtin_pcre2']:
- jit_blacklist = ['javascript']
+ jit_blacklist = ['javascript', 'uwp']
thirdparty_dir = '#thirdparty/pcre2/src/'
thirdparty_flags = ['-DPCRE2_STATIC', '-DHAVE_CONFIG_H']
if 'platform' in env and env['platform'] not in jit_blacklist:
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 48145495e4..765fe4c2f2 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -974,11 +974,6 @@ bool VisualScript::is_tool() const {
return false;
}
-String VisualScript::get_node_type() const {
-
- return String();
-}
-
ScriptLanguage *VisualScript::get_language() const {
return VisualScriptLanguage::singleton;
@@ -2412,6 +2407,10 @@ bool VisualScriptLanguage::has_named_classes() const {
return false;
}
+bool VisualScriptLanguage::supports_builtin_mode() const {
+
+ return true;
+}
int VisualScriptLanguage::find_function(const String &p_function, const String &p_code) const {
return -1;
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 4ae50ee829..0f60b103c9 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -339,8 +339,6 @@ public:
virtual bool is_tool() const;
- virtual String get_node_type() const;
-
virtual ScriptLanguage *get_language() const;
virtual bool has_script_signal(const StringName &p_signal) const;
@@ -569,6 +567,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() const;
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 1980f86114..7c9d306831 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -78,6 +78,8 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"rad2deg",
"linear2db",
"db2linear",
+ "wrapi",
+ "wrapf",
"max",
"min",
"clamp",
@@ -198,6 +200,8 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case MATH_LERP:
case MATH_INVERSE_LERP:
case MATH_DECTIME:
+ case MATH_WRAP:
+ case MATH_WRAPF:
case LOGIC_CLAMP:
return 3;
case MATH_RANGE_LERP:
@@ -364,6 +368,22 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_DB2LINEAR: {
return PropertyInfo(Variant::REAL, "db");
} break;
+ case MATH_WRAP: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::INT, "value");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::INT, "min");
+ else
+ return PropertyInfo(Variant::INT, "max");
+ } break;
+ case MATH_WRAPF: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::REAL, "value");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::REAL, "min");
+ else
+ return PropertyInfo(Variant::REAL, "max");
+ } break;
case LOGIC_MAX: {
if (p_idx == 0)
return PropertyInfo(Variant::REAL, "a");
@@ -549,9 +569,13 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_DEG2RAD:
case MATH_RAD2DEG:
case MATH_LINEAR2DB:
+ case MATH_WRAPF:
case MATH_DB2LINEAR: {
t = Variant::REAL;
} break;
+ case MATH_WRAP: {
+ t = Variant::INT;
+ } break;
case LOGIC_MAX:
case LOGIC_MIN:
case LOGIC_CLAMP: {
@@ -898,6 +922,18 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(0);
*r_return = Math::db2linear((double)*p_inputs[0]);
} break;
+ case VisualScriptBuiltinFunc::MATH_WRAP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_WRAPF: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case VisualScriptBuiltinFunc::LOGIC_MAX: {
if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
@@ -1258,6 +1294,8 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(MATH_RAD2DEG);
BIND_ENUM_CONSTANT(MATH_LINEAR2DB);
BIND_ENUM_CONSTANT(MATH_DB2LINEAR);
+ BIND_ENUM_CONSTANT(MATH_WRAP);
+ BIND_ENUM_CONSTANT(MATH_WRAPF);
BIND_ENUM_CONSTANT(LOGIC_MAX);
BIND_ENUM_CONSTANT(LOGIC_MIN);
BIND_ENUM_CONSTANT(LOGIC_CLAMP);
@@ -1280,6 +1318,11 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_MAX);
}
+VisualScriptBuiltinFunc::VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func) {
+
+ this->func = func;
+}
+
VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
func = MATH_SIN;
@@ -1288,9 +1331,7 @@ VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
template <VisualScriptBuiltinFunc::BuiltinFunc func>
static Ref<VisualScriptNode> create_builtin_func_node(const String &p_name) {
- Ref<VisualScriptBuiltinFunc> node;
- node.instance();
- node->set_func(func);
+ Ref<VisualScriptBuiltinFunc> node = memnew(VisualScriptBuiltinFunc(func));
return node;
}
@@ -1340,6 +1381,8 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/max", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/min", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>);
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index af24f16a2f..34a2825938 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -77,6 +77,8 @@ public:
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
+ MATH_WRAP,
+ MATH_WRAPF,
LOGIC_MAX,
LOGIC_MIN,
LOGIC_CLAMP,
@@ -132,6 +134,7 @@ public:
virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance);
+ VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func);
VisualScriptBuiltinFunc();
};
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index bc033418ba..3c9076246d 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -82,7 +82,7 @@ String VisualScriptYield::get_text() const {
switch (yield_mode) {
case YIELD_RETURN: return ""; break;
case YIELD_FRAME: return "Next Frame"; break;
- case YIELD_PHYSICS_FRAME: return "Next Fixed Frame"; break;
+ case YIELD_PHYSICS_FRAME: return "Next Physics Frame"; break;
case YIELD_WAIT: return rtos(wait_time) + " sec(s)"; break;
}
@@ -186,7 +186,7 @@ void VisualScriptYield::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_wait_time", "sec"), &VisualScriptYield::set_wait_time);
ClassDB::bind_method(D_METHOD("get_wait_time"), &VisualScriptYield::get_wait_time);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,FixedFrame,Time", PROPERTY_USAGE_NOEDITOR), "set_yield_mode", "get_yield_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,Physics Frame,Time", PROPERTY_USAGE_NOEDITOR), "set_yield_mode", "get_yield_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wait_time"), "set_wait_time", "get_wait_time");
BIND_ENUM_CONSTANT(YIELD_FRAME);
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index 0afb889199..6235799fc2 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -92,7 +92,7 @@ long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) {
return fa->get_position();
}
-int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_bufer, int p_frames) {
+int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_buffer, int p_frames) {
if (!playing)
return 0;
@@ -109,9 +109,9 @@ int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_bufer, int p_frames) {
//printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t));
#ifdef BIG_ENDIAN_ENABLED
- long ret = ov_read(&vf, (char *)p_bufer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, &current_section);
+ long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, &current_section);
#else
- long ret = ov_read(&vf, (char *)p_bufer, todo * stream_channels * sizeof(int16_t), 0, 2, 1, &current_section);
+ long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 0, 2, 1, &current_section);
#endif
if (ret < 0) {
@@ -162,7 +162,7 @@ int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_bufer, int p_frames) {
frames_mixed += ret;
- p_bufer += ret * stream_channels;
+ p_buffer += ret * stream_channels;
p_frames -= ret;
}
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h
index 929b2651e9..79eadec56e 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/vorbis/audio_stream_ogg_vorbis.h
@@ -103,7 +103,7 @@ public:
virtual int get_mix_rate() const { return stream_srate; }
virtual int get_minimum_buffer_size() const { return 0; }
- virtual int mix(int16_t *p_bufer, int p_frames);
+ virtual int mix(int16_t *p_buffer, int p_frames);
AudioStreamPlaybackOGGVorbis();
~AudioStreamPlaybackOGGVorbis();