diff options
Diffstat (limited to 'modules/mono')
12 files changed, 233 insertions, 12 deletions
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml index 1eb3404f9e..e1e9d1381f 100644 --- a/modules/mono/doc_classes/CSharpScript.xml +++ b/modules/mono/doc_classes/CSharpScript.xml @@ -1,16 +1,21 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CSharpScript" inherits="Script" version="4.0"> <brief_description> + A script implemented in the C# programming language (Mono-enabled builds only). </brief_description> <description> + This class represents a C# script. It is the C# equivalent of the [GDScript] class and is only available in Mono-enabled Godot builds. + See also [GodotSharp]. </description> <tutorials> + <link>https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html</link> </tutorials> <methods> <method name="new" qualifiers="vararg"> <return type="Variant"> </return> <description> + Returns a new instance of the script. </description> </method> </methods> diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml index 19a08d2036..417f8ac704 100644 --- a/modules/mono/doc_classes/GodotSharp.xml +++ b/modules/mono/doc_classes/GodotSharp.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GodotSharp" inherits="Object" version="4.0"> <brief_description> + Bridge between Godot and the Mono runtime (Mono-enabled builds only). </brief_description> <description> + This class is a bridge between Godot and the Mono runtime. It exposes several low-level operations and is only available in Mono-enabled Godot builds. + See also [CSharpScript]. </description> <tutorials> </tutorials> @@ -11,26 +14,30 @@ <return type="void"> </return> <description> - Attaches the current thread to the mono runtime. + Attaches the current thread to the Mono runtime. </description> </method> <method name="detach_thread"> <return type="void"> </return> <description> - Detaches the current thread from the mono runtime. + Detaches the current thread from the Mono runtime. </description> </method> <method name="get_domain_id"> <return type="int"> </return> <description> + Returns the current MonoDomain ID. + [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash. </description> </method> <method name="get_scripts_domain_id"> <return type="int"> </return> <description> + Returns the scripts MonoDomain's ID. This will be the same MonoDomain ID as [method get_domain_id], unless the scripts domain isn't loaded. + [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash. </description> </method> <method name="is_domain_finalizing_for_unload"> @@ -39,26 +46,28 @@ <argument index="0" name="domain_id" type="int"> </argument> <description> - Returns whether the domain is being finalized. + Returns [code]true[/code] if the domain is being finalized, [code]false[/code] otherwise. </description> </method> <method name="is_runtime_initialized"> <return type="bool"> </return> <description> + Returns [code]true[/code] if the Mono runtime is initialized, [code]false[/code] otherwise. </description> </method> <method name="is_runtime_shutting_down"> <return type="bool"> </return> <description> + Returns [code]true[/code] if the Mono runtime is shutting down, [code]false[/code] otherwise. </description> </method> <method name="is_scripts_domain_loaded"> <return type="bool"> </return> <description> - Returns whether the scripts domain is loaded. + Returns [code]true[/code] if the scripts domain is loaded, [code]false[/code] otherwise. </description> </method> </methods> diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs index 7ab5c5fc59..012b69032e 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs +++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs @@ -25,8 +25,9 @@ namespace GodotTools.Core bool rooted = path.IsAbsolutePath(); path = path.Replace('\\', '/'); + path = path[path.Length - 1] == '/' ? path.Substring(0, path.Length - 1) : path; - string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim(); diff --git a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs index 3cf495f025..3de3d8d318 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs @@ -20,8 +20,8 @@ namespace GodotTools private ItemList buildTabsList; private TabContainer buildTabs; - private ToolButton warningsBtn; - private ToolButton errorsBtn; + private Button warningsBtn; + private Button errorsBtn; private Button viewLogBtn; private void _UpdateBuildTabsList() @@ -285,7 +285,7 @@ namespace GodotTools toolBarHBox.AddSpacer(begin: false); - warningsBtn = new ToolButton + warningsBtn = new Button { Text = "Warnings".TTR(), ToggleMode = true, @@ -296,7 +296,7 @@ namespace GodotTools warningsBtn.Toggled += _WarningsToggled; toolBarHBox.AddChild(warningsBtn); - errorsBtn = new ToolButton + errorsBtn = new Button { Text = "Errors".TTR(), ToggleMode = true, diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 403e25781d..f330f9ed2c 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -30,7 +30,7 @@ namespace GodotTools private AcceptDialog aboutDialog; private CheckBox aboutDialogCheckBox; - private ToolButton bottomPanelBtn; + private Button bottomPanelBtn; public GodotIdeManager GodotIdeManager { get; private set; } @@ -513,7 +513,7 @@ namespace GodotTools menuPopup.IdPressed += _MenuOptionPressed; - var buildButton = new ToolButton + var buildButton = new Button { Text = "Build", HintTooltip = "Build solution", diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs index 98e8d13be0..17f3339560 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs @@ -12,6 +12,7 @@ using GodotTools.IdeMessaging; using GodotTools.IdeMessaging.Requests; using GodotTools.IdeMessaging.Utils; using GodotTools.Internals; +using GodotTools.Utils; using Newtonsoft.Json; using Directory = System.IO.Directory; using File = System.IO.File; @@ -362,8 +363,13 @@ namespace GodotTools.Ides private static async Task<Response> HandleCodeCompletionRequest(CodeCompletionRequest request) { + // This is needed if the "resource path" part of the path is case insensitive. + // However, it doesn't fix resource loading if the rest of the path is also case insensitive. + string scriptFileLocalized = FsPathUtils.LocalizePathWithCaseChecked(request.ScriptFile); + var response = new CodeCompletionResponse {Kind = request.Kind, ScriptFile = request.ScriptFile}; - response.Suggestions = await Task.Run(() => Internal.CodeCompletionRequest(response.Kind, response.ScriptFile)); + response.Suggestions = await Task.Run(() => + Internal.CodeCompletionRequest(response.Kind, scriptFileLocalized ?? request.ScriptFile)); return response; } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs new file mode 100644 index 0000000000..c6724ccaf7 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; +using Godot; +using GodotTools.Core; +using JetBrains.Annotations; + +namespace GodotTools.Utils +{ + public static class FsPathUtils + { + private static readonly string ResourcePath = ProjectSettings.GlobalizePath("res://"); + + private static bool PathStartsWithAlreadyNorm(this string childPath, string parentPath) + { + // This won't work for Linux/macOS case insensitive file systems, but it's enough for our current problems + bool caseSensitive = !OS.IsWindows; + + string parentPathNorm = parentPath.NormalizePath() + Path.DirectorySeparatorChar; + string childPathNorm = childPath.NormalizePath() + Path.DirectorySeparatorChar; + + return childPathNorm.StartsWith(parentPathNorm, + caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); + } + + public static bool PathStartsWith(this string childPath, string parentPath) + { + string childPathNorm = childPath.NormalizePath() + Path.DirectorySeparatorChar; + string parentPathNorm = parentPath.NormalizePath() + Path.DirectorySeparatorChar; + + return childPathNorm.PathStartsWithAlreadyNorm(parentPathNorm); + } + + [CanBeNull] + public static string LocalizePathWithCaseChecked(string path) + { + string pathNorm = path.NormalizePath() + Path.DirectorySeparatorChar; + string resourcePathNorm = ResourcePath.NormalizePath() + Path.DirectorySeparatorChar; + + if (!pathNorm.PathStartsWithAlreadyNorm(resourcePathNorm)) + return null; + + string result = "res://" + pathNorm.Substring(resourcePathNorm.Length); + + // Remove the last separator we added + return result.Substring(0, result.Length - 1); + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs new file mode 100644 index 0000000000..20b11a48dd --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs @@ -0,0 +1,17 @@ +using System; +using System.Runtime.CompilerServices; +using Godot.Collections; + +namespace Godot +{ + public partial class SceneTree + { + public Array<T> GetNodesInGroup<T>(StringName group) where T : class + { + return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(Object.GetPtr(this), StringName.GetPtr(group), typeof(T))); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, IntPtr group, Type elemType); + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index b5ac124c9a..06ec2483c8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -53,6 +53,7 @@ <Compile Include="Core\Extensions\NodeExtensions.cs" /> <Compile Include="Core\Extensions\ObjectExtensions.cs" /> <Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" /> + <Compile Include="Core\Extensions\SceneTreeExtensions.cs" /> <Compile Include="Core\GD.cs" /> <Compile Include="Core\GodotSynchronizationContext.cs" /> <Compile Include="Core\GodotTaskScheduler.cs" /> diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index ee99a300b9..f6999d01fb 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -35,6 +35,7 @@ #include "gd_glue.h" #include "nodepath_glue.h" #include "rid_glue.h" +#include "scene_tree_glue.h" #include "string_glue.h" #include "string_name_glue.h" @@ -50,6 +51,7 @@ void godot_register_glue_header_icalls() { godot_register_object_icalls(); godot_register_rid_icalls(); godot_register_string_icalls(); + godot_register_scene_tree_icalls(); } // Used by the generated glue diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp new file mode 100644 index 0000000000..bea9544b08 --- /dev/null +++ b/modules/mono/glue/scene_tree_glue.cpp @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* scene_tree_glue.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "scene_tree_glue.h" + +#ifdef MONO_GLUE_ENABLED + +#include "core/class_db.h" +#include "modules/mono/csharp_script.h" +#include "modules/mono/mono_gd/gd_mono_utils.h" +#include "scene/main/node.h" + +Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype) { + List<Node *> nodes; + Array ret; + + // Retrieve all the nodes in the group + ptr->get_nodes_in_group(*group, &nodes); + + // No need to bother if the group is empty + if (!nodes.empty()) { + MonoType *elem_type = mono_reflection_type_get_type(refltype); + MonoClass *mono_class = mono_class_from_mono_type(elem_type); + GDMonoClass *klass = GDMono::get_singleton()->get_class(mono_class); + + if (klass == GDMonoUtils::get_class_native_base(klass)) { + // If we're trying to get native objects, just check the inheritance list + StringName native_class_name = GDMonoUtils::get_native_godot_class_name(klass); + for (int i = 0; i < nodes.size(); ++i) { + if (ClassDB::is_parent_class(nodes[i]->get_class(), native_class_name)) + ret.push_back(nodes[i]); + } + } else { + // If we're trying to get csharpscript instances, get the mono object and compare the classes + for (int i = 0; i < nodes.size(); ++i) { + CSharpInstance *si = CAST_CSHARP_INSTANCE(nodes[i]->get_script_instance()); + + if (si != nullptr) { + MonoObject *obj = si->get_mono_object(); + if (obj != nullptr && mono_object_get_class(obj) == mono_class) { + ret.push_back(nodes[i]); + } + } + } + } + } + + return memnew(Array(ret)); +} + +void godot_register_scene_tree_icalls() { + mono_add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", (void *)godot_icall_SceneTree_get_nodes_in_group_Generic); +} + +#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/scene_tree_glue.h b/modules/mono/glue/scene_tree_glue.h new file mode 100644 index 0000000000..e9af35a30b --- /dev/null +++ b/modules/mono/glue/scene_tree_glue.h @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* scene_tree_glue.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SCENE_TREE_GLUE_H +#define SCENE_TREE_GLUE_H + +#ifdef MONO_GLUE_ENABLED + +#include "core/array.h" +#include "core/string_name.h" +#include "scene/main/scene_tree.h" + +#include "../mono_gd/gd_mono_marshal.h" + +Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype); + +// Register internal calls + +void godot_register_scene_tree_icalls(); + +#endif // MONO_GLUE_ENABLED + +#endif // SCENE_TREE_GLUE_H |