summaryrefslogtreecommitdiff
path: root/modules/mono
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono')
-rw-r--r--modules/mono/csharp_script.cpp2
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp105
-rw-r--r--modules/mono/editor/bindings_generator.h1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs101
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs21
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h4
11 files changed, 208 insertions, 54 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index bd29dc1876..25cc64393a 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -3644,7 +3644,7 @@ void CSharpScript::get_members(Set<StringName> *p_members) {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 85edd8b9c6..a31135cd32 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -542,7 +542,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public:
- RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false) override;
+ RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
void get_recognized_extensions(List<String> *p_extensions) const override;
bool handles_type(const String &p_type) const override;
String get_resource_type(const String &p_path) const override;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
index 5ef55fea49..774c49e705 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
@@ -86,7 +86,7 @@ namespace GodotTools.Build
{
case BuildTool.DotnetCli:
{
- string dotnetCliPath = OS.PathWhich("dotnet");
+ string dotnetCliPath = FindBuildEngineOnUnix("dotnet");
if (!string.IsNullOrEmpty(dotnetCliPath))
return (dotnetCliPath, BuildTool.DotnetCli);
GD.PushError($"Cannot find executable for '{BuildManager.PropNameDotnetCli}'. Fallback to MSBuild from Mono.");
@@ -122,7 +122,11 @@ namespace GodotTools.Build
if (OS.IsMacOS)
{
result.Add("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
+ result.Add("/opt/local/bin/");
result.Add("/usr/local/var/homebrew/linked/mono/bin/");
+ result.Add("/usr/local/bin/");
+ result.Add("/usr/local/bin/dotnet/");
+ result.Add("/usr/local/share/dotnet/");
}
result.Add("/opt/novell/mono/bin/");
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 38e403b2e1..167e9d75a1 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -783,6 +783,72 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
}
}
+void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
+ p_output.append("using System;\n\n");
+ p_output.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ // The class where we put the extensions doesn't matter, so just use "GD".
+ p_output.append(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
+
+#define ARRAY_IS_EMPTY(m_type) \
+ p_output.append("\n" INDENT2 "/// <summary>\n"); \
+ p_output.append(INDENT2 "/// Returns true if this " #m_type " array is empty or doesn't exist.\n"); \
+ p_output.append(INDENT2 "/// </summary>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array check.</param>\n"); \
+ p_output.append(INDENT2 "/// <returns>Whether or not the array is empty.</returns>\n"); \
+ p_output.append(INDENT2 "public static bool IsEmpty(this " #m_type "[] instance)\n"); \
+ p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(INDENT3 "return instance == null || instance.Length == 0;\n"); \
+ p_output.append(INDENT2 CLOSE_BLOCK);
+
+#define ARRAY_JOIN(m_type) \
+ p_output.append("\n" INDENT2 "/// <summary>\n"); \
+ p_output.append(INDENT2 "/// Converts this " #m_type " array to a string delimited by the given string.\n"); \
+ p_output.append(INDENT2 "/// </summary>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"delimiter\">The delimiter to use between items.</param>\n"); \
+ p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
+ p_output.append(INDENT2 "public static string Join(this " #m_type "[] instance, string delimiter = \", \")\n"); \
+ p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(INDENT3 "return String.Join(delimiter, instance);\n"); \
+ p_output.append(INDENT2 CLOSE_BLOCK);
+
+#define ARRAY_STRINGIFY(m_type) \
+ p_output.append("\n" INDENT2 "/// <summary>\n"); \
+ p_output.append(INDENT2 "/// Converts this " #m_type " array to a string with brackets.\n"); \
+ p_output.append(INDENT2 "/// </summary>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
+ p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
+ p_output.append(INDENT2 "public static string Stringify(this " #m_type "[] instance)\n"); \
+ p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(INDENT3 "return \"[\" + instance.Join() + \"]\";\n"); \
+ p_output.append(INDENT2 CLOSE_BLOCK);
+
+#define ARRAY_ALL(m_type) \
+ ARRAY_IS_EMPTY(m_type) \
+ ARRAY_JOIN(m_type) \
+ ARRAY_STRINGIFY(m_type)
+
+ ARRAY_ALL(byte);
+ ARRAY_ALL(int);
+ ARRAY_ALL(long);
+ ARRAY_ALL(float);
+ ARRAY_ALL(double);
+ ARRAY_ALL(string);
+ ARRAY_ALL(Color);
+ ARRAY_ALL(Vector2);
+ ARRAY_ALL(Vector2i);
+ ARRAY_ALL(Vector3);
+ ARRAY_ALL(Vector3i);
+
+#undef ARRAY_ALL
+#undef ARRAY_IS_EMPTY
+#undef ARRAY_JOIN
+#undef ARRAY_STRINGIFY
+
+ p_output.append(INDENT1 CLOSE_BLOCK); // End of GD class.
+ p_output.append(CLOSE_BLOCK); // End of namespace.
+}
+
void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
// Constants (in partial GD class)
@@ -926,6 +992,19 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
+ // Generate source file for array extensions
+ {
+ StringBuilder extensions_source;
+ _generate_array_extensions(extensions_source);
+ String output_file = path::join(base_gen_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_extensions.cs");
+ Error save_err = _save_file(output_file, extensions_source);
+ if (save_err != OK) {
+ return save_err;
+ }
+
+ compile_items.push_back(output_file);
+ }
+
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
const TypeInterface &itype = E.get();
@@ -1479,6 +1558,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
ERR_FAIL_COND_V_MSG(prop_itype->is_singleton, ERR_BUG,
"Property type is a singleton: '" + p_itype.name + "." + String(p_iprop.cname) + "'.");
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(prop_itype->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Property '" + p_itype.name + "." + String(p_iprop.cname) + "' has type '" + prop_itype->name +
+ "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+
if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype);
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
@@ -1575,6 +1660,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
ERR_FAIL_COND_V_MSG(return_type->is_singleton, ERR_BUG,
"Method return type is a singleton: '" + p_itype.name + "." + p_imethod.name + "'.");
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(return_type->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Method '" + p_itype.name + "." + p_imethod.name + "' has return type '" + return_type->name +
+ "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+
String method_bind_field = "__method_bind_" + itos(p_method_bind_count);
String arguments_sig;
@@ -1593,6 +1684,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
"Argument type is a singleton: '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(arg_type->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Argument '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "' has type '" +
+ arg_type->name + "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+
if (iarg.default_argument.size()) {
CRASH_COND_MSG(!_arg_default_value_is_assignable_to_type(iarg.def_param_value, *arg_type),
"Invalid default value for parameter '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
@@ -1806,7 +1903,13 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
- "Argument type is a singleton: '" + iarg.name + "' of signal" + p_itype.name + "." + p_isignal.name + "'.");
+ "Argument type is a singleton: '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "'.");
+
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(arg_type->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Argument '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "' has type '" +
+ arg_type->name + "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
// Add the current arguments to the signature
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index b18dfb0ec4..876046176b 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -661,6 +661,7 @@ class BindingsGenerator {
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output);
+ void _generate_array_extensions(StringBuilder &p_output);
void _generate_global_constants(StringBuilder &p_output);
Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, StringBuilder &p_output);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 90141928ca..0c333d06ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -104,7 +104,7 @@ namespace Godot
/// <summary>
/// The HSV hue of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHsv"/>.</value>
+ /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHSV"/>.</value>
public float h
{
get
@@ -145,14 +145,14 @@ namespace Godot
}
set
{
- this = FromHsv(value, s, v, a);
+ this = FromHSV(value, s, v, a);
}
}
/// <summary>
/// The HSV saturation of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHsv"/>.</value>
+ /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHSV"/>.</value>
public float s
{
get
@@ -166,14 +166,14 @@ namespace Godot
}
set
{
- this = FromHsv(h, value, v, a);
+ this = FromHSV(h, value, v, a);
}
}
/// <summary>
/// The HSV value (brightness) of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHsv"/>.</value>
+ /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHSV"/>.</value>
public float v
{
get
@@ -182,7 +182,7 @@ namespace Godot
}
set
{
- this = FromHsv(h, s, value, a);
+ this = FromHSV(h, s, value, a);
}
}
@@ -455,7 +455,7 @@ namespace Godot
/// </summary>
/// <param name="includeAlpha">Whether or not to include alpha. If false, the color is RGB instead of RGBA.</param>
/// <returns>A string for the HTML hexadecimal representation of this color.</returns>
- public string ToHtml(bool includeAlpha = true)
+ public string ToHTML(bool includeAlpha = true)
{
var txt = string.Empty;
@@ -532,18 +532,50 @@ namespace Godot
}
/// <summary>
+ /// Constructs a color either from an HTML color code or from a
+ /// standardized color name. Supported
+ /// color names are the same as the <see cref="Colors"/> constants.
+ /// </summary>
+ /// <param name="code">The HTML color code or color name to construct from.</param>
+ public Color(string code)
+ {
+ if (HtmlIsValid(code))
+ {
+ this = FromHTML(code);
+ }
+ else
+ {
+ this = Named(code);
+ }
+ }
+
+ /// <summary>
+ /// Constructs a color either from an HTML color code or from a
+ /// standardized color name, with `alpha` on the range of 0 to 1. Supported
+ /// color names are the same as the <see cref="Colors"/> constants.
+ /// </summary>
+ /// <param name="code">The HTML color code or color name to construct from.</param>
+ /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
+ public Color(string code, float alpha)
+ {
+ this = new Color(code);
+ a = alpha;
+ }
+
+ /// <summary>
/// Constructs a color from the HTML hexadecimal color string in RGBA format.
/// </summary>
/// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param>
- public Color(string rgba)
+ private static Color FromHTML(string rgba)
{
+ Color c;
if (rgba.Length == 0)
{
- r = 0f;
- g = 0f;
- b = 0f;
- a = 1.0f;
- return;
+ c.r = 0f;
+ c.g = 0f;
+ c.b = 0f;
+ c.a = 1.0f;
+ return c;
}
if (rgba[0] == '#')
@@ -577,47 +609,48 @@ namespace Godot
throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
}
- a = 1.0f;
+ c.a = 1.0f;
if (isShorthand)
{
- r = ParseCol4(rgba, 0) / 15f;
- g = ParseCol4(rgba, 1) / 15f;
- b = ParseCol4(rgba, 2) / 15f;
+ c.r = ParseCol4(rgba, 0) / 15f;
+ c.g = ParseCol4(rgba, 1) / 15f;
+ c.b = ParseCol4(rgba, 2) / 15f;
if (alpha)
{
- a = ParseCol4(rgba, 3) / 15f;
+ c.a = ParseCol4(rgba, 3) / 15f;
}
}
else
{
- r = ParseCol8(rgba, 0) / 255f;
- g = ParseCol8(rgba, 2) / 255f;
- b = ParseCol8(rgba, 4) / 255f;
+ c.r = ParseCol8(rgba, 0) / 255f;
+ c.g = ParseCol8(rgba, 2) / 255f;
+ c.b = ParseCol8(rgba, 4) / 255f;
if (alpha)
{
- a = ParseCol8(rgba, 6) / 255f;
+ c.a = ParseCol8(rgba, 6) / 255f;
}
}
- if (r < 0)
+ if (c.r < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
}
- if (g < 0)
+ if (c.g < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
}
- if (b < 0)
+ if (c.b < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
}
- if (a < 0)
+ if (c.a < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
}
+ return c;
}
/// <summary>
@@ -640,9 +673,8 @@ namespace Godot
/// the constants defined in <see cref="Colors"/>.
/// </summary>
/// <param name="name">The name of the color.</param>
- /// <param name="alpha">The alpha (transparency) component represented on the range of 0 to 1. Default: 1.</param>
/// <returns>The constructed color.</returns>
- public static Color ColorN(string name, float alpha = 1f)
+ private static Color Named(string name)
{
name = name.Replace(" ", String.Empty);
name = name.Replace("-", String.Empty);
@@ -656,9 +688,7 @@ namespace Godot
throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
}
- Color color = Colors.namedColors[name];
- color.a = alpha;
- return color;
+ return Colors.namedColors[name];
}
/// <summary>
@@ -671,11 +701,11 @@ namespace Godot
/// <param name="value">The HSV value (brightness), typically on the range of 0 to 1.</param>
/// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
/// <returns>The constructed color.</returns>
- public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f)
+ public static Color FromHSV(float hue, float saturation, float value, float alpha = 1.0f)
{
if (saturation == 0)
{
- // acp_hromatic (grey)
+ // Achromatic (grey)
return new Color(value, value, value, alpha);
}
@@ -715,7 +745,7 @@ namespace Godot
/// <param name="hue">Output parameter for the HSV hue.</param>
/// <param name="saturation">Output parameter for the HSV saturation.</param>
/// <param name="value">Output parameter for the HSV value.</param>
- public void ToHsv(out float hue, out float saturation, out float value)
+ public void ToHSV(out float hue, out float saturation, out float value)
{
float max = (float)Mathf.Max(r, Mathf.Max(g, b));
float min = (float)Mathf.Min(r, Mathf.Min(g, b));
@@ -803,7 +833,8 @@ namespace Godot
}
// Check if each hex digit is valid.
- for (int i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++)
+ {
if (ParseCol4(color, i) == -1)
{
return false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
index 5f64c09a89..74fa05d1fd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
@@ -2,7 +2,7 @@ namespace Godot
{
public static partial class ResourceLoader
{
- public static T Load<T>(string path, string typeHint = null, bool noCache = false) where T : class
+ public static T Load<T>(string path, string typeHint = null, CacheMode noCache = CacheMode.Reuse) where T : class
{
return (T)(object)Load(path, typeHint, noCache);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index 4dc182fb73..98efa89ef0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -462,18 +462,18 @@ namespace Godot
}
// <summary>
- // Hash the string and return a 32 bits integer.
+ // Hash the string and return a 32 bits unsigned integer.
// </summary>
- public static int Hash(this string instance)
+ public static uint Hash(this string instance)
{
- int index = 0;
- int hashv = 5381;
- int c;
+ uint hash = 5381;
- while ((c = instance[index++]) != 0)
- hashv = (hashv << 5) + hashv + c; // hash * 33 + c
+ foreach(uint c in instance)
+ {
+ hash = (hash << 5) + hash + c; // hash * 33 + c
+ }
- return hashv;
+ return hash;
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 42dbdf25c3..3b895bbbf6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -111,10 +111,10 @@ namespace Godot
}
/// <summary>
- /// Returns the minimum angle to the given vector, in radians.
+ /// Returns the unsigned minimum angle to the given vector, in radians.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
+ /// <returns>The unsigned angle between the two vectors, in radians.</returns>
public real_t AngleTo(Vector3 to)
{
return Mathf.Atan2(Cross(to).Length(), Dot(to));
@@ -469,6 +469,23 @@ namespace Godot
}
/// <summary>
+ /// Returns the signed angle to the given vector, in radians.
+ /// The sign of the angle is positive in a counter-clockwise
+ /// direction and negative in a clockwise direction when viewed
+ /// from the side specified by the `axis`.
+ /// </summary>
+ /// <param name="to">The other vector to compare this vector to.</param>
+ /// <param name="axis">The reference axis to use for the angle sign.</param>
+ /// <returns>The signed angle between the two vectors, in radians.</returns>
+ public real_t SignedAngleTo(Vector3 to, Vector3 axis)
+ {
+ Vector3 crossTo = Cross(to);
+ real_t unsignedAngle = Mathf.Atan2(crossTo.Length(), Dot(to));
+ real_t sign = crossTo.Dot(axis);
+ return (sign < 0) ? -unsignedAngle : unsignedAngle;
+ }
+
+ /// <summary>
/// Returns the result of the spherical linear interpolation between
/// this vector and `to` by amount `weight`.
///
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index e1d283242c..dafd36c36b 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -189,8 +189,6 @@ void GDMonoLog::initialize() {
GDMonoLog::GDMonoLog() {
singleton = this;
-
- log_level_id = -1;
}
GDMonoLog::~GDMonoLog() {
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 9a95e3cb0a..f7a53156ab 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -46,9 +46,9 @@
class GDMonoLog {
#ifdef GD_MONO_LOG_ENABLED
- int log_level_id;
+ int log_level_id = -1;
- FileAccess *log_file;
+ FileAccess *log_file = nullptr;
String log_file_path;
bool _try_create_logs_dir(const String &p_logs_dir);