diff options
Diffstat (limited to 'modules/mono')
27 files changed, 698 insertions, 120 deletions
diff --git a/modules/mono/SCsub b/modules/mono/SCsub index b3a2d26e4a..1d5c145027 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -134,6 +134,7 @@ def find_msbuild_unix(filename): def find_msbuild_windows(): import mono_reg_utils as monoreg + mono_root = '' bits = env['bits'] if bits == '32': diff --git a/modules/mono/config.py b/modules/mono/config.py index 70fd1a35f1..01649a972e 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -99,6 +99,8 @@ def configure(env): if not mono_root: raise RuntimeError('Mono installation directory not found') + print('Found Mono root directory: ' + mono_root) + mono_version = mono_root_try_find_mono_version(mono_root) configure_for_mono_version(env, mono_version) @@ -164,6 +166,14 @@ def configure(env): if os.getenv('MONO64_PREFIX'): mono_root = os.getenv('MONO64_PREFIX') + if not mono_root and sys.platform == 'darwin': + # Try with some known directories under OSX + hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current', '/usr/local/var/homebrew/linked/mono'] + for hint_dir in hint_dirs: + if os.path.isdir(hint_dir): + mono_root = hint_dir + break + # We can't use pkg-config to link mono statically, # but we can still use it to find the mono root directory if not mono_root and mono_static: @@ -172,6 +182,8 @@ def configure(env): raise RuntimeError('Building with mono_static=yes, but failed to find the mono prefix with pkg-config. Specify one manually') if mono_root: + print('Found Mono root directory: ' + mono_root) + mono_version = mono_root_try_find_mono_version(mono_root) configure_for_mono_version(env, mono_version) @@ -216,6 +228,9 @@ def configure(env): else: assert not mono_static + # TODO: Add option to force using pkg-config + print('Mono root directory not found. Using pkg-config instead') + mono_version = pkgconfig_try_find_mono_version() configure_for_mono_version(env, mono_version) @@ -248,7 +263,7 @@ def configure(env): def configure_for_mono_version(env, mono_version): if mono_version is None: raise RuntimeError('Mono JIT compiler version not found') - print('Mono JIT compiler version: ' + str(mono_version)) + print('Found Mono JIT compiler version: ' + str(mono_version)) if mono_version >= LooseVersion("5.12.0"): env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS']) @@ -282,7 +297,14 @@ def pkgconfig_try_find_mono_version(): def mono_root_try_find_mono_version(mono_root): from compat import decode_utf8 - output = subprocess.check_output([os.path.join(mono_root, 'bin', 'mono'), '--version']) + mono_bin = os.path.join(mono_root, 'bin') + if os.path.isfile(os.path.join(mono_bin, 'mono')): + mono_binary = os.path.join(mono_bin, 'mono') + elif os.path.isfile(os.path.join(mono_bin, 'mono.exe')): + mono_binary = os.path.join(mono_bin, 'mono.exe') + else: + return None + output = subprocess.check_output([mono_binary, '--version']) first_line = decode_utf8(output.splitlines()[0]) try: return LooseVersion(first_line.split()[len('Mono JIT compiler version'.split())]) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b9209fce92..91fd482235 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1174,7 +1174,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { GDMonoProperty *property = script->script_class->get_property(p_name); if (property) { - property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value)); + property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type())); return true; } @@ -1541,18 +1541,20 @@ MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(GDMonoClassMember * if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) return MultiplayerAPI::RPC_MODE_REMOTE; - if (p_member->has_attribute(CACHED_CLASS(SyncAttribute))) - return MultiplayerAPI::RPC_MODE_SYNC; if (p_member->has_attribute(CACHED_CLASS(MasterAttribute))) return MultiplayerAPI::RPC_MODE_MASTER; + if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute))) + return MultiplayerAPI::RPC_MODE_PUPPET; if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute))) - return MultiplayerAPI::RPC_MODE_SLAVE; + return MultiplayerAPI::RPC_MODE_PUPPET; if (p_member->has_attribute(CACHED_CLASS(RemoteSyncAttribute))) return MultiplayerAPI::RPC_MODE_REMOTESYNC; + if (p_member->has_attribute(CACHED_CLASS(SyncAttribute))) + return MultiplayerAPI::RPC_MODE_REMOTESYNC; if (p_member->has_attribute(CACHED_CLASS(MasterSyncAttribute))) return MultiplayerAPI::RPC_MODE_MASTERSYNC; - if (p_member->has_attribute(CACHED_CLASS(SlaveSyncAttribute))) - return MultiplayerAPI::RPC_MODE_SLAVESYNC; + if (p_member->has_attribute(CACHED_CLASS(PuppetSyncAttribute))) + return MultiplayerAPI::RPC_MODE_PUPPETSYNC; return MultiplayerAPI::RPC_MODE_DISABLED; } diff --git a/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs b/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs index 303be3b732..fba4a8f65c 100644 --- a/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs +++ b/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs @@ -2,13 +2,23 @@ using System; using System.IO; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; namespace GodotSharpTools.Editor { public class MonoDevelopInstance { - private Process process; - private string solutionFile; + public enum EditorId + { + MonoDevelop = 0, + VisualStudioForMac = 1 + } + + readonly string solutionFile; + readonly EditorId editorId; + + Process process; public void Execute(string[] files) { @@ -16,6 +26,35 @@ namespace GodotSharpTools.Editor List<string> args = new List<string>(); + string command; + + if (Utils.OS.IsOSX()) + { + string bundleId = codeEditorBundleIds[editorId]; + + if (IsApplicationBundleInstalled(bundleId)) + { + command = "open"; + + args.Add("-b"); + args.Add(bundleId); + + // The 'open' process must wait until the application finishes + if (newWindow) + args.Add("--wait-apps"); + + args.Add("--args"); + } + else + { + command = codeEditorPaths[editorId]; + } + } + else + { + command = codeEditorPaths[editorId]; + } + args.Add("--ipc-tcp"); if (newWindow) @@ -33,25 +72,73 @@ namespace GodotSharpTools.Editor if (newWindow) { - ProcessStartInfo startInfo = new ProcessStartInfo(MonoDevelopFile, string.Join(" ", args)); - process = Process.Start(startInfo); + process = Process.Start(new ProcessStartInfo() + { + FileName = command, + Arguments = string.Join(" ", args), + UseShellExecute = false + }); } else { - Process.Start(MonoDevelopFile, string.Join(" ", args)); + Process.Start(new ProcessStartInfo() + { + FileName = command, + Arguments = string.Join(" ", args), + UseShellExecute = false + }); } } - public MonoDevelopInstance(string solutionFile) + public MonoDevelopInstance(string solutionFile, EditorId editorId) { + if (editorId == EditorId.VisualStudioForMac && !Utils.OS.IsOSX()) + throw new InvalidOperationException($"{nameof(EditorId.VisualStudioForMac)} not supported on this platform"); + this.solutionFile = solutionFile; + this.editorId = editorId; } - private static string MonoDevelopFile + [MethodImpl(MethodImplOptions.InternalCall)] + private extern static bool IsApplicationBundleInstalled(string bundleId); + + static readonly IReadOnlyDictionary<EditorId, string> codeEditorPaths; + static readonly IReadOnlyDictionary<EditorId, string> codeEditorBundleIds; + + static MonoDevelopInstance() { - get + if (Utils.OS.IsOSX()) + { + codeEditorPaths = new Dictionary<EditorId, string> + { + // Rely on PATH + { EditorId.MonoDevelop, "monodevelop" }, + { EditorId.VisualStudioForMac, "VisualStudio" } + }; + codeEditorBundleIds = new Dictionary<EditorId, string> + { + // TODO EditorId.MonoDevelop + { EditorId.VisualStudioForMac, "com.microsoft.visual-studio" } + }; + } + else if (Utils.OS.IsWindows()) + { + codeEditorPaths = 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 + // is to use Visual Studio instead. Since there are no official builds, we + // will rely on custom MonoDevelop builds being added to PATH. + { EditorId.MonoDevelop, "MonoDevelop.exe" } + }; + } + else if (Utils.OS.IsUnix()) { - return "monodevelop"; + codeEditorPaths = new Dictionary<EditorId, string> + { + // Rely on PATH + { EditorId.MonoDevelop, "monodevelop" } + }; } } } diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj index 1c8714e31d..773e8196f7 100644 --- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj @@ -40,6 +40,7 @@ <Compile Include="Project\ProjectGenerator.cs" /> <Compile Include="Project\ProjectUtils.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Utils\OS.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs b/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs deleted file mode 100644 index 0cbafdc20d..0000000000 --- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs +++ /dev/null @@ -1,14 +0,0 @@ -<Properties StartupItem="GodotSharpTools.csproj"> - <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" /> - <MonoDevelop.Ide.Workbench ActiveDocument="Build/BuildSystem.cs"> - <Files> - <File FileName="Build/ProjectExtensions.cs" Line="1" Column="1" /> - <File FileName="Build/ProjectGenerator.cs" Line="1" Column="1" /> - <File FileName="Build/BuildSystem.cs" Line="37" Column="14" /> - </Files> - </MonoDevelop.Ide.Workbench> - <MonoDevelop.Ide.DebuggingService.Breakpoints> - <BreakpointStore /> - </MonoDevelop.Ide.DebuggingService.Breakpoints> - <MonoDevelop.Ide.DebuggingService.PinnedWatches /> -</Properties>
\ No newline at end of file diff --git a/modules/mono/editor/GodotSharpTools/Utils/OS.cs b/modules/mono/editor/GodotSharpTools/Utils/OS.cs new file mode 100644 index 0000000000..148e954e77 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Utils/OS.cs @@ -0,0 +1,62 @@ +using System; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace GodotSharpTools.Utils +{ + public static class OS + { + [MethodImpl(MethodImplOptions.InternalCall)] + extern static string GetPlatformName(); + + const string HaikuName = "Haiku"; + const string OSXName = "OSX"; + const string ServerName = "Server"; + const string UWPName = "UWP"; + const string WindowsName = "Windows"; + const string X11Name = "X11"; + + public static bool IsHaiku() + { + return HaikuName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + } + + public static bool IsOSX() + { + return OSXName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + } + + public static bool IsServer() + { + return ServerName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + } + + public static bool IsUWP() + { + return UWPName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + } + + public static bool IsWindows() + { + return WindowsName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + } + + public static bool IsX11() + { + return X11Name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + } + + static bool? IsUnixCache = null; + static readonly string[] UnixPlatforms = new string[] { HaikuName, OSXName, ServerName, X11Name }; + + public static bool IsUnix() + { + if (IsUnixCache.HasValue) + return IsUnixCache.Value; + + string osName = GetPlatformName(); + IsUnixCache = UnixPlatforms.Any(p => p.Equals(osName, StringComparison.OrdinalIgnoreCase)); + return IsUnixCache.Value; + } + } +} diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index b01f8e66c3..d397814fa7 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -94,7 +94,12 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() { #if defined(WINDOWS_ENABLED) switch (build_tool) { case GodotSharpBuilds::MSBUILD_VS: { - static String msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path(); + static String msbuild_tools_path; + + if (msbuild_tools_path.empty() || !FileAccess::exists(msbuild_tools_path)) { + // Try to search it again if it wasn't found last time or if it was removed from its location + msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path(); + } if (msbuild_tools_path.length()) { if (!msbuild_tools_path.ends_with("\\")) @@ -128,15 +133,25 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() { CRASH_NOW(); } #elif defined(UNIX_ENABLED) - static String msbuild_path = _find_build_engine_on_unix("msbuild"); - static String xbuild_path = _find_build_engine_on_unix("xbuild"); + static String msbuild_path; + static String xbuild_path; if (build_tool == GodotSharpBuilds::XBUILD) { + if (xbuild_path.empty() || !FileAccess::exists(xbuild_path)) { + // Try to search it again if it wasn't found last time or if it was removed from its location + xbuild_path = _find_build_engine_on_unix("msbuild"); + } + if (xbuild_path.empty()) { WARN_PRINT("Cannot find binary for '" PROP_NAME_XBUILD "'"); return NULL; } } else { + if (msbuild_path.empty() || !FileAccess::exists(msbuild_path)) { + // Try to search it again if it wasn't found last time or if it was removed from its location + msbuild_path = _find_build_engine_on_unix("msbuild"); + } + if (msbuild_path.empty()) { WARN_PRINT("Cannot find binary for '" PROP_NAME_MSBUILD_MONO "'"); return NULL; @@ -192,7 +207,11 @@ MonoBoolean godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows() { #endif } -void GodotSharpBuilds::_register_internal_calls() { +void GodotSharpBuilds::register_internal_calls() { + + static bool registered = false; + ERR_FAIL_COND(registered); + registered = true; 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); diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index 4afc284d45..c6dc6b6236 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -61,9 +61,6 @@ private: static GodotSharpBuilds *singleton; - friend class GDMono; - static void _register_internal_calls(); - public: enum BuildTool { MSBUILD_MONO, @@ -75,6 +72,8 @@ public: _FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; } + static void register_internal_calls(); + static void show_build_error_dialog(const String &p_message); void build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index faeb58e5a7..3ee38515bf 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -38,12 +38,17 @@ #include "../csharp_script.h" #include "../godotsharp_dirs.h" #include "../mono_gd/gd_mono.h" +#include "../mono_gd/gd_mono_marshal.h" #include "../utils/path_utils.h" #include "bindings_generator.h" #include "csharp_project.h" #include "godotsharp_export.h" #include "net_solution.h" +#ifdef OSX_ENABLED +#include "../utils/osx_utils.h" +#endif + #ifdef WINDOWS_ENABLED #include "../utils/mono_reg_utils.h" #endif @@ -169,6 +174,31 @@ void GodotSharpEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed); } +MonoBoolean godot_icall_MonoDevelopInstance_IsApplicationBundleInstalled(MonoString *p_bundle_id) { +#ifdef OSX_ENABLED + return (MonoBoolean)osx_is_app_bundle_installed(GDMonoMarshal::mono_string_to_godot(p_bundle_id)); +#else + (void)p_bundle_id; // UNUSED + ERR_FAIL_V(false); +#endif +} + +MonoString *godot_icall_Utils_OS_GetPlatformName() { + return GDMonoMarshal::mono_string_from_godot(OS::get_singleton()->get_name()); +} + +void GodotSharpEditor::register_internal_calls() { + + static bool registered = false; + ERR_FAIL_COND(registered); + registered = true; + + mono_add_internal_call("GodotSharpTools.Editor.MonoDevelopInstance::IsApplicationBundleInstalled", (void *)godot_icall_MonoDevelopInstance_IsApplicationBundleInstalled); + mono_add_internal_call("GodotSharpTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName); + + GodotSharpBuilds::register_internal_calls(); +} + void GodotSharpEditor::show_error_dialog(const String &p_message, const String &p_title) { error_dialog->set_title(p_title); @@ -181,8 +211,36 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int ExternalEditor editor = ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor"))); switch (editor) { - case EDITOR_CODE: { + case EDITOR_VSCODE: { + static String vscode_path; + + if (vscode_path.empty() || !FileAccess::exists(vscode_path)) { + // Try to search it again if it wasn't found last time or if it was removed from its location + vscode_path = path_which("code"); + } + List<String> args; + +#ifdef OSX_ENABLED + // The package path is '/Applications/Visual Studio Code.app' + static const String vscode_bundle_id = "com.microsoft.VSCode"; + static bool osx_app_bundle_installed = osx_is_app_bundle_installed(vscode_bundle_id); + + if (osx_app_bundle_installed) { + args.push_back("-b"); + args.push_back(vscode_bundle_id); + + // The reusing of existing windows made by the 'open' command might not choose a wubdiw that is + // editing our folder. It's better to ask for a new window and let VSCode do the window management. + args.push_back("-n"); + + // The open process must wait until the application finishes (which is instant in VSCode's case) + args.push_back("--wait-apps"); + + args.push_back("--args"); + } +#endif + args.push_back(ProjectSettings::get_singleton()->get_resource_path()); String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); @@ -194,18 +252,47 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int args.push_back(script_path); } - static String program = path_which("code"); +#ifdef OSX_ENABLED + ERR_EXPLAIN("Cannot find code editor: VSCode"); + ERR_FAIL_COND_V(!osx_app_bundle_installed && vscode_path.empty(), ERR_FILE_NOT_FOUND); - Error err = OS::get_singleton()->execute(program.length() ? program : "code", args, false); + String command = osx_app_bundle_installed ? "/usr/bin/open" : vscode_path; +#else + ERR_EXPLAIN("Cannot find code editor: VSCode"); + ERR_FAIL_COND_V(vscode_path.empty(), ERR_FILE_NOT_FOUND); + + String command = vscode_path; +#endif + + Error err = OS::get_singleton()->execute(command, args, false); if (err != OK) { - ERR_PRINT("GodotSharp: Could not execute external editor"); + ERR_PRINT("Error when trying to execute code editor: VSCode"); return err; } } break; +#ifdef OSX_ENABLED + case EDITOR_VISUALSTUDIO_MAC: + // [[fallthrough]]; +#endif case EDITOR_MONODEVELOP: { - if (!monodevel_instance) - monodevel_instance = memnew(MonoDevelopInstance(GodotSharpDirs::get_project_sln_path())); +#ifdef OSX_ENABLED + bool is_visualstudio = editor == EDITOR_VISUALSTUDIO_MAC; + + MonoDevelopInstance **instance = is_visualstudio ? + &visualstudio_mac_instance : + &monodevelop_instance; + + MonoDevelopInstance::EditorId editor_id = is_visualstudio ? + MonoDevelopInstance::VISUALSTUDIO_FOR_MAC : + MonoDevelopInstance::MONODEVELOP; +#else + MonoDevelopInstance **instance = &monodevelop_instance; + MonoDevelopInstance::EditorId editor_id = MonoDevelopInstance::MONODEVELOP; +#endif + + if (!*instance) + *instance = memnew(MonoDevelopInstance(GodotSharpDirs::get_project_sln_path(), editor_id)); String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); @@ -213,7 +300,7 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int script_path += ";" + itos(p_line + 1) + ";" + itos(p_col); } - monodevel_instance->execute(script_path); + (*instance)->execute(script_path); } break; default: return ERR_UNAVAILABLE; @@ -231,7 +318,10 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { singleton = this; - monodevel_instance = NULL; + monodevelop_instance = NULL; +#ifdef OSX_ENABLED + visualstudio_mac_instance = NULL; +#endif editor = p_editor; @@ -314,7 +404,18 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { // External editor settings EditorSettings *ed_settings = EditorSettings::get_singleton(); EDITOR_DEF("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 Code")); + + String settings_hint_str = "None"; + +#ifdef WINDOWS_ENABLED + settings_hint_str += ",MonoDevelop,Visual Studio Code"; +#elif OSX_ENABLED + settings_hint_str += ",Visual Studio,MonoDevelop,Visual Studio Code"; +#elif UNIX_ENABLED + settings_hint_str += ",MonoDevelop,Visual Studio Code"; +#endif + + ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, settings_hint_str)); // Export plugin Ref<GodotSharpExport> godotsharp_export; @@ -328,9 +429,9 @@ GodotSharpEditor::~GodotSharpEditor() { memdelete(godotsharp_builds); - if (monodevel_instance) { - memdelete(monodevel_instance); - monodevel_instance = NULL; + if (monodevelop_instance) { + memdelete(monodevelop_instance); + monodevelop_instance = NULL; } } diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h index 66da814c8b..46b6bd5ebf 100644 --- a/modules/mono/editor/godotsharp_editor.h +++ b/modules/mono/editor/godotsharp_editor.h @@ -50,7 +50,10 @@ class GodotSharpEditor : public Node { GodotSharpBuilds *godotsharp_builds; - MonoDevelopInstance *monodevel_instance; + MonoDevelopInstance *monodevelop_instance; +#ifdef OSX_ENABLED + MonoDevelopInstance *visualstudio_mac_instance; +#endif bool _create_project_solution(); @@ -74,12 +77,24 @@ public: enum ExternalEditor { EDITOR_NONE, +#ifdef WINDOWS_ENABLED + //EDITOR_VISUALSTUDIO, // TODO EDITOR_MONODEVELOP, - EDITOR_CODE, + EDITOR_VSCODE +#elif OSX_ENABLED + EDITOR_VISUALSTUDIO_MAC, + EDITOR_MONODEVELOP, + EDITOR_VSCODE +#elif UNIX_ENABLED + EDITOR_MONODEVELOP, + EDITOR_VSCODE +#endif }; _FORCE_INLINE_ static GodotSharpEditor *get_singleton() { return singleton; } + static void register_internal_calls(); + void show_error_dialog(const String &p_message, const String &p_title = "Error"); Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col); diff --git a/modules/mono/editor/monodevelop_instance.cpp b/modules/mono/editor/monodevelop_instance.cpp index 9f05711fd6..1d858d80bf 100644 --- a/modules/mono/editor/monodevelop_instance.cpp +++ b/modules/mono/editor/monodevelop_instance.cpp @@ -47,7 +47,7 @@ void MonoDevelopInstance::execute(const Vector<String> &p_files) { execute_method->invoke(gc_handle->get_target(), args, &exc); if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL(); } } @@ -59,7 +59,7 @@ void MonoDevelopInstance::execute(const String &p_file) { execute(files); } -MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) { +MonoDevelopInstance::MonoDevelopInstance(const String &p_solution, EditorId p_editor_id) { _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) @@ -67,15 +67,16 @@ MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) { MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_mono_ptr()); - GDMonoMethod *ctor = klass->get_method(".ctor", 1); + GDMonoMethod *ctor = klass->get_method(".ctor", 2); MonoException *exc = NULL; Variant solution = p_solution; - const Variant *args[1] = { &solution }; + Variant editor_id = p_editor_id; + const Variant *args[2] = { &solution, &editor_id }; ctor->invoke(obj, args, &exc); if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL(); } diff --git a/modules/mono/editor/monodevelop_instance.h b/modules/mono/editor/monodevelop_instance.h index 73cf0f54cc..29de4a4735 100644 --- a/modules/mono/editor/monodevelop_instance.h +++ b/modules/mono/editor/monodevelop_instance.h @@ -42,10 +42,15 @@ class MonoDevelopInstance { GDMonoMethod *execute_method; public: + enum EditorId { + MONODEVELOP = 0, + VISUALSTUDIO_FOR_MAC = 1 + }; + void execute(const Vector<String> &p_files); void execute(const String &p_file); - MonoDevelopInstance(const String &p_solution); + MonoDevelopInstance(const String &p_solution, EditorId p_editor_id); }; #endif // MONODEVELOP_INSTANCE_H diff --git a/modules/mono/glue/Managed/Files/Array.cs b/modules/mono/glue/Managed/Files/Array.cs index c80cb7cc83..d5a35d7ae0 100644 --- a/modules/mono/glue/Managed/Files/Array.cs +++ b/modules/mono/glue/Managed/Files/Array.cs @@ -128,7 +128,7 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - yield return godot_icall_Array_At(GetPtr(), i); + yield return this[i]; } } @@ -167,6 +167,9 @@ namespace Godot.Collections internal extern static object godot_icall_Array_At(IntPtr ptr, int index); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -195,12 +198,23 @@ namespace Godot.Collections [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass); } public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> { Array objectArray; + internal static int elemTypeEncoding; + internal static IntPtr elemTypeClass; + + static Array() + { + Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass); + } + public Array() { objectArray = new Array(); @@ -230,7 +244,7 @@ namespace Godot.Collections { get { - return (T)objectArray[index]; + return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); } set { @@ -287,7 +301,7 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - array[arrayIndex] = (T)objectArray[i]; + array[arrayIndex] = (T)this[i]; arrayIndex++; } } @@ -298,7 +312,7 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - yield return (T)objectArray[i]; + yield return (T)this[i]; } } diff --git a/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs index 6bf9560bfa..2398e10135 100644 --- a/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs +++ b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs @@ -12,6 +12,9 @@ namespace Godot public class MasterAttribute : Attribute {} [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)] + public class PuppetAttribute : Attribute {} + + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)] public class SlaveAttribute : Attribute {} [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)] @@ -21,5 +24,5 @@ namespace Godot public class MasterSyncAttribute : Attribute {} [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)] - public class SlaveSyncAttribute : Attribute {} + public class PuppetSyncAttribute : Attribute {} } diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs index ec96a9e2fa..a5618cb28d 100644 --- a/modules/mono/glue/Managed/Files/Basis.cs +++ b/modules/mono/glue/Managed/Files/Basis.cs @@ -165,6 +165,38 @@ namespace Godot ); } + internal Quat RotationQuat() + { + Basis orthonormalizedBasis = Orthonormalized(); + real_t det = orthonormalizedBasis.Determinant(); + if (det < 0) + { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + orthonormalizedBasis = orthonormalizedBasis.Scaled(Vector3.NegOne); + } + + return orthonormalizedBasis.Quat(); + } + + internal void SetQuantScale(Quat quat, Vector3 scale) + { + SetDiagonal(scale); + Rotate(quat); + } + + private void Rotate(Quat quat) + { + this *= new Basis(quat); + } + + private void SetDiagonal(Vector3 diagonal) + { + _x = new Vector3(diagonal.x, 0, 0); + _y = new Vector3(0, diagonal.y, 0); + _z = new Vector3(0, 0, diagonal.z); + + } + public real_t Determinant() { return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) - diff --git a/modules/mono/glue/Managed/Files/Dictionary.cs b/modules/mono/glue/Managed/Files/Dictionary.cs index 523e48c31a..7695f03cd6 100644 --- a/modules/mono/glue/Managed/Files/Dictionary.cs +++ b/modules/mono/glue/Managed/Files/Dictionary.cs @@ -204,6 +204,9 @@ namespace Godot.Collections internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -235,6 +238,12 @@ namespace Godot.Collections [MethodImpl(MethodImplOptions.InternalCall)] internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass); } public class Dictionary<TKey, TValue> : @@ -244,6 +253,14 @@ namespace Godot.Collections { Dictionary objectDict; + internal static int valTypeEncoding; + internal static IntPtr valTypeClass; + + static Dictionary() + { + Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass); + } + public Dictionary() { objectDict = new Dictionary(); @@ -273,7 +290,7 @@ namespace Godot.Collections { get { - return (TValue)objectDict[key]; + return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); } set { @@ -382,7 +399,7 @@ namespace Godot.Collections public bool TryGetValue(TKey key, out TValue value) { object retValue; - bool found = objectDict.TryGetValue(key, out retValue); + bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass); value = found ? (TValue)retValue : default(TValue); return found; } diff --git a/modules/mono/glue/Managed/Files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs index e432d5b52c..068007d7f0 100644 --- a/modules/mono/glue/Managed/Files/Transform.cs +++ b/modules/mono/glue/Managed/Files/Transform.cs @@ -20,6 +20,25 @@ namespace Godot return new Transform(basisInv, basisInv.Xform(-origin)); } + public Transform InterpolateWith(Transform transform, real_t c) + { + /* not sure if very "efficient" but good enough? */ + + Vector3 sourceScale = basis.Scale; + Quat sourceRotation = basis.RotationQuat(); + Vector3 sourceLocation = origin; + + Vector3 destinationScale = transform.basis.Scale; + Quat destinationRotation = transform.basis.RotationQuat(); + Vector3 destinationLocation = transform.origin; + + var interpolated = new Transform(); + interpolated.basis.SetQuantScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c)); + interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, c); + + return interpolated; + } + public Transform Inverse() { Basis basisTr = basis.Transposed(); diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index d9dba1c60d..059e2ff6de 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -53,6 +53,14 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) { return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index)); } +MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) { + if (index < 0 || index > ptr->size()) { + GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); + return NULL; + } + return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class)); +} + void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) { if (index < 0 || index > ptr->size()) { GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); @@ -122,6 +130,14 @@ void godot_icall_Array_RemoveAt(Array *ptr, int index) { ptr->remove(index); } +void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) { + MonoType *elem_type = mono_reflection_type_get_type(refltype); + + *type_encoding = mono_type_get_type(elem_type); + MonoClass *type_class_raw = mono_class_from_mono_type(elem_type); + *type_class = GDMono::get_singleton()->get_class(type_class_raw); +} + Dictionary *godot_icall_Dictionary_Ctor() { return memnew(Dictionary); } @@ -144,6 +160,20 @@ MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) { return GDMonoMarshal::variant_to_mono_object(ret); } +MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) { + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + if (ret == NULL) { + MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr()); +#ifdef DEBUG_ENABLED + CRASH_COND(!exc); +#endif + GDMonoUtils::runtime_object_init(exc); + GDMonoUtils::set_pending_exception((MonoException *)exc); + return NULL; + } + return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class)); +} + void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) { ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value); } @@ -211,10 +241,29 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb return true; } +bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + if (ret == NULL) { + *value = NULL; + return false; + } + *value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class)); + return true; +} + +void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) { + MonoType *value_type = mono_reflection_type_get_type(refltype); + + *type_encoding = mono_type_get_type(value_type); + MonoClass *type_class_raw = mono_class_from_mono_type(value_type); + *type_class = GDMono::get_singleton()->get_class(type_class_raw); +} + void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add); @@ -225,10 +274,12 @@ void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", (void *)godot_icall_Dictionary_GetValue_Generic); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values); @@ -240,6 +291,8 @@ void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo); } #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h index fa8e4c28aa..b9b1338510 100644 --- a/modules/mono/glue/collections_glue.h +++ b/modules/mono/glue/collections_glue.h @@ -45,6 +45,8 @@ void godot_icall_Array_Dtor(Array *ptr); MonoObject *godot_icall_Array_At(Array *ptr, int index); +MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class); + void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value); int godot_icall_Array_Count(Array *ptr); @@ -65,6 +67,8 @@ bool godot_icall_Array_Remove(Array *ptr, MonoObject *item); void godot_icall_Array_RemoveAt(Array *ptr, int index); +void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class); + // Dictionary Dictionary *godot_icall_Dictionary_Ctor(); @@ -73,6 +77,8 @@ void godot_icall_Dictionary_Dtor(Dictionary *ptr); MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key); +MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class); + void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value); Array *godot_icall_Dictionary_Keys(Dictionary *ptr); @@ -95,6 +101,10 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); +bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class); + +void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class); + // Register internal calls void godot_register_collections_icalls(); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index b2b5a90507..9311aa3930 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -259,14 +259,15 @@ void GDMono::initialize() { // The following assemblies are not required at initialization #ifdef MONO_GLUE_ENABLED if (_load_api_assemblies()) { - if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) { - // Everything is fine with the api assemblies, load the project assembly - _load_project_assembly(); - } else { + // Everything is fine with the api assemblies, load the project assembly + _load_project_assembly(); + } else { + if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) || + (editor_api_assembly && editor_api_assembly_out_of_sync)) { #ifdef TOOLS_ENABLED - // The assembly was successfuly loaded, but the full api could not be cached. - // This is most likely an outdated assembly loaded because of an invalid version in the metadata, - // so we invalidate the version in the metadata and unload the script domain. + // The assembly was successfully loaded, but the full api could not be cached. + // This is most likely an outdated assembly loaded because of an invalid version in the + // metadata, so we invalidate the version in the metadata and unload the script domain. if (core_api_assembly_out_of_sync) { ERR_PRINT("The loaded Core API assembly is out of sync"); @@ -290,12 +291,12 @@ void GDMono::initialize() { #else ERR_PRINT("The loaded API assembly is invalid"); CRASH_NOW(); -#endif +#endif // TOOLS_ENABLED } } #else print_verbose("Mono: Glue disabled, ignoring script assemblies."); -#endif +#endif // MONO_GLUE_ENABLED print_verbose("Mono: INITIALIZED"); } @@ -319,7 +320,7 @@ void GDMono::_register_internal_calls() { #endif #ifdef TOOLS_ENABLED - GodotSharpBuilds::_register_internal_calls(); + GodotSharpEditor::register_internal_calls(); #endif } @@ -448,8 +449,10 @@ bool GDMono::_load_core_api_assembly() { return true; #ifdef TOOLS_ENABLED - if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) + if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) { + print_verbose("Mono: Skipping loading of Core API assembly because it was invalidated"); return false; + } #endif bool success = load_assembly(API_ASSEMBLY_NAME, &core_api_assembly); @@ -460,8 +463,12 @@ bool GDMono::_load_core_api_assembly() { core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash || GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || CS_GLUE_VERSION != api_assembly_ver.cs_glue_version; -#endif + if (!core_api_assembly_out_of_sync) { + GDMonoUtils::update_godot_api_cache(); + } +#else GDMonoUtils::update_godot_api_cache(); +#endif } return success; @@ -474,8 +481,10 @@ bool GDMono::_load_editor_api_assembly() { return true; #ifdef TOOLS_ENABLED - if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) + if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) { + print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated"); return false; + } #endif bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); @@ -533,16 +542,22 @@ bool GDMono::_load_api_assemblies() { if (OS::get_singleton()->is_stdout_verbose()) print_error("Mono: Failed to load Core API assembly"); return false; - } else { + } + + 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()) - print_error("Mono: Failed to load Editor API assembly"); - return false; - } -#endif + if (!_load_editor_api_assembly()) { + if (OS::get_singleton()->is_stdout_verbose()) + print_error("Mono: Failed to load Editor API assembly"); + return false; } + if (editor_api_assembly_out_of_sync) + return false; +#endif + return true; } @@ -708,43 +723,42 @@ Error GDMono::reload_scripts_domain() { #ifdef MONO_GLUE_ENABLED if (!_load_api_assemblies()) { - return ERR_CANT_OPEN; - } + if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) || + (editor_api_assembly && editor_api_assembly_out_of_sync)) { + // The assembly was successfully loaded, but the full api could not be cached. + // This is most likely an outdated assembly loaded because of an invalid version in the + // metadata, so we invalidate the version in the metadata and unload the script domain. - if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) { - // Everything is fine with the api assemblies, load the project assembly - _load_project_assembly(); - } else { - // The assembly was successfuly loaded, but the full api could not be cached. - // This is most likely an outdated assembly loaded because of an invalid version in the metadata, - // so we invalidate the version in the metadata and unload the script domain. - - if (core_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Core API assembly is out of sync"); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { - ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } + if (core_api_assembly_out_of_sync) { + ERR_PRINT("The loaded Core API assembly is out of sync"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { + ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } - if (editor_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Editor API assembly is out of sync"); - metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); - } + if (editor_api_assembly_out_of_sync) { + ERR_PRINT("The loaded Editor API assembly is out of sync"); + metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); + } - Error err = _unload_scripts_domain(); - if (err != OK) { - WARN_PRINT("Mono: Failed to unload scripts domain"); - } + Error err = _unload_scripts_domain(); + if (err != OK) { + WARN_PRINT("Mono: Failed to unload scripts domain"); + } - return ERR_CANT_RESOLVE; + return ERR_CANT_RESOLVE; + } else { + return ERR_CANT_OPEN; + } } - if (!_load_project_assembly()) + if (!_load_project_assembly()) { return ERR_CANT_OPEN; + } #else print_verbose("Mono: Glue disabled, ignoring script assemblies."); -#endif +#endif // MONO_GLUE_ENABLED return OK; } diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index 2fe05006f1..4f2efc7b92 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -44,9 +44,14 @@ struct ManagedType { int type_encoding; GDMonoClass *type_class; - ManagedType() { - type_encoding = 0; - type_class = NULL; + ManagedType() : + type_encoding(0), + type_class(NULL) { + } + + ManagedType(int p_type_encoding, GDMonoClass *p_type_class) : + type_encoding(p_type_encoding), + type_class(p_type_class) { } }; diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 1ad0a4a6ea..cc0ab5fa05 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -97,10 +97,14 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) { MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type); MonoObject *variant_to_mono_object(const Variant *p_var); -_FORCE_INLINE_ MonoObject *variant_to_mono_object(Variant p_var) { +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) { return variant_to_mono_object(&p_var); } +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { + return variant_to_mono_object(&p_var, p_type); +} + Variant mono_object_to_variant(MonoObject *p_obj); // Array diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 8fbaca0992..b97a24b09c 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -126,10 +126,11 @@ void MonoCache::clear_members() { class_RemoteAttribute = NULL; class_SyncAttribute = NULL; class_MasterAttribute = NULL; + class_PuppetAttribute = NULL; class_SlaveAttribute = NULL; class_RemoteSyncAttribute = NULL; class_MasterSyncAttribute = NULL; - class_SlaveSyncAttribute = NULL; + class_PuppetSyncAttribute = NULL; class_GodotMethodAttribute = NULL; field_GodotMethodAttribute_methodName = NULL; @@ -225,10 +226,11 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute)); CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute)); + CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute)); CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute)); CACHE_CLASS_AND_CHECK(RemoteSyncAttribute, GODOT_API_CLASS(RemoteSyncAttribute)); CACHE_CLASS_AND_CHECK(MasterSyncAttribute, GODOT_API_CLASS(MasterSyncAttribute)); - CACHE_CLASS_AND_CHECK(SlaveSyncAttribute, GODOT_API_CLASS(SlaveSyncAttribute)); + CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute)); CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute)); CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName")); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 96ff3e8116..ec3a57eb46 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -131,8 +131,9 @@ struct MonoCache { GDMonoClass *class_SyncAttribute; GDMonoClass *class_RemoteSyncAttribute; GDMonoClass *class_MasterSyncAttribute; - GDMonoClass *class_SlaveSyncAttribute; + GDMonoClass *class_PuppetSyncAttribute; GDMonoClass *class_MasterAttribute; + GDMonoClass *class_PuppetAttribute; GDMonoClass *class_SlaveAttribute; GDMonoClass *class_GodotMethodAttribute; GDMonoField *field_GodotMethodAttribute_methodName; diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp new file mode 100644 index 0000000000..f520706a0c --- /dev/null +++ b/modules/mono/utils/osx_utils.cpp @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* osx_utils.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "osx_utils.h" + +#include "core/print_string.h" + +#ifdef OSX_ENABLED + +#include <CoreFoundation/CoreFoundation.h> +#include <CoreServices/CoreServices.h> + +bool osx_is_app_bundle_installed(const String &p_bundle_id) { + + CFURLRef app_url = NULL; + CFStringRef bundle_id = CFStringCreateWithCString(NULL, p_bundle_id.utf8(), kCFStringEncodingUTF8); + OSStatus result = LSFindApplicationForInfo(kLSUnknownCreator, bundle_id, NULL, NULL, &app_url); + CFRelease(bundle_id); + + if (app_url) + CFRelease(app_url); + + switch (result) { + case noErr: + return true; + case kLSApplicationNotFoundErr: + break; + default: + break; + } + + return false; +} + +#endif diff --git a/modules/mono/utils/osx_utils.h b/modules/mono/utils/osx_utils.h new file mode 100644 index 0000000000..68479b4f44 --- /dev/null +++ b/modules/mono/utils/osx_utils.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* osx_utils.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "core/ustring.h" + +#ifndef OSX_UTILS_H + +#ifdef OSX_ENABLED + +bool osx_is_app_bundle_installed(const String &p_bundle_id); + +#endif + +#endif // OSX_UTILS_H |