diff options
Diffstat (limited to 'modules/mono')
28 files changed, 284 insertions, 129 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 078a490b22..f8d201b4ca 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -629,7 +629,6 @@ void CSharpLanguage::frame() { if (exc) { GDMonoUtils::debug_unhandled_exception(exc); - GD_UNREACHABLE(); } } } @@ -2914,11 +2913,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call r_error.error = Variant::CallError::CALL_OK; REF ref; - Object *owner = NULL; ERR_FAIL_NULL_V(native, Variant()); - owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); + Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); Reference *r = Object::cast_to<Reference>(owner); if (r) { diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 1edc426e00..233aab45b3 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -85,7 +85,7 @@ namespace GodotTools.ProjectEditor void AddPropertyIfNotPresent(string name, string condition, string value) { if (root.PropertyGroups - .Any(g => g.Condition == string.Empty || g.Condition == condition && + .Any(g => (g.Condition == string.Empty || g.Condition == condition) && g.Properties .Any(p => p.Name == name && p.Value == value && diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs index f849356919..d8cb9024c3 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs @@ -137,7 +137,7 @@ namespace GodotTools.Build private static string BuildArguments(string solution, string config, string loggerOutputDir, List<string> customProperties) { - string arguments = $@"""{solution}"" /v:normal /t:Rebuild ""/p:{"Configuration=" + config}"" " + + string arguments = $@"""{solution}"" /v:normal /t:Build ""/p:{"Configuration=" + config}"" " + $@"""/l:{typeof(GodotBuildLogger).FullName},{GodotBuildLogger.AssemblyPath};{loggerOutputDir}"""; foreach (string customProperty in customProperties) diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs index f0068385f4..926aabdf89 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs @@ -15,7 +15,6 @@ namespace GodotTools.Build { private static string _msbuildToolsPath = string.Empty; private static string _msbuildUnixPath = string.Empty; - private static string _xbuildUnixPath = string.Empty; public static string FindMsBuild() { @@ -44,7 +43,6 @@ namespace GodotTools.Build return Path.Combine(_msbuildToolsPath, "MSBuild.exe"); } - case GodotSharpBuilds.BuildTool.MsBuildMono: { string msbuildPath = Path.Combine(Internal.MonoWindowsInstallRoot, "bin", "msbuild.bat"); @@ -56,19 +54,6 @@ namespace GodotTools.Build return msbuildPath; } - - case GodotSharpBuilds.BuildTool.XBuild: - { - string xbuildPath = Path.Combine(Internal.MonoWindowsInstallRoot, "bin", "xbuild.bat"); - - if (!File.Exists(xbuildPath)) - { - throw new FileNotFoundException($"Cannot find executable for '{GodotSharpBuilds.PropNameXbuild}'. Tried with path: {xbuildPath}"); - } - - return xbuildPath; - } - default: throw new IndexOutOfRangeException("Invalid build tool in editor settings"); } @@ -76,20 +61,7 @@ namespace GodotTools.Build if (OS.IsUnix()) { - if (buildTool == GodotSharpBuilds.BuildTool.XBuild) - { - if (_xbuildUnixPath.Empty() || !File.Exists(_xbuildUnixPath)) - { - // Try to search it again if it wasn't found last time or if it was removed from its location - _xbuildUnixPath = FindBuildEngineOnUnix("msbuild"); - } - - if (_xbuildUnixPath.Empty()) - { - throw new FileNotFoundException($"Cannot find binary for '{GodotSharpBuilds.PropNameXbuild}'"); - } - } - else + if (buildTool == GodotSharpBuilds.BuildTool.MsBuildMono) { if (_msbuildUnixPath.Empty() || !File.Exists(_msbuildUnixPath)) { @@ -101,9 +73,13 @@ namespace GodotTools.Build { throw new FileNotFoundException($"Cannot find binary for '{GodotSharpBuilds.PropNameMsbuildMono}'"); } - } - return buildTool != GodotSharpBuilds.BuildTool.XBuild ? _msbuildUnixPath : _xbuildUnixPath; + return _msbuildUnixPath; + } + else + { + throw new IndexOutOfRangeException("Invalid build tool in editor settings"); + } } throw new PlatformNotSupportedException(); diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs index a884b0ead0..de3a4d9a6e 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs @@ -18,7 +18,6 @@ namespace GodotTools public const string PropNameMsbuildMono = "MSBuild (Mono)"; public const string PropNameMsbuildVs = "MSBuild (VS Build Tools)"; - public const string PropNameXbuild = "xbuild (Deprecated)"; public const string MsBuildIssuesFileName = "msbuild_issues.csv"; public const string MsBuildLogFileName = "msbuild_log.txt"; @@ -26,8 +25,7 @@ namespace GodotTools public enum BuildTool { MsBuildMono, - MsBuildVs, - XBuild // Deprecated + MsBuildVs } private static void RemoveOldIssuesFile(MonoBuildInfo buildInfo) @@ -64,7 +62,7 @@ namespace GodotTools private static string GetIssuesFilePath(MonoBuildInfo buildInfo) { - return Path.Combine(Godot.ProjectSettings.LocalizePath(buildInfo.LogsDirPath), MsBuildIssuesFileName); + return Path.Combine(buildInfo.LogsDirPath, MsBuildIssuesFileName); } private static void PrintVerbose(string text) @@ -202,6 +200,9 @@ namespace GodotTools // case the user decided to delete them at some point after they were loaded. Internal.UpdateApiAssembliesFromPrebuilt(); + var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings(); + var buildTool = (BuildTool)editorSettings.GetSetting("mono/builds/build_tool"); + using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1)) { pr.Step("Building project solution", 0); @@ -209,7 +210,7 @@ namespace GodotTools var buildInfo = new MonoBuildInfo(GodotSharpDirs.ProjectSlnPath, config); // Add Godot defines - string constants = OS.IsWindows() ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\""; + string constants = buildTool == BuildTool.MsBuildVs ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\""; foreach (var godotDefine in godotDefines) constants += $"GODOT_{godotDefine.ToUpper().Replace("-", "_").Replace(" ", "_").Replace(";", "_")};"; @@ -217,7 +218,7 @@ namespace GodotTools if (Internal.GodotIsRealTDouble()) constants += "GODOT_REAL_T_IS_DOUBLE;"; - constants += OS.IsWindows() ? "\"" : "\\\""; + constants += buildTool == BuildTool.MsBuildVs ? "\"" : "\\\""; buildInfo.CustomProperties.Add(constants); @@ -267,8 +268,8 @@ namespace GodotTools ["name"] = "mono/builds/build_tool", ["hint"] = Godot.PropertyHint.Enum, ["hint_string"] = OS.IsWindows() ? - $"{PropNameMsbuildMono},{PropNameMsbuildVs},{PropNameXbuild}" : - $"{PropNameMsbuildMono},{PropNameXbuild}" + $"{PropNameMsbuildMono},{PropNameMsbuildVs}" : + $"{PropNameMsbuildMono}" }); EditorDef("mono/builds/print_build_output", false); diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 90dec43412..9b5afb94a3 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -298,7 +298,16 @@ namespace GodotTools if (line >= 0) scriptPath += $";{line + 1};{col}"; - GetMonoDevelopInstance(GodotSharpDirs.ProjectSlnPath).Execute(scriptPath); + try + { + GetMonoDevelopInstance(GodotSharpDirs.ProjectSlnPath).Execute(scriptPath); + } + catch (FileNotFoundException) + { + string editorName = editor == ExternalEditor.VisualStudioForMac ? "Visual Studio" : "MonoDevelop"; + GD.PushError($"Cannot find code editor: {editorName}"); + return Error.FileNotFound; + } break; } diff --git a/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs b/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs index 75fdacc0da..3a74fa2f66 100644 --- a/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs +++ b/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs @@ -61,41 +61,48 @@ namespace GodotTools { using (var file = new Godot.File()) { - Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read); - - if (openError != Error.Ok) - return; - - while (!file.EofReached()) + try { - string[] csvColumns = file.GetCsvLine(); + Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read); - if (csvColumns.Length == 1 && csvColumns[0].Empty()) + if (openError != Error.Ok) return; - if (csvColumns.Length != 7) + while (!file.EofReached()) { - GD.PushError($"Expected 7 columns, got {csvColumns.Length}"); - continue; + string[] csvColumns = file.GetCsvLine(); + + if (csvColumns.Length == 1 && csvColumns[0].Empty()) + return; + + if (csvColumns.Length != 7) + { + GD.PushError($"Expected 7 columns, got {csvColumns.Length}"); + continue; + } + + var issue = new BuildIssue + { + Warning = csvColumns[0] == "warning", + File = csvColumns[1], + Line = int.Parse(csvColumns[2]), + Column = int.Parse(csvColumns[3]), + Code = csvColumns[4], + Message = csvColumns[5], + ProjectFile = csvColumns[6] + }; + + if (issue.Warning) + WarningCount += 1; + else + ErrorCount += 1; + + issues.Add(issue); } - - var issue = new BuildIssue - { - Warning = csvColumns[0] == "warning", - File = csvColumns[1], - Line = int.Parse(csvColumns[2]), - Column = int.Parse(csvColumns[3]), - Code = csvColumns[4], - Message = csvColumns[5], - ProjectFile = csvColumns[6] - }; - - if (issue.Warning) - WarningCount += 1; - else - ErrorCount += 1; - - issues.Add(issue); + } + finally + { + file.Close(); // Disposing it is not enough. We need to call Close() } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs b/modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs index 0c8d86e799..61a0a992ce 100644 --- a/modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs +++ b/modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs @@ -4,6 +4,7 @@ using System.IO; using System.Collections.Generic; using System.Diagnostics; using GodotTools.Internals; +using GodotTools.Utils; namespace GodotTools { @@ -30,7 +31,7 @@ namespace GodotTools if (Utils.OS.IsOSX()) { - string bundleId = CodeEditorBundleIds[editorId]; + string bundleId = BundleIds[editorId]; if (Internal.IsOsxAppBundleInstalled(bundleId)) { @@ -47,12 +48,12 @@ namespace GodotTools } else { - command = CodeEditorPaths[editorId]; + command = OS.PathWhich(ExecutableNames[editorId]); } } else { - command = CodeEditorPaths[editorId]; + command = OS.PathWhich(ExecutableNames[editorId]); } args.Add("--ipc-tcp"); @@ -70,6 +71,9 @@ namespace GodotTools args.Add("\"" + Path.GetFullPath(filePath.NormalizePath()) + cursor + "\""); } + if (command == null) + throw new FileNotFoundException(); + if (newWindow) { process = Process.Start(new ProcessStartInfo @@ -99,20 +103,20 @@ namespace GodotTools this.editorId = editorId; } - private static readonly IReadOnlyDictionary<EditorId, string> CodeEditorPaths; - private static readonly IReadOnlyDictionary<EditorId, string> CodeEditorBundleIds; + private static readonly IReadOnlyDictionary<EditorId, string> ExecutableNames; + private static readonly IReadOnlyDictionary<EditorId, string> BundleIds; static MonoDevelopInstance() { if (Utils.OS.IsOSX()) { - CodeEditorPaths = new Dictionary<EditorId, string> + ExecutableNames = new Dictionary<EditorId, string> { // Rely on PATH {EditorId.MonoDevelop, "monodevelop"}, {EditorId.VisualStudioForMac, "VisualStudio"} }; - CodeEditorBundleIds = new Dictionary<EditorId, string> + BundleIds = new Dictionary<EditorId, string> { // TODO EditorId.MonoDevelop {EditorId.VisualStudioForMac, "com.microsoft.visual-studio"} @@ -120,7 +124,7 @@ namespace GodotTools } else if (Utils.OS.IsWindows()) { - CodeEditorPaths = new Dictionary<EditorId, string> + ExecutableNames = new Dictionary<EditorId, string> { // XamarinStudio is no longer a thing, and the latest version is quite old // MonoDevelop is available from source only on Windows. The recommendation @@ -131,7 +135,7 @@ namespace GodotTools } else if (Utils.OS.IsUnix()) { - CodeEditorPaths = new Dictionary<EditorId, string> + ExecutableNames = new Dictionary<EditorId, string> { // Rely on PATH {EditorId.MonoDevelop, "monodevelop"} diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs index 3ae6c10bbf..288c65de74 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs @@ -10,8 +10,9 @@ namespace GodotTools.Utils { foreach (T elem in enumerable) { - if (predicate(elem) != null) - return elem; + T result = predicate(elem); + if (result != null) + return result; } return orElse; diff --git a/modules/mono/glue/Managed/Files/AABB.cs b/modules/mono/glue/Managed/Files/AABB.cs index a2ebbc0736..98a73382f4 100644 --- a/modules/mono/glue/Managed/Files/AABB.cs +++ b/modules/mono/glue/Managed/Files/AABB.cs @@ -5,6 +5,7 @@ // file: core/variant_call.cpp // commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 using System; +using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else @@ -13,6 +14,8 @@ using real_t = System.Single; namespace Godot { + [Serializable] + [StructLayout(LayoutKind.Sequential)] public struct AABB : IEquatable<AABB> { private Vector3 _position; diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs index 9cc31a0557..421532b68f 100644 --- a/modules/mono/glue/Managed/Files/Basis.cs +++ b/modules/mono/glue/Managed/Files/Basis.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Basis : IEquatable<Basis> { @@ -225,7 +226,7 @@ namespace Godot return orthonormalizedBasis.Quat(); } - internal void SetQuantScale(Quat quat, Vector3 scale) + internal void SetQuatScale(Quat quat, Vector3 scale) { SetDiagonal(scale); Rotate(quat); @@ -241,7 +242,6 @@ namespace Godot Row0 = new Vector3(diagonal.x, 0, 0); Row1 = new Vector3(0, diagonal.y, 0); Row2 = new Vector3(0, 0, diagonal.z); - } public real_t Determinant() diff --git a/modules/mono/glue/Managed/Files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs index 84ff19fc54..447697c671 100644 --- a/modules/mono/glue/Managed/Files/Color.cs +++ b/modules/mono/glue/Managed/Files/Color.cs @@ -1,7 +1,10 @@ using System; +using System.Runtime.InteropServices; namespace Godot { + [Serializable] + [StructLayout(LayoutKind.Sequential)] public struct Color : IEquatable<Color> { public float r; @@ -375,7 +378,7 @@ namespace Godot return c; } - public string ToHtml(bool include_alpha = true) + public string ToHtml(bool includeAlpha = true) { var txt = string.Empty; @@ -383,7 +386,7 @@ namespace Godot txt += ToHex32(g); txt += ToHex32(b); - if (include_alpha) + if (includeAlpha) txt = ToHex32(a) + txt; return txt; @@ -465,13 +468,13 @@ namespace Godot for (int i = 0; i < 2; i++) { - char[] c = { (char)0, (char)0 }; + char c; int lv = v & 0xF; if (lv < 10) - c[0] = (char)('0' + lv); + c = (char)('0' + lv); else - c[0] = (char)('a' + lv - 10); + c = (char)('a' + lv - 10); v >>= 4; ret = c + ret; @@ -490,12 +493,17 @@ namespace Godot bool alpha; - if (color.Length == 8) - alpha = true; - else if (color.Length == 6) - alpha = false; - else - return false; + switch (color.Length) + { + case 8: + alpha = true; + break; + case 6: + alpha = false; + break; + default: + return false; + } if (alpha) { diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index 6c1a51fcf9..15adf0a13b 100644 --- a/modules/mono/glue/Managed/Files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs @@ -336,14 +336,14 @@ namespace Godot public static int Wrap(int value, int min, int max) { - int rng = max - min; - return rng != 0 ? min + ((value - min) % rng + rng) % rng : min; + int range = max - min; + return range == 0 ? min : min + ((value - min) % range + range) % range; } public static real_t Wrap(real_t value, real_t min, real_t max) { - real_t rng = max - min; - return !IsEqualApprox(rng, default(real_t)) ? min + ((value - min) % rng + rng) % rng : min; + real_t range = max - min; + return IsZeroApprox(range) ? min : min + ((value - min) % range + range) % range; } } } diff --git a/modules/mono/glue/Managed/Files/NodePath.cs b/modules/mono/glue/Managed/Files/NodePath.cs index 94a4ed1de9..4de4e1e6a9 100644 --- a/modules/mono/glue/Managed/Files/NodePath.cs +++ b/modules/mono/glue/Managed/Files/NodePath.cs @@ -55,7 +55,7 @@ namespace Godot get { return ptr; } } - public NodePath() : this(string.Empty) { } + public NodePath() : this(string.Empty) {} public NodePath(string path) { diff --git a/modules/mono/glue/Managed/Files/Plane.cs b/modules/mono/glue/Managed/Files/Plane.cs index e16d4315be..a13161d2e6 100644 --- a/modules/mono/glue/Managed/Files/Plane.cs +++ b/modules/mono/glue/Managed/Files/Plane.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else @@ -7,6 +8,8 @@ using real_t = System.Single; namespace Godot { + [Serializable] + [StructLayout(LayoutKind.Sequential)] public struct Plane : IEquatable<Plane> { private Vector3 _normal; diff --git a/modules/mono/glue/Managed/Files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs index 0d4349084a..845c7c730e 100644 --- a/modules/mono/glue/Managed/Files/Quat.cs +++ b/modules/mono/glue/Managed/Files/Quat.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Quat : IEquatable<Quat> { @@ -95,6 +96,7 @@ namespace Godot return this / Length; } + [Obsolete("Set is deprecated. Use the Quat(" + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)] public void Set(real_t x, real_t y, real_t z, real_t w) { this.x = x; @@ -103,16 +105,19 @@ namespace Godot this.w = w; } + [Obsolete("Set is deprecated. Use the Quat(" + nameof(Quat) + ") constructor instead.", error: true)] public void Set(Quat q) { this = q; } + [Obsolete("SetAxisAngle is deprecated. Use the Quat(" + nameof(Vector3) + ", " + nameof(real_t) + ") constructor instead.", error: true)] public void SetAxisAngle(Vector3 axis, real_t angle) { this = new Quat(axis, angle); } + [Obsolete("SetEuler is deprecated. Use the Quat(" + nameof(Vector3) + ") constructor instead.", error: true)] public void SetEuler(Vector3 eulerYXZ) { this = new Quat(eulerYXZ); @@ -229,9 +234,9 @@ namespace Godot public Quat(Vector3 eulerYXZ) { - real_t half_a1 = eulerYXZ.y * (real_t)0.5; - real_t half_a2 = eulerYXZ.x * (real_t)0.5; - real_t half_a3 = eulerYXZ.z * (real_t)0.5; + real_t half_a1 = eulerYXZ.y * 0.5f; + real_t half_a2 = eulerYXZ.x * 0.5f; + real_t half_a3 = eulerYXZ.z * 0.5f; // R = Y(a1).X(a2).Z(a3) convention for Euler angles. // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) @@ -246,7 +251,7 @@ namespace Godot x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3; y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3; - z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3; + z = cos_a1 * cos_a2 * sin_a3 - sin_a1 * sin_a2 * cos_a3; w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3; } diff --git a/modules/mono/glue/Managed/Files/Rect2.cs b/modules/mono/glue/Managed/Files/Rect2.cs index 888f300347..f3dc9d8490 100644 --- a/modules/mono/glue/Managed/Files/Rect2.cs +++ b/modules/mono/glue/Managed/Files/Rect2.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Rect2 : IEquatable<Rect2> { diff --git a/modules/mono/glue/Managed/Files/StringExtensions.cs b/modules/mono/glue/Managed/Files/StringExtensions.cs index b43034fbb5..6045c83e95 100644 --- a/modules/mono/glue/Managed/Files/StringExtensions.cs +++ b/modules/mono/glue/Managed/Files/StringExtensions.cs @@ -98,6 +98,66 @@ namespace Godot } // <summary> + // Return the amount of substrings in string. + // </summary> + public static int Count(this string instance, string what, bool caseSensitive = true, int from = 0, int to = 0) + { + if (what.Length == 0) + { + return 0; + } + + int len = instance.Length; + int slen = what.Length; + + if (len < slen) + { + return 0; + } + + string str; + + if (from >= 0 && to >= 0) + { + if (to == 0) + { + to = len; + } + else if (from >= to) + { + return 0; + } + if (from == 0 && to == len) + { + str = instance; + } + else + { + str = instance.Substring(from, to - from); + } + } + else + { + return 0; + } + + int c = 0; + int idx; + + do + { + idx = str.IndexOf(what, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); + if (idx != -1) + { + str = str.Substring(idx + slen); + ++c; + } + } while (idx != -1); + + return c; + } + + // <summary> // Return a copy of the string with special characters escaped using the C language standard. // </summary> public static string CEscape(this string instance) diff --git a/modules/mono/glue/Managed/Files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs index bd79144873..cc4d26158d 100644 --- a/modules/mono/glue/Managed/Files/Transform.cs +++ b/modules/mono/glue/Managed/Files/Transform.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Transform : IEquatable<Transform> { @@ -33,7 +34,7 @@ namespace Godot Vector3 destinationLocation = transform.origin; var interpolated = new Transform(); - interpolated.basis.SetQuantScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c)); + interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c)); interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, c); return interpolated; diff --git a/modules/mono/glue/Managed/Files/Transform2D.cs b/modules/mono/glue/Managed/Files/Transform2D.cs index 33ff286769..814332dc07 100644 --- a/modules/mono/glue/Managed/Files/Transform2D.cs +++ b/modules/mono/glue/Managed/Files/Transform2D.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Transform2D : IEquatable<Transform2D> { @@ -98,6 +99,8 @@ namespace Godot return x[columnIndex]; case 1: return y[columnIndex]; + case 2: + return origin[columnIndex]; default: throw new IndexOutOfRangeException(); } @@ -112,6 +115,9 @@ namespace Godot case 1: y[columnIndex] = value; return; + case 2: + origin[columnIndex] = value; + return; default: throw new IndexOutOfRangeException(); } @@ -136,7 +142,7 @@ namespace Godot inv[0] *= new Vector2(detInv, -detInv); inv[1] *= new Vector2(-detInv, detInv); - inv[2] = BasisXform(-inv[2]); + inv[2] = inv.BasisXform(-inv[2]); return inv; } diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs index a7f26283a7..b1c1dae3c2 100644 --- a/modules/mono/glue/Managed/Files/Vector2.cs +++ b/modules/mono/glue/Managed/Files/Vector2.cs @@ -14,6 +14,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector2 : IEquatable<Vector2> { @@ -222,11 +223,13 @@ namespace Godot return new Vector2(Mathf.Round(x), Mathf.Round(y)); } + [Obsolete("Set is deprecated. Use the Vector2(" + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)] public void Set(real_t x, real_t y) { this.x = x; this.y = y; } + [Obsolete("Set is deprecated. Use the Vector2(" + nameof(Vector2) + ") constructor instead.", error: true)] public void Set(Vector2 v) { x = v.x; diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs index 16803ae55c..c2da7b8bb1 100644 --- a/modules/mono/glue/Managed/Files/Vector3.cs +++ b/modules/mono/glue/Managed/Files/Vector3.cs @@ -14,6 +14,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector3 : IEquatable<Vector3> { @@ -248,12 +249,14 @@ namespace Godot return new Basis(axis, phi).Xform(this); } + [Obsolete("Set is deprecated. Use the Vector3(" + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)] public void Set(real_t x, real_t y, real_t z) { this.x = x; this.y = y; this.z = z; } + [Obsolete("Set is deprecated. Use the Vector3(" + nameof(Vector3) + ") constructor instead.", error: true)] public void Set(Vector3 v) { x = v.x; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 2497f083b5..45f79074be 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -283,6 +283,18 @@ void GDMono::initialize() { add_mono_shared_libs_dir_to_path(); + { + PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM, + vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR)); + unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP); + ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop); + + if (Engine::get_singleton()->is_editor_hint()) { + // Unhandled exceptions should not terminate the editor + unhandled_exception_policy = POLICY_LOG_ERROR; + } + } + GDMonoAssembly::initialize(); gdmono_profiler_init(); @@ -602,12 +614,12 @@ bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type) { String GDMono::update_api_assemblies_from_prebuilt() { -#define FAIL_REASON(m_out_of_sync, m_prebuilt_exist) \ +#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \ ( \ (m_out_of_sync ? \ String("The assembly is invalidated") : \ String("The assembly was not found")) + \ - (m_prebuilt_exist ? \ + (m_prebuilt_exists ? \ String(" and the prebuilt assemblies are missing") : \ String(" and we failed to copy the prebuilt assemblies"))) @@ -619,16 +631,18 @@ String GDMono::update_api_assemblies_from_prebuilt() { if (!api_assembly_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) return String(); // No update needed + print_verbose("Updating API assemblies"); + String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) - return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ false); + return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ false); // Copy the prebuilt Api if (!copy_prebuilt_api_assembly(APIAssembly::API_CORE) || !copy_prebuilt_api_assembly(APIAssembly::API_EDITOR)) - return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ true); + return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ true); return String(); // Updated successfully @@ -643,7 +657,14 @@ bool GDMono::_load_core_api_assembly() { #ifdef TOOLS_ENABLED // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date - String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll"); + + // If running the project manager, load it from the prebuilt API directory + String assembly_dir = !Main::is_project_manager() ? + GodotSharpDirs::get_res_assemblies_dir() : + GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); + + String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); + bool success = FileAccess::exists(assembly_path) && load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly); #else @@ -674,7 +695,14 @@ bool GDMono::_load_editor_api_assembly() { return true; // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date - String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + + // If running the project manager, load it from the prebuilt API directory + String assembly_dir = !Main::is_project_manager() ? + GodotSharpDirs::get_res_assemblies_dir() : + GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); + + String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + bool success = FileAccess::exists(assembly_path) && load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly); @@ -699,9 +727,6 @@ bool GDMono::_try_load_api_assemblies() { return false; } - if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) - return false; - #ifdef TOOLS_ENABLED if (!_load_editor_api_assembly()) { if (OS::get_singleton()->is_stdout_verbose()) @@ -713,6 +738,12 @@ bool GDMono::_try_load_api_assemblies() { return false; #endif + // Check if the core API assembly is out of sync only after trying to load the + // editor API assembly. Otherwise, if both assemblies are out of sync, we would + // only update the former as we won't know the latter also needs to be updated. + if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) + return false; + return true; } @@ -723,6 +754,12 @@ void GDMono::_load_api_assemblies() { // The API assemblies are out of sync. Fine, try one more time, but this time // update them from the prebuilt assemblies directory before trying to load them. + // Shouldn't happen. The project manager loads the prebuilt API assemblies + if (Main::is_project_manager()) { + ERR_EXPLAIN("Failed to load one of the prebuilt API assemblies"); + CRASH_NOW(); + } + // 1. Unload the scripts domain if (_unload_scripts_domain() != OK) { ERR_EXPLAIN("Mono: Failed to unload scripts domain"); @@ -1058,6 +1095,8 @@ GDMono::GDMono() { #ifdef TOOLS_ENABLED api_editor_hash = 0; #endif + + unhandled_exception_policy = POLICY_TERMINATE_APP; } GDMono::~GDMono() { diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index deebe5fd50..c5bcce4fa1 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -80,6 +80,13 @@ String to_string(Type p_type); class GDMono { +public: + enum UnhandledExceptionPolicy { + POLICY_TERMINATE_APP, + POLICY_LOG_ERROR + }; + +private: bool runtime_initialized; bool finalizing_scripts_domain; @@ -102,6 +109,8 @@ class GDMono { HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies; + UnhandledExceptionPolicy unhandled_exception_policy; + void _domain_assemblies_cleanup(uint32_t p_domain_id); bool _are_api_assemblies_out_of_sync(); @@ -162,7 +171,9 @@ public: static GDMono *get_singleton() { return singleton; } - static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data); + GD_NORETURN static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data); + + UnhandledExceptionPolicy get_unhandled_exception_policy() const { return unhandled_exception_policy; } // Do not use these, unless you know what you're doing void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly); diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index a84332d4cd..e50e3b0794 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -108,9 +108,18 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { void unhandled_exception(MonoException *p_exc) { mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well - // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders - GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL); - GD_UNREACHABLE(); + + if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) { + // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders + GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL); + GD_UNREACHABLE(); + } else { +#ifdef DEBUG_ENABLED + GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc); + if (ScriptDebugger::get_singleton()) + ScriptDebugger::get_singleton()->idle_poll(); +#endif + } } } // namespace GDMonoInternals diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h index 2d77bde27c..0d82723913 100644 --- a/modules/mono/mono_gd/gd_mono_internals.h +++ b/modules/mono/mono_gd/gd_mono_internals.h @@ -45,7 +45,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged); * Do not call this function directly. * Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead. */ -GD_NORETURN void unhandled_exception(MonoException *p_exc); +void unhandled_exception(MonoException *p_exc); } // namespace GDMonoInternals diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 5987fa8ebb..7afdfc8ac8 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -37,6 +37,10 @@ #include "core/project_settings.h" #include "core/reference.h" +#ifdef TOOLS_ENABLED +#include "editor/script_editor_debugger.h" +#endif + #include "../csharp_script.h" #include "../utils/macros.h" #include "../utils/mutex_utils.h" @@ -596,8 +600,14 @@ void debug_print_unhandled_exception(MonoException *p_exc) { void debug_send_unhandled_exception_error(MonoException *p_exc) { #ifdef DEBUG_ENABLED - if (!ScriptDebugger::get_singleton()) + if (!ScriptDebugger::get_singleton()) { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + ERR_PRINTS(GDMonoUtils::get_exception_name_and_message(p_exc)); + } +#endif return; + } _TLS_RECURSION_GUARD_; @@ -621,7 +631,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { if (unexpected_exc) { GDMonoInternals::unhandled_exception(unexpected_exc); - GD_UNREACHABLE(); + return; } Vector<ScriptLanguage::StackInfo> _si; @@ -655,7 +665,6 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { void debug_unhandled_exception(MonoException *p_exc) { GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well - GD_UNREACHABLE(); } void print_unhandled_exception(MonoException *p_exc) { @@ -665,11 +674,9 @@ void print_unhandled_exception(MonoException *p_exc) { void set_pending_exception(MonoException *p_exc) { #ifdef NO_PENDING_EXCEPTIONS debug_unhandled_exception(p_exc); - GD_UNREACHABLE(); #else if (get_runtime_invoke_count() == 0) { debug_unhandled_exception(p_exc); - GD_UNREACHABLE(); } if (!mono_runtime_set_pending_exception(p_exc, false)) { diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index f535fbb6d0..d73743bf0b 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -289,7 +289,7 @@ void set_exception_message(MonoException *p_exc, String message); void debug_print_unhandled_exception(MonoException *p_exc); void debug_send_unhandled_exception_error(MonoException *p_exc); -GD_NORETURN void debug_unhandled_exception(MonoException *p_exc); +void debug_unhandled_exception(MonoException *p_exc); void print_unhandled_exception(MonoException *p_exc); /** |